نقش و اهمیت نسخه‌زدن در نرم‌افزار

بسمه تعالی

نسخه آقا! نسخه! نسخه مهمه. اگر درست نسخه نزنیم، مدیریت چرخه حیات آرتیفکت‌های نرم‌افزاری از دست‌تون خارج میشه.

1. چی رو نسخه بزنیم؟

از همه مهمتر «کد» باید نسخه بخوره. وقتی کد به نقطه‌ای رسید که خواستیم release بدیم، اول نسخه می‌زنیم. شماره نسخه قاعدتاً یه جاهایی در کد منعکس میشه. ما جاواکارها در فایل تنظیمات maven یا gradle میگذرایمش. مثل این و این. در مرحله بعد باید شماره نسخه در نام آرتیفکت‌هایی که از روی اون کد ساخته شده ظاهر بشه. مثلاً در jar فایل یا داکر ایمیجی که از روی کد می‌سازید. مثل اینها.

2. آرتیفکت Immutable یعنی چی؟

اگر قرار باشه آرتیکفت‌هامون Immutable یا غیر قابل تغییر باشند، با کمترین تغییر کد، لازمه شماره نسخه رو تغییر بدیم. با شماره جدید، دوباره روی گیت تگ می‌زنیم و یک آرتیفکت با نام جدید می‌سازیم. اینطوری از روی نام آرتیفکت دقیقاً میشه فهمید با چه نسخه‌ای از کد طرف هستیم. دیگه دو جور نسخه x نداریم. کش کردن آرتیفکت‌ها هم امکان‌پذیر میشه.

3. نسخه زدن به چه دردی می‌خوره؟

کدها تغییر می‌کنند. با تغییر کدها، آرتیفکت‌های جدید ساخته میشه. آرتیفکت‌ها، نصب و اجرا میشن. وقتی همه چی نسخه داشته باشه، اگر باگی پیش بیاد خیلی راحت می‌تونیم کدی که باگ داره رو پیدا کنیم. در حالیکه ممکنه اون کد نسبت به چیزی که نصب شده، چندین بار تغییر کرده باشه. همین‌طور اگر بخواهیم روی آرتیفکت در حال اجرا تغییر و توسعه جزئی داشته باشیم، کد اون نسخه رو از روی تگ‌های گیت پیدا می‌کنیم، تغییر میدیم و دوباره نسخه می‌زنیم.

4. نسخه رو چطور نامگذاری کنیم؟


رایج‌ترین قالب نام‌گذاری نسخه‌ها Semantic Versioning نام داره. در این قالب اسم نسخه از سه بخش major version و minor version و patch version تشکیل میشه مثل 1.2.0 یا 9.2.20 . هر توسعه‌ای در کد اتفاق بیفته minor version افزایش پیدا می‌کنه و همزمان patch version برمیگرده روی صفر. مثلاً از 1.2.5 میریم روی 1.3.0. اگر توسعه خیلی اساسی باشه و مخصوصاً ‌Backward Compatible نباشه major version میره بالا و minor version و patch version ریست میشه روی صفر. مثلاً از 1.2.5 میره به 2.0.0. اگر تغییر کد فقط در راستای رفع باگ باشه یا به عبارتی specification کد تغییر نکنه و فقط implementation اصلاح بشه، عدد سوم زیاد میشه مثلاً از 1.2.5 میریم روی 1.2.6.

5. دیگه چی رو نسخه بزنیم؟

یکی از جاهای مهم دیگه که نسخه ثبت میشه Issue ها هستند. نسخه‌های مختلف نرم‌افزار (مثل 1.9.1و 1.9.0) در Issue Tracker پروژه (مثل جیرا) تعریف میشه و به ازای هر Issue مشخص میشه که تغییرات روی چه نسخه‌ای (یا چه نسخه‌هایی) اعمال شده. برای ثبت این داده، جیرا فیلدی به نام Fix Version پیش‌بینی کرده. معمولاً رفع ‌باگ روی چندین نسخه (که تحت پشتیبانی فعال هستند) همزمان اعمال میشه و بنابراین در ایشوهای از نوع باگ، ثبت چند Fix Version طبیعیه. اگر Fix Version رو در Issue Tracker ثبت کنیم، به صورت خودکار برای هر نسخه‌ای که ترخیص کنیم Release Notes خواهیم داشت.

6. رابطه سیاست‌های پشتیبانی و نسخه‌ها

نرم‌افزارها و کتابخانه‌ها معمولاً همه نسخه‌های قبلی رو به صورت فعال پشتیبانی نمی‌کنند. یعنی اگر باگی پیدا بشه روی همه نسخه‌های قبلی فیکسش نمی‌کنند. یک یا چند بازه از نسخه‌ها تحت پشتیبانی هستند. یعنی میگن از فلان نسخه تا فلان نسخه تحت پشتیبانی هستند.

مثلاً از 1.9 تا 1.10 به علاوه 2.1 تا 2.3. بعضی‌ها سیاست‌های از پیش تعیین شده دارند مثلاً از قبل اعلام می‌کنند شش ماه از هر major version پشتیبانی می‌کنند. برخی از نسخه‌ها به عنوان LTS (یا Long Time Support) معرفی میشن. یعنی دوره پشتیبانی‌شون طولانی‌تره مثلاً سه سال. یک نگاهی به برنامه پشتیبانی نسخ جاوا بیندازید.

7. نسخه snapshot یا pre-release چیه؟

وسط اسپرینت که مشغول کد زدن هستیم و قصد ترخیص و نصب نداریم، لازم نیست با هر تغییری نسخه زده بشه. پس شماره نسخه رو با پسوند SNAPSHOT مشخص می‌کنیم. در واقع میشه گفت نسخه SNAPSHOT یه جورایی immutable نیست. بنابراین قابل کش هم نیستند یا موقع کش کردن باید براشون سیاست به‌روزرسانی مشخص کنید. یعنی تعیین کنید روزی یه بار یا ساعتی یه بار یا حتی هر بار نسخه جدید دانلود بشه.

8. مرور همه چی کنار هم

فرض کنید که برای مخزن کد از گیت و برای مدیریت پروژه از جیرا استفاده می‌کنیم و یک پروژه جاوایی داریم که کار build اش رو به maven سپردیم. گامهای اول پروژه اینطور برداشته میشه:

  • 1) پروژه رو می‌سازیم. نسخه توی pom.xml رو برابر 1.0.0-SNAPSHOT مقدار میدیم. اولین فایلهای پروژه در شاخه master پوش میشه.
  • 2) هر تسکی رو انجام دادیم کدش رو کامیت و پوش می‌کنیم. فعلاً در pom.xml، نسخه تغییر نمی‌کنه و هر تسکی که انجام میشه و کدش میاد داخل مخزن گیت، fix version اون تسک در جیرا رو 1.0.0 می‌گذاریم.
  • 3) وقتی تصمیم گرفتیم release بدیم، نسخه در pom.xml به 1.0.0 تغییر می‌کنه و کامیت و پوش میشه. یعنی پسوند SNAPSHOT حذف میشه.
  • 4) روی مخزن گیت، از روی شاخه master تگ 1.0.0 ساخته میشه.
  • 5) از روی شاخه master، آرتیفکت با نسخه 1.0.0ساخته میشه مثلاً myapp-1.0.0. jar
  • 6) در شاخه master در فایل pom.xml نسخه رو یکی می‌بریم بالا. یعنی میریم روی نسخه 1.1.0-SNAPSHOT.
  • 7) در جیرای پروژه نسخه 1.0.0 رو release میدیم و نسخه 1.1.0 رو باز می‌کنیم.

در ظاهر کار طولانی و سخت شد. ولی عمده کارها مثل ساخت تگ و تولید آرتیفکت‌ها رو میشه به پایپلاین CI/CD سپرد.

۹. اگر باگی روی 1.0.0 گزارش بشه چه کنیم؟

  • ۱) موقع ترخیص تگ 1.0.0 رو ساخته بودیم. از روی این تگ شاخه‌ای به نام 1.0.x می‌سازیم. در اسم شاخه به جای patch version از حرف x استفاده کردیم. چون برای patch version های بعدی هم از همین شاخه استفاده می‌کنیم.
  • ۲) در فایل pom.xml مقدار نسخه رو از 1.0.0 به 1.0.1-SNAPSHOT تغییر میدیم.
  • ۳) اصلاحات رو در کدها اعمال و در شاخه 1.0.x کامیت و پوش می‌کنیم.
  • ۴) کار که تموم شد، نسخه رو در pom.xml به 1.0.1 تغییر میدیم (یعنی «SNAPSHOT» رو از تهش برمی‌داریم) و کامیت و پوش می‌کنیم.
  • ۵) در مخزن گیت، تگ 1.0.1 رو از روی برنچ 1.0.x می‌سازیم.
  • ۶) آرتیفکت با نسخه 1.0.1 ساخته میشه مثلاً myapp-1.0.1. jar
  • ۷) در ایشوی رفع باگ در جیرا مقدار fix version رو برابر 1.0.1 قرار میدیم.

‫۱۰. از پایپ‌لاین CI/CD کمک بگیرید

‫در ظاهر کار طولانی و سخت شد. ولی عمده کارها مثل ساخت تگ و تولید آرتیفکتها رو میشه به پایپلاین CI/CD سپرد. اینطوری هم سرعت بالاتر میره و هم مطمئن هستیم همه مراحل به صورت منظم انجام میشه. مثلاً مطمئن میشیم که هر آرتیفکتی ساخته شده حتماً روی گیت، تگ معادلش موجوده.