اثر مایکل فدرز (Michael Feathers)
نویسنده: مایکل فدرز
سال انتشار: ۲۰۰۴ (چاپ مجدد با ویرایشهای جدید)
تعداد صفحات: 464 صفحه
ژانر: مهندسی نرمافزار، تست نرمافزار، بازسازی کد (Refactoring)
سطح مطالعه: متوسط تا پیشرفته (آشنایی با مفاهیم پایه تست و شیءگرایی)
چرا این کتاب؟ چرا حالا؟
احتمالاً برایت پیش آمده که به یک پروژهی قدیمی اضافه شدهای. کد را باز میکنی، چند خط میخوانی، بعد فکر میکنی: «این کد را چه کسی نوشته؟» بعد از چند دقیقه میفهمی که خودت دو سال پیش نوشتهای.
شوخی کنار. واقعیت این است که اکثر نرمافزارهای جهان، کد قدیمی (Legacy Code) هستند. نه فقط سیستمهای دههی هشتاد و نود، بلکه پروژهای که سه ماه پیش شروع شده و حالا به خاطر عجله و بیتوجهی به معماری، تبدیل به یک آشفتگی غیرقابل لمس شده است.
در طول سالها مشاوره معماری، با تیمهای زیادی کار کردهام که بزرگترین مشکلشان کد قدیمی است. اما جالب اینجاست که تعریفشان از کد قدیمی اشتباه است. فکر میکنند کدی قدیمی است که دیروز نوشته شده یا زبانش قدیمی است. در حالی که مایکل فدرز در این کتاب یک تعریف ساده و ترسناک ارائه میدهد:
کد قدیمی (Legacy Code)، کدی است که تست ندارد.
نه سن کد، نه زبانش، نه تکنولوژیاش. نبود تست. چون وقتی تست نباشد، نمیتوانی با اطمینان تغییرش دهی. و وقتی نتوانی تغییرش دهی، قفل میشوی. و وقتی قفل شوی، پروژه میمیرد.
این کتاب، راه نجات است.
مشکل اصلی: چرا تغییر در کد قدیمی اینقدر ترسناک است؟
تصور کن باید یک ویژگی جدید به سیستمی اضافه کنی که ده سال پیش نوشته شده. مستندی نیست. تیم اولیه رفتهاند. کدها آنقدر درهم هستند که نمیدانی یک تغییر کوچک چه عواقبی دارد. چه کار میکنی؟
اکثر تیمها سه راه اشتباه را انتخاب میکنند:
-
بازنویسی از صفر (Rewrite): میگویند «بیایید همه چیز را دور بریزیم و از اول بنویسیم». نتیجه؟ شش ماه بعد، سیستم جدید هنوز به قابلیتهای سیستم قدیم هم نرسیده، و تیم از کار افتاده است.
-
اضافه کردن روی قلاب: تغییر را به زور وارد میکنند، با کلی if و patch، سیستم را شکنندهتر میکنند، و بعد فرار میکنند.
-
انجماد (Freeze): میگویند «دیگر به این سیستم دست نزنید». سیستم میماند تا آرام آرام بمیرد، در حالی که رقبا جلو میروند.
فدرز در این کتاب راه چهارمی پیشنهاد میدهد: تغییر تدریجی و ایمن با ایجاد یک شبکه ایمنی (Safety Net) از تستها.
تعریف کلیدی؛ Legacy Code یعنی کد بدون تست
یکی از تأثیرگذارترین تعاریف کتاب، همین است:
کد قدیمی، کدی است که تست ندارد.
این تعریف را جدی بگیر. یعنی اگر پروژهات دیروز شروع شده و تست ندارد، همین الان کد قدیمی داری. یعنی حتی تمیزترین معماری، اگر بدون تست باشد، با اولین تغییر جدی میشکند.
اما نکته مثبت این تعریف این است که قابل حل است. میتوانی کدِ بدون تست را به کدِ با تست تبدیل کنی. و هر چقدر پوشش تست بیشتر باشد، کد کمتر «قدیمی» میشود.
فدرز به جای اینکه به تو یاد بدهد کدهای قدیمی را درمان کنی، به تو یاد میدهد چطور با آنها زندگی کنی، چطور قدم به قدم آنها را امنتر کنی، و چطور بدون ترس تغییرشان دهی.
هسته کتاب: تغییر امن با تست
کل فلسفه کتاب بر اساس یک چرخه ساده استوار است:
شناسایی نقطه تغییر
↓
نوشتن تست برای رفتار فعلی (Characterization Test)
↓
اعمال تغییر کوچک
↓
اجرای تستها (اگر شکست خورد، یعنی رفتار عوض شده)
↓
در صورت موفقیت، تغییر بعدی
به این تستها، تست شخصیتدهی (Characterization Tests) میگویند. تو رفتار فعلی سیستم را «ثبت» میکنی، بدون اینکه بدانی درست است یا غلط. بعد تغییر را اعمال میکنی. اگر تستها پاس نشدند، یعنی رفتار عوض شده. اگر پاس شدند، یعنی تغییرات تو رفتار را خراب نکردهاند.
این روش به تو اجازه میدهد بدون دانش کامل از سیستم، آن را تغییر دهی. فقط کافی است بدانی «فعلاً این خروجی را دارد»، بعداً تصمیم بگیری که آیا این خروجی درست است یا نه.
بخش پنجم: ابزارهای کلیدی کتاب
فدرز در کتاب، ابزارهای عملی زیادی برای کار با کد قدیمی ارائه میدهد. مهمترین آنها:
۱. جداسازی وابستگیها (Dependency Breaking)
بیشتر کدهای قدیمی غیرقابل تست هستند چون وابستگیهای پنهان دارند: اتصال به دیتابیس، فراخوانی API خارجی، خواندن از فایل، یا استفاده از کلاسهای Singleton.
فدرز تکنیکهایی مثل Extract Interface، Introduce Instance Delegator، و Sprout Method/Class را آموزش میدهد تا بتوانی بدون تغییر منطق اصلی، وابستگیها را «بشکنی» و کد را قابل تست کنی.
۲. تست شخصیتدهی (Characterization Tests)
وقتی با یک قطعه کد بزرگ مواجه میشوی که اصلاً نمیدانی چه کار میکند، اولین قدم نوشتن تستی است که ورودی مشخص را میدهد و خروجی فعلی را تأیید میکند. این تست به تو میگوید: «اگر بعداً کسی این تابع را تغییر داد و خروجی عوض شد، من به تو خبر میدهم».
۳. تغییرات پلهای و کوچک
فدرز بر خلاف بسیاری از نویسندگان، بازسازی بزرگ (Big Refactoring) را توصیه نمیکند. او میگوید هر بار یک تغییر بسیار کوچک انجام بده و بعد تستها را اجرا کن. به این روش Refactoring در مقیاس میکرو میگویند.
۴. تفکر سیستمی در Legacy
جالب است که این کتاب ارتباط مستقیمی با شعار آکادمی ما Think in Systems دارد. فدرز میگوید وقتی با کد قدیمی مواجه میشوی، نباید فقط به تکتکههای کد نگاه کنی. باید کل سیستم را ببینی: وابستگیها، نقاط ورود و خروج، رفتارهای جانبی. این یعنی تفکر سیستمی در عمل.
نظر شخصی من
نقطه قوت اصلی کتاب، واقعگرایی محض آن است. فدرز فرض نمیکند شما تیم ایدهآلی دارید یا میتوانید همه چیز را از صفر بسازید. او در همان سنگر کثیف، با همان کدهای لعنتی، دست و پنجه نرم میکند و راهکارهای قابل اجرا ارائه میدهد.
نقطه ضعف کتاب؟ شاید این باشد که مثالهای آن به زبان ++C و جاواست و اگر با این زبانها آشنا نباشید، درک برخی تکنیکها سخت میشود. همچنین کتاب برای تازهکاران اصلاً مناسب نیست، حداقل دو سال تجربه عملی میخواهد.
با این حال، اگر قرار باشد من فقط چند کتاب به تیمهای فنی توصیه کنم، یکی از آنها همین است.
این کتاب برای چه کسانی است؟
| گروه | چرا این کتاب برای آنها مفید است؟ |
|---|---|
| توسعهدهندگانی که به تیم قدیمی اضافه شدهاند | یاد میگیرید چطور بدون ترس و با ضمانت، تغییر ایجاد کنید |
| تیمهایی که با بحران بدهی فنی مواجه هستند | یک نقشه راه عملی برای کاهش تدریجی بدهی فنی دریافت میکنید |
| معمارانی که میخواهند فرآیند مهاجرت به معماری جدید را مدیریت کنند | میآموزید چطور سیستم قدیمی را زنده نگه دارید تا سیستم جدید آماده شود |
| هر کسی که از تغییر کد میترسد | این ترس را از بین نمیبرد، اما به شما ابزار کنترل آن را میدهد |
کتاب برای تازهکاران مطلق مناسب نیست. اگر با مفاهیم شیءگرایی و تست نویسی آشنایی ندارید، ابتدا آنها را یاد بگیرید و بعد سراغ این کتاب بیایید.
نقل قولهای کلیدی از کتاب
کد قدیمی، کدی است که تست ندارد.
هدف از Refactoring، زیبا کردن کد نیست. هدف، قابل تغییر کردن کد است.
اگر از تغییر کد میترسی، اشکالی ندارد. اما اگر راهی برای کنترل ترس نداشته باشی، مشکل داری.
هر تغییری را با یک تست کوچک شروع کن. بعد تغییر کوچک. بعد تست بعدی. اینجا هیچ میانبری وجود ندارد.
نظرات بزرگان درباره این کتاب
رابرت مارتین (Uncle Bob):
این کتاب به تو یاد میدهد چطور در سنگر کدهای قدیمی، بدون ترس و با اعتماد به نفس، جلو بروی. یکی از ضروریترین کتابهای مهندسی نرمافزار.
بعد از این کتاب، چه بخوانیم؟
| کتاب | دلیل |
|---|---|
| Refactoring (مارتین فاولر) | کتابی که پایههای Refactoring را بنا نهاد. مکمل این کتاب است. |
| Clean Code (رابرت مارتین) | برای اینکه بدانی کد تمیز چه کدی است. چون Legacy معمولاً برعکس آن است. |
| Design Patterns (گاما و رفقاش) | بسیاری از تکنیکهای کتاب نیاز به شناخت الگوهای طراحی دارد. |
سخن پایانی
کتاب Working Effectively with Legacy Code، فقط یک کتاب فنی نیست. یک تغییر نگرش است. به تو یاد میدهد که با کدهای قدیمی نجنگی، بلکه با آنها زندگی کنی. آنها را تدریجاً به سمت سلامت حرکت دهی. و مهمتر از همه، بدون ترس تغییرشان دهی.