مقدمه
یکی از مباحث چالش برانگیز بین برنامه نویسان نوشتن آزمون قبل از کد یا نوشتن آزمون بعد از آن است و اینکه کدامیک بر دیگری ارجحیت دارد؟ آیا صرف نوشتن آزمون به معنای اتخاذ رویکرد TDD است؟ در این مقاله سعی می کنم توضیح عملگرایانه و واقع بینانه ای، از این که چطور قدرت واقعی TDD با استفاده از رویکرد Test-Before به طرز چشمگیری نمایان می شود، ارائه دهم.
- “قدرت TDD موثر و عملگرایانه است نه تصنعی”.
به همین دلیل “Test-Before” واقعا مهم است. در اینجا به هفت مزیت “Test-Before” بر “Test-After” اشاره می کنیم:
-
- ما را به سمت هدف هدایت می کند.
- کاملتر است.
- تاثیر انگیزشی قابل توجهی در به چالش کشیدن ما برای پاس کردن آزمونهایمان دارد.
- با توجه به ظرفیت محدود ذهنی ما، منجر به تمرکزی عمیق و ریزبینانه و با درکی شفاف از حوزه مساله می شود که بسیار مفید است!
- با توجه به این که SOLID یک پیاده سازی موثر و عملیاتی از اصول طراحی مدرن است، منجر به طراحی خوبی بر اساس اصول SOLID می شود.
- چارچوب خوبی برای همکاری است به نحوی که برنامهنویس با آمادهسازی (Setup)، عمل(Action) و تائید (Assertion) سرنخهای خوبی برای خود و دیگران به جا می گذارد.
- کد “غیرقابل آزمون” یا کد “آزمون نشده”ای نخواهید داشت.
گاهی اوقات افراد نوشتن آزمون بعد از نوشتن کد عملیاتی را پیشنهاد می کنند. این نگاه اصولا معطوف به “داشتن” آزمون است بنابراین نتیجه این میشود که تفاوتی نمی کند شما آزمون را قبل از کد بنویسید یا انتهای آن.
این نگاه ناقص است و TDD را منحصر به خروجی ایجاد شده از آزمونها میکند در حالی که این خروجی یکی از عوامل موازنه سه عاملی TDD است:
- آزمون نوشته شده (Made)
- نوشتن آزمون (Making)
- نویسنده آزمون (Maker)
قطعا یکی از فواید TDD خروجیهای تولید شده آن است: آزمونهای نوشته شده با ارزش هستند و این را به آسانی با مقایسه کدهایی که آزمون دارند(صرفنظر از این که چه زمانی این آزمونها نوشته شده اند) و آنهایی که ندارند، متوجه میشویم.
اما این همهی فواید TDD نیست و TDD فواید مهم و بزرگ دیگری غیر از آزمونهای نوشته شده (Made) دارد. همچون عملیات و فرایند تولید خود آزمونها و همچنین تاثیری که بر نویسنده آزمونها می گذارد.
با این مقدمه به شرح هفت فایده Before-Testing که After-Testing میسر نمی کند ( یا به طرز موثری فراهم نمی کند) می پردازیم:
- اول:
در رویکرد Test-Before لازم است که یک سرنخ یا راهنما در مورد این که با کد کجا می رویم داشته باشیم. این امر تا حدی از بیرون اتفاق می افتد مثلا تعیین یک API یا ساختار داده. همچنین این شروع جزئیات طراحی هم هست. بدون شروع این چنینی شما فقط در حال تایپ کردن هستید!
بسیار پیش می آید که یک تازه کار به من می گوید که نمی تواند آزمون بنویسد چون نمیداند به کجا می رود. نکته دقیقا همینجاست، عالی است که شما می دانید که نمیدانید به کدام سمت می روید و درحال تلاش هستید تا بفهمید.
همچنین در نظر داشته باشید اگر برای نوشتن یک آزمون به اندازه کافی نمی دانید پس حتما کدی هم نمی توانید بنویسید که به محیط عملیاتی ، Push کنید. من همیشه به این افراد می گویم: “برو باهاش ور برو تا یه سر نخی پیدا کنی بعد از آن برگرد و یه آزمون بنویس!”
البته همچنان در این مواقع با ممانعت مواجه می شوم. صادقانه بگم نه از برنامهنویس های جوان بلکه از با سابقه ها! آنها توقع دارند مدت زمانی روی موضوع کار می کنند و دقیقا همان چیزی را که رویش کار کرده اند را Push کنند.این ارزش و اولویت دادن به تایپ کردن و کم ارزش دیدن فکر کردن است.
- دوم:
آزمونهایی که به سبک Test-Before نوشته می شوند عموما بسیار کاملتر از آزمونهای Test-After هستند.
دوباره به این موضوع توجه کنید که این رویکرد بسیار عملگرایانه است: زیرا ما آزمون مینویسیم تا در واقع کارکرد بیشتری به کد اضافه کنیم. در این حالت تناسب و سازگاری بین کد و آزمون بسیار بیشتر خواهد بود.
بعد از این که کد نوشته شد، زمانی که من آزمونی برای آن می نویسم، در واقع از ترکیب “به خاطر آوردن” و “دوباره خوانی کد” برای نوشتن آزمون استفاده میکنم. که اولی غیرقابل اعتماد و دومی ناکارا و کم اثر خواهد بود به اضافه این که مجبور به صرف انرژی بیشتری خواهم شد.
Test-After مطمئنا فوایدی دارد و ممکن است به اندازه یک آزمونگر، موثر ظاهر شود. اما وقتی می توانیم بر “نتیجه طبیعی و منطقی” تکیه کنیم، اعتماد به “انضباط انسانی” امر اشتباهی خواهد بود.
اینجا ما نه فقط به آزمون (Made) و فرایند نوشتن آزمون (Making)، بلکه به نویسنده آزمون(Maker) هم توجه میکنیم.
- سوم:
صحبت از نویسنده آزمونها(Maker) شد. در رویکرد Test-Before تاثیر انگیزشی قابل توجهی وجود دارد. ما در زمان نوشتن آزمونی قبل از کد، در حال به چالش کشیدن خودمان برای پاس کردن آن هستیم. وقتی آن را پاس می کنیم به عنوان یک جایزه به خودمان یک نوشابه انرژیزا داده ایم!
نوشتن یک آزمون بعد از نوشتن کد نام دیگری هم دارد: “خرحمالی!”.به عنوان یک برنامه نویس TDD محور، شک ندارم که در رویکرد Test-After زمانهایی هست که شما مجبورید به صورت ناخودآگاه کد اضافه بیشتری بنویسید یا عملکرد جدیدی اضافه کنید و تضمین می کنم که از پاس نشدن آزمونها متنفر خواهید بود (همهی ما همینطور هستیم) به خصوص زمانی که کد اصلی در محیط عملیاتی عملکرد درستی دارد ولی آزمون نوشته شده، عملکرد درستی ارائه نمیدهد.
اما فراخوانی و پاسخ آزمون در رویکرد Test-Before چنین حسی نمی دهد و در عین حال همین ترفند کوچک ، در آن واحد شما را به هدف آزمون، تسلط بر آن و ریتم که اجزا اساسی انگیزه بخشی برای انسان هستند، هدایت می کند.
- چهارم:
دوباره از نویسنده آزمون(Maker) صحبت کنیم. رویکرد Test-Before تمرکزی عمیق و ریزبینانه و با درکی شفاف از حوزه مساله ایجاد می کند و این تمرکز عمیق همبستگی ثمربخشی با ظرفیت محدود ذهنی ما پیدا می کند.
وقتی ما به خودمان به عنوان موجوداتی باهوش فکر می کنیم، تمایل داریم کمتر به وجه حیوانیمان توجه کنیم به خصوص به خاطر تاثیر ناخوشایندی که تجسم بدن یک حیوان در ذهن ما ایجاد می کند. اما بدن ما -ساختار واقعی فیزیکی بدن ما- محدودیت های عمیقی دارد که یکی از آنها میزان جزئیاتی است که در آن واحد می تواند پردازش کند.
(یکی دیگر از محدودیتهای جدی ما که در موقعیت های مختلف امتحان کرده ام، میزان غذاهای هندی است که در یک وعده غذایی می توان خورد!)
تقریبا هرچیزی که بتواند دامنه اعمال (Scope) را محدود کند یک “بُرد” برای موجود باهوش است و Test-Before به طرز قابل تحسینی این دامنه را محدود می کند. گرچه ما در حالت ایدهآل می توانیم با انضباط بر این چالش غلبه کنیم اما دور زدن “نیاز به انضباط”برای همه ما بسیار آسانتر خواهد بود.
- پنجم:
ما از رویکرد Test-Before بهرهمند می شویم چون پیادهسازی عملی از اصول طراحی مدرن را برای ما فراهم می کند. توضیح این امر در تئوری دشوار ولی در عمل آسان است.
اگر به SOLID به عنوان مدل اصول طراحی مدرن اشاره کنیم. این مزیت از یک همبستگی قابل توجه ناشی می شود: کارهایی که لازم است در رویکرد Test-Before انجام دهید به صورت گسترده ای همان کارهایی است که شما برای پیادهسازی طراحی SOLID محور باید انجام دهید.
به طرز قابل توجه ای وقتی به صورت مرحله به مرحله با رویکرد Test-Before آزمون می نویسید دشوار است که کدی مخالف اصول SOLID تولید کنید. آزمونپذیری بر روی طراحی خوب نگاشت شده است، اگرچه شاید تعریف دقیقی از آن نشده باشد. نکات سادهای البته وجود دارد: به طور مشخص میتوان گفت DIP و ISP خودشان را به آزمونپذیری وام میدهند.
موارد دیگری هم که چنین کارکردی دارند وجود دارد، اما صادقانه بگویم من اهمیتی نمیدهم که چرا آنها اینطور موثر عمل می کنند.
- ششم:
رویکرد Test-Before یک چارچوب شگفتانگیز برای همکاری را ایجاد می کند.
زوج -برنامهنویس (Pairs) نوشتن کد را با آزمون شروع می کنند، آزمونی که یک تعریف سختگیرانه است از کاری که آن کد قرار است انجام دهد قبل از آن که کاری انجام دهد!
کد آزمون، آمادهسازی(Setup)، عمل (Act) ، تائید (Assertion)، بلافاصله همکارم را راهنمایی می کند که کجا هستم و کجا می روم،چه خوب یا بد. این بهترین زمان برای توقف کردن و انجام کار دیگری است.
وقتی من و همکارم در مسیر متفاوتی هستیم، مجبور نخواهیم بود دوباره برگردیم و کشف کنیم کجا هستیم و کجا میرویم بلکه دقیقا می دانیم که ابتدای مسیر کجا قرار دارد. این مزیت بزرگی در صرفه جویی زمان و انرژی است.
- هفتم:
کدی که با رویکرد Test-Before نوشته شده است هیچ وقت غیرقابلآزمون یا آزمون نشده نخواهد بود.
فقط یک آدم سادهلوح ممکن است بگوید که تا حالا کد غیرقابلآزمون ندیده است در حالی چنین کدی هرجایی پیدا میشود. باور نمیکنید؟ بعضی سورس کدهای بزرگ و قدیمی که صدهزار خط کد دارند و شاید بیش از 10 سال قدمت داشته باشند را دریافت کنید. برای پیدا کردن کدی که به تلاش قابل توجهای برای آزمون کردن نیاز نداشته باشد، مجبور به جستجوی بسیاری خواهید شد. چرا؟ به این دلیل که آنها برای برای آزمونپذیری نوشته نشده اند.
اما اهمیتی ندارد، حتی اگر کد شما آزمونپذیر هم باشد، با رویکرد Test-After تنها “احتمال” دارد کد شما آزمون شده باشد و تضمینی برای آن وجود ندارد. حفظ انضباط در رویکرد Test-After مانند مقاومت در مقابل یک فشار دائمی است و به طور معمول وقتی با مشکل و فشار مواجه میشویم اولین چیزی که حذف میکنیم آزمونها هستند.
- نتیجهگیری
مردم می پرسند: چرا باید قبل از کد، آزمون بنویسیم در حالی که می توانیم بعد از آن بنویسیم؟
پاسخ این است: که به دلیل تاثیر عملی و موثر آن است.
ارزش TDD فقط در قدرت ساخته های (Made) آن یعنی آزمونها نیست بلکه قدرت آن در تعادل بین ساختهها (Made)، فرایند نوشتن آزمون (Making) و نویسنده آزمون (Maker) است.
منبع : توئیتر/ نویسنده : GeePawHill و Thomas Deniffel