تبدیلگر ایران سیستم به یونیکد
- Pre-alpha
این مرحله شامل تمام فعالیتهای انجام شده قبل از مرحله تست میباشد. در این دوره آنالیز نیازمندیها، طراحی نرم افزار، توسعه نرم افزار و حتی تست واحد باشد. در نرم افزارهای سورس باز چندین نسخه قبل از آلفا ممکن است عرضه شوند. - Alpha
این مرحله شامل همه فعالیتها از زمان شروع تست میباشد. البته منظور از تست، تست تیمی و تست خود نرم افزار میباشد. نرم افزارهای آلفا هنوز ممکن است خطا و اشکالاتی داشته باشند و ممکن است اطلاعات شما از بین رود. در این مرحله امکانات جدیدی مرتبا به نرم افزار اضافه میگردد. - Beta
نرم افزار بتا، همه قابلیتهای آن تکمیل شده و خطاهای زیادی برای کامل شدن نرم افزار وجود دارد. در این مرحله بیشتر به تست کاهش تاثیرات به کاربران و تست کارایی دقت میشود. نسخه بتا، اولین نسخهای خواهد بود که بیرون شرکت و یا سازمان در دسترس قرار میگیرد. برخی توسعه دهندگان به این مرحله preview، technical preview یا early access نیز میگویند. - Release candidate
در این مرحله نرم افزار، آماده عرضه به مصرف کنندگان است و نرم افزارهایی مثل سیستم عاملهای ویندوز در دسترس تولید کنندگان قرار گرفته تا با جدیدترین سخت افزار خود یکپارچه شوند. -
General availability (GA)
در این مرحله، عرضه عمومی نرم افزار و بازاریابی و فروش نرم افزار مد نظر است و علاوه بر این تست امنیتی و در نرم افزارهای خیلی بزرگ عرضه جهانی صورت میگیرد
- Major Version
وقتی افزایش مییابد که تغییرات قابل توجهی در نرم افزار ایجاد شود - Minor Version
وقتی افزایش یابد که ویژگی جزئی یا اصلاحات قابل توجهی به نرم افزار ایجاد شود. - Build Number
به ازای هر بار ساخته شدن پروژه افزایش مییابد. - Revision
وقتی افزایش مییابد که نواقص و باگهای کوچکی رفع شوند.
major.minor[.build[.reversion]]
major.minor[.maintenance[.build]]
به عنوان یک راه حل، مجموعهی سادهای از قوانین و الزامات که چگونگی طراحی شمارههای نسخه و افزایش آن را مشخص میکند، وجود دارد. برای کار کردن با این سیستم، شما ابتدا نیاز به اعلام API عمومی دارید. این خود ممکن است شامل مستندات و یا اجرای کد باشد.
علیرغم آن، مهم است که این API، روشن و دقیق باشد. هنگامیکه API عمومی خود را تعیین کردید، تغییرات برنامه شما بر روی نسخه API عمومی تاثیر خواهد داشت و آنرا افزایش خواهد داد. بر این اساس، این مدل نسخهبندی را در نظر بگیرید: X.Y.Z یعنی (Major.Minor.Patch).
رفع حفرههایی که بر روی API عمومی تاثیر نمیگذارند، مقدار Patch را افزایش میدهند، تغییرات جدیدی که سازگار با نسخه قبلی است، مقدار Minor را افزایش میدهند و تغییرات جدیدی که کاملا بدیع هستند و به نحوی با تغییرات قبلی سازگار نیستند مقدار Major را افزایش میدهند.
- نرمافزارهایی که از نسخه بندی معنایی استفاده میکنند، باید یک API عمومی داشته باشند. این API میتواند در خود کد یا و یا به طور صریح در مستندات باشد که باید دقیق و جامع باشد.
- یک شماره نسخه صحیح باید به شکل X.Y.Z باشد که در آن X،Y و Z اعداد صحیح غیر منفی هستند. X نسخهی Major میباشد، Y نسخهی Minor و Z نسخهی Patch میباشد. هر عنصر باید یک به یک و بصورت عددی افزایش پیدا کند. به عنوان مثال: 1.9.0 -> 1.10.0 -> 1.11.0
- هنگامی که به یک نسخهی Major یک واحد اضافه میشود، نسخهی Minor و Patch باید به حالت 0 (صفر) تنظیم مجدد گردد. هنگامی که به شماره نسخهی Minor یک واحد اضافه میشود، نسخهی Patch باید به حالت 0 (صفر) تنظیم مجدد شود. به عنوان مثال: 1.1.3 -> 2.0.0 و 2.1.7 -> 2.2.0
- هنگامیکه یک نسخه از یک کتابخانه منتشر میشود، محتوای کتابخانه مورد نظر نباید به هیچ وجه تغییری داشته باشد. هر گونه تغییر جدیدی باید در قالب یک نسخه جدید انتشار پیدا کند.
- نسخهی Major صفر (0.Y.Z) برای توسعهی اولیه است. هر چیزی ممکن است در هر زمان تغییر یابد. API عمومی را نباید پایدار در نظر گرفت.
- نسخه 1.0.0 در حقیقت API عمومی را تعریف میکند. چگونگی تغییر و افزایش هر یک از نسخهها بعد از انتشار این نسخه، وابسته به API عمومی و تغییرات آن میباشد.
- نسخه Patch یا (x.y.Z | x > 0) فقط در صورتی باید افزایش پیدا کند که تغییرات ایجاد شده در حد برطرف کردن حفرههای نرمافزار باشد. برطرف کردن حفرههای نرمافزار شامل اصلاح رفتارهای اشتباه در نرمافزار میباشد.
- نسخه Minor یا (x.Y.z | x > 0) فقط در صورتی افزایش پیدا خواهد کرد که تغییرات جدید و سازگار با نسخه قبلی ایجاد شود. همچنین این نسخه باید افزایش پیدا کند اگر بخشی از فعالیتها و یا رفتارهای قبلی نرمافزار به عنوان فعالیت منقرض شده اعلام شود. همچنین این نسخه میتواند افزایش پیدا کند اگر تغییرات مهم و حیاتی از طریق کد خصوصی ایجاد و اعمال گردد. تغییرات این نسخه میتواند شامل تغییرات نسخه Patch هم باشد. توجه به این نکته ضروری است که در صورت افزایش نسخه Minor، نسخه Patch باید به 0 (صفر) تغییر پیدا کند.
- نسخه Major یا (X.y.z | X > 0) در صورتی افزایش پیدا خواهد کرد که تغییرات جدید و ناهمخوان با نسخه فعلی در نرمافزار اعمال شود. تغییرات در این نسخه میتواند شامل تغییراتی در سطح نسخه Minor و Patch نیز باشد. باید به این نکته توجه شود که در صورت افزایش نسخه Major، نسخههای Minor و Patch باید به 0 (صفر) تغییر پیدا کنند.
- یک نسخه قبل از انتشار میتواند توسط یک خط تیره (dash)، بعد از نسخه Patch (یعنی در انتهای نسخه) که انواع با نقطه (dot) از هم جدا میشوند، نشان داده شود. نشانگر نسخه قبل از انتشار باید شامل حروف، اعداد و خط تیره باشد [0-9A-Za-z-]. باید به این نکته دفت داشت که نسخههای قبل از انتشار خود به تنهایی یک انتشار به حساب میآیند اما اولویت و اهمیت نسخههای عادی را ندارد. برای مثال: 1.0.0-alpha ، 1.0.0-alpha.1 ، 1.0.0-0.3.7 ، 1.0.0-x.7.z.92
- یک نسخه Build میتواند توسط یک علامت مثبت (+)، بعد از نسخه Patch یا نسخه قبل از انتشار (یعنی در انتهای نسخه) که انواع آن با نقطه (dot) از هم جدا میشوند، نشان داده شود. نشانگر نسخه Build باید شامل حروف، اعداد و خط تیره باشد [0-9A-Za-z-]. باید به این نکته دقت داشت که نسخههای Build خود به تنهایی یک انتشار به حساب میآیند و اولویت و اهمیت بیشتری نسبت به نسخههای عادی دارند. برای مثال: 1.0.0+build.1 ، 1.3.7+build.11.e0f985a
- اولویتبندی نسخهها باید توسط جداسازی بخشهای مختلف یک نسخه به اجزای تشکیل دهنده آن یعنی Minor، Major، Patch، نسخه قبل از انتشار و نسخه Build و ترتیب اولویت بندی آنها صورت گیرد. نسخههای Minor، Major و Patch باید بصورت عددی مقایسه شوند. مقایسه نسخههای قبل از انتشار و نسخه Build باید توسط بخشهای مختلف که توسط جداکنندهها (نقطههای جداکننده) تفکیک شده است، به این شکل سنجیده شود:
بخشهایی که فقط حاوی عدد هستند، بصورت عددی مقایسه میشوند و بخشهایی که حاری حروف و یا خط تیره هستند بصورت الفبایی مقایسه خواهند شد.
بخشهای عددی همواره اولویت پایینتری نسبت به بخشهای غیر عددی دارند. برای مثال:
1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0-rc.1+build.1 < 1.0.0 < 1.0.0+0.3.7 < 1.3.7+build < 1.3.7+build.2.b8f12d7 < 1.3.7+build.11.e0f985a
منبع نسخه بندی معنایی : semver.org
یادگیری ماشین (ML) ، که بسیاری از صنایع را بهبود بخشیده است ، به تازگی شروع به تست نرم افزارها میکند. این صنعت دیگر هرگز مانند گذشته نخواهد بود. در حالی که یادگیری ماشین هنوز در حال رشد و تکامل است ، صنعت نرم افزار بیشتر و بیشتر از آن استفاده میکند ، و تأثیر آن شروع به تغییر قابل توجهی در روش آزمایش نرم افزار با پیشرفت فناوری میکند. ..
در مقالهی قبلی وقتی نسخهی یک اسمبلی را مشخص میکردیم، از 4 عدد که با نقطه از هم جدا شده بودند، استفاه کردیم که در جدول زیر این 4 نامگذاری را مشاهده میکنید:
شماره بازبینی Revision Number | شماره ساخت Build Number | شماره جزئی Minor Number | شماره اصلی Major Number |
2 | 719 | 5 | 2 |
اسمبلی بالا به ورژن یا نسخهی 2.5.719.2 اشاره دارد که دو شمارهی اول (2.5) مثل تمامی برنامهها به میزان تغییرات کارکردی یک اسمبلی اشاره دارد و عموم مردم هم نسخه یک نرم افزار را به همین دو عدد میشناسند. عدد سوم به این اشاره دارد که در شرکت، این ورژن از اسمبلی چندبار build شده است و شما باید به ازای هر Build این عدد را افزایش دهید. عدد آخری به این اشاره دارد که در طول روز انتشار، این چندمین Build بوده است. اگر در زمان ارائهی این اسمبلی باگ مهمی در آن یافت شود، با هر بار Build آن در یک روز، باید این عدد افزایش یابد و برای روزهای آتی این مقدار مجددا آغاز میشود. مایکروسافت از این سیستم نسخه بندی استفاده میکند و بسیار توصیه میشود که توسعه دهندگان هم از این روش تبعیت کنند.
در جدول سابق شما متوجه شدید که سه نسخه بندی را میتوان روی یک اسمبلی اعمال کرد که به شرح زیر است:
AssemblyFileVersion: این شماره نسخه در منابع اطلاعاتی Win32 ذخیره میگردد و کاربرد آن تنها جهت نمایش این اطلاعات است و CLR هیچ گونه ارجاع یا استفادهای از آن ندارد. در حالت عادی، شما باید دو شماره اولی را جهت نمایش عمومی مشخص کنید. سپس با هر بار Build کردن، شمارههای ساخت و بازبینی را هم به همان ترتیب افزایش میدهید. حالت ایدهآل این است که ابزار AL یا CSC به طور خودکار با هر بار Build شدن، با توجه به زمان سیستم، به طور خودکار این دو شماره آخر را مشخص کنند ولی متاسفانه واقعیت این است که چنین کاری صورت نمیگیرد. این اعداد جهت نمایش و شناسایی اسمبلی برای اشکال زدایی مشکلات اسمبلی به کار میرود.
AssemblyInformationalVersion: این شماره نسخه هم در منابع اطلاعاتی Win32 ذخیره میگردد و تنها هدف اطلاعاتی دارد. مجددا اینکه CLR هیچ گونه اهمیتی به آن نمیدهد. این شماره نسخه به محصولی اشاره میکند که شامل این اسمبلی است.
به عنوان مثال ورژن 2 یک نرم افزار ممکن است شامل چند اسمبلی باشد که ورژن یکی از این اسمبلیها یک است و دلیلش هم این است که این اسمبلی از نسخهی 2 به بعد اضافه شده و در نسخهی یک نرم افزار وجود نداشته است. به همین دلیل در این مدل از نسخه بندی شما دو شماره اول را به نسخه خود نرم افزار مقداردهی کرده و سپس مابقی اعداد را با هر بار پکیج شدن کل نرم افزار با توجه به زمان افزایش میدهید.
AssemblyVersion: این شماره نسخه در جدول متادیتای AssemblyDef ذخیره میگردد. CLR از این شماره نسخه جهت اتصال نام قوی Strongly Named به اسمبلی استفاده میکند (این مورد در فصل سه کتاب توضیح داده شده است). این شماره نسخه بسیار مهم بوده و به عنوان شناسهی یکتا برای اسمبلی استفاده میشود.
موقعیکه شما شروع به توسعهی یک اسمبلی میکنید، باید هر 4 شماره نسخه را مقداردهی کرده و تا زمانیکه توسعهی نسخه بعدی آن اسمبلی را آغاز نکردهاید، نباید آن را تغییر دهید. علت اصلی آن این است که موقعیکه اسمبلی «الف» با یک نام قوی به اسمبلی «ب» ارجاع میکند، نسخهی اسمبلی «ب» در ورودی جدول AssemblyRef اسمبلی «الف» قرار گرفته است. این مورد باعث میشود زمانیکه CLR به بارگزاری اسمبلی «ب» احتیاج دارد، دقیقا میداند که چه نسخهای با اسمبلی «الف» ساخته و تست شده است . البته این احتمال وجود دارد که CLR نسخهای متفاوت از اسمبلی را با Binding Redirect بار کند که ادامهی این مباحث در فصل سوم دنبال میشود.
مایکرو سرویس چیست ؟
در یک تعریف کوتاه، در معماری مایکرو سرویس، توسعه یک نرم افزار بهصورت مجموعهای از سرویسهای کوچک میباشد که این سرویسها بهصورت کاملا مستقلی قابلیت استقرار دارند و هر کدام از این سرویسها میتوانند توسط تیمهای جداگانهای با پلتفرم توسعه و زبان برنامه نویسی و بانک اطلاعاتی جداگانهای توسعه داده شوند و با یک مکانیزم سبک وزن مانند Http با یکدیگر در ارتباط باشند.چرا معماری مایکرو سرویس؟
در مطالب بعدی در موردی مشخصههای مایکرو سرویسها صحبت خواهیم کرد.
Defensive Coding به معنی است که شما با انجام یکسری کارها و در نظر گرفتن یکسری زیر ساختها در توسعهی نرم افزار خود، به اهداف ذیل دست پیدا کنید:
1. Quality (کیفیت)
2. Comprehensible (جامعیت)
3. Predictable (قابلیت پیش بینی)
دستیابی به هر کدام از این اهداف و روشهای اعمال آنها بر روی یک پروژهی نرم افزاری، در ادامه بحث خواهند شد.
1. Clean Code
یکی از اهداف Defensive Coding که در ابتدای مقاله بحث شد جامعیت یا Comprehension بود. برای رسید به این هدف از مفهومی به نام Clean Code استفاده میشود. Clean Code علاوه بر این مسئله، در پی ساده کردن ساختار بندی پشتیبانی و کاهش باگهای نرم افزار نیز هست. ویژگیهای Clean Code در بالا با توجه به شکل ذیل تشریح میشوند:
· Easy to read
یک کد Clean قابلیت خوانایی بالایی دارد. بسیاری از برنامه نویسان در سطوح مختلف با اهمیت این مسئله در توسعه نرم افزار آشنایی دارند. ولی بسیاری از همین برنامه نویسان این اصول را رعایت نمیکنند و سعی نمیکنند با اصول پیاده سازی آن در نرم افزارآشنا شوند.
اگر قابلیت خوانایی یک کد بالا باشد:
§ شما میتوانید Pattern های موجود در کد خود را که میتوانید به عنوان نامزدهایی جهت Refactoring هستند، تشخیص دهید.
§ برنامه نویسان دیگر به راحتی قصد و اهداف ( intent ) شما را از نوشتن یک کد خاص درک خواهند کرد و در طول زمان با خطاهای زیادی روبرو نمیشوند.
§ توسعهی راحتتر و در شرایط وجود فشار، ایجاد سریع یک قابلیت جدید در نرم افزار.
· Clear intent
یک کد Clear دارای اهداف روشن و قابل فهمی میباشد.
· Simple
پیچیدگی با کم هزینه بودن توسعهی و پشتیبانی تضاد مستقیم دارد. بنابراین سادگی در کدها باید جزو اهداف اصلی قرار بگیرد.
· Minimal
کد باید به گونهای باشد که تنها یک چیز را انجام داده و آن را به درستی انجام دهد. همچنین وابستگی بین اجزای کد باید در کمترین حد ممکن باشند.
· Thoughtful
یک کد Clean کدی است که ساختار آن متفکرانه طراحی شده باشد. از نحوهی طراحی یک کلاس گرفته تا layering و Tiering پروژه باید کاملا هوشمندانه و با توجه به پارامترهای موجود باشند. همچنین خطاهای خطرناک و استثناءها باید کاملا هندل شوند.
همهی ما با دیدن کد بالا سریعا مفهوم اسپاگتی کد به ذهنمان خطور میکند. تغییر، توسعه و پشتیبانی نرم افزارهایی که کد آنها به این صورت نوشته شده است، بسیار سخت و پر هزینه میباشد. در این حالت تغییر هر یک از اجزاء ممکن است بر سایر قسمتهای دیگر تاثیرات مختلفی داشته باشد. راه کاری که در این حالت ارائه میشود، Refactoring میباشد. در این روش کد را به کلاسها و متدهایی بر حسب عملکرد تقسیم خواهیم کرد. در نهایت کد تولید شده دارای کمترین تاثیر بر سایر قسمتها خواهد بود. توجه داشته باشید که با انجام این کار، قدمی به سوی SOC یا Separation Of Concern برداشتهاید.
1. Testable Code & Unit Test
یکی دیگر از اهداف Defensive Coding افزایش کیفیت یا Quality میباشد که برای رسیدن به این هدف از مفهوم Testable Code & Unit Test استفاده میشود. بسیاری از ویژگیهای Testable Code و Clean Code با هم مشابه میباشند. برای مثال Refactor کردن هر متد به متدهای کوچکتر، تست آن را سادهتر خواهند کرد. در نتیجه نوشتن کدهای Testable ، با نوشتن کدهای clean شروع میشود.
در این قسمت اشارهای به Unit Test شده است؛ اما این مفهوم میتواند به یک مفهوم گستردهتر به نام Automated Code testing، تعمیم داده شود. به این دلیل که تست فقط به Unit Testing محدود نمیشود و میتواند شامل سایر انواع تستها مانند integration test نیز باشد.
برای مثال شکل ذیل را در نظر بگیرید. در انتهای این سناریو یک Page جدید اضافه شده است. خوب؛ برای تست کد اضافه شده، مجبورید برنامه را اجرا کنید، login کنید، دادههای مورد نظر را در فرم وارد کرده و در نهایت شرایط لازم را جهت تست، فراهم کنید تا بتوانید کد جدید را تست کنید. در این بین با خطایی مواجه میشوید. پس برنامه را متوقف میکنید و تغییرات لازم را اعمال میکنید. حال فرض کنید این خطا به این زودیها رفع نشود. در این حالت باید فرآیند بالا را چندین و چند بار انجام دهید. نتیجه اینکه این روش بسیار زمان بر و پر هزینه خواهد بود. البته میزان هزینه و زمان رابطهی نزدیکی با وسعت تغییرات دارند. برای رفع مسائلی از این دست مایکروسافت زیرساختی به نام MS Test ارائه داده است که میتوان با آن سناریوهای تست متفاوتی را پیاده سازی و اجرا نمود. متاسفانه این مسئله در بسیار از جوامع توسعه نرم افزار رعایت نمیشود و در بسیاری از این جوامع، نیروی انسانی، این فرآیند و فرآیندهایی از این دست را انجام میدهند. درحالیکه چنین فرآیندهایی به راحتی توسط ابزارهای ارائه شدهی توسط شرکتهای مختلف قابل مدیریت است.
1. Predictability
یکی دیگر از اهداف Defensive Coding، قابلیت پیش بینی یا Predictability میباشد. فرآیند تشخیص و پیش بینی خطاها را Predictability میگویند. با درنظر گرفتن امکان وقوع خطاهای مختلف و تصمیم گرفتن در مورد اینکه در هنگام رخ دادن این خطا باید چه کاری صورت بگیرد، میتوان در رسیدن به این هدف قدم بزرگی برداشت.
برای رسیدن به این هدف باید اصل Trust but Verify را دنبال کنیم. برای مثال این اصل به ما میگوید که در هنگام تعریف متدهای public باید یکسری موارد را در نظر بگیریم. یک متد باید از یکسری قراردادها پیروی کند. یک متد قرارداد میکند که یکسری پارامترها را با یک data type خاص به عنوان ورودی دریافت کند. قرارداد میکند که یک مقدار خاص با یک data type خاص را به عنوان نوع بازگشتی بازگرداند یا اینکه هیچ مقداری را باز نگرداند و در نهایت یک متد متعهد میشود که یکسری Exception تعریف شده و پیش بینی شده را صادر کند. اما برای اینکه مطمئن شویم یک application واقعا قابل پیش بینی است و این اصل را به درستی پیاده سازی کرده است، اعتماد میکنیم اما Verify را هم انجام میدهیم. برای verify کردن باید پارامترها، دیتاهای متغیر، مقادیر بازگشتی و استثناءها به گونهای بررسی شوند که مطمئن شویم انتظارت ما را برآورده کردهاند.
زیاده روی بیش از حد خوب نیست و آدم باید همیشه حد اعتدال را رعایت کند. این مسئله اینجا هم صادق است؛ به گونهای که زیاده روی بیش از حد در پیاده سازی و اعمال هر کدام یک از این مواردی که در بالا ذکر گردید، ممکن است باعث پیچیدگی ساختار کد و به طبع آن Application شود. بنابراین رعایت حد اعتدال میتواند در رسیدن به این هدف بسیار مهم باشد.
امروزه توسعه و نگه داری از یک نرم افزار هر چند مهمتر از مراحل ساخت آن نباشد دارای ارزش کمتری نیست! همهی ما مجبوریم پس از مدتی به پروژهی گذشتهی خود بر گردیم و اینجاست که اگر از خط و محورهای خاصی در تولید نرم افزار پیروی نکرده باشیم ارزش اینگونه Patternهای ساخت نرم افزار را درک میکنیم ، داشتن یک خط مشی مشخص در تولید و نگه داری نرم افزار قطعن باعث از بین رفتن سر دردهای آینده خواهد شد و مهمتر از آن باعث کاهش هزینههای بعد از تولید نرم افزار خواهد بود
در این کتاب نه تنها با پترن MVVM آشنا میشوید بلکه در راه رسیدن به این موضوع نویسنده شما را با انواع وجههای مختلف در ساخت یک برنامهی تجاری آشنا و آماده خواهد کرد!