خلاصه‌ی The Clean Coder - قسمت ۰۵ - توسعه تست محور (TDD)

این مقاله یکی از مجموعه مقالات کتاب the clean coder هست. برای پیدا کردن دید بهتر از کل این مجموعه و محتوایی که تو این مقاله می‌خونید، پیشنهاد می‌کنم مقاله‌ی صفرم رو هم یه نگاه بهش بندازید.

  • اوایل فصل، عمو باب لطف کردن و با چندتا سوال در قالب استفهام انکاری، لزوم استفاده از TDD رو به ما گفتن:
    • وقتی حتی مطمئن نیستیم همه‌ی کدی که نوشتیم کار می‌کنه یا نه، چطور می‌تونیم خودمون رو «برنامه‌نویس حرفه‌ای» بدونیم؟
    • اگه بعد از هر تغییری که توی پروژه می‌دیم اون رو تست نکنیم، چطور می‌تونیم مطمئن باشیم که همش کار می‌کنه و مشکلی پیش نیومده؟
    • اگه تست اتوماتیک نداشته باشیم چطور می‌تونیم مطمئن باشیم همش کار می‌کنه؟ (هر بار دستی همشو تست کنیم؟)
    • اگه درصد خیلی بالایی از کدمون، تست واحد (unit test) نداشته باشه، می‌تونیم مطمئن باشیم همه چیز اوکیه؟
    • سوال آخر هم این‌که، اگه از TDD استفاده نکنیم، چطور قراره این حجم از تست‌های واحد رو بنویسیم؟
  • سه قانون TDD:
    • قبل از نوشتن هر کد [و بعد از نام و یاد خدا]، اول یه تست واحد شکست خورنده می‌نویسی (چرا شکست خورنده؟‌ چون هنوز کدی ننوشتیم که این تست پاس/موفق شه)
    • تست واحدی که نوشتی باید حداقل کد لازم برای شکست خوردن باشه، نه بیش‌تر. (مثلا فقط متدی که هنوز پیاده سازی نشده رو صرفا صدا بزنه).
    • حداقل کد ممکن واسه پاس شدن این تستی که نوشتی رو می‌نویسی

همین سه قانون، ما رو به یه‌سری چرخه‌های کوتاه حدود ۳۰ ثانیه‌ای می‌رسونن (از نوشتن تست شکست‌خورنده تا کد پاس کننده) و ما تو این چرخه می‌چرخیم و می‌چرخیم و می‌نوشیم از این جام TDD. تو این چرخ‌زدنای ما، یه اتفاق جالبی داره میفته، اونم اینه که همزمان هم کد اصلی (production) ما داره نوشته می‌شه و هم تست‌های ما (که قرار بود درصد بالایی از کدمون رو پوشش بدن و خب این شکلی، می‌دن)

  • فهرست مزیت‌هایی TDD:
    • قطعیت
      • چون ما برای هر قسمت از کدمون از قبل تست نوشتیم، با درصد بالایی مطمئنیم که پروژمون کار می‌کنه. عمو باب به پروژه‌ی خودش به اسم FITNESSE اشاره می‌کنه که ۶۴ هزار خط کده و ۲۸ هزار خطش مربوط به تست‌های واحده (حدود ۲۲۰۰ تا تست واحد!!) که ۹۰٪ کد اصلیش رو تو حدود ۹۰ ثانیه تست می‌کنن!
    • باگ‌خیزی
      • مطالعات و گزارش‌های زیادی هست که نشون می‌دن استفاده از TDD باعث کاهش قابل توجه باگ‌های جدید توی پروژه می‌شه. حتی شرکت‌هایی مثل مایکروسافت و IBM و غیره هم تجربه‌ی کاهش باگ‌ها به نصف و حتی گاها به یک‌دهم رو داشتن [!!] و این آمار چیزی نیست که یه دولوپر حرفه‌ای بتونه راحت از کنارش بگذره.
    • شجاعت
      • وقتی تست‌هایی که باید بنویسی رو نوشته باشی، تقریبا هیچ ترسی از تغییر کد نداری، چون بلافاصله بعد از تغییر می‌تونی تست‌ها رو اجرا کنی و اگه کاری که انجام دادی روی بخش دیگه‌ای از کد تاثیر داشته (اثر جانبی یا اصطلاحا side effect) داشته، خیلی راحت و سریع متوجه می‌شی.
        خیلی وقت‌ها نداشتن همچین تست‌هایی باعث می‌شه که ما کدمون رو تمیز نکنیم، ریفکتور نکنیم و کلا تغییرش ندیم چون وقتی کد کار می‌کنه که کسی بهش دست نمی‌زنه! (البته کد بدون تست)
    • مستندسازی
      • وقتی تست داشته باشیم، واسه هر کاری یه تست نوشته شده و به‌ بهترین شکل و با جزئیات (با کد) مشخصه که چطور باید هرکاری رو انجام داد. به‌عبارتی همین تست‌های واحد(unit test)ی که نوشتیم، خودشون مستندسازی پروژه هستن. این کار باعث می‌شه که مستندسازی داشته باشیم که مبهم نیست، دقیقه و به زبانی نوشته شده که مخاطبش (دولوپری که قراره روی پروژه کار کنه) اونو به‌خوبی متوجه می‌شه.
    • طراحی (design)
      • یکی از مشکلاتی که تست نوشتن داره این که معمولا باید کد رو ایزوله کنی. معمولا تست کردن تابعی که تابع‌های دیگه رو صدا می‌زنه کار سختیه. به‌خاطر همین مجبوری راهی پیدا کنی که هر تابع، از توابع دیگه جدا (decouple) باشه. به‌عبارتی، این‌که اول تست رو بنویسیم، ما رو مجبور می‌کنه که طراحی خوبی داشته باشیم (و پیاده‌سازیش کنیم).
      • اگه اول تست ننوشته باشیم، چیز دیگه‌ای نیست که ما رو مجبور کنه توابع رو جدا از هم بنویسیم و به یه کد ناپایدار و به‌هم‌ریخته نرسیم نهایتا! خب اگه آخر سر تست بنویسیم چی‌میشه؟ ممکنه بتونیم ورودی و خروجی اون کد به‌هم‌ریخته‌ی ناپایدار رو تست کنیم ولی احتمالا تست کردن همه‌ی تابع‌ها کار خیلی سختی می‌شه (چون جدا از هم نوشته نشدن).
  • البته TDD یه فرمول جادویی یا وحی مُنزَل نیست. جاهایی هست که ضررش به نفعش می‌چربه ولی خب جاهای خیلی کمی هستن.