یک شرکت باربری بینشهری در قزوین کرایه هر بسته را از روی وزن، ابعاد و مقصد درمیآورد. تابعی که تحویل گرفته شد بیست سطر بود و کار میکرد. نسخه بازنویسیشده شش سطر است و روی هر سه فاکتور نمونه دقیقاً همان عددهای قبلی را میدهد: ۸۴۸۰۰ برای مشهد، ۱۲۵۱۲۰ برای زاهدان و ۸۲۸۰۰ برای تهران.
def keraye(vazn_kg, tool, arz, ertefa, shahr):vazn_mohasebe = max(vazn_kg, vazn_hajmi(tool, arz, ertefa))mablagh = PAYE.get(shahr, PAYE_PISHFARZ) + vazn_mohasebe * NERKH_KILOif shahr in DOOR: mablagh *= ZARIB_DOORreturn mablagh
چهار حرکت این کار را کرد و هرکدام یک حرکت است نه یک سلیقه. نام چیز را بگذارید نه نوع چیز را: vazn_kg بهتر از w است، و shahr بهتر از c. جدول جای زنجیره شرط را میگیرد و PAYE.get(shahr, PAYE_PISHFARZ) پنج شاخه را یکی میکند، و شهر تازه از این به بعد یک سطر داده است نه یک شاخه کد؛ شهری که در جدول نباشد کرایه پایه پیشفرض ۷۵۰۰۰ میگیرد. max(vazn_kg, vazn_hajmi(tool, arz, ertefa)) همان کاری را میکند که if و else میکردند، و چون وزن حجمی حالا اسم دارد، دو بار حساب نمیشود. و ضریب مسیر دور یک ثابت نامدار شد بهجای عددی که وسط یک شرط نشسته بود.
چیزی که این بازنویسی را بازآرایی کرد، مهارت نبود
سه عدد بالا پیش از دست زدن به تابع نوشته شده بودند. بازآرایی یعنی آزمونها قبل و بعد سبز باشند و جواب تکان نخورد؛ بدون آن، همین ویرایشها بازنویسیاند، و بازنویسی برنامه تازهای است که ایرادهای برنامه قبلی را ندارد و ایرادهای خودش را دارد.
حلقه عمداً کوچک است: یک تغییر شکل، اجرای بررسی، کامیت. اگر تغییر نام c به shahr و تخت کردن شاخهها در یک کامیت انجام شود، وقتی کرایه زاهدان عوض شد دو متهم دارید و راهی برای جدا کردنشان ندارید. جدا انجام دادنشان یک دقیقه خرج دارد و قطعیت میخرد، و همین انضباط عوض کردن شکل، بدون عوض کردن رفتار است.
تابعی را استخراج کنید که بلوکش برای فهمیدن به توضیح نیاز دارد، و آزمونی که این را صادق نگه میدارد این است: اگر نتوانستید اسم تابع استخراجشده را بگذارید، آن بلوک یک ایده نبوده. تلاش اول برای بیرون کشیدن یک hesab_kon شکست خورد چون آن بلوک هم وزن را حساب میکرد و هم تخفیف را اعمال میکرد، و همان بینامی بود که این را گفت.
آنچه کد نمیتواند بگوید
توضیحی که میگوید کد چه میکند، تغییر نامی است که ندادید، و میپوسد چون هیچ چیز بررسیاش نمیکند. توضیح ارزشمند میگوید چرا، و کد نمیتواند چرا را بگوید. کرایه زاهدان پانزده درصد بیشتر است چون مسیر از یک مرکز میانی رد نمیشود و ماشین خالی برمیگردد؛ هیچ چیز در keraye نمیتواند این را حمل کند، و روزی که کسی ZARIB_DOOR را «سادهسازی» کند، دلیلش هم با آن میرود. همین مرز و لبههایش چیزی که کد خودش نمیتواند بگوید است، و نامها که ارزانترین نیمه ماجرا هستند ارزانترین مستندی که وجود دارد.
توضیحها
چه چیزی باید نوشته شود، و چه چیزی را کد از قبل گفته است
پرسش هیچوقت این نیست که چند توضیح. این است که آن حرف جای دیگری برای زندگی کردن دارد یا نه.
- چرا زاهدان پانزده درصد بیشتر استماشین خالی برمیگردد. هیچ کدی این را نمیتواند حمل کند.
- یک تابع عمومی چه قولی میدهدیک داکاسترینگ. قرارداد جای دیگری برای ماندن ندارد.
- چرا کرایه پایه پیشفرض ۷۵۰۰۰ استشهری که در جدول نیست همین را میگیرد، و عدد تا وقتی گفته نشود دلبخواهی به نظر میرسد.
- اینکه این حلقه چه میکندبهجایش نامها را عوض کنید. نام مثل توضیح کهنه نمیشود.
- اینکه mablagh جمع میشودهیچکس تا حالا به گفتنش نیاز نداشته.
این جایگذاریها مالِ یک نگهدارنده است و از سه سال کار با همین نرمافزار درآمده. کس دیگری داکاسترینگ را جابهجا میکند، و بحث درباره جای آن، نیمه بهدردبخور ماجراست.
ابزار، و سالی که این حرف درست است
Ruff در سال ۲۰۲۶ هم قالببند پایتون است و هم بازرس آن، رایگان و متنباز، و جای flake8 و isort و black را گرفت که هرکدام کل فایل را جدا میخواندند. روی تابع قدیمی، شاخهای را که هیچوقت اجرا نمیشد و نامی را که یک نام داخلی را پوشانده بود بدون بحث سلیقهای نشان میدهد، و همان نیمه بازبینی است که از اول نباید کار آدم میبود.
pytest دومی است و جای همان کلاسسازی اجباری را گرفت که unittest هنوز در کتابخانه استاندارد میخواهد. سه سطر که ۸۴۸۰۰ و ۱۲۵۱۲۰ و ۸۲۸۰۰ را ادعا میکنند، همان چیزی است که بازنویسی بالا را از قمار به بازآرایی تبدیل کرد. تنها ابزار این صفحه است که نصب میخواهد، و از ایران یعنی همان تنظیم --index-url که برای هر بسته دیگری هم لازم است.
دستیار کدنویسی داخل ویرایشگر نیمه مکانیکی این کار را انجام میدهد و این را باید دقیق گفت: جای تغییر نام دستی در چهل فایل را گرفت و در همان کار از آدم بهتر است. درباره اینکه این تغییر اصلاً ارزش داشت یا نه با اطمینان اشتباه میکند، چون آن قضاوت به داستان ماشین خالی نیاز دارد که در هیچ مخزنی نیست. دسترسی هم صاف نیست: بیشتر این سرویسها از ایران پرداخت و گاهی اتصال میخواهند، و نسخههای رایگانشان برای همین نیمه مکانیکی کافی است. تغییر نام را بگیرید. بازسازی ساختار را بخوانید.
اشتباه: بازنویسی که اسمش را بازآرایی گذاشتهاند
تابع بیست سطری زشت بود و وسوسهاش این است که از صفر نوشته شود. کسی که این کار را بدون نوشتن سه عدد بالا انجام بدهد، به احتمال زیاد ZARIB_DOOR را جا میاندازد، چون آن شرط ته تابع قدیمی و دور از بقیه منطق نشسته بود. آن وقت کرایه زاهدان بهجای ۱۲۵۱۲۰، عدد ۱۰۸۸۰۰ درمیآید: هیچ خطایی، هیچ آزمون قرمزی، و یک شکاف که سه ماه بعد در تسویه با نماینده زاهدان پیدا میشود.
جایی که این درس در ایران میایستد هم دقیقاً همینجاست، و شکل عجیبی دارد. «کد تمیز» اینجا بهشکل فهرستی از قاعده وارد شده: تابع کوتاه باشد، توضیح ننویسید، نامها بامعنا باشند. قاعدهها حفظ میشوند و در بازبینی به هم گفته میشوند، و بازبینی تبدیل میشود به بحث سلیقهای درباره طول تابع. اما هیچکدام از آن قاعدهها نمیگوید جواب را از قبل بنویس، که تنها چیزی است که تفاوت بازآرایی و قمار را میسازد. تیمی که هر سه قاعده را رعایت میکند و هیچ ادعای عددی ندارد، تمیزتر مینویسد و بیشتر خراب میکند.
بازبینی وقتی برمیگردد که بیست نظر روی آن باشد و مثل نمره خوانده میشود. راهش این است که پیش از جواب دادن، مرتبشان کنید: معمولاً دو سهتا نقصاند، یعنی کد اشتباه است و موردی هست که ثابتش میکند، و بقیه ترجیحاند. مرتب کردن آن هجدهتا از آن دوتا بیشتر دنبال چه بگردید، و چطور بگویید است. چیزی که این صفحه نگفت این است که وقتی عدد اشتباه درآمد چطور پیدایش میکنید، که مهارتی دیگر با روالی مشخص است: اشکالزدایی. سه ادعایی هم که این بازآرایی را امن کرد کوچکترین نسخه چیزی است که زیر انتشار و استقرار جدی میشود، و شکلهای نامداری که یک بازآرایی معمولاً به آنها میرسد الگوهای طراحی هستند، همه زیر ایدههایی که با عوض شدن زبان از بین نمیروند.