วันนี้อ่านเจอบทความที่น่าสนใจ เรื่อง Recycle test in TDD
ซึ่งเป็นอีกแนวคิดหนึ่งในการเขียน test ตามแนวคิดของ TDD (Test-Driven Development)
น่าจะพอช่วยให้การเขียน test น่าสนใจ และ ชัดเจนขึ้นมา
มาดูกันดีกว่า ว่าเป็นอย่างไร ?

เริ่มต้นที่พื้นฐานของ TDD

สามารถอธิบายด้วยคำว่า Red-Green-Refactor
ซึ่งวนอยู่ในวงจรนี้ไปเรื่อยๆ
โดยสามารถอธิบายแบบละเอียดได้ดังนี้

  1. Red คือ การเขียน test ที่ failure ขึ้นมา
  2. Green คือ การเขียน code เพื่อทำให้ test ผ่านโดยเร็วที่สุดเท่าที่จะทำได้
  3. Refactor คือ การปรับปรุงการออกแบบ และ โครงสร้างของระบบ แน่นอนว่า จะปลอดภัยต้องมี test โดยหลังจากทำการ refactor แล้ว test ยังต้องผ่าน หรือ ทำงานถูกต้องนะ
  4. วนกลับไปที่ข้อ 1

แสดงดังรูป

Screen Shot 2558-04-17 at 1.21.23 PM

โดยสิ่งที่ผู้เขียนบทความนี้ อธิบายคือ

ในขั้นตอนที่ 1 คือ Red นั้น สามารถอธิบายใหม่ได้ว่า
Red คือ การเขียน test ที่ failure ขึ้นมา
หรือ ทำให้ test ที่มีอยู่ failure ซ้ำแล้วซ้ำอีก (Recycle Test)

ฟังแล้วก็ยังงงๆ ดังนั้น มาดูตัวอย่างกันดีกว่า

ตัวอย่างที่บทความยกขึ้นมาคือ Print Diamond
Screen Shot 2558-04-17 at 9.24.35 PM

โดยแนวทางการแก้ปัญหาด้วย TDD นั้นยกมา 2 แบบคือ

  1. Gorilla
  2. Moose

คำแนะนำ
แนะนำให้ลองไปแก้ไขปัญหา Print Diamond ด้วยตัวเองก่อนนะครับ
แล้วจึงอ่านรายละเอียดต่อไป
มันจะทำให้คุณเห็นภาพชัดเจนมากขึ้น
เมื่อนำสิ่งที่คุณทำ กับ สิ่งใหม่ ที่จะแนะนำ

แบบ Gorilla

คือการแก้ไขปัญหาแบบใหญ่ๆ
ซึ่งเป็นแนวทางปกติ ที่ developer มักจะทำกัน ดังนี้

Test case ที่ 1 :: ทำการทดสอบ A
printDiamond(“A”);
ผลการทำงานคือ
A

Test case ที่ 2 :: ทำการทดสอบ B
printDiamond(“B”);
ผลการทำงานคือ
A
B B
A

Test case ที่ 3 :: ทำการทดสอบ C
printDiamond(“C”);
ผลการทำงานคือ
A
B B
C C C
B B
A

หลังจากผ่านไป 3 test case
คุณลองกลับไปดู code ที่คุณเขียนขึ้นมาสิ
ว่า code เหล่านั้น มันยากต่อการ refactor หรือเพิ่ม test case หรือไม่ ?
ถ้ายาก แสดงว่า คุณพยายามแก้ไขทุกๆ ปัญหา ในครั้งเดียว !!

นั่นคือ ปัญหานี้ประกอบไปด้วยหลายปัญหา เช่น

  • ทำการแสดงผลข้อมูลหลายๆ บรรทัด
  • ต้องทำการใส่ space bar เข้าไปในการแสดงผล
  • จำนวน space bar ที่ใส่เข้าไปในแต่ละจุด
  • แสดงผลข้อมูลซ้ำๆ กัน
  • แสดงข้อมูลในรูปแบบ diamond
  • และปัญหาอื่นๆ อีก

แน่นอนว่า ปัญหาทั้งหมดนั้น
คุณพยายามแก้ไขภายในครั้งเดียว หรือ test case เดียว
ใช่หรือไม่ ?
ถ้าใช่ นั่นแหละคือปัญหา … ที่ต้องได้รับการแก้ไข !!

มาดูแบบ Moose กันบ้าง

Test case ที่ 1 :: ทำการทดสอบ A
printDiamond(“A”);
ผลการทำงานคือ
A

Test case ที่ 2 :: ทำการทดสอบ B
printDiamond(“B”);

แต่แทนที่จะแก้ไขทุกๆ ปัญหาพร้อมๆ กัน
ก็ทำการแก้ไข หรือ เขียน test case แก้ไขทีละปัญหา ดังนี้

เริ่มจาก
Test case ที่ 2.1 ทำการทดสอบ B
โดยคาดหวังเพียงให้ผลลัพธ์ที่ได้ AB
นั่นคือเรียงลำดับตัวอักษรให้ถูกต้อง

ต่อจากนั้น Test case ที่ 2.2 เริ่มให้แสดงผลลัพธ์ ABB
เพื่อแก้ไขปัญหาการแสดงผลลัพธ์คือ BB ซ้ำกัน
นั่นคือ เริ่มทำการสร้าง loop

จากนั้นต่อด้วย Test case 2.3 ให้ทำการแยกบรรทัดของข้อมูล
คือ A\nBB\n

ตั้งแต่ Test case ที่ 2.1 ถึง 2.3 นั้น คือการแก้ไข test case ที่ 2 ซ้ำแล้วซ้ำเล่า (Recycle Test)
ต่อไปสามารถแก้ไข test case เพื่อจัดการกับพวก space bar และจำนวนของ space bar
และสุดท้ายคือ ทำให้เกิดรูป diamond ที่สมบูรณ์

ขอแนะนำให้ลองกลับไปเขียน code ใน Cyber Dojo อีกครั้ง
ตามสิ่งที่บทความแนะนำ
แล้วให้สังเกตการแก้ไขปัญหา ว่า แตกต่างจากเดิมหรือไม่ ?

โดยสรุปแล้ว

ใน test case ที่ 2 จะทำการ recycle หรือแก้ไขซ้ำแล้วซ้ำอีก
เพื่อให้ได้ผลลัพธ์การทำงาน หรือ code ที่ต้องการ
มันใกล้เคียงกับสิ่งที่ต้องการเข้าไปเรื่อยๆ
ซึ่งแนวทางนี้เหมือนมีคนนำทางให้เรา

ลองกลับไปดูสิ่งที่เราทำกันดูสิว่า
เรามักจะแบ่งงานใหญ่ๆ ออกมาเป็นงานย่อยๆ เช่น User story, Product backlog item เป็นต้น
ซึ่งมันคือการค่อยๆ สร้างระบบแบบ feature-by-feature แบบภาพใหญ่แบบ high level

ดังนั้นใน low level หรือระดับ code นั้น

ก็สามารถนำแนวคิดดังกล่าวมาประยุกต์ใช้ได้เช่นกัน
นั่นคือ เราไม่สามารถเขียน code
เพื่อตอบโจทย์ หรือ test case หลายๆ test case ได้พร้อมๆ กัน
ทำแบบ test case by test case น่าจะดีกว่า
หรือเรียกว่า small step

ไม่เช่นนั้น
คุณจะพบว่า code ของคุณมันจะ refactor ยากมากๆ !!

สุดท้ายแล้ว ลองไปฝึกกันดูครับ
หรืออาจจะลองไปฝึกที่ Cyber Dojo ได้นะครับ

ไม่ลงมือทำเอง แล้วจะรู้ได้อย่างไร !!

Tags: