قسمت پنجم از سری «زنجیرهٔ تفکر»: اینبار تکنیک را میبریم سراغ کد. اینکه چطور بهجای گرفتن یک پچ کور، مدل را وادار کنی مسیر رسیدن به باگ را بنویسد، چطور بازخوانی کد و نوشتن تست را گامبهگام کنی، و کجا در پروژههای بزرگ این روش کم میآورد.

لیست مطالب
۱. چرا دیباگ ذاتاً یک مسئلهٔ چندمرحلهای است
وقتی یک تابع خروجی اشتباه میدهد، بین «علامت» و «علت» معمولاً چند حلقه فاصله است. علامت چیزی است که میبینی: یک استثنا، یک عدد غلط، یک صفحهٔ خالی. علت جای دیگری است: یک شرط مرزی، یک تبدیل نوع بیصدا، یک مقدار پیشفرض که کسی دو ماه پیش عوض کرده. راهِ رسیدن از علامت به علت یک پرش نیست، یک زنجیره است.
وقتی کد را میدهی و میگویی «درستش کن»، از مدل خواستهای همین زنجیره را در ذهنش طی کند و فقط نتیجه را بنویسد. خروجی معمولاً یک پچ آبرومند است که ممکن است علامت را از بین ببرد بدون آنکه علت را لمس کند. این بدترین حالت ممکن است، چون باگ از دید تو ناپدید میشود اما در کد باقی میماند.
زنجیرهٔ تفکر اینجا نقش متفاوتی نسبت به مسائل ریاضی دارد. در حساب، هدف اصلی جلوگیری از خطای محاسبه بود؛ در کد، هدف اصلی این است که بتوانی استدلال مدل را رد کنی. اگر مدل بنویسد «فرض من این است که ورودی همیشه مرتبشده میرسد» و تو بدانی این فرض غلط است، در همان خط ماجرا تمام شده — بدون آنکه حتی یک خط پچ را اجرا کرده باشی.
۲. تفاوت «کد را درست کن» با «باگ را ردیابی کن»
این دو درخواست دو خروجی کاملاً متفاوت میسازند. درخواست اول مدل را در حالت تولیدکننده میگذارد: کد جدید مینویسد. درخواست دوم مدل را در حالت بازرس میگذارد: دربارهٔ کد موجود حرف میزند. برای دیباگ، حالت دوم تقریباً همیشه بهتر است، حتی اگر در نهایت به کد جدید برسی.
یک تفاوت عملی دیگر هم هست. وقتی میگویی «درستش کن»، مدل انگیزه دارد تغییری بدهد، حتی اگر کد سالم باشد. تجربهٔ رایج این است که مدل چند خط بیربط را هم بازنویسی میکند، متغیرها را تغییر نام میدهد و در نهایت دیفی به تو میدهد که مرورش از خودِ باگ سختتر است. وقتی میگویی «فقط ردیابی کن و هنوز چیزی ننویس»، این انگیزه را برداشتهای.
قاعدهٔ عملی: مرحلهٔ تشخیص را از مرحلهٔ اصلاح جدا کن، و بین این دو مرحله خودت یک بار مداخله کن. جدا کردن این دو، همان کاری است که در قسمت چهارم با چند زنجیرهٔ موازی انجام دادیم، فقط اینجا بهجای رأیگیری، تو داورِ بین دو مرحلهای.
۳. پروتکل پنجمرحلهای ردیابی باگ
ساختاری که در کد بهتر از «قدمبهقدم فکر کن» جواب میدهد، یک زنجیرهٔ مرحلهدار با نامهای مشخص است. پنج مرحلهای که در عمل کافیاند:
مرحلهٔ اول، بازگویی علامت. مدل باید با زبان خودش بنویسد دقیقاً چه چیزی خراب است و چه چیزی سالم. این مرحله بیشترین بدفهمیها را همان اول رو میکند.
مرحلهٔ دوم، فهرست فرضیهها. سه تا پنج علت محتمل، بدون قضاوت. مهم است که چند فرضیه بخواهی، وگرنه مدل روی اولین حدسش قفل میشود.
مرحلهٔ سوم، شواهد له و علیه هر فرضیه، مستقیماً با ارجاع به خطهای کد. اینجا جایی است که فرضیههای ضعیف میریزند.
مرحلهٔ چهارم، انتخاب محتملترین علت و نوشتن یک آزمایش کوچک که آن را تأیید یا رد کند — یک لاگ، یک تست، یک ورودی خاص.
مرحلهٔ پنجم، و فقط بعد از تأیید، پیشنهاد اصلاح بهصورت کمترین تغییر ممکن.
ترتیب این پنج مرحله تصادفی نیست. مرحلهٔ سوم بدون مرحلهٔ دوم بیمعنی است، و مرحلهٔ پنجم بدون مرحلهٔ چهارم همان حدسزدنی است که میخواستیم از آن فرار کنیم.

۴. بازخوانی کد پیش از اجرا
کاربرد دوم زنجیرهٔ تفکر در کد، بازخوانی است: کدی که هنوز باگ گزارششدهای ندارد، اما میخواهی پیش از ادغام مرورش کنی. اینجا مسئله این است که مرور کلی («این کد را بررسی کن») تقریباً همیشه به جملههای تعارفی ختم میشود.
راهحل، دادن یک مسیر بازخوانی مشخص به مدل است. از او بخواه کد را در سه گذر بخواند و نتیجهٔ هر گذر را جدا بنویسد: گذر اول فقط جریان داده — چه چیزی وارد میشود، کجا تغییر شکل میدهد، چه چیزی برمیگردد. گذر دوم فقط حالتهای مرزی — ورودی خالی، مقدار تهی، عدد منفی، آرایهٔ تکعضوی، رشتهٔ خیلی بلند. گذر سوم فقط خطاها — چه چیزی میتواند استثنا بیندازد و آیا کسی آن را میگیرد.
سه گذر جدا، سه زنجیرهٔ کوتاه است بهجای یک زنجیرهٔ بلندِ درهم. مزیتش این است که هر گذر تمرکز خودش را دارد و خروجیاش قابل چک است. اگر همه را در یک درخواست بریزی، مدل معمولاً دو مورد از گذر اول را میگوید و بقیه را رها میکند.
۵. نوشتن تست با استدلال گامبهگام
در نوشتن تست، اشتباه رایج این است که مستقیم میگوییم «برای این تابع تست بنویس» و مدل چند تست بدیهی مینویسد که همگی سبز میشوند و هیچچیز را ثابت نمیکنند. علت روشن است: مدل بدون فکر کردن به رفتار، از روی امضای تابع تست ساخته.
ترتیب درست این است: اول از مدل بخواه قرارداد تابع را بنویسد — ورودیهای معتبر، خروجی مورد انتظار، رفتار در حالتهای نامعتبر. بعد از او بخواه فهرست حالتهایی را بسازد که ارزش تست دارند و کنار هرکدام بنویسد چه چیزی را ثابت میکند. تنها در گام سوم اجازه بده کد تست را بنویسد.
مزیت این ترتیب فقط کیفیت تست نیست؛ فهرست گام دوم خودش سندی است که میتوانی بخوانی و بگویی «حالت ورودی تکراری را جا انداختی». مرور یک فهرست دهخطی از مرور صد خط کد تست بسیار سریعتر است.
۶. پرامپت آمادهٔ کپی برای ردیابی باگ
این قالب را میتوانی بدون تغییر بردار. تنها کاری که باید بکنی، چسباندن کد و شرح علامت است:
نقش تو ردیاب باگ است، نه نویسندهٔ کد. تا وقتی نگفتم «اصلاح کن»، هیچ کد اصلاحشدهای ننویس.
خروجی را دقیقاً در پنج بخش شمارهدار بده.
بخش یک با عنوان «علامت»: با زبان خودت بنویس چه چیزی خراب است و چه چیزی درست کار میکند.
بخش دو با عنوان «فرضیهها»: سه تا پنج علت محتمل را فهرست کن، از محتملترین به کماحتمالترین، بدون توضیح اضافه.
بخش سه با عنوان «شواهد»: برای هر فرضیه، شواهد موافق و مخالف را با ارجاع به شمارهٔ خط بنویس. اگر برای فرضیهای شاهدی نداری، همان را بنویس.
بخش چهار با عنوان «آزمایش»: یک آزمایش کوچک و مشخص پیشنهاد بده که محتملترین فرضیه را رد یا تأیید کند، و بنویس اگر نتیجه الف بود یعنی چه و اگر ب بود یعنی چه.
بخش پنج با عنوان «فرضهای من»: هر فرضی که دربارهٔ محیط، نسخه یا داده گذاشتی صریح بنویس.
اگر برای ردیابی به اطلاعاتی نیاز داری که در اختیارت نیست، بهجای حدس زدن در بخش پنج بنویس چه چیزی لازم داری.
علامت: [اینجا بنویس چه اتفاقی میافتد و چه انتظاری داشتی]
کد: [اینجا کد را بچسبان]
نکتهٔ کلیدی این قالب، جملهٔ اول است. بدون آن، مدل معمولاً همان بخش اول را مینویسد و بعد بیاجازه میپرد سراغ کد اصلاحشده، و کل ساختار میریزد.

۷. مرزها: کجا این روش در پروژهٔ بزرگ کم میآورد
محدودیت اول، دامنهٔ دید است. زنجیرهٔ تفکر فقط دربارهٔ چیزی میتواند استدلال کند که جلوی چشمش باشد. اگر علت باگ در فایلی است که نچسباندهای، مدل با اطمینان کامل دربارهٔ فایلهای موجود استدلال میکند و به علتی میرسد که اصلاً علت نیست. راه مقابله ساده است: در بخش فرضها صریح از او بخواه بنویسد چه چیزی را ندیده.
محدودیت دوم، رفتار زمان اجرا. باگهای همزمانی، شرایط رقابتی، نشت حافظه و مشکلات وابسته به بار، از روی خواندن کد بهسختی قابل استدلالاند. اینجا زنجیرهٔ تفکر میتواند فرضیه بسازد، اما داور نهایی لاگ و پروفایلر است نه متن مدل.
محدودیت سوم، طول زنجیره. هرچه فایلهای بیشتری بدهی، احتمال اینکه مدل در میانهٔ راه رشتهٔ استدلال را گم کند بیشتر میشود. راهحل عملی، شکستن مسئله است: اول از مدل بخواه بگوید باگ محتملاً در کدام لایه است، بعد فقط همان لایه را با جزئیات بده.
محدودیت چهارم، و مهمترینشان، استدلالی است که قانعکننده بهنظر میرسد ولی به نتیجهاش وصل نیست. مدل ممکن است پنج بخش را بینقص بنویسد و در بخش پنجم اصلاحی پیشنهاد دهد که با استدلال خودش همخوان نیست. این پدیده آنقدر مهم است که موضوع اصلی قسمت ششم است.
۸. پرسشهای پرتکرار
آیا برای زبانهای برنامهنویسی خاص باید قالب را عوض کنم؟ ساختار پنجبخشی زبانمستقل است. تنها چیزی که ارزش اضافه کردن دارد، نسخهٔ زبان و کتابخانه است، چون رفتار مرزی بین نسخهها فرق میکند.
چقدر کد بچسبانم؟ کمترین مقداری که مسئله را کامل توصیف کند: تابع خطادار، امضای چیزهایی که صدا میزند، و یک نمونهٔ ورودی واقعی. چسباندن کل فایل معمولاً کیفیت استدلال را پایین میآورد، نه بالا.
اگر مدل در بخش شواهد شمارهٔ خط اشتباه بدهد چه کنم؟ این نشانهٔ خوبی است که دامنهٔ دید کافی نبوده. بهجای اصلاح کردن او، کد را با شمارهگذاری صریح خط بچسبان و همان درخواست را تکرار کن.
این روش را با نقشدهی هم میشود ترکیب کرد؟ بله، و ترکیب درست این دو تکنیک موضوع قسمت هفتم است. اگر با اصول اولیهٔ نوشتن پرامپت راحت نیستی، ابتدا راهنمای پرامپتنویسی برای مبتدیها را ببین و بعد سراغ ترکیب برو.
برای تمرین بیشتر روی ابزارها کجا بروم؟ مجموعهٔ آموزشهای ChatGPT نمونههای عملی بیشتری دارد که میتوانی همین ساختار را رویشان پیاده کنی.
در پروتکل ردیابی باگ، چرا مرحلهٔ «فرضیهها» باید قبل از مرحلهٔ «شواهد» بیاید؟
این تمرین ویژهٔ اعضاست
برای دیدن این بخش باید عضو ویژه (VIP) باشی. با شمارهٔ موبایلت وارد شو تا ۱۴ روز دسترسی رایگان فعال شود.
🎁 ورود / ثبتنام و شروع ۱۴ روز رایگان