แนวคิดการพัฒนาแบบ Test-Driven Development (TDD) นั้น
เราจะรู้ว่ามันประกอบไปด้วย 3 สถานะคือ
- Red
- Green
- Refactor
- ทำซ้ำไปเรื่อยๆ
แต่สิ่งหนึ่งที่ยังไม่ได้พูดถึงก็คือ
ในแต่ละสถานะนั้นเป็นอย่างไร ?
เราจะย้ายจากสถานะหนึ่งไปอีกสถานะหนึ่งอย่างไร ?
ดังนั้น จึงสรุปในแบบที่ผมเข้าใจ เป็นดังนี้
การอธิบายเรื่อง TDD
สิ่งที่ผมชอบก็คือ กฏ 3 ข้อ ของคุณ Robert C. Martin (Uncle Bob)
กล่าวไว้ว่า
1. You are not allowed to write any production code unless it is to make a failing unit test pass.
2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
3. You are not allowed to write any more production code than is sufficient to pass the one failing unit test.
แปลง่ายๆ ได้ว่า
1. จะไม่เขียน production code ใดๆ จนกว่าจะทำให้ unit test ผ่านทั้งหมด
2. จะไม่เขียน code ใดๆ ยกเว้นเขียน unit test ให้มัน fail
3. จะไม่เขียน production code มากไปกว่าให้ unit test มันผ่าน
พร้อมกับอธิบายในรูปแบบของ Red-Green-Refactor มันเป็นสิ่งที่ดีมากๆ
แต่สำหรับผู้เริ่มต้นปฏิบัติตามแนวคิดนี้
อาจจะต้องมีอะไรอธิบายเพิ่มขึ้นมาหน่อย เพื่อให้เข้าใจได้ง่ายขึ้น
มีเป้าหมายเพื่อให้ developer ที่สนใจเริ่มต้นได้ง่าย
ดังนั้น จึงขออธิบายเพิ่มในเรื่องของการย้ายสถานะใน Red-Green-Refactor
ว่าการย้ายในแต่ละสถานะนั้นเป็นอย่างไร ?
ต้องผ่านเงื่อนไขอะไรบ้าง ?
สำหรับการเริ่มต้นนั้น ผมขอเพิ่มสถานะหนึ่งขึ้นมาคือ Start
แสดงดังรูป
การย้ายสถานะต่างๆ ของ Test-Driven Development
Start
ทำความเข้าใจกับปัญหาที่กำลังจะทำ
วิเคราะห์ถึงปัญหาว่าเป็นอย่างไร
ทำความเข้าใจว่า function ใหม่ที่กำลังจะทำถูกเรียกจากที่ไหนบ้าง
มีตัวอย่าง และ guide ในการทดสอบอะไรบ้าง โดยใช้จาก Acceptance criteria
สรุปสิ่งที่ต้องมีการทดสอบ
ทำการย้ายไปยังขั้นตอนต่อไปคือ Red
เมื่อคุณเข้าใจในเป้าหมาย และ เลือกการทดสอบแรกแล้ว
Red
ทำการตั้งชื่อ และ ประกาศตัวแปรต่างๆ ของการทดสอบขึ้นมา
โดยการทดสอบที่ดีควรมีโครงสร้างตาม Arrange-Act-Assert
ซึ่ง code นั้นต้องไม่ error
และถูกหลักไวยกรณ์ของภาษาโปรแกรมนั้นๆ
Green
ทำการ implement code ขึ้นมา ซึ่งจากหนังสือ Test-Driven Development by Example
อธิบายว่าการทำให้การทดสอบมันเดินไปข้างหน้า สามารถทำได้ดังนี้
- Fake it คือการโกง หรือ ทำอะไรไปแบบโง่ๆ เช่นถ้าในการทดสอบต้องการค่าอะไร ก็ return ค่านั้นกลับไปเลย มันอาจจะดูไม่ดี แต่สิ่งที่ได้ มันสามารถทำงานได้ถูกต้องนะ
- Use obvious implementation คือการ code ที่ดีที่ควรเพื่อแก้ไขปัญหา ซึ่งเป็นวิธีการหลักที่จะทำให้ TDD วิ่งไปอย่างรวดเร็ว
- Triangulation เมื่อเราต้องการความมั่นใจในการทำงานของ code ที่สร้างขึ้นมา เช่นอาจจะใช้วิธีที่ 1 เพื่อสร้าง code ขึ้นมา ดังนั้นสิ่งที่สามารถทำได้คือ การเพิ่มการทดสอบ ด้วยข้อมูลอื่นๆ ที่ยังอยู่ในขอบเขตเดิมหรือเงื่อนไขเดิม เพื่อที่จะทำให้ code ที่มันเฉพาะเจาะจง (Specific) ไปให้อยู่ในรูปทั่วไป (Generic)
Refactor
เพื่อทำการขจัดสิ่งที่เรา hardcode หรือ fake ไว้
เพื่อทำการขจัด Code smell เช่น Duplication code, Long method เป็นต้น
เพื่อทำการขจัด code ที่อ่าน และ ทำความเข้าใจได้ออกไป
ส่งผลทำให้ code มันอ่านและทำความเข้าใจได้ง่าย
ไม่ใช่การสร้าง function การทำงานเพิ่มเข้ามานะครับ
และอย่าลืมว่าสถานะของการทดสอบต้องเป็น Green ด้วยเสมอ
แนะนำให้ทำการ refactor แบบเล็กๆ และ บ่อยๆ
ซึ่งมันจะนำไปสู่การออกแบบที่ดีขึ้น
การ refactor นั้น คือ
การหาจุดอ่อนที่อยู่ใน code
รวมทั้งเป็นการหาว่า การทำงานส่วนไหนที่ยังไม่มีการทดสอบ
มันจะนำไปสู่ การสร้าง test case หรือ การทดสอบใหม่ขึ้นมา
ไม่ใช่แก้ไข code เลยนะ แต่เน้นย้ำว่าต้องเขียน test case ขึ้นมาใหม่ก่อนเสมอ
ตัวอย่างเช่น
ถ้าเราพบว่ามีการ hardcode ค่าที่ return ออกมาจาก function การทำงานหนึ่งแล้ว
สิ่งที่เราต้องคิดและทำก็คือ เราจะทำการสร้าง test case ใหม่ขึ้นมา
เพื่อส่งผลให้เกิดการเขียน code ใหม่ที่ดีขึ้น เพื่อขจัด hardcode ออกไป
เมื่อทุกอย่างเรียบร้อย เราสามารถย้ายไปแก้ไขปัญหาต่อไปได้อย่างมีความสุข
ซึ่งมันส่งผลดีต่อ code และ การออกแบบระบบ
สามารถไปเขียน test case ใหม่ หรือ กลับไปดูและศึกษาปัญหาใหม่ๆ ในสถานะ Start ต่อไป
ขอให้ทำต่อไป อย่าหยุดครับ เพื่อพัฒนาตัวเราเองอยู่เสมอ
มันจะส่งผลดีๆ ต่อสิ่งที่เราทำอย่างแน่นอน