سایت خبر خوان تیم تیم

هرآنچه برای حمله به یک Legacy Code نیاز دارید!

هرآنچه برای حمله به یک Legacy Code نیاز دارید!

پنج شنبه 15 آذر 97 | 16:25 virgool.io 1
یک ماه بود که تیممون درگیر یه باگ توی یه سیستم Monolithic خیلی گ...

یک ماه بود که تیممون درگیر یه باگ توی یه سیستم Monolithic خیلی گنده و Legacy بود تا امروز بالاخره کاملا فیکس شد. انقدر تجربه جالبی بود مراحل فیکس کردن این باگ که به خودم قول دادم وقتی فیکس شد یه مطلب اینجا بنویسم شاید به بقیه هم کمک کنه.

خب شرکت ما اصولا پروژهای اوت سورس شرکت های بزرگ مثل آمازون و… رو انجام میده که مثل بهشت میمونن این پروژه ها چون Green Field هستند. یا نقش شرکت مشاوره ای رو برای شرکت های بزرگ دیگه رو بازی میکنه که این پروژه ها مثل جهنم بی سروته هستن که معمولا LegacyCode های پر از باگ هستن که ما باید مثله سوپرمن بپریم وسط و تمام مشکلاتش رو حل کنیم. من تا چند ماه پیش رسما برای آمازون کار میکردم و چون پروژهایی که روشون کار میکردم Green Field بودن مثل بهشت بود برام، تا اینکه یه روز مدیرم تصمیم گرفت پرتم کنه وسط جهنم پروژه ای که الان روش کار میکنم. این کد مربوط به یه Ecommerce هست که تو تمام دنیا به جز چند کشور داره کار میکنه در نتیجه به لحاظ تعداد یوزر و گردش مالی خیلی بزرگه.

وقتی این باگ رو پیدا کردیم دو تا راه پیش رومون بود ۱. راه راحت و پرریسک، اینجوری که فقط باگ رو حل کنیم بدون نوشتن هیچ تستی. ۲. راه سخت و با ریسک کمتر، نوشتن تست برای تمام قسمت هایی که تحت تاثیر این باگ قرار میگرفت برای فریز کردن رفتار این قسمت از کد و بعدش تغییر کد. دلیلمون هم این بود که ما قصد بهبود و تکه تکه کردن این Monolithic به سرویس های جداگانه رو داریم و این کار میتونه شروعی برای بهبود این LegacyCode باشه.

اولین کاری که باید بکنید اینه که محدوده ی کارتون رو باید محدود به تیکه هایی از کد بکنید که باگتون اونجا رو لمس کرده یا به زبان دیگه نقاط ورودی ای که به باگتون ختم میشه. چون شما خدا نیستید و در یک مرحله نمیتونید برای هزاران هزار خط کد بی سر و ته تست بنویسید. اینطوری مطمئن میشید وقتی باگتون رو فیکس کردین ناخواسته رفتار جای دیگه ای از سیستم رو که داشته درست عمل میکرده رو عوض نکردید.

اما برای Legacy Code ها با dependency های زیاد و پیچیده، چه نوع تستی باید نوشت؟ اصلا باید چطوری تست نوشت؟

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

وقتی با یک LegacyCode روبرو هستید در مرحله ای به این نتیجه میرسید که باید وضع موجود رو بهبود بدید و زندگی خودتون رو راحتر کنید! تو این مرحلست که باید راجع به Characterization Test یا Golden Master Test بدونید.

اما Charactrization Test یا همون Golden Master چیه ؟

وقتی که برای سیستمی که در حال توسعه اون هستیم تست مینویسیم این فرض وجود داره که میدونیم رفتار سیستممون چطور باید باشه و برای مطمئن شدن از درست بودن این رفتار تست مینویسیم. اما در برخورد با LegacyCode ها چطور، آیا از رفتار دقیق سیستم آگاهیم؟ در نتیجه مجبوریم سیستمی رو عوض کنیم که دقیقا نمیدونیم چه اتفاقی داره داخلش میفته! اینجاست که میتونیم شروع به فهمیدن دقیق رفتار سیستم فعلی بکنیم، به جای اینکه تمرکزمون رو بذاریم رو تشخیص غلط یا درست بودن خط به خط کد.

اینجوری شما میتونید رفتار فعلی سیستمتون رو فریز کنید و شروع به تغییر در جهت بهبود سیستم یا همون Refactoring بکنید. این فرض وجود داره که هیچ تغییری در رفتار سیستم در نتیجه Refactoring نباید به وجود بیاد و با استفاده از Charactrization تسته که میتونید مطمئن بشید که این فرض درسته.

با نوشتن Charactrization تست در واقع داریم براساس فهم خودمون ازیک سیستم Legacy، تست مینویسیم. در نتیجه خیلی وقتا در طول پروسه نوشتن Charactrization تست ها اتفاق میفته که متوجه میشیم فرضمون از رفتار سیستم اشتباه بوده یا قسمتی از رفتار سیستم رو کلا ندیده بودیم، که باعث ایجاد کلی سوال از رفتار سیستم میشه و این نقطه شروعی برای بررسی دقیقتر رفتار سیستم هست. اگر فکر میکنید رفتار پنهانی که تو سیستم پیدا کردید باگ نیست بهترین راه اینه که برای این رفتار پنهان هم تست بنویسید. این دانش و فهمی که از رفتار سیستم در نتیجه بررسی برای نوشتن Charactrization تست ایجاد میشه یکی از ارزشمندترین نتایج حاصل از نوشتن این نوع تست هست.

و اصلی ترین هدف Charactrization تست رو میشه داکیومنت کردن رفتار واقعی سیستم بیان کرد نه رفتاری که ما از سیستم انتظار داریم.

نکته ای در برخورد با LegacyCode ها باید حواسمون باشه اینه که وقتی سیستمی لانچ میشه با تمام خصوصیات و رفتاراش برای یوزرهاش شناخته میشه، جدا از اینکه اون خصوصیات از نظر فنی درست یا غلط باشه. به طور خلاصه هررفتاری که از نظر ما ممکنه باگ باشه از نظر کاربرهای اون سیستم ممکنه فیچر و رفتار طبیعی محسوب بشه. این نکته ی خیلی مهمیه که باید زمان Refactor یک LegacyCode بهش توجه کنیم جدا از اینکه ما فکر میکنیم اون رفتار غلط یا درسته.

تو این پست سعی کردم یه تصویر خیلی کلی از CharactrizationTest بهتون بدم اگه دوست دارید بیشتر راجع به بهبود Legacy Code ها بدونید، بهتون پیشنهاد میکنم کتاب Working Effectively with Legacy Code رو بخونید و این تمرین رو انجام بدید.