Faragiri

همهٔ زبان‌ها

آموزش حل مسئله با بلند گفتنشاشکال‌زدایی

بلند گفتن مسئله کار می‌کند چون شما را وادار می‌کند فرض‌ها را جمله کنید. همان جمله‌ها را به‌شکل assert بنویسید تا مفسر بگوید کدامشان غلط است.

۴بخش
۳دقیقه خواندن
۴عمق

سه طرف، و طرفی که غایب است

چه کسی واقعا باگ را پیدا کرد

طرفی که کمترین نقش را دارد شنونده است، و طرفی که همه کار را می‌کند جمله‌ای است که مجبور شدید بسازید.

  • مجبور به جمله کردن
  • قابل بررسی می‌شود
  • هیچ چیزی لازم نیست بداند
  • شما
  • جمله‌ای که ساختید
  • شنونده
  • شمافرض‌های ضمنی را دارید و تا وقتی نگفته‌اید نمی‌بینیدشان
  • جمله‌ای که ساختیدهمان که ضمنی را صریح می‌کند، و بیشتر باگ‌ها همین‌جا پیدا می‌شوند
  • شنوندهمی‌تواند یک همکار باشد یا هیچ‌کس؛ نقشش وادار کردن شماست

این نمودار می‌گوید کار کجا انجام می‌شود و نه اینکه شنونده بی‌فایده است. یک همکار می‌تواند فرض بعدی را هم بپرسد، و assert فقط همان‌هایی را بررسی می‌کند که نوشته‌اید.

وقتی مسئله را برای کسی شرح می‌دهید و وسط توضیح خودتان جواب را پیدا می‌کنید، اتفاقی که افتاده این نیست که آن شخص چیزی گفته باشد. شما مجبور شده‌اید فرض‌های ضمنی را به جمله تبدیل کنید، و یکی از آن جمله‌ها همان لحظه غلط از آب درآمده.

همان کار را می‌شود بدون آدم و با دقت بیشتر انجام داد: هر جمله را به یک assert با پیام تبدیل کنید و بگذارید مفسر بگوید کدام غلط است.

  • assert satrha, "fayl satr dasht"
  • assert all("vazn" in r for r in satrha), "har satr sotune vazn darad"
  • assert all(r["vazn"] > 0 for r in satrha), "hich vazni sefr nist"

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

فرض را به‌شکل مقدار بنویسید، نه به‌شکل احساس

«فکر کنم داده مشکل دارد» قابل بررسی نیست. «فایل باید سه ستون داشته باشد و همه مقادیر وزن مثبت‌اند» قابل بررسی است و در دو سطر نوشته می‌شود. تفاوت این دو، تفاوت میان یک ساعت گشتن و یک دقیقه است.

قاعده‌ای که این را عملی می‌کند: هر جمله‌ای که در سرتان با «باید» شروع می‌شود یک assert است. هر جمله‌ای که با «فکر کنم» شروع می‌شود هنوز به جمله تبدیل نشده و اول باید دقیق شود.

assert جای اعتبارسنجی ورودی نیست

این تفاوت را زیاد اشتباه می‌گیرند و گران هم هست. اجرای پایتون با پرچم بهینه‌سازی، تمام assertهای برنامه را حذف می‌کند. پس هر بررسی‌ای که برای امنیت یا برای درستی ورودی کاربر لازم است باید یک if و یک raise باشد و نه یک assert. جای assert فرض‌های داخلی برنامه است: چیزهایی که اگر غلط باشند یعنی خود کد اشتباه است. مرزش را شکست پرصدا، شکست بی‌خطر، و فرق این دو می‌کشد.

و وقتی یک assert واقعا مفید بود، آن را دور نیندازید. همان جمله را به یک آزمون منتقل کنید تا دفعه بعد کسی لازم نباشد دوباره کشفش کند: یک چیز در هر بار، سریع و جدا.

جایی که کار گیر می‌کند، نبودن کسی برای گفتن است

خیلی از برنامه‌نویس‌ها در ایران تنها یا در تیم‌های دو نفره کار می‌کنند، اغلب دورکار، و طرف مقابلی که بشود مسئله را برایش گفت در دسترس نیست. راه‌حلی که خیلی‌ها انتخاب می‌کنند این است که همان توضیح را برای یک دستیار هوش مصنوعی بنویسند، و این واقعا کار می‌کند، ولی نه به دلیلی که فکر می‌کنند: بیشتر ارزشش در همان نوشتن است و نه در جواب. مسئله وقتی شروع می‌شود که جواب پذیرفته شود بی‌آنکه فرض‌ها بررسی شده باشند. عادتی که هر دو را نگه می‌دارد این است: پیش از فرستادن سوال، فرض‌ها را به‌شکل assert بنویسید و اجرا کنید. اگر یکی رد شد، معمولا دیگر لازم نیست سوال را بفرستید.

ابزار، و سالی که این حرف درست است

در سال ۲۰۲۶ دستور assert در خود زبان است و رایگان، و جای اضافه کردن print برای دیدن اینکه داده به چه شکلی است را می‌گیرد؛ تفاوتش این است که فرض را ثبت می‌کند و نه فقط مقدار را. برای مواردی که فرض درباره ساختار داده است، dataclasses در کتابخانه استاندارد بخشی از همان بررسی را به ساختار منتقل می‌کند و آن دیگر با پرچم بهینه‌سازی هم حذف نمی‌شود.

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

کنار این

بالای این