قدم هایی برای بازنویسی نرم افزارهای Legacy
در مقاله قبلی در رابطه با دلایل اصلی شکست تلاش های صورت گرفته برای بازنویسی نرم افزارهای Legacy صحبت کردیم و در این مقاله قصد داریم به قدم هایی برای بازنویسی این نرم افزارها و به حداقل رساندن احتمال شکست اشاره کنیم.
در ابتدا سناریو های ممکن برای بازنویسی نرم افزار Legacy را در زیر تشریح میکنیم.
- در سناریو اول سازمان شما نرم افزاری را از تامین کننده ای خریداری کرده و سالهاست از آن استفاده میکند و اکنون تامین کننده ورشکسته شده و یا به هر دلیلی از بازار کنار رفته است و به دلیل نیاز به تغییرات و عدم امکان اعمال آنها نیاز به بازنویسی نرم افزار خواهید داشت.
- در حالت دوم سازمان یک نرم افزار را در داخل خود توسعه داده و سالیان سال است که از آن استفاده میکند و در یکی دو سال اخیر به دلیل تغییراتی مانند قوانین جدید، افزایش اقبال و بازار، معرفی محصولات جدید، افزایش مشتریان و …. نیاز به مقیاس پذیری، انطباق با قوانین و یا اضافه کردن فیچرهایی (که امکان اضافه کردن آن در کدبیس قدیمی وجود ندارد و یا بسیار هزینه بر است) نیاز به بازنویسی نرم افزار دارید.
در هر دو صورت نیاز دارید که اقداماتی را قبل از شروع توسعه انجام داده و در حین توسعه به نکاتی بسیار مهم توجه کنید تا بتوانید تلاش برای بازنویسی را با مخاطرات کمتری به پایان برسانید.
سوال بسیار مهمی وجود دارد که باید قبل از طی کردن تمامی این مسیر از خودتان و سازمانتان بپرسید و بدون هیچگونه سوگیری به آن پاسخ دهید و این سوال هیچ چیزی نیست جز: «آیا ما واقعا به بازنویسی نرم افزار نیاز داریم؟»
چرا این سوال را باید بپرسیم؟ به دلیل وجود Buzzword ها و حصول اطمینان از درستی نیاز! گاهی اوقات فکر میکنید برای دستیابی به مقیاس پذیری نیاز به بازنویسی یک پروژه مونولیث با معماری میکروسرویس دارید؟ آیا با اجری نسخه های متعدد و قراردادن آنها پشت یک لود بالانسر با سشن های استیکی مشکلات حل نمیشود؟ آیا با Shard کردن دیتابیس مشکلات حل نمیشد؟ با خودتان رو راست باشید چرا که مسیر سختی در پیش است!
اگر بعد از پاسخ دادن به این سوالات به صورت سازمانی، واقعا به این نتیجه رسیدین که به این تلاش یعنی بازنویسی نرم افزار Legacy نیاز دارید قدم های زیر میتوانند تا حدی تهدید شکست را کاهش دهند و شما را به موفقیت نزدیک تر کنند.
قدم اول: همه چیز از افراد شروع میشود!
قبل از شروع فرآیند بازنویسی اولین کاری که باید انجام دهید حصول اطمینان از همراهی مدیریت ارشد سازمان و ذینفعان تاثیرگذار بر محصول شما با تلاشی که در شرف صورت گرفتن است می باشد.
موفقیت یک محصول و یا تلاش چیزی به جز رضایت نهایی و نسبی ذینفعان آن نیست!
همچنین اگر درک کنید که همراهی و همگامی ذینفعان در فرآیند تولید یک محصول، یا تلاش برای بازنویسی یک نرم افزار و یا انجام یک پروژه چه تاثیر مثبتی میتواند بر فرآیند کامل کار داشته باشد، به شما اطمینان میدهم که شخص به شخص با ذینفعان تاثیرگذار کارتان، به جلسه رو در رو نشسته و با آنها صحبت می کنید. به افراد اطمینان بدهید که این تلاش در راستای بر آورده کردن نیاز های سازمان بوده و موقعیت هیچ شخصی را تهدید نمیکند. همچنین همواره افرادی مقاوم در برابر تغییرات در هر سازمانی وجود دارند و باید مطمئن شوید که با این افراد ارتباطات بیشتر و نزدیک تری داشته باشید و از دست آنها فراری نباشید.
قدم دوم: تغییر نگاه از پروژه محور به محصول محور:
زمانی که از کلمه پروژه برای اشاره به یک تلاش برای توسعه یک محصول استفاده می کنیم اولین چیزی که به ذهن افراد میرسد تبعیین یک زمانبندی و بودجه سفت و سخت در ابتدا و پایبندی به آن در هر صورتی می باشد.
مدیریت پروژه Predictive متناسب با محصولاتی بوده که در گستره مسائل شناخته شده می باشند یا حداقل بیش از ۸۰ درصد پروژه قبل از شروع آن مشخص است. برای مثال ساخت یک ساختمان ۵ طبقه را در نظر بگیرید. ساخت یک ساختمان ۵ طبقه در گستره مشکلات شناخته شده و همچنین دارای پیشینه دانشی بسیار طولانی تری نسبت به توسعه نرم افزار و از آن جدیدتر بازنویسی نرم افزار های Legacy می باشند.
توسعه نرم افزار در گستره ی مسائل پیچیده بوده و هر چقدر این پیچیدگی بیشتر باشد محصول را بیشتر به سمت گستره آشوب سوق می دهد یعنی پیچیدگی محض که نیاز به تلاش فراوان برای شناسایی اصل مسئله، شناسایی الگو ها و حل آن ها می باشد.
اما حرف من را اشتباه تفسیر نکنید. درست است که حل مشکلات پیچیده با نگاه پروژه محور بسیار مشکل بوده و اغلب امکان پذیر نیست و نیاز به تغییر تفکر از پروژه محوری به محصول محوری وجود دارد، اما این تغییر تفکر به معنی رها کردن همه چیز و عدم کنترل نسبی بر روی فرآیند ها و سیر توسعه نیست!
برای تغییر تفکر از پروژه محوری به محصول محوری ۱۲ تغییر کلیدی وجود دارد که در مقاله ای دیگر به بررسی این ۱۲ مورد به صورت موردی خواهیم پرداخت اما برای اشاره باید مطمئن شوید که ۱۲ اتفاق و تغییر زیر در سازمانتان قبل از شروع کار رخ داده یا بدهد:
- تغییر متره های کلیدی از درست انجام دادن کار به یادگیری و پیشرفت
- تغییر شیوه ی گزارش دهی و اطلاع رسانی از یک جهته به چند جهته (بالا به پایین، پایین به بالا و به صورت افقی)
- تغییر رویارویی با ریسک های از بررسی و تحلیل بسیار ریز قبل از شروع کار به روند رویارویی با ریسک به صورت JIT
- تغییر تمرکز از سازمان به مشتریان
- تغییر طرز تفکر مطابقت با طرح های اولیه به تلاش برای ارائه ارزش
- تغییر تفکر از انجام دستورات به حل مسئله
- تغییر تفکر در رهبری و جایگزینی تیم من با تیم ما
- تغییر رفتار با نیروی انسانی از نیرو های در گردش به تیم های مقیم و پایدار (عدم جذب و رها سازی نیرو پس از اتمام کار)
- تغییر تفکر از بچسب و دنبال کن به عملگرا و تطبیقی بودن
- تغییر انجام روند کار از پروژه و اتمام، به تحول متداول
- تغییر روند رییس را دنبال کن به ارزش را دنبال کن
- تغییر ساختار شکست کار ثابت با یک بکلاگ زنده
قدم سوم: اطمینان از وجود اصول، فرآیند ها و رویه های منطبق با دو مورد بالا!
قبل از شروع تلاش برای بازنویسی نرم افزار Legacy که بخشی از یا کل سازمانتان را شکل داده است باید از وجود اصول و فرآیند ها و رویه های منطبق با دو قدم قبلی اطمینان حاصل کنید و یا در صورت نیاز به وسیله آموزش و هم افزایی این موارد را به بلوغ نسبی در سازمان برسانید.
برای اشاره میتوان به نیاز وجود طرز تفکر چابک و استفاده از چهار چوب های آن مانند اسکرام، کانبان، XP و یا حتی اسکرام بان در سازمان، وجود چهارچوب های مدیریت فناوری اطلاعات مانند ITIL و همچنین حاکمیت فناوری اطلاعات در سازمان مانند Cobit اشاره نمود.
مطمئن شوید که به جز تیم های توسعه ذینفعان هم تا حدودی از ماهیت این موارد اطلاع داشته باشند. در صورتی که ذینفعانتان اطلاعات کافی در رابطه با این موارد نداشته باشند هنگام گفتگو با شما ممکن است دیوانه ای بیش به نظر نرسند!!!!!
قدم چهارم: سازمانی کوچک هم راستا با اهداف استراتژیک و کسب و کار در دل سازمانتان تشکیل دهید.
بعد از اینکه نسبت به قدم های قبلی تا حدود قابل قبولی اطمینان حاصل کردید نوبت به تشکیل سازمان محصول محورتان است. منظور از تشکیل سازمان تعیین و قراردادن افراد در پست های سازمانی مناسب و تعریف مسئولیت های آن ها، تعیین اهداف سازمانتان و همچنین روند های مورد استفاده و یا حتی ابزار های مورد نیاز کارتان است.
تا اینجای کار تمامی قدم ها تغریبا مدیریتی و استراتژیک بودند. باید به این نکته اشاره کرد که کارهای حوصله سر بر یک تلاش، بخش بسیار مهمی از آن تلاش را تشکیل میدهند.
از این بخش مقاله به بعد به قدم های فنی اشاره میکنیم.
قدم پنجم: بدون سوگیری تصمیم بگیرید!
اکنون نوبت تصمیم گیری در رابطه با استک تکنولوژی و معماری بازنویسی است. معمولا نرم افزارهای Legacy معماری یکپارچه و مونولیث و همچنین دارای ۳ لایه می باشند که متشکل از رابط کاربری، منطق (اپلیکیشن) و دیتابیس است.
معمولا جذابیت مهاجرت به معماری میکروسرویس بسیار زیاد بوده و در اکثر تلاش ها برای بازنویسی نرم افزارهای Legacy به سمت این معماری می روند. درست است که این معماری مزیت های بسیاری را برای توسعه مخصوصا برای پروژه های بزرگ دارد اما به ازای هر مزیت ۱ و یا ۲ تهدید نیز به همراه میاورد و اگر بدون دانش کافی وارد این محدوده شوید احتمال شکست خود را افزایش می دهید.
در صورتی که واقعا نیاز به این معماری ندارید؛ سمت آن نروید! هچنین این معماری برای شما آزادی عمل بسیاری به همراه می آورد. استفاده از زبان ها و چهارچوب های مختلف، دیتابیس های مختلف، تکنولوژی های ارتباطی مختلف و ….؛ اما مراقب باشید. از همان ابتدا یک سری قوانین برای بازی خودتان تعیین کنید. استک تکنولوژی که تیم درآن به بلوغ رسیده و دانش آن در سازمان وجود دارد را انتخاب کنیدو تلاش کنید تا آنجایی که میتوانید به آن پایبند باشید.
اگر در حال تشکیل و یا گسترش تیم هستید مطمئن شوید که تکنولوژی های انتخابی انطباق بهتری با پروژه شما دارند، بلوغ مناسبی دارند، نیروی کاربه راحتی در آن تکنولوژی قابل جذب است و انجمن های فعال و گستره ابزاری بیشتری دارند.
بعد از این تصمیم گیری ها و انجام این پیش نیازها نوبت قدم بعدی است.
قدم ششم: شناسایی اجزای کد
هر نرم افزاری از تعدادی اجزای منطقی که به آنها کامپوننت یا ماژول هم گفته میشود تشکیل شده است. گاهی اوقات در نرم افزار های Legacy این ماژول ها به درستی جدا و دسته بندی و شناساییی نشده اند و اصطلاحا شما با یک اسپاگتی مواجه هستید که از ابتدا میتوانسته دلیل اصلی شما برای بازنویسی نرم افزار باشد.
پس اولین قدم شناسایی این کامپوننت ها می باشد. نکته ای که باید به آن توجه داشته باشید در کنار شناسایی اجزای تشکیل دهنده کدهای منطق یا همان لایه اپلیکیشن اجزای لایه رابط کاربری و همچنین داده ها یا همان دیتابیس را هم مورد توجه قرار دهید چرا که در شکست این اسپاگتی به میکروسرویس ها چه از میکرو فرانت استفاده کنید چه نکنید، کمک میکند.
قدم هفتم: مرتب سازی، تمیزکردن و ریفکتورینگ اجزای شناسایی شده
پس از شناسایی اجزای کد و کامپوننت های اطلاعاتی سیستم شامل Data Objects, Data Actions و کارهایی که نیاز هست صورت بگیرد و یوزکیس های آنها نوبت به ترتمیز کردن و دسته بندی این اجزا می باشد.
در این مرحله هر گونه کد تکراری و هر گونه Object تکراری را حذف کرده ،کد را به سمت ماژولار شدن ریفکتور کنید و سعی کنید نسخه بهتری از کد در انتهای این تلاش داشته باشید.
شاید این سوال پیش بیاید خب چرا به جای این فرآیند مستقیما به دنبال توسعه میکروسرویس ها نرویم؟! سوالی به جاست. به این دلیل که زمانی که کد ساختار بهتری پیدا کند و در صدد تلاش برای شکست آن به میکروسرویس تلاش کنیم به مراتب در نهایت حجم بسیار کمتری از دوباره کاری و خطا در سیستم وجود خواهد داشت.
سپس یک نقشه کامل از تمامی ماژول ها تهیه کنید و سعی کنید تمام این تلاش ها منطبق بر Domain Driven Design باشد.
قدم هشتم: شناسایی روابط بین ماژول ها
بعد از اینکه ماژول های سیستم را شناسایی کردید و کدتان را ریفکتور کردید نوبت به شناسایی روابط و Dependency این ماژول ها با یکدیگر است.
در این مرحله باید دقت بسیار زیادی صورت پذیرد که روابط تا حد ممکن به صورت کامل شناسایی شوند. همچنین روابط موجود در دیتابیس را فراموش نکنید و در نهایت اینکه قسمت های مختلف خدمت دهنده لایه رابط کاربری را نیز شناسایی کنید . چرا که ممکن است یک کامپوننت سمت فرانت اند توسط چند ماژول تغذیه شود.!
قدم نهم: گروه بندی ماژول ها
از آنجایی که ماژول ها در یک کد تمیز معمولا از قائده single responsibility پیروی میکنند شما نیاز دارید تا ماژول ها مرتبط را با هم دسته بندی کرده و bounded Context ها را شناسایی کنید.
بنابراین ماژول های مرتبط را با هم دسته بندی کرده و گروه های مشخصی را با روابط مشخص با یکدیگر شناسایی کنید.
نکته: در این مسیر و در تمامی قدم ها ریفکتورینگ را فراموش نکنید تا کار برایتان ساده تر باشد.!
قدم دهم: مهاجرت گروه ماژول ها به سرویس ها – مهم
اکنون نوبت به مهاجرت گروه های کامپوننت یا همان Bounded Context ها به سرویس های مستقل است. اما در این مرحله باید به چند نکته توجه داشت.
- اول از همه از کوچک ترین و راحت ترین گروه شروع کنید! چرا؟ تا سریع تر به بازخورد رسیده و مطمئن شوید که در مسیر درستی قرار دارید و یا اقدامات لازم را درست انجام داده اید.
- بازنویسی از ریشه یا همان بیگ بنگ ممنوع مگر هیچ راهی نداشته باشید!!!! تلاش کنید تا آنجا که ممکن است از ریشه یک نرم افزار را بازنویسی نکنید. در عوض تکه تکه سرویس های جدید را جایگزین کد های قدیمی کنید. بدین وسیله شما میتوانید هر درخواست تغییری را نیز در سرویس جدید اعمال کرده و از اعمال تغییرات بر روی دو کدبیس به صورت همزمان جلوگیری کنید. بدین وسیله فرآیند سازگاری مشتریان و کاربران هم راحت تر خواهد بود. (در صورت تغییر رابط کاربری وگرنه اگر رابط کاربری تغییری نکند کاربران متوجه چیزی نخواهند شد). این موضوع اشاره ای به کشتی تسئوس دارد. کشتی تسئوس در متافیزیک هویت یک آزمایش فکری است که این سؤال را پدید میآورد که آیا چیزی که همه اجزای آن جایگزین شده، اساساً همان چیز باقی میماند؟ و یا توسط هویت جدید قابل تشخیص است؟
- از الگو های پراکسی یا facade برای جایگزینی سرویس ها با ماژول ها استفاده کنید.
- به دنبال ریز کردن بیش از حد سرویس ها در قدم های اولیه نباشید. میتوانید به جای میکروسرویس از لفظ ماکروسرویس استفاد کنید تا کسی به شما خرده نگیرد.
- هر میکروسرویس میتواند یک Bounded context باشد ولی هر Bounded context لزوما یک سرویس نیست!!!! در تبدیل و مهاجرت گروه ها یا همان Bounded Context ها به میکروسرویس ها، فاکتور های بیشتری را مد نظر قرار دهید.
- به اصول تعیین محدوده سرویس ها دقت کنید. تا آنجا که میتوانید مفاهیم فنی را در سرویس مخفی کنید. به این اصل Information Hiding میگویند. انسجام کد را در سرویس ها حفظ کنید. کدهایی که با هم تغییر میکنند بهتر است در یک سرویس قرار گیرند. تلاش کنید تا Coupling را تا آنجا که میتوانید کاهش دهید. کاپلینگ نسبی بوده و هیچ معماری میکروسرویسی وجود ندارد که ۱۰۰ درصد Loosely Coupled باشد. بده بستان های غیر فنی و عملیاتی را فراموش نکنید. گاهی اوقات به دلیل یک نیاز غیر اجرایی و یا ایجاد ارزش افزوده شاید مجبور شوید ۲ یا چند سرویس کوچک را با هم ترکیب کنید و در یک سرویس قرار دهید.
- اگر مجبور شدید Dry را زیر پا بگذارید ناراحت نشوید. برای همه اتفاق میافتد. گاهی اوقات نیاز است که بخشی از کد را در چند سرویس جدا استفاده کنید و امکان ایجاد یک سرویس مستقل هم منطقی نیست. میتواند کد را در همه میکروسرویس ها کپی کنید. همچنین اگر تغییرات زیادی در کد نخواهید داشت میتوانید کد را Package کرده و در هر میکروسرویس نصب کنید. البته مراقب باشید چرا که در صورت داشتن Backward Incompatible Change در کد همین پکیج ها ممکن است در میکروسرویس هایتان دچار تغییرات مخرب شوید.
- ۱۰۰ مطمئن شوید که این کار را تکه تکه انجام میدهید و یا پیش میروید. Incremental Development
- و ……
قدم یازدهم: تست و پیاده سازی
در قدم یازدهم اطمینان حاصل کنید که رفتار های هر میکروسرویس را در قالب Unit Test در Isolation تست کرده و رفتار های سیستم هم در محیط تست به صورت کامل توسط تست های اتوماتیک E2E تست کنید.
همچنین اطمینان حاصل کنید که تا آنجا که امکان دارید از Practice ها DEVOPS و هم چنین CI/CD بهره ببرید تا زندگی برایتان شیرین تر شود.
قدم دوازدهم: به تکامل ادامه دهید
در اقدامات بعدی میتوانید تلاش برای کوچک تر کردن میکروسرویس ها و همچنین تلاش برای دستیابی به Deployment در محیط های مختلف را در دستور کار خود قرار داده و برای بهبود سرویس ها تلاش کنید چرا که اکنون درس های بسیاری را آموخته اید و دید بهتری نسبت به سیستم دارید.
در این مقاله تلاش کردم که به صورت خلاصه در کمترین سطر ممکن کلیات را بیان کنم. اما همانطور که میدانید به دلیل گستردگی دانشی و پیچیدگی فناوری اطلاعات و توسعه نرم افزار امکان نوشتن چند کتاب برای هر قدم وجود دارد.
امیدوارم برایتان مفید واقع شده باشید.
در صورتی که نکته نظری یا توصیه ای دارید میتوانید از طریق ایمیل، لینکدین و کامنت های وب سایت با من در ارتباط باشید.
دیدگاه خود را بنویسید