مشکل ارتقای اجزای نرم‌افزار

یکی از مشکلات بزرگی که نرم‌افزار نویس‌ها مدام با آن دسته و پنجه نرم می‌کنند مشکل ارتقا اجزا و بخش‌های مختلف یک نرم‌افزار است. برای این مشکل مثال‌های زیادی وجود دارند:
۱- برنامه را با VB6 نوشته‌اید ولی حالا که به VB.NET ارتقا داده‌اید متوجه شده‌اید که پیش‌فرض VB.NET برای اعضای کلاس private است نه public.
۲- برنامه را با NHibernate 1.2 نوشته‌اید ولی بعد از ارتقا به NHibernate 2.0 فهمیده‌اید که برنامه با آن configuration قدیمی کار نمی‌کند و باید web.config/app.config را هم عوض کنید.
۳- برنامه را با فلان library نوشته‌اید و بعد از ارتقا به نسخه جدید فهمیده‌اید که نسخه جدید به خیلی از مسائلی که قبلاً گیر نمی‌داد حالا گیر می‌دهد و نمی‌گذارد برنامه اجرا شود.
۴- در برنامه‌های ASP.NET از کنترل‌های Telerik استفاده کرده‌اید و بعد از ارتقا فهمیدید که tagهای استفاده شده در markup اسمشان عوض شده و حالا دچار parser error شده‌اید.
۵- در برنامه‌ای که برای ویندوز ۹۵ نوشته شده از یک API خاص استفاده شده که دیگر در ویندوزهای جدیدتر وجود ندارد.
۶- در بخشی از برنامه از نسخه x یک library استفاده کرده‌اید و بعداً لازم می‌شود بخشی از یک نرم‌افزار دیگر را به نرم‌افزار فعلی‌تان الحاق کنید اما این بخش جدید از نسخه y استفاده می‌کند نه x.
۷-…

این مسئله که برای برنامه‌نویسان عذاب‌آور و برای مدیران ترس‌آور است را می‌توان به دو بخش خارجی و داخلی تقسیم کرد. بخش خارجی مربوط است به dllها، libraryها، APIها و platformهایی که از خارج شرکت/تیم می‌آیند و معمولاً حق انتخاب زیادی در مورد آنها وجود ندارد. بخش داخلی مربوط است به اجزا و dllهایی که در داخل شرکت ساخته می‌شود و version زدن آنها یک مصیبت بزرگ است. در مورد dllهای داخلی مسئله backward comaptiblity و وابستگی به dllهای دیگر هم باید چک شود. چیزی که معمولاً در مورد dllهای خارجی بهتر رعایت می‌شود.

برای کاهش مشکلات ارتقا به نظر بنده موارد زیر را می‌توان در نظر گرفت:
۱- مثبت‌نگر باشید. ارتقا dllها خصوصاً در مورد dllهای خارجی معمولاً نوید دهنده امکانات بهتر و کامل‌تر است. معمولاً هدف از ارائه نسخه جدیدتر رفع اشکالات نسخ قبلی، بهبود عملکرد و… است. پس بنابراین خوشحال باشید که رفع مشکلات مربوط به نسخه جدید به معنی ارتقا کیفیت نرم‌افزار شما خواهد بود.
۲- پیروی از اصل KISS (Keep It Simple Stupid)‎: یعنی تا آنجا که می‌توانید برنامه را ساده نگه داشته و بیخودی از هر کتابخانه، class و dll دیگری استفاده نکنید.
۳- Dependency Injection: برنامه‌ها با حداقل وابستگی به هم نوشته شوند.
۴- موتوا قبل ان تموتوا (بمیرید قبل از آن که بمیرید): قبل از آن که مجبور شوید ارتقا دهید، ارتقا دهید. تولید کنندگان نرم‌افزار معمولاً قبل از ارائه نهایی نسخ جدید آنها را به صورت نسخه‌های آزمایشی ارائه می‌دهند و حتی قبل از آن کلی بحث راه می‌اندازند، نظر سنجی و اطلاع‌رسانی می‌کنند که ما قرار است فلان چیز را به نرم‌افزارمان اضافه کنیم یا تغییر بدهیم. بنابراین فرصت خیلی زیادی دارید که خود را به موقع ارتقا دهید.
۵- پیروی از تجارب TDD مثل Unit Test و Continuous integration: این راه‌حل خصوصاً در مورد dllهای داخلی خیلی خوب جواب می‌دهد. اگر برای همه بخش‌هایی ممکن unit test نوشته باشید آن وقت نگرانی کمتری برای ارتقا دارید چون خیلی سریع می‌فهیمد که آیا چیزی خراب شده یا نه. Continuous integration هم به همین شکل کمک می‌کند که در حداقل زمان ممکن خطا را کشف کنید.
۶- به هیچ وجه Warningهای هنگام کامپایل را دستکم نگیرید. خیلی از warningهای نسخه امروز به compile errorهای نسخه فردا تبدیل خواهند شد.
۷- استفاده از الگوهای جدیدی مثل MVC چون کار تست را راحت‌تر کرده و decoupling که با استفاده از dependency injection محقق می‌شود را بهتر اجرا می‌کنند.

شما چه راه‌هایی برای کاهش این طور مشکلات سراغ دارید؟

‫مهاجرت پروژه‌های دات نت از VS 2005 به 2008 و از Framework 2.0 به 3.5

migrate small برای این مهاجرت (ارتقا) باید ملاحظات زیادی را در نظر گرفته و دقت زیادی می‌کردم. چون حجم پروژه‌ها و solutionها خیلی زیاد بود و وابستگی‌های زیادی به هم داشتند و کم‌ترین اشتباه دردسرهای زیادی را درست می‌کردند. خصوصا این که کل سورس با ملاحظات امنیتی مختلفی روی Source Safe قرار داشتند. مشکلاتی را که در انجام این کار با آنها برخورد کرده‌ام را در ادامه خلاصه کرده‌ام:

۱- Build Break: از آخرین Build بعضی از پروژه‌ها وقت خیلی زیادی می‌گذشت و بعضی از آنها به دلیل تغییرات پروژه‌های دیگر build error پیدا کرده بودند. به خصوص پروژه‌های Initialization که همان اول‌ها و با عجله نوشته شده و بعد از آن خیلی کم استفاده شده بودند. بنابراین باید کل پروژه را در همان نسخه ۲۰۰۵ یک بار به طور کامل build کنم تا در ۲۰۰۸ فقط build errorهای ناشی از به روز رسانی را داشته باشم نه چیز دیگر.

۲- تعلیق کلیه فعالیت‌های توسعه و نگهداری: من سورس کد را از Source Safe گرفته بودم و می‌خواستم آن را در یک جای جدید VSS اضافه کنم بنابراین مجبور بودم به همه اعلام کنم تا پایان upgrade از هرگونه check in و check out خودداری و سورس‌های خود را عوض نکنند چون بعدا مجبور می‌شوند آنها را به طور دستی در نسخه ۲۰۰۸ وارد کنند و این یعنی استرس کاری و کمبود وقت در پروسه کاری مهاجرت از ۲۰۰۵ به ۲۰۰۸.

۳- پروژه‌های تست: به خاطر مشکلی که در convert فایل‌های ‎.vsmdi و localtestrun.testrunconfig داشتم و به خاطر قدیمی بودن پروژه‌های تست و استفاده کمی که از آنها می‌شد تبدیل پروژه‌های تست را بی‌خیال شده و آنها را unload کردم (به همین سادگی!).

۴- تغییر NameSpaceها: در یک مورد خاص NameSpace یکی از datasetها به طور خود به خود تغییر پیدا کرده و عبارت ‎.Entities به ته آن اضافه شده و این قضیه باعث شده بود که کل solution به دلیل عوض شدن این Name Space دچار build break شود. Name Space یک DataSet به طور خودکار از روی پروژه دربرگیرنده آن ساخته می‌شود و علی الظاهر روش ساخت این NameSpace در نسخه‌های ۲۰۰۵ و ۲۰۰۸ ویژوال استودیو با هم فرق کرده است. هر DataSet دارای دو NameSpace یکی برای خودش و دیگری برای اجزای آن است. این مشکل در مورد یکی از ریسورس‌ها (‎.resx) که در فولدر Properties یکی از پروژه‌ها بود هم اتفاق افتاده بود.

۵- جابجایی بعضی typeها و کلاس‌های داخلی دات نت: این قضیه فقط یک بار اتفاق افتاده بود و آن هم جابجایی System.Data.TypeTableBase از اسمبلی System.Data به System.Data.DataSetExtensions است. این جابجایی منجر به اضافه کردن reference جدید می‌شود.

۶- عوض کردن Target Framework از ‎.Net framework 2.0 به ‎.Net framework 3.5: که خود این کار هم کار وقت‌گیری بود چون باید تک تک پروژه‌ها را باز می‌کردم و این تنظیم را به طور دستی عوض می‌کردم. انجام این کار از طریق جستجو در فایل‌های ‎.csproj هم امکان پذیر نبود چون تا زمانی که این مقدار برابر ‎.Net Framework 2.0 باشد تگ TargetFrameworkVersion به xml آن اضافه نمی‌شد.

۷- عوض کردن جداگانه پروژه گزارشات از نسخه ۲۰۰۵ به نسخه ۲۰۰۸: که خود حدیث مفصلی داشت. برای کسب اطلاع بیشتر از جزییات موضوع به وبلاگ حاجلو مراجعه کنید.

۸- مشکلات مصیبت بار web.config: همانطور که می‌دانید شماره نسخه خیلی از کلاس‌ها و اسمبلی‌های دات نت در web.config نگهداری می‌شود. در حالت عادی خود ویژوال استودیو تقریبا همه شماره نسخه‌ها را به روز رسانی می‌کند ولی بعضی موارد هستند که به طور خودکار انجام نمی‌شوند و نیاز به دست کاری دستی دارند. قسمت بد این قضیه این است که بعضی از این موارد را نمی‌شود به این راحتی پیدا کرد و باید آنقدر مشکلات عجیب و غریب و لاینحل در برنامه دید و هزار تا منبع را بالا و پایین کرد تا منبع مشکل و راه حل آن پیدا شود. به عنوان مثال موردی که باعث شده بود یکی از صفحات خراب شده و واقعا گریه مرا درآورد، وجود عبارت ‎xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0" در نود configuration بود. وجود این عبارت در نرم افزار مبتنی بر framework 3.5 ما باعث شده بود یکی از صفحات دچار خطای Unable to cast object of type ‘System.Web.Configuration.ScriptingScriptResourceHandlerSection’ to type ‘System.Web.Configuration.ScriptingScriptResourceHandlerSection’.شود.

۹- کنترل‌های شخص ثالث: در بعضی صفحات وب از کنترل‌هایی غیر از کنترل‌های مادرزاد دات نت استفاده شده است مثل کنترل‌های شخصی شرکت‌ها یا کنترل ReportViewer مایکروسافت. گاهی اوقات کد register این اسمبلی به جای web.config به طور مستقیم در همان صفحه وب (aspx,ascx) استفاده کننده قرار داده شده‌اند. در حین به روز رسانی باید به این مشکل هم توجه شده و اگر شماره نسخه کنترل‌ها عوض شده کد رجیستر هم به روز رسانی گردد. ما این مشکل را با کنترل مشاهده گزارشات MS SQL Reporting Services یعنی Microsoft.ReportViewer.WebForms داشتیم. چون نسخه آن را از 8.0.0.0 به 9.0.0.0 عوض نکرده و دچار مشکل Unable to load client print control شده بودیم. به این نوشته مسعود هم که در مورد همین مشکل است دقت کنید.

۱۰- ویرایش مخصوص framework 3.5 نرم افزارهای شخص ثالث: در حین این به روز رسانی بهتر است (بعضی وقت‌ها اجباری است) که نسخه مخصوص framework 3.5 کامپوننت‌ها و کتابخانه‌های متفرقه غیر مایکروسافتی به جای نسخه قبلی مورد استفاده قرار گیرد. مثل NHibernate و Enterprise Library.

۱۱- پیش فرض‌های قدیمی: گاهی اوقات در حین به روز رسانی‌ها، بعضی از پیش فرض‌های سیستم یا نرم افزار جدید عوض شده و کار را خراب می‌کنند. باید مواظب این طور تغییرات بود. بعضی از این پیش فرض‌ها عبارتند از: تغییر پیش فرض Call by Value و Call by Reference از VB6 به VB.Net که شهرت زیادی پیدا کرد، مقدار timeout در نسخه‌های جدیدتر Sql Server و…

 

پایان خوش: خوشبختانه تغییرات نسخه ۳٫۵ دات‌نت نسبت به نسخه ۲٫۰ چندان اساسی نبوده و بیشتر در حد توسعه Class Library بوده و این ارتقا تاثیر نامطلوبی روی کارکرد برنامه حداقل در طول دوره آزمایشی آن نداشته است.

پ. ن.: در مورد ۸ خطای The control with ID ‘cbeDeleteLastAACDocument’ requires a ScriptManager on the page. The ScriptManager must appear before any controls that need it. را هم داشتیم که با برداشتن آن xmlns حل شد.