باگ نرم‌افزاری چیست؟ از تعریف تا چرخهٔ عمر

باگ نرم‌افزاری چیست؟ از تعریف تا چرخهٔ عمر
در این مقاله می‌خوانید
  1. تعریف باگ
  2. از کجا آمد این واژه؟
  3. آناتومی یک باگ: خطا، نقص، خرابی
  4. انواع باگ
  5. باگ منطقی
  6. باگ زمان‌بندی
  7. باگ مرزی
  8. باگ یکپارچگی
  9. باگ محیطی
  10. باگ رگرسیون
  11. چرخهٔ عمر یک باگ
  12. شدت در برابر اولویت
  13. باگ‌هایی که تصمیم می‌گیرید حل نکنید
  14. چه کسی مسئول یک باگ است؟
  15. باگ‌ها تصادفی پخش نمی‌شوند
  16. هزینهٔ باگ با گذشت زمان چند برابر می‌شود
  17. یک گزارش باگ خوب چه چیزهایی دارد؟
  18. چرا «باگ صفر» ممکن نیست
  19. منابع و مطالعهٔ بیشتر

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

تعریف باگ

باگ نرم‌افزاری یعنی اختلاف بین رفتار واقعی سیستم و رفتار مورد انتظار آن. دو کلمهٔ کلیدی در این تعریف هست که معمولاً نادیده گرفته می‌شوند:

«مورد انتظار» یعنی انتظار چه کسی؟ اگر برنامه دقیقاً همان کاری را بکند که در مستندات نوشته شده ولی کاربر انتظار چیز دیگری داشته باشد، این هم باگ است — منتها باگ طراحی، نه باگ کد. تیم‌هایی که فقط «مطابق مستندات» را ملاک می‌گیرند، دسته‌ای کامل از مشکلات واقعی را نادیده می‌گیرند.

«رفتار واقعی» یعنی در چه شرایطی؟ کدی که با دادهٔ درست کار می‌کند و با دادهٔ خالی می‌شکند، باگ دارد — حتی اگر ۹۹ درصد مواقع درست کار کند.

از کجا آمد این واژه؟

روایت مشهور به سال ۱۹۴۷ برمی‌گردد: تیمی در دانشگاه هاروارد که روی رایانهٔ Mark II کار می‌کرد، علت یک خرابی را یک پروانهٔ واقعی یافت که لای رلهٔ شمارهٔ ۷۰ گیر کرده بود. آن‌ها حشره را برداشتند، به دفترچهٔ ثبت وقایع چسباندند و نوشتند «اولین مورد واقعی پیدا شدن یک باگ».

نکتهٔ ظریف همین جمله است: عبارت «اولین مورد واقعی» نشان می‌دهد که واژهٔ باگ به معنی نقص فنی، پیش از آن هم رایج بوده است. مهندسان برق از دههٔ ۱۸۰۰ آن را به کار می‌بردند. آن پروانه اولین باگ تاریخ نبود؛ فقط بامزه‌ترینش بود.

آناتومی یک باگ: خطا، نقص، خرابی

مهندسی نرم‌افزار سه واژهٔ متمایز دارد که تفکیکشان به‌شدت در تحلیل ریشه‌ای کمک می‌کند:

  • Error (اشتباه): کار انسانی نادرست. برنامه‌نویس شرط را برعکس نوشت.
  • Fault (نقص): نتیجهٔ آن اشتباه در کد. یک > که باید >= می‌بود.
  • Failure (خرابی): لحظه‌ای که آن نقص باعث رفتار غلط قابل مشاهده می‌شود.

چرا این تفکیک مهم است؟ چون هر نقصی به خرابی منجر نمی‌شود. ممکن است سال‌ها کدی با نقص داشته باشید که هرگز اجرا نمی‌شود، یا فقط با ورودی خاصی که تا امروز پیش نیامده. وقتی می‌گویید «این باگ تازه ایجاد شده»، معمولاً منظورتان این است که خرابی تازه دیده شده — نقص از قبل آنجا بوده.

انواع باگ

باگ منطقی

کد اجرا می‌شود، خطایی هم نمی‌دهد، ولی نتیجه غلط است. محاسبهٔ تخفیف که ۱۰ درصد را ۱ درصد حساب می‌کند. خطرناک‌ترین نوع، چون هیچ سیستمی خودکار متوجهش نمی‌شود.

باگ زمان‌بندی

کد درست است ولی ترتیب اجرا آن چیزی نیست که فرض کرده‌اید. Race condition نمونهٔ کلاسیک است: دو عملیات هم‌زمان که نتیجه‌شان به این بستگی دارد کدام زودتر تمام شود.

باگ مرزی

سیستم برای حالت عادی درست کار می‌کند ولی در لبه‌ها می‌شکند: فهرست خالی، عدد صفر، رشتهٔ خیلی بلند، آخرین روز ماه. خطای Off-by-One معروف‌ترین عضو این خانواده است.

باگ یکپارچگی

هر قطعه جداگانه درست کار می‌کند ولی کنار هم نه. معمولاً به‌خاطر تفاوت در فرضیات دو ماژول دربارهٔ فرمت داده.

باگ محیطی

روی دستگاه شما کار می‌کند و روی دستگاه کاربر نه. نسخهٔ متفاوت مرورگر، تنظیمات منطقهٔ زمانی، حافظهٔ کم، شبکهٔ کند. این دسته را جداگانه در چرا باگ‌ها فقط در محیط production ظاهر می‌شوند بررسی کرده‌ایم.

باگ رگرسیون

چیزی که قبلاً کار می‌کرد، بعد از یک تغییر خراب شد. این نوع بیشترین آسیب را به اعتماد کاربر می‌زند، چون کاربر قبلاً تجربهٔ درست را داشته است.

چرخهٔ عمر یک باگ

یک باگ در تیم سالم این مسیر را طی می‌کند:

  • کشف — کسی یا چیزی متوجهش می‌شود: کاربر، تستر، یا سیستم رصد خطا.
  • ثبت — با اطلاعات کافی برای بازتولید ثبت می‌شود. اگر این مرحله ضعیف باشد، بقیهٔ مسیر کند می‌شود.
  • تأیید و اولویت‌بندی — آیا واقعاً باگ است؟ چقدر جدی است؟ چه کسی مسئولش است؟
  • تخصیص و رفع — علت ریشه‌ای پیدا و اصلاح می‌شود.
  • تأیید رفع — کسی غیر از رفع‌کننده بررسی می‌کند که واقعاً حل شده.
  • بستن — و ترجیحاً افزودن تستی که مانع بازگشتش شود.

بیشترین اتلاف وقت در تیم‌ها بین مرحلهٔ دوم و سوم می‌افتد: باگی ثبت می‌شود که اطلاعات کافی ندارد، توسعه‌دهنده نمی‌تواند بازتولیدش کند، به گزارش‌دهنده برمی‌گردد، و رفت‌وبرگشت شروع می‌شود. یک اسکرین‌شات و اطلاعات مرورگر در لحظهٔ ثبت، معمولاً چند روز از این چرخه را حذف می‌کند.

شدت در برابر اولویت

این دو را مدام با هم اشتباه می‌گیرند، در حالی که کاملاً مستقل‌اند:

شدت (Severity) یعنی این باگ چقدر خراب می‌کند — یک واقعیت فنی. اولویت (Priority) یعنی چقدر زود باید حل شود — یک تصمیم کسب‌وکاری.

باگی که کل سیستم را از کار می‌اندازد ولی فقط در حالتی رخ می‌دهد که هیچ کاربری استفاده نمی‌کند: شدت بالا، اولویت پایین. غلط املایی در نام شرکت روی صفحهٔ اصلی: شدت پایین، اولویت بالا. اگر تیم شما فقط یک عدد برای هر باگ دارد، احتمالاً دارد اشتباه اولویت‌بندی می‌کند.

باگ‌هایی که تصمیم می‌گیرید حل نکنید

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

تفاوت این دو حالت در یک چیز است: ثبت کردن دلیل. باگی که با یادداشت «فقط در نسخهٔ ۹ اینترنت اکسپلورر رخ می‌دهد؛ سهم کاربرانش زیر یک دهم درصد است» بسته می‌شود، تصمیم است. باگی که بدون توضیح ته صف می‌ماند، بدهی است — و شش ماه بعد کسی نمی‌داند چرا آنجاست و آیا هنوز موضوعیت دارد.

دسته‌هایی که معمولاً منطقی است حل نشوند: باگ‌های محیط‌هایی که عملاً کاربر ندارند، مشکلاتی که راه دور زدن ساده دارند و به‌ندرت رخ می‌دهند، و باگ‌هایی که رفعشان نیازمند بازنویسی بخشی است که به‌هرحال قرار است حذف شود.

چه کسی مسئول یک باگ است؟

سؤالی که بیشترین اصطکاک را در تیم‌ها ایجاد می‌کند، و پاسخ سالمش این است: مسئولیت باگ با تیم است، نه با فردی که آن خط را نوشته.

تیم‌هایی که دنبال «مقصر» می‌گردند، دو اتفاق در آن‌ها می‌افتد. اول اینکه افراد باگ‌ها را گزارش نمی‌کنند یا کوچک جلوه می‌دهند. دوم اینکه تحلیل ریشه‌ای متوقف می‌شود، چون وقتی به «فلانی اشتباه کرد» رسیدید، دیگر نمی‌پرسید چرا بازبینی کد آن را نگرفت، چرا تستی نبود، و چرا اصلاً ممکن بود چنین اشتباهی رخ دهد.

سؤال درست بعد از هر باگ جدی این است: «چه چیزی در فرآیند ما اجازه داد این تا اینجا برسد؟» — نه «کی این را نوشت؟»

باگ‌ها تصادفی پخش نمی‌شوند

یکی از مفیدترین یافته‌های تجربی مهندسی نرم‌افزار این است که باگ‌ها به‌طور یکنواخت در کد پخش نیستند؛ آن‌ها خوشه‌ای هستند. بخش کوچکی از ماژول‌ها معمولاً بخش بزرگی از مشکلات را تولید می‌کنند.

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

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

هزینهٔ باگ با گذشت زمان چند برابر می‌شود

یک باگ در لحظه‌های مختلف، هزینه‌های بسیار متفاوتی دارد:

  • حین نوشتن کد: ارزان‌ترین حالت. برنامه‌نویس هنوز در همان زمینه است و ظرف چند دقیقه اصلاح می‌کند.
  • در بازبینی کد: هنوز ارزان. یک نفر دیگر باید زمینه را بفهمد، ولی کد تازه است.
  • در تست: گران‌تر. چرخهٔ گزارش، بازتولید، رفع و تأیید مجدد راه می‌افتد.
  • در production: گران. حالا کاربران واقعی آسیب دیده‌اند، پشتیبانی درگیر شده، و ممکن است دادهٔ خرابی تولید شده باشد که باید تعمیر شود.
  • در production و ماه‌ها بعد: گران‌ترین. هیچ‌کس دیگر آن کد را به یاد ندارد، شاید نویسنده‌اش رفته باشد، و رفعش نیازمند فهمیدن دوبارهٔ کل زمینه است.

این نمودار صعودی، دلیل اصلی وجود سیستم‌های رصد خطاست. تفاوت بین دیدن یک باگ در روز اول و دیدنش شش ماه بعد، تفاوت بین یک ساعت کار و چند روز کار است — و در این فاصله، کاربرانی که به آن خورده‌اند رفته‌اند. حساب مالی‌اش را در هزینهٔ پنهان نداشتن سیستم رصد خطا ببینید.

یک گزارش باگ خوب چه چیزهایی دارد؟

هر باگی که ثبت می‌شود، در نهایت باید توسط کسی که آن را ندیده بازتولید شود. گزارشی که این کار را ممکن نکند، عملاً هزینه است نه کمک. حداقل‌های لازم:

  • چه کردید — مراحل دقیق، نه خلاصه. «روی ذخیره زدم» کافی نیست؛ «فرم را با ایمیل خالی پر کردم و روی ذخیره زدم» قابل بازتولید است.
  • چه انتظاری داشتید — گاهی همین‌جا معلوم می‌شود که اصلاً باگ نبوده و انتظار اشتباه بوده است.
  • چه دیدید — با اسکرین‌شات، نه توصیف.
  • محیط — مرورگر، دستگاه، اندازهٔ صفحه، و آدرس دقیق صفحه.
  • هر بار تکرار می‌شود یا گاهی؟ — این یک سؤال، اغلب تفاوت بین یک باگ ساده و یک race condition را مشخص می‌کند.

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

چرا «باگ صفر» ممکن نیست

هدف نرم‌افزار بدون باگ، هدف اشتباهی است. دلیلش ریاضی است: تعداد حالت‌های ممکن یک برنامهٔ متوسط از تعداد آزمون‌هایی که می‌توانید بنویسید بی‌نهایت بیشتر است. ادسخر دایکسترا جملهٔ معروفی دارد که تست می‌تواند وجود باگ را نشان دهد، نه نبودشان را.

هدف واقع‌بینانه این است: باگ‌ها را سریع پیدا کنید، سریع حل کنید، و نگذارید یکی دو بار تکرار شود. تیمی که باگ‌هایش را ظرف چند ساعت می‌بیند، از تیمی که ادعا می‌کند باگ ندارد ولی خبر ندارد، بسیار جلوتر است.

و این دقیقاً همان‌جاست که تفاوت بین دیدن و ندیدن اهمیت پیدا می‌کند: باگی که کسی گزارش نمی‌دهد، حل هم نمی‌شود.

منابع و مطالعهٔ بیشتر

باگ‌ماگ را رایگان امتحان کنید

خطاهای سایتتان را خودکار ثبت کنید و بگذارید کاربران با یک کلیک باگ گزارش دهند.

شروع رایگان