چه یک برنامهنویس فریلنسر باشید و چه در یک شرکت به عنوان برنامهنویس یا مهندس نرمافزار مشغول به کار شده باشید، احتمالاً روزی خواهد رسید که یکی از پروژههای قدیمی و فعالی که شما مسئولیت آن را دارید به پایان زمان پشتیبانی خود نزدیک باشد. در چنین حالتی، تنها اقدام منطقی و لازم بروزرسانی کدهای قدیمی است که هر چه پروژه بزرگتر باشد، دارای احتمال خطای بیشتری خواهد بود.
این چالشی بود که ما در وندار با آن روبهرو شدیم، نیازمندی پروژههای سنگین به بروزرسانیهای متعدد. از زبان برنامهنویسی مورد استفاده گرفته تا فریمورک اصلی و پکیجهایی که برخی از آنها، در نسخههای قدیمی رها شده بودند. در این مطلب، فرایند مورد استفاده ما برای بروزرسانی پروژهها را میخوانید.
مهمترین و بزرگترین مشکلی که میتواند بروزرسانی یک پروژه قدیمی را برای شما دردآور کند، عدم وجود راهکاری است که پس از بروزرسانی بتوانید مطمئن شوید که کدها به همان شکلی که پیش از این کار میکردند، به کار خود ادامه خواهند داد. بروزرسانیهای عظیم معمولاً شامل منسوخشدن متدها و کدهای قدیمی میشوند و ممکن است راهکاری که شما پیاده کردید را به کل غیرقابل استفاده کنند. به همین دلیل، پیش از بروزرسانی هر پروژهای، نیاز است راهکارهایی برای تست خودکار و دستی پروژه ایجاد کنید.
تستهای خودکار میتوانند از طریق فریمورک یا زبانی که از آن استفاده میکنید پیاده شوند. برای ما، این مسئله از طریق راهکارهای لاراول برای تست قابل انجام بود و تلاش کردیم با بالا بردن پوشش (coverage) تستها، احتمال پنهان ماندن خطاها پس از بروزرسانی را کاهش دهیم.
تستهای دستی هم میتوانند به اشکال مختلفی انجام شوند. برای مثال اگر پروژه شما یک سیستم مدیریت محتواست، تعیین فرایندهایی که باید پس از بروزرسانی انجام شوند (برای مثال فرایند ایجاد، ویرایش و حذف یک مطلب، و یا درج یک نظر در پست منتشر شده و…) و انجام آنها پیش از آنکه دست به کد ببرید میتواند انتظار شما از پروژه بروزرسانیشده را مشخص کند.
با توجه به اینکه ما در وندار، از RESTFul APIها برای ارائه خدماتمان استفاده میکنیم، توانستیم همچنین از Postman و نرمافزارهای مشابه آن بهره ببریم که از طریق آنها، سناریوهای تست از پیش تعیین شده و نتایج تستها قبل و بعد از بروزرسانی مقایسه میشوند. این روش را هم به شکل خودکار و هم به شکل دستی میتوان به کار برد.
در اکثر پروژههای بزرگ، فارغ از اینکه از چه زبان و فریمورکی استفاده کرده باشید، یک مدیر بسته (package manager) وجود دارد که خود فریمورک و در کنار آن، پکیجهای رسمی و غیررسمی که از آنها در پروژه استفاده است از طریق آن نصب و بروزرسانی میشوند. طبیعی است که برخی از پکیجهای (خصوصاً غیررسمی) که پیش از این در پروژه استفاده شدهاند رها شده باشند یا توسعهدهندهی آنها، برنامهای برای بروزرسانی این پکیجها نداشته باشد. در این حالت، نیاز است که موارد استفاده از چنین پکیجهایی بررسی شده و در صورت امکان، یکی از راهحلهای زیر استفاده شود:
در وندار، ما پس از فهرست کردن پکیجهای مورد استفاده پروژهها و بررسی هر یک از آنها، با توجه به ماهیت پکیجها، مجبور به جایگزین کردن پکیجها حین بروزرسانی شدیم. این پروسه فهرست کردن، شامل چارتی از نام پکیجها، ورژن فعلی آنها و ورژنی که قصد داریم به آن بروزرسانی کنیم بود، در کنار توضیح آنکه کدام سناریو برای هر پکیج رخ میدهد.
پس از پکیجهای رها شده، نوبت به بروزرسانی زبان برنامهنویسی، فریمورک، پکیجهای رسمی و پکیجهایی که بروزرسانی شدهاند میرسد. برای یک بروزرسانی صحیح نیاز است که تغییرات هر یک از مواردی که ذکر شد بررسی شود. در موارد مرتبط با زبان برنامهنویسی، فریمورکها و پکیجهای رسمی، معمولاً یک راهنمای بروزرسانی و یا فهرستی از تغییرات منتشر میشود که کار بررسی را برای تیم بروزرسانی سادهتر میکند.
برای مثال در وندار، از راهنمای بروزرسانی لاراول، راهنمای بروزرسانی پیاچپی و فهرست تغییرات Laravel Passport برای اطمینان از یک بروزرسانی بدون خطا استفاده شده است. استفاده از چنین راهنمایی (خصوصاً زمانی که این راهنما توسط توسعهدهندگان اصلی این پروژهها نوشته شده باشد) احتمال بروز خطا در نسخههای جدید را بیش از پیش کاهش میدهد.
پس از آنکه بروزرسانی را انجام دادید (برای ما در یک استک لاراولی، این به معنای اعمال تغییرات بر پایه راهنماها و اجرای composer install بود) زمان استفاده از تستهایی که در قدم اول ایجاد کردیم فرا رسیده است. حتی در این قدم هم، تلاش برای تعریف سناریوهای جدید و بررسی اینکه پروژه نتایج درستی ارائه میدهد، با توجه به حساسیت پروژه نسبت به چنین خطاهایی ضروری است. در صورتی که پروژه سربلند از این تستها بیرون آمد و تست خودکار و دستی باگهای جدیدی ایجاد نکرد، بالاخره زمان پیادهسازی فرا میرسد.
در پیادهسازی، با توجه به حساسیت پروژه میتوان دو حالت را در نظر گرفت، یکی نگهداری یک نسخه فعال از پروژه قدیمی و پیادهسازی نسخه جدید به شکل جدا، به شکلی که بتوان با تغییر یک کانفیگ در وبسرور به نسخه قبلی بازگشت و دیگری انجام بروزرسانی بر روی کدبیس اصلی (که باز هم احتمالا از طریق گیت قابل بازگردانی است)
همچنین، در صورتی که تغییرات نیازمند بروزرسانی نرمافزارهای روی سرور است (برای مثال زمانی که پروژه شما به صورت bare-metal بر روی سرور اجرا میشود)، باید چنین تغییراتی پیش از بروزرسانی به متخصص dev-ops اطلاع رسانی شود، چنین تغییری احتمالاً مختص پکیجمنیجر (composer, npm, pypi) و فریمورک خواهد شد.
با وجود اینکه کل فرایند بروزرسانی یک پروژه که در اینجا شرح دادیم با هدف رساندن خطاها به صفر طراحی شده است، باز هم (خصوصا در صورت نبود پوشش ۱۰۰ درصدی تستها) احتمال بروز خطاهای غیرمنتظره وجود دارد. بسته به حجم ترافیک ورودی به پروژه، ممکن است نیاز باشد برای یک دوره زمانی ۲۴ ساعته تا یکهفتهای آمادگی ارائه تغییرات سریع را داشته باشید.
سعی کنید هنگام بروزرسانی، مشکلات و چالشهایی که با آنها روبهرو شدید را فهرست کرده و در گزارشی آنها را مستند کنید. بدین شکل حتی پس از پایان یک بروزرسانی، فرایند بهبود کدها متوقف نمیشود. برای مثال، افزایش تعداد و حالات مختلف تستها برای جلوگیری از بروز خطاهای بعدی، عدم استفاده از پکیجهایی که ممکن است پیش از پایان عمر محصول رها شوند و به جای آن استفاده از راهحلهای درون سازمانی برخی از مواردی است که در تجربه بروزرسانی ما ایجاد شد.
شما چه تجربیات دیگری با بروزرسانی پروژههای قدیمی داشتید؟ چه قدمهای دیگری را برای یک فرایند بروزرسانی بهتر پیشنهاد میکنید؟ نظراتتان را با ما به اشتراک بگذارید.