«این پروژه README ندارد.» «پس از کجا شروع کنم؟» این گفتوگو روز اول هر کار تازهای تکرار میشود، و جواب رایجش، یعنی «از فایل اصلی شروع کن و بخوان»، بدترین جواب ممکن است.
بیشتر عمر حرفهای یک برنامهنویس به خواندن کد دیگران میگذرد، نه نوشتن کد خودش، و این مهارت تقریبا جایی آموزش داده نمیشود. با آمدن دستیارهای کدنویسی هم اهمیتش کم نشده، بیشتر شده است: ایجنتی که کدبیس را نفهمد، کدی مینویسد که به آن نمیخورد، و کسی که باید خروجیاش را قضاوت کند، خودش باید کدبیس را بفهمد.
چرا خواندن از اول جواب نمیدهد
کدبیس ناآشنا مثل ساختمانی است که باید در آن کار کنی و نقشهاش گم شده. خواندن کل کد یعنی دیوار به دیوار وارسی کنی؛ شدنی نیست و بیشترش هم به کارت نمیآید. مستندات، اگر باشند، معمولا کهنهاند. ولی یک مسیر اجرای واقعی همیشه راست میگوید. دنبال کردن یک مسیر مثل باز کردن شیر آب است: میبینی آب از کجا میآید و به کجا میرود، و در ده دقیقه بیشتر از یک روز نقشهخوانی یاد میگیری.
مسیر یک چیز دیگر هم نشان میدهد: چه چیزی واقعا استفاده میشود. در کدبیس قدیمی، بخش بزرگی از کد مرده است و خواندنش فقط وقت میبرد.
چهار پرسش، دقیقا به همین ترتیب
ورودی از کجا میآید؟
مسیرهای وب، صف، کارهای زمانبندیشده، وبهوک. فهرست نقطههای ورود، نقشهی واقعی سیستم است.
داده کجا مینشیند؟
جدولها و مدلها. شکل داده معمولا معماری را بهتر از خود کد لو میدهد.
چه چیزی بیرون میرود؟
پاسخ، پیامک، صدا زدن سرویسهای دیگر، پرداخت. اینها عوارض جانبیاند و پرخطرترین بخش هر کدبیس، چون برگشتپذیر نیستند.
وقتی میشکند، کجا معلوم میشود؟
لاگ، هشدار، یا هیچجا. اگر جواب «هیچجا» است، این مهمترین یافتهی روز اول توست.
ترتیب مهم است. اگر از پرسش سوم شروع کنی، هر بار در کدی گم میشوی که هنوز نمیدانی چه وقت صدا زده میشود.
یک جلسهی چهلدقیقهای روی هفتاد هزار خط
کدبیسی که این روش رویش اجرا میشود حدود هفتاد هزار خط کد دارد، هیچ README ندارد و هیچ تست خودکاری هم ندارد. بزرگترین فایلش شش هزار و دویست و شصت خط است و دومی سه هزار و ششصد و چهل و هشت خط با صد و پنجاه و هفت هندلر. این دو فایل بخش عمدهی کد مسیرها را در خود دارند. برای کار خودت، این عددها را فرضی بگیر؛ نمونهایاند تا روش دیده شود.
دقیقههای اول، نقطههای ورود. بهجای باز کردن فایلها، با یک جستوجوی متنی در پوشهی مسیرها همهی تعریفهای get و post و put و delete شمرده میشوند و بر اساس نوع دسته میشوند. حالا معلوم است چند نقطهی ورود هست و از چه نوعی، بیآنکه یک خط منطق خوانده شده باشد.
دقیقههای بعد، شکل داده. فهرست جدولها درمیآید: شصت و نه جدول. چیزی که بلافاصله به چشم میآید، جدولی به اسم users است و جدول دیگری به اسم user_products؛ یعنی سیستم در مدل دادهاش چندمحصولی است. این یک پرسش فوری میسازد: آیا همهی کوئریها به محصول محدود میشوند؟ جوابش بعدا معلوم شد: نه.
بعد، عوارض جانبی. جستوجو برای جاهایی که پیامک میفرستند، پرداخت میکنند یا سرویس بیرونی را صدا میزنند. این خطوط علامت میخورند. اولین چیزی که در یک کدبیس ناآشنا باید بدانی این است که کدام خطوط پول خرج میکنند.
دقیقههای آخر، دیدن خرابی. تست خودکار: صفر. یعنی هیچ شبکهی ایمنیای وجود ندارد.
تصمیمی که برخلاف غریزه است
غریزه میگوید سراغ فایل ششهزارخطی برو و بشکنش؛ بزرگترین و زشتترین چیز روی میز است. روش چیز دیگری میگوید: اول تست. نه چون تست کار خوبی است، چون بدون آن نمیفهمی چیزی را شکستهای. بازسازی هفتاد هزار خط بدون شبکهی ایمنی قمار است.
و تست اول باید از جنس خاصی باشد: تست توصیفی. یعنی تستی که بگوید الان چه اتفاقی میافتد، نه اینکه چه باید بیفتد. اگر رفتار فعلی باگ دارد، تست توصیفی همان باگ را ثبت میکند، و این درست است، چون هدف این مرحله حفظ رفتار است، نه اصلاحش. اصلاح بعدا و جدا میآید.
دربارهی خود فایل بزرگ هم یک نکته. اندازه به تنهایی نه خوب است نه بد. فایل بزرگی که یک کار منسجم انجام میدهد از پنج فایل کوچک درهمتنیده بهتر است. پرسش درست این است که این فایل به چند دلیل متفاوت ممکن است تغییر کند. اگر پنج دلیل، پنج مسئولیت دارد. شکستنش پیش از فهمیدن این، تکرار را فقط به فایلهای بیشتری پخش میکند.
در کدبیس ناآشنا، اولین کار بهتر کردن کد نیست؛ ساختن راهی است که بفهمی کی خرابش کردهای.
وقتی فردا صبح باید یک باگ را در همین کد درست کنی
نقشهی چهلدقیقهای برای تصمیم کلی است. ولی خیلی وقتها کار روز اول مشخصتر است: یک باگ گزارش شده و باید درستش کنی. اینجا هم از فایل اصلی شروع نکن و سراغ ساختار پوشهها هم نرو. یک درخواست واقعی را از ورودی تا خروجی دنبال کن؛ همان درخواستی که باگ در آن دیده شده.
از نقطهی ورودش شروع کن: کدام مسیر وب یا کدام کار زمانبندیشده آن را میگیرد؟ بعد ببین داده را از کدام جدول میخواند و در کدام مینویسد. بعد ببین چه چیزی از آن بیرون میرود. در هر قدم فقط همان چند خطی را بخوان که مسیر از آن رد میشود و بقیه را نادیده بگیر. معمولا پیش از اینکه به صد خط برسی، جای باگ تنگ شده است.
در همین مسیر حواست به پرسشی باشد که از شکل داده درآمد. اگر سیستم چندمحصولی است و کوئریای که از آن رد میشوی به محصول محدود نشده، ممکن است باگ گزارششده فقط نشانهی همین باشد: دادهی یک محصول در صفحهی محصول دیگر. چنین چیزی را یادداشت کن، حتی اگر کار امروزت نیست.
چهار نشانه که بیخواندن کد پیدا میشوند
| نشانه | چرا مهم است | چطور پیدا میشود |
|---|---|---|
| کد تکراری | اگر یک منطق ده جا کپی شده، اصلاح امنیتی بعدی باید ده بار انجام شود و یک بارش فراموش میشود | جستوجوی بلوکهای یکسان، نه دنبال کد زشت گشتن |
| رمز یا کلیدی که در مخزن ثبت شده | پاک کردنش از فایل کافی نیست؛ در تاریخچهی گیت میماند | جستوجوی کلمههایی مثل secret و password و api_key در تاریخچه |
| وابستگی با نسخهی قفلشده و بیتوضیح | دلیلی داشته که نوشته نشده؛ نفر بعدی آزادش میکند و چیزی میشکند | مقایسهی نسخههای دقیق با بقیهی وابستگیها |
| کامنت «یادت باشد اینجا را دستی عوض کنی» | وابستگی میان دو جا که هیچ ابزاری از آن محافظت نمیکند | جستوجوی کامنتهایی که به جای دیگری ارجاع میدهند |
کامنت آخر مفید است ولی راهحل نیست. راهحل یا یک منبع واحد برای آن مقدار است، یا تستی که وقتی دو جا از هم جدا شدند قرمز شود. «یادت باشد دستی» یعنی این روزی خراب میشود و کسی نمیفهمد.
یک ساعت، صد خط، یک کدبیس
کدبیسی انتخاب کن که ننوشتهای: یک پروژهی متنباز متوسط، کد محل کارت، یا پروژهی قدیمی خودت که جزئیاتش یادت رفته. قاعدهی اصلی این است که حق نداری بیش از صد خط کد بخوانی. بقیه باید از ساختار و ابزار دربیاید.
- چهار پرسش را به ترتیب جواب بده و کنار هر جواب، دستوری را که برایش زدی بنویس.
- نقطههای ورود را دربیاور و بشمار.
- فهرست جدولها یا مدلها را دربیاور و سه تای مرکزی را حدس بزن.
- خطوطی را که پول خرج میکنند یا پیام میفرستند پیدا کن.
- جواب «وقتی میشکند کجا معلوم میشود؟» را صریح بنویس، حتی اگر «هیچجا» است.
- چهار نشانه را جستوجو کن و نتیجهی هر کدام را بنویس.
- در یک جمله بگو اگر فقط یک چیز را اول درست میکردی، چه بود و چرا.
جملهی آخر باید یک انتخاب باشد با دلیل، نه فهرستی از مشکلات. اگر جواب پرسش چهارم «هیچجا» بود، که در بیشتر کدبیسها هست، آن جمله تقریبا همیشه این است: اول دیده شدن خرابی، بعد بقیه. یک استثنا دارد. اگر کدبیس کاری دارد که پول خرج میکند و هیچ محافظتی ندارد، آن اولویت اول است، چون هزینهاش همین حالا در حال جمع شدن است، نه فقط خطری برای آینده.
این نقشه تو را صاحب کدبیس نمیکند
یک ساعت نقشهبرداری کافی است تا بدانی از کجا شروع کنی و چه چیزی را نشکنی. برای قضاوت دربارهی معماری کافی نیست؛ آن قضاوت بعد از دنبال کردن چند مسیر واقعی میآید، نه پیش از آن. اگر میخواهی خواندن کد دیگران را کنار تاریخچهی گیت، پیدا کردن شکست خاموش، تستی که محافظت میکند و قضاوت دربارهی خروجی دستیار کدنویسی تمرین کنی، جزئیات این دوره را ببین.