رفتن به مطلب
جامعه‌ی برنامه‌نویسان مُدرن ایران

برنامه نویسی

  • نوشته‌
    21
  • دیدگاه
    14
  • مشاهده
    2,893

مشارکت‌کنندگان این وبلاگ

معرفی و راهنمای استفاده از نسخه‌بندی معنایی

کامبیز اسدزاده

68 بازدید


معرفی نسخه‌بندی معنایی ویرایش ۲.۰

در دنیای مدیریت نرم‌افزار مکان مخوفی به نام «جهنم وابستگی» (dependency hell) وجود دارد. هر چه سیستم شما بزرگتر باشد و بسته‌های (package) بیشتری با نرم‌افزار شما یکپارچه شده باشند، احتمال بیشتری وجود دارد که روزی خود را دراین گودال ناامیدی بیابید.

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

برای پاسخگویی به این مشکل، من یکسری قوانین و پیش‌نیازهای ساده را پیشنهاد میدهم که نحوهٔ تخصیص و افزایش شماره‌های نسخه را دیکته می‌کند. این قوانین برپایه‌ی شیوه‌های موجود رایج و گسترده‌ی در حال استفاده، هم در نرم‌افزارهای متن‌باز و غیر متن‌باز است، اگرچه لزوماً محدود به آن نیست. برای آنکه این سیستم کار کند نخست لازم است یک API عمومی (public) تعریف کنید. این امر ممکن است شامل مستندسازی، یا بوسیله‌ی خود کد مقید شده باشد. صرف نظر از این موضوع، مهم است که این API دقیق و واضح باشد. زمانیکه API عمومی خود را مشخص کردید، تغییرات آن را با افزایش معین شماره‌ی نسخه‌ی خود مرتبط می‌سازید. قالب نسخهای به صورت X.Y.Z را در نظر بگیرید. خطاهایی که تاثیری بر API ندارند، نسخه‌ی وصله (Patch) را افزایش می‌دهند، افزایش یا تغییر API که با نسخه‌های قبلی سازگار است، نسخه‌ی جزئی (Minor) را افزایش می‌دهند، و تغییرات API که با نسخه‌های قبل ناسازگار هستند، نسخه‌ی اصلی (Major) را افزایش می‌دهند.

SEMVER.png

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

به فرض اینکه نسخه‌ی MAJOR.MINOR.PATCH یا اصلی.جزیی.وصله داده شده است:

  1. شماره‌ی نسخه‌ی اصلی (MAJOR) را زمانی افزایش دهید که تغییرات API ناسازگار اعمال کرده‌اید،
  2. شماره‌ی نسخه‌ی جزئی (MINOR) را زمانی افزایش دهید که قابلیت‌هایی اضافه کرده‌اید که با نسخه‌های قبل سازگار هستند،
  3. شماره‌ی نسخه‌ی وصله (PATCH) را زمانی افزایش دهید که تصحیح خطاهایی (bug) اعمال کرده‌اید که با نسخه‌های قبل سازگار هستند.

برچسب‌های اضافی برای پیش‌نشر و ساختن فراداده به صورت پسوندهایی برای قالب MAJOR.MINOR.PATCH فراهم است.

ویژگی‌های نسخه‌بندی معنایی (SemVer)

کلمات کلیدی «باید»، «نباید»، «نیاز است»، «می‌بایست»، «نمی‌بایست»، «توصیه شده است»، «ممکن است» و «اختیاری» در این مستند می‌بایست بر مبنای آنچه در RFC 2119 تعریف شده است، معنا شوند.

  1. نرم‌افزارهایی که از نسخه‌بندی معنایی استفاده می‌کنند باید یک API عمومی اعلام کنند. این API می‌تواند در خود کد اعلام شود، یا به طور واضح در مستندسازی وجود داشته باشد. هر طور که انجام شود، می‌بایست دقیق و جامع باشد.

  2. یک شماره‌ی نسخه‌ی عادی باید قالب X.Y.Z را داشته باشه طوری که در آن X ،Y و Z اعداد صحیح غیرمنفی هستند و نباید صفر اضافه (leading zero) داشته باشند. X نسخه‌ی اصلی، Y نسخه جزیی، و Z نسخهٔ وصله است. هر عنصر باید به صورت شمارشی افزایش یابد. به عنوان مثال 1.9.0 -> 1.10.0 -> 1.11.0.

  3. زمانی‌که یک بسته‌ی نسخه‌بندی شده منتشر شد، محتوای آن نسخه نباید دستکاری شود. هرگونه تغییری باید به عنوان نسخه‌ی جدید منتشر شود.

  4. نسخه‌ی اصلی شمارهٔ صفر (0.y.z) برای توسعه‌های ابتدایی است. هرچیزی در هر زمانی ممکن است تغییر کند. API عمومی نمی‌بایست ماندگار در نظر گرفته شود.

  5. نسخهٔ 1.0.0 API عمومی را تعریف می‌کند. روشی که شمارهٔ نسخه‌ی بعد از این انتشار افزوده می‌شود، به این API عمومی و نحوهٔ تغییر آن وابسته است.

  6. نسخه‌ی وصله Z (x.y.Z | x > 0) باید در صورتی افزوده شود که تصحیح‌های خطای سازگار با نسخهٔ قبلی معرفی شده باشند. یک تصحیح خطا به عنوان یک تغییر داخلی تعریف می‌شود که رفتارهای نادرست را اصلاح می‌کند.

  7. نسخهٔ جزیی Y (x.Y.z | x > 0) باید در صورتی افزوده شود که عملکرد سازگار با نسخه‌های قبل جدیدی به API عمومی معرفی شده باشد. همچنین اگر هرگونه عملکرد API عمومی به عنوان منسوخ‌شده برچسب خورده باشد، این شماره باید افزوده شود. اگر عملکرد جدید یا بهبود قابل توجهی در کدهای داخلی معرفی شده باشد، ممکن است نسخهٔ جزیی افزوده شود. ممکن است که شامل تغییرات سطح وصله هم باشد. زمانیکه نسخه جزیی افزوده شود، نسخهٔ وصله باید به 0 بازنشانده شود.

  8. نسخه‌ی اصلی X (X.y.z | X > 0) باید در صورتی افزوده شود که هرگونه تغییرات ناسازگار با نسخه‌های قبل به API عمومی معرفی شده باشد. ممکن است این تغییرات شامل سطوح جزیی و وصله نیز باشد. نسخه‌ی جزئی و وصله زمانیکه نسخه‌ی اصلی افزوده می‌شود باید به 0 بازنشانی شوند.

  9. یک نسخه‌ی پیش‌انتشار ممکن است با اضافه کردن یک خط تیره و یک سری شناسه‌هایی که به وسیله‌ی نقطه از هم جدا ‌شده‌اند و بلافاصله به دنبال نسخه‌ی وصله می‌آیند، نشانه‌گذاری شود. شناسه‌ها باید تنها شامل اعداد و حروف الفبای اَسکی (ASCII) و خط تیره [A-Za-z0-9] باشند. شناسه‌ها نباید تهی باشند. شناسه‌های عددی نباید با صفر اضافه آغاز شوند. نسخه‌ی پیش‌انتشار از اولویت پایین‌تری نسبت به نسخه‌ی عادی مرتبط برخوردار است. یک نسخه‌ی پیش‌انتشار حاکی از آن است که نسخه‌ی ناپایدار است و ممکن است نیازمندی‌های سازگاری مورد نظر را آنگونه که در نسخه‌ی عادی مرتبط نشان داده شده است، برآورده نکند. مثال: 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92.

  10. متادیتای ساخت (build metadata) ممکن است با افزودن یک علامت جمع (+) و یک سری شناسه‌هایی که به وسیلهٔ نقطه ازهم جدا شده‌اند، و بلافاصله به دنبال نسخه‌ی وصله یا پیش‌انتشار می‌آیند، نشانه‌گذاری شود. شناسه‌ها باید تنها شامل اعداد و حروف الفبای اَسکی (ASCII) و خط تیره [A-Za-z0-9] باشند. شناسه‌ها نباید تهی باشند. متادیتای ساخت می‌بایست در زمان تعیین اولویت نسخه درنظر گرفته نشود. بنابراین دو نسخه که تنها در متادیتای ساخت با یکدیگر متفاوت هستند، اولویت یکسان دارند. مثال: 1.0.0-alpha+001, 1.0.0+20130313144700, 1.0.0-beta+exp.sha.5114f8

  11. اولویت اشاره دارد به اینکه چگونه نسخه‌ها زمانی‌که مرتب شده‌اند با یکدیگر مقایسه می‌شوند. اولویت باید به وسیله‌ی جداسازی نسخه به اصلی، جزیی، وصله و شناسه‌های پیش‌انتشار به همین ترتیب، محاسبه شود (متادیتای ساخت در اولویت نمایان نمی‌شود). اولویت، به وسیلهٔ اولین تفاوت تعیین می‌شود هنگامی که این مشخصه‌ها از چپ به راست مقایسه شوند، بدین صورت: نسخه‌های اصلی، جزیی و وصله همیشه به صورت عددی مقایسه می‌شوند. مثال: 1.0.0 < 2.0.0 < 2.1.0 < 2.1.1. زمانی که اصلی و جزیی و وصله برابر هستند، یک نسخهٔ پیش‌انتشار از اولویت کمتری نسبت به نسخهٔ عادی برخوردار است. مثال: 1.0.0- alpha < 1.0.0 اولویت برای دو نسخه‌ی پیش‌انتشار با نسخه‌ی اصلی، جزیی و وصله‌ی مشابه باید به وسیله‌ی مقایسه‌ی هر مشخصه‌ای که با نقطه جدا شده، از چپ به راست مشخص شود تا زمانی که یک تفاوت به شرح زیر یافت شود: شناسه‌هایی که تنها شامل اعداد صحیح هستند به صورت عددی و شناسه‌هایی که با حروف یا خط‌های تیره به صورت الفبایی به ترتیب ASCII مقایسه می شوند. مشخصه‌های عددی همیشه از اولویت کمتری نسبت به مشخصه‌های غیرعددی برخوردار هستند. مجموعه‌های بزرگتری از بخشهای پیش‌انتشار اولویت بیشتری نسبت به مجموعه‌های کوچکتر دارند، اگر همه مشخصه‌های اولویت برابر باشند. مثال: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0.

چرا از نسخه‌بندی معنایی استفاده شود؟

این ایده‌ای جدید یا انقلابی نیست. در واقع، احتمالاً شما چیزی مشابه به این را پیش از این انجام داده‌اید. مشکل اینجاست که «مشابه» به اندازه‌ی کافی خوب نیست. بدون انطباق با نوعی تعریف رسمی، شماره‌های نسخه ضرورتاً برای مدیریت وابستگی (dependency) بلااستفاده هستند. بوسیله‌ی اختصاص اعداد و تعاریف واضح به ایده‌های بالا، برقراری ارتباط میان کاربران نرم‌افزار شما و اهدافتان آسان‌تر می‌شود. به‌مجرد اینکه این اهداف واضح شود، مشخصات وابستگی انعطاف‌پذیر (نه آن‌چنان انعطاف‌پذیر) می‌تواند نهایتاً ایجاد شود.

یک مثال ساده می‌تواند نشان دهد که چگونه نسخه‌بندی معنایی می‌تواند جهنم وابستگی را به خاطره‌ای از گذشته تبدیل کند. کتابخانه‌ای به نام «Firetruck» را در نظر بگیرید. این کتابخانه به یک بسته به نام «Ladder» که به صورت معنایی نسخه‌بندی شده، احتیاج دارد. در زمانی که firetruck ساخته شده، Ladder در نسخه‌ی 3.1.0 است، شما می‌توانید وابستگی Ladder را با آسودگی به عنوان بزرگتر یا برابر با 3.1.0 و نه کمتر از 4.0.0 تعیین کنید. شما می‌توانید آن‌ها را در سیستم مدیریت بستهٔ خود منتشر کنید و بدانید که آن‌ها با نرم‌افزار وابسته موجود سازگار هستند.

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

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

 

سوالات متداول

چگونه باید با نسخه‌ها در فاز توسعه‌ی ابتدایی 0.y.z کنار بیایم؟

ساده‌ترین کار برای انجام دادن این است که توسعهٔ ابتدایی خود را از انتشار 0.1.0 آغاز کنید و سپس نسخهٔ جزیی را برای هر انتشار آتی افزایش دهید.

چگونه بدانم چه زمانی باید 1.0.0 را منتشر کنم؟

اگر نرم‌افزار شما در طول تولید مورد استفاده قرار گرفته است، احتمالاً می‌بایست هم‌اکنون 1.0.0 باشد. اگر یک API ماندگار دارید که کاربران روی آن حساب می‌کنند، شما باید 1.0.0 باشید. اگر در مورد سازگاری با نسخه‌های قبل خیلی نگران هستید، احتمالاً می‌بایست هم‌اکنون 1.0.0 باشید.

آیا این روش، توسعه و تکرار سریع را کند نمی کند؟

نسخه‌ی اصلی صفر تماماً در مورد توسعهٔ سریع است. اگر شما API را هر روز تغییر می‌دهید، یا باید هنوز در نسخه‌ی 0.y.z باشید یا در یک شاخه‌ی توسعه‌ی جداگانه که بر نسخه‌ی اصلی بعدی کار می‌کند هستید.

اگر حتی کوچکترین تغییرات ناسازگار با نسخه‌های قبل در API عمومی نیازمند یک نسخهٔ اصلی باشد، آیا من خیلی سریع به نسخه 42.0.0 نخواهم رسید؟

این سوال یک توسعه‌دهنده‌ی مسئولیت‌پذیر و آینده‌نگر است. تغییرات ناسازگار نمی‌بایست به راحتی در نرم‌افزاری که کدهای وابسته‌ی زیادی دارد معرفی شود. هزینه‌ای که برای ارتقاء باید متحمل شد می‌تواند قابل توجه باشد. اجبار برای ایجاد نسخه‌های اصلی برای انتشار تغییرات ناسازگار، یعنی شما به تأثیر تغییراتتان فکر خواهید کرد و نرخ هزینه/سود مورد نظر را خواهید سنجید.

مستندسازی تمامی API عمومی کار بسیار زیاد می‌برد!

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

چه کار می‌توانم بکنم اگر تصادفاً یک تغییر ناسازگار با نسخه‌های قبل را به عنوان نسخه‌ی جزئی منتشر کردم؟

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

چه کار باید بکنم اگر وابستگی‌های خودم را بدون تغییر دادن API عمومی به‌روزرسانی کردم؟

این مورد تا زمانی که API عمومی را متأثر نسازد سازگار تلقی خواهد شد. نرم‌افزاری که صریحاً به همان وابستگی‌هایی که بسته‌ی شما وابسته است، وابسته باشد، باید مشخصات وابستگی خود را داشته باشد و نویسنده باید هرگونه مغایرت را ذکر کند. تشخیص اینکه آیا تغییر ازنوع دستکاری در سطح جزیی است یا سطح وصله، به این بستگی دارد که آیا شما وابستگی‌های خود را جهت تصحیح یک خطا یا برای یک کاربرد جدید به‌روزرسانی کرده‌اید. من معمولاً کد اضافی برای موارد آتی در نظر می‌گیرم، که بدون شک این موارد افزایش سطح جزیی می‌باشد.

چه می شود اگر من بدون اعلام قبلی API عمومی را به صورتی تغییر دهم که با تغییر عدد نسخه سازگار نباشد؟ (یعنی کد به نادرست تغییر اصلی‌ای را در انتشار وصله معرفی می‌کند)

از بهترین قضاوت خود استفاده کنید. اگر شما مخاطبان زیادی دارید که به شدت به وسیله‌ی تغییر رفتار به آنچه قبلاً برای API عمومی در نظر گرفته شده، متأثر خواهند شد، پس بهترین کار انجام یک انتشار نسخه‌ی اصلی است، حتی اگر اصلاح اعمال شده مؤکداً یک انتشار وصله محسوب شود. به یاد داشته باشید، نسخه‌بندی معنایی تماماً درباره‌ی انتقال معنا بوسیله چگونگی تغییر عدد نسخه می‌باشد. اگر این تغییرات برای کاربران شما مهم است، از عدد نسخه برای آگاه‌سازی آن‌ها استفاده کنید.

چگونه باید با منسوخ کردن عملکرد (deprecating functionality) کنار بیایم؟

منسوخ کردن عملکرد موجود بخشی عادی از توسعه‌ی نرم‌افزار است و معمولاً برای این‌که پیشرفت رو به جلو حاصل شود مورد نیاز است. زمانی‌که بخشی از API عمومی خود را منسوخ می‌کنید، باید دو کار انجام دهید: ۱) مستندسازی خود را به‌روزرسانی کنید تا به کاربر اجازه دهید از تغییرات باخبر شود. ۲) یک انتشار جزیی که در آن قسمت منسوخ شده در جایگاه خود باشد منتشر کنید. قبل از آنکه عملکرد را به طورکامل در یک انتشار اصلی حذف کنید حتماً باید حداقل یک انتشار جزیی که شامل قسمت منسوخ شده است وجود داشته باشد تا کاربران به راحتی بتوانند به API جدید منتقل شوند.

آیا SemVer محدودیت اندازه بر روی رشته‌ی نسخه دارد؟

خیر، اما از قضاوت مناسبی استفاده کنید. به عنوان مثال یک نسخه‌ی ۲۵۵ نویسه‌ای احتمالاً مفید نخواهد بود! همچنین، سیستم‌های خاص ممکن است محدودیت‌های خود برای اندازه‌ی رشته اعمال کنند.

- منبع

  • پسندیدن 1
  • ترکوندی! 1
  • تشکر شده 1


2 دیدگاه


نظرهای پیشنهاد شده

اصولا همیشه اعتقاد دارم که کسی که یک مطلب آموزشی را مورد پسند قرار میده باید خودش از درجه علمی بالایی برخوردار باشه که بتونه بگه مورد پسندم هست یانه!

وبرای همین که من دراین سطح نیستم! که فقط بگم پسندیدم! قطعا فقط میتونم بگم تشکر بسیار آموزش مفیدی بود، جناب اسدزاده

به اشتراک گذاری این دیدگاه


لینک به دیدگاه
در 1 ساعت قبل، فرهاد شیری گفته است :

اصولا همیشه اعتقاد دارم که کسی که یک مطلب آموزشی را مورد پسند قرار میده باید خودش از درجه علمی بالایی برخوردار باشه که بتونه بگه مورد پسندم هست یانه!

وبرای همین که من دراین سطح نیستم! که فقط بگم پسندیدم! قطعا فقط میتونم بگم تشکر بسیار آموزش مفیدی بود، جناب اسدزاده

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

به اشتراک گذاری این دیدگاه


لینک به دیدگاه
مهمان
افزودن دیدگاه

×   شما در حال چسباندن محتوایی با قالب بندی هستید.   حذف قالب بندی

  تنها استفاده از ۷۵ اموجی مجاز می باشد.

×   لینک شما به صورت اتوماتیک جای گذاری شد.   نمایش به عنوان یک لینک به جای

×   محتوای قبلی شما بازگردانی شد.   پاک کردن محتوای ویرایشگر

×   شما مستقیما نمی توانید تصویر خود را قرار دهید. یا آن را اینجا بارگذاری کنید یا از یک URL قرار دهید.

  • کاربران آنلاین در این صفحه   0 کاربر

    هیچ کاربر عضوی،در حال مشاهده این صفحه نیست.

×
×
  • جدید...