TDD Misconception

บทความนี้เป็นความเห็นล้วนๆ ไม่ได้อ้างอิงอะไรนอกจากประสบการณ์และความเห็นส่วนตัว

จากที่ผมลองเริ่มทำ TDD และลองถามตัวเองรวมถึงย้อนนึกไปถึงว่าทำไมทีมเก่าๆ ถึงไม่ได้ทำ TDD หรือลองทำแล้วล้มเลิก มันเกิดจากอะไรบ้าง ผมก็เลยรวบรวมเท่าที่นึกออกมาเผื่อใครที่เจอปัญหาแบบเดียวกันจะได้ลองอ่านดูให้เป็นประโยชน์

TDD ไม่ได้ทำให้ลด Bug

นี่เป็น Misconception ใหญ่อันนึงเลย คือ TDD ไม่ได้มีไว้ทำให้ Bug น้อยลง แต่มันมีไว้ทำให้เรามี Feedback loop ที่เร็วขึ้นและทำให้เราไม่ทำ Bug ซ้ำ

ตอนที่ผมเริ่มทำ TDD ผมเข้าใจตรงนี้ผิดไปมาก รวมถึง Management เองก็เข้าใจผิดว่าถ้ามีสิ่งนี้แล้วคุณควรจะทำ Bug น้อยลงตั้งแต่แรก ก็คิดเทสให้มันครอบคลุมสิ คิดให้มันเยอะๆ ก่อนเขียนเทสสิ

ซึ่งนั่นแหละขัดกับหลัก Agile และความรวดเร็วทุกประการ

ตอนนี้สิ่งที่ผมทำคือ เขียนเทสให้โง่และง่ายที่สุด เขียนโค้ดให้ผ่านเทส แล้วถ้ามันผ่านก็เลิก ไปทำอย่างอื่นต่อ ถ้าไม่ได้เป็นประเด็นที่มันใหญ่ๆ ที่ต้องการความชัวร์มากๆ ผมจะทำแค่นี้

พอมี Bug จาก QA หรือพอเราลองกดแล้วเจอ Bug เมื่อนั้นผมก็จะ Add test และ Add production code เข้าไป

ซึ่งพอย้อนไปย้อนมาตอนนี้ถึงได้เข้าใจว่าทำไม Kent Beck ผู้ก่อตั้ง TDD ถึงบอกว่า Make it work, make it right, make it fast. และเจ้าตัวเองก็บอกว่า Write test just enough to make a sleep at night. และทำไมถึงบอกว่า Release often

เพราะเมื่อคุณทำ TDD สิ่งที่คุณได้ไม่ใช่ Perfect software แต่เป็น Software มี Bug เหมือนเดิมนั่นแหละ แต่ใช้เวลาในการแก้ Bug สั้นลงมากๆ นั่นแหละคือความหมายลึกๆ ที่ว่า TDD ควร Release often

ข้อผิดพลาดแรก: พยายามเขียนเทสให้ครอบคลุมเกินไป

อย่าพยายามบอกให้เพื่อนร่วมทีมว่าคิดนานๆ คิดดีๆ ก่อนเขียนเทส เขียนให้เยอะให้ครอบคลุม เขียนให้ Perfect ฝั่งบริหารก็อย่าบอกว่าทำเทสแล้วทำไมไม่ทำให้ครอบคลุมให้มันดีๆ วิธีคิดและ Attitude แบบนี้นั่นแหละที่ทำให้เรารู้สึกว่าเขียนเทสมันเสียเวลา

เราเขียน Test เพื่อลด Mental workload จากความกลัวที่จะเขียนโค้ด (กลัวพัง) แต่ถ้าเราไปสร้างความกลัวที่จะเขียนเทสไม่ครอบคลุมแต่แรก นี่มันไม่ได้อะไรขึ้นมาเลยนะ

Make it work, before make it right

ทำการทดสอบมากเกินไปใน 1 เคส

ผมมีหลักส่วนตัวแล้วว่า Test ต้องคิดได้ใน 2 นาที และเขียนเสร็จภายใน 10 นาที แต่โดยเฉลี่ยผมจะเสียเวลาต่อเทสไม่เกิน 5 นาทีเสมอ

ถ้าเกินกว่านั้นผมจะเริ่มถามตัวเองแล้วว่า เราเทสเยอะไปมั้ย

เช่น ผมทำตัว Aggregrate ข้อมูล เคสแรกที่ผมจะเขียน

It should aggregate correctly

สำหรับคำว่า Correctly ที่นี้ก็จะเป็นอะไรที่โง่ๆ ที่สุด

assert(aggregrate([ 
{ title: ‘Data1’, value: 3},
{ title: ‘Data2’, value:4 }
]).equal(7)

แล้วก็เริ่ม Production code เลย

พอทำเสร็จเราเจอปัญหาว่า เห้ย บางที Field ไม่ได้ชื่อ Value นะ เราก็มาเพิ่มเทสเคสใหม่ แล้วเพิ่ม Production code ใหม่

พอเจอปัญหาว่าบางทีส่งค่าไปในฟังก์ชั่นเป็น Null แล้วฟังก์ชั่นพัง เกิดเป็น Bug ขึ้นมาเราก็เพิ่ม

It should return 0 when get null

นั่นแหละ ผมเจอปัญหาก่อนแล้วค่อยเพิ่มเทสเคสไปทีละเคส ไม่ใช่พยายามเขียนเทสให้ครอบคลุมทุกปัญหา เทสทีละอย่าง ทีละปัญหา

Premature optimization is root of all evil

สำหรับผม ผมมองว่าเราไม่ควรจะต้องคิดเยอะมากกับการทำเทส เราไม่ได้ทำเทสเพื่อให้เกิด Perfect software และเอาจริงๆ Perfect software ก็ไม่มีจริงในโลก แต่เราทำเทสให้ “ไม่ย้อนกลับไปเจอ Bug เดิม”

สำหรับผมเอง ในตอนเริ่มต้น TDD ผมจะพยายามร่างสเปคฟังก์ชั่นทั้งหมดออกมาให้ได้ แล้วนั่นน่ะเสียเวลามากๆ จนเป็นที่มาของความรู้สึกว่า TDD เสียเวลา

แต่ตอนนี้ผมทำ TDD แบบรู้สึกว่าบางครั้งทำได้เร็วกว่าเขียนไม่มีเทสต์อีก

Test one thing and only one thing
Make it work, make it right, then make it fast.

ผมพึ่งเข้าใจว่าทำไมคนที่พูดเรื่อง TDD ที่น่าจะช้าและละเอียดละออ กลับพูดอะไรที่ขัดกันก็ตอนนี้แหละ เพราะเค้าไม่ได้ตั้งใจให้เราทำทุกอย่าง Perfect แต่แรก และคนที่เริ่ม TDD ก็มักจะเข้าใจผิดและพยายามทำทุกอย่าง Perfect แต่แรกนี่เอง

สรุปสำหรับคนเริ่มต้น TDD ที่รู้สึกว่าตัวเองลำบากใจที่จะทำ นี่เป็นข้อแนะนำส่วนตัวของผม

  1. เขียนเทสให้โง่และเร็วที่สุด ควรจะโง่และใช้เวลาทำน้อยๆ ถึงแม้จะมีจำนวนบรรทัดเยอะ แต่มันจะโง่และเขียนได้เร็วเสมอ
  2. เทสเคสจะถูกเพิ่มเมื่อเจอ Bug
  3. อย่าคาดหวังว่าทำ TDD แล้วจะไม่มี Bug อย่าพยายามเขียนเทสให้ครอบคลุมทุกอย่างตั้งแต่แรก นั่นจะยิ่งทำให้ช้าและทำลาย Purpose ของการทำเทส เทสเราทำให้ไม่ต้องเสียเวลาคิดนานคิดแล้วคิดอีกก่อนแก้โปรแกรม แต่นี่เรากลับมานั่งคิดแล้วคิดอีกตอนเขียนเทส มันใช่เหรอ?
  4. สำหรับ Management หรือ Senior อยากให้ จำคำ Kent Beck ไว้ว่า TDD มีไว้ให้โปรแกรมเมอร์เลิกกลัวที่จะเขียนโค้ด เลิกกลัวที่จะแก้ไขโค้ด ถ้า TDD ทำให้ลูกทีมกลัวที่จะเขียนโค้ด แสดงว่ามีบางอย่างผิดพลาด การ “ลดความกลัวที่จะเขียนโค้ด” ควรจะเป็น Value สูงสุดในการทำ TDD เสมอ อย่าลืม Purpose นี้ อย่าเห็นแก่ Process จนลืมเป้าหมายเด็ดขาด

ผมคงมีเรื่องแชร์จากประสบการณ์แค่นี้ครับ

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.