วันนี้ได้พูดคุยเรื่อง TDD และ Unit test พอสมควร
ซึ่งต่างคนก็ต่างมุมมอง แต่ปลายทางคือเรื่องของคุณภาพด้วยกันทั้งนั้น
แน่นอนว่า แนวทางของแต่ละคนย่อมไม่เหมือนกันอยู่แล้ว
ถ้าอะไรที่มันเหมือนกันหมด แล้วเราจะเรียนรู้อะไรล่ะ !!
ดังนั้นมาดูปัญหาจากการนำ TDD มาใช้ดีกว่า ว่ามีอะไรบ้าง

ข้อมูลต่างๆ ใน blog นี้ผมก็ไม่ได้คิดเองอีกแล้ว แต่เอามาจากเอกสารต่างๆ
ซึ่งอยู่ในส่วนของ Reference Websites นะครับ

มาเริ่มกันเลยดีกว่า

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

บางคนอาจจะถามว่า ถ้า TDD มันง่ายจริง ทำไมไม่เห็นมีใครใช้เลยล่ะ !!

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

1. Developer ไม่ชอบ test หรือ มีเวลาไม่พอหรอกนะที่จะมาเขียน test

น่าจะเป็นความผิดของชื่อ TDD และ unit test ที่ดันมีคำว่า test อยู่
ไม่เช่นนั้น Developer อาจจะชอบก็ได้นะ ..

Developer ส่วนใหญ่อาจจะถามด้วยว่า unit test นั้นใครเป็นคนทำ ?
Developer ใช่ไหมที่ต้องเขียน unit test ?
เพราะว่า Developer ส่วนใหญ่เข้าใจเสมอว่า test ไม่ใช่งานของฉัน
การ test ก็ไปให้ tester ทำสิ
… ใช่แล้ว มันก็ถูกนะ ผิดตรงไหนล่ะ …

และเมื่อต้องพัฒนางานที่ใกล้เวลาที่ต้องส่งหรือ deadline ด้วย
Developer จะบอกทันทีว่าไม่มีเวลามานั่งเขียน test หรอกนะ
แค่จะเขียน code ให้เสร็จยังยากเลย …

แต่มันคือเรื่องจริงนะ  เพราะว่า เวลามันมีไม่เพียงพอจริงๆ นะ
การเขียน unit test กับ code ไปด้วยกัน มันใช้เวลามากกว่าเดิมจริงๆ

แต่การเขียน code ที่ไม่มี test นั้น เรามักใช้เวลาในการกด keyboard
ประมาณ 15-40% หรือมากกว่านั้น ซึ่งบางคนเรียกช่วงนี้ว่า Hitting Keyboard Phase
และสิ่งที่ได้จากกระบวนการนี้คือ ระบบที่ทดสอบยากมาก แถมแก้ไขยากอีก
คุณยังคิดว่า มันคือแนวทางที่ดีหรือ ?

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

และมีผลงานการวิจัยจากทาง Microsoft ในปี 2009 บอกไว้ว่า
การเขียน unit test นั้น ทำให้เวลาการพัฒนาเพิ่มขึ้น
แต่เวลาโดยรวมในการพัฒนากลับลดลงซะอย่างนั้น

การวิจัย เป็นการนำแนวคิด TDD มาใช้พัฒนาระบบงาน ของ IBM และ Microsoft
พบว่าเวลาการพัฒนาเพิ่มเขียน 15-40%
แต่สิ่งที่รับกลับมาคือ จำนวน defect ที่ลดลงไป 40-90%
ส่งผลให้เวลาการพัฒนาโดยรวมลดลง ดังรูป

image_thumb6

ที่มา 1 : TDD  improve quality 
ที่มา 2 : The cost of TDD
ที่มา 3 : Paper งานวิจัยเรื่อง Realizing quality improvement through test driven development: results and experiences of four industrial teams

อย่างไรก็ตาม มันคือเรื่องการลงทุนล้วนๆ
คุณคือคนตัดสินใจเองว่าจะลงทุนทำหรือไม่ ไม่มีใครไปห้ามคุณได้
แต่ในการตัดสินใจนั้น ควรดูเรื่อง cost ต่างๆ ก่อนการตัดสินใจนะ …

2. การเขียน test ก่อนที่จะเขียน code จริงๆ นั้นมันถูกต่อต้านโดยธรรมชาติอยู่แล้ว

เนื่องจาก Developer ส่วนใหญ่ไม่สามารถเดาได้หรอกว่า
อนาคตมันจะเป็นอย่างไร จะไปในทิศทางไหน
ดังนั้น คุณจะรู้ได้อย่างไร ว่า test ที่เขียนก่อนการ code นั้นจะทำให้เกิดการเขียน code จริงๆ ขึ้นมาได้  ??

แต่ผมเชื่อว่าเหตุผลหลักๆ ของคนที่ไม่ยอมมาเขียน test ก่อนเขียน code จริงๆ นั้น
มีเหตุผลดังต่อไปนี้

ข้อที่หนึ่ง ไม่อยากออกมาจาก confort zone ของตัวเอง
เนื่องจากสิ่งที่ทำมากันอย่างช้านาน ก็คือ เราจะต้องออกแบบทุกสิ่งทุกอย่างออกมา
เพื่อหา solution ที่ดีที่สุด เพื่อที่นำมาพัฒนาได้อย่างดีที่สุด

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

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

ดังนั้นการจะขายแนวคิด TDD ให้กับ developer เป็นเรื่องที่ยากมาก
แต่ใช่ว่าจะทำไม่ได้นะ  ?
เริ่มต้นด้วยการลองออกมาจาก confort zone ของตัวเองก่อน
ลองเขียน test ก่อนเขียน code ดูด้วยสิ …

แต่มันมีแนวคิดหนึ่งจากหลายๆ คนพูดว่าว่า
สามารถเขียน test ก่อนหรือหลัง การเขียน code ก็ได้
แต่ในความคิดผมนั้น เชื่อว่าการเขียน test หลังจาก code นั้น
เป็นสิ่งที่น่ากลัวมาก เพราะว่าจะทำให้เราเขียน test ยากมาก
รวมทั้งทำให้เป้าหมายหลักของ TDD หายไป นั่นคือ การออกแบบ
เนื่องจาก TDD นั้นไม่ใช้เพียงการทดสอบนะ
แต่มันคือการออกแบบ ที่เรียกว่า Emergent design
โดยที่ unit test คือ product ที่ถูกผลิตออกมาจาก TDD

ดังนั้นจำนวน code ที่เพิ่มขึ้นนั้น
จะเกิดขึ้นมาจากความต้องการ
จะเกิดขึ้นมาจากการ Emergent design
ไม่ใช่เกิดขึ้นขึ้นมาจาก unit test
unit test เป็นเพียงผลผลิตจากขั้นตอนของ TDD เท่านั้น

3. การทดสอบใช่ว่าจะทำได้กับทุกๆ สิ่งนะครับ

เป็นเหตุผลที่ดีมาก เพราะว่า ไม่ใช่ว่าเราจะเขียน test มันไปซะทุกอย่าง
เพราะว่าบางส่วนของระบบมันก็ไม่สามารถเขียนได้จริงๆ
เช่น UI, VDO Streaming, พวก product ที่เรียกว่า black-box หรือระบบปิด

แต่ต้องมั่นใจว่ามันทดสอบยาก หรือ ทดสอบไม่ได้ กันแน่
ถ้าทดสอบยาก แสดงว่า ทดสอบได้
ตัวอย่างเช่น พวกตระกูล MV* สามารถเขียน unit test เพื่อทดสอบได้
และสามารถนำพวก Mock tool มาช่วยจัดการระบบที่เกี่ยวข้องได้ด้วย
หรือถ้าไม่ได้จริงๆ ก็เขียน integration test มันเลย ซึ่งก็เป็นส่วนหนึ่งของ TDD เช่นกัน
และยังมีแนวทางอื่นๆ อีกมากมาย แต่ไม่ขออธิบายตรงนี้ล่ะกัน

ดังนั้นมาถึงตรงนี้ ในระบบของคุณ อาจจะมีทั้ง code ที่มีและไม่มี test
แต่อย่างน้อยก็ทำให้คุณมั่นใจได้ว่า code ที่คุณได้มานั้นดูแลรักษาได้ง่ายขึ้น
สามารถแก้ไขได้ง่ายขึ้น

4. เขาบอกมาว่า TDD มันคือการ lock ในเรื่องของการออกแบบ

บ่อยครั้งที่มักจะเจอกับคำถามที่ว่า
เมื่อจะทำการเขียน test แล้วนั้น ถ้าเราต้องการเปลี่ยนการออกแบบที่ผ่านมาละ่ จะต้องทำอย่างไร มันจะเกิดอะไรขึ้นกับ test ของเรา ?

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

ถ้ามีปัญหาในเรื่องแบบนี้ ผมแนะนำให้กลับไปดูแนวปฏิบัติของการออกแบบ test ที่ดีนะ
กล่าวคือ ในแต่ละ test ควรมีเป้าหมายการทดสอบเพียงอย่างเดียว
และ ไม่ต้องทำการทดสอบ private method ที่ถูกใช้งานจาก code ที่มี test อยู่แล้ว

ดังนั้นสิ่งที่เราต้องเรียนรู้คือ การเขียน test ที่มีประสิทธิภาพมันเป็นอย่างไร
เพื่อลด cost หรือค่าใช้จ่ายในการดูแลรักษา test
เมื่อมีการแก้ไข requirement หรือแก้ไขความผิดพลาดของ code

พูดง่ายๆ ก็คือ
test ที่ดีมันจะเรียบง่าย มีความเสถียร ง่ายต่อการแก้ไข
test ที่ไม่ดี คือเมื่อมีการเปลี่ยนแปลง code แล้ว จะต้องทำการลบและเขียน test ใหม่ขึ้นมา

สรุปดีกว่า เดี๋ยวยาวไป

TDD นั้นไม่ใช่ว่าจะดีเลิศไปเสียหมด เนื่องจากมันต้องการ

  • เวลาในการลงทุนเพื่ออนาคต
  • เวลาในการเรียนรู้ เนื่องจากมันคือสิ่งใหม่ ( ตามจริงมันมีมานานแล้ว แต่เราเพิ่งรู้จัก )
  • เวลาในการสร้างความเชื่อถือและเชื่อมั่น
  • และมันก็ไม่ได้เหมาะสมไปซะทุกบริบทหรือทุกๆ เหตุการณ์

ดังนั้นการลงทุนมีความเสี่ยง กรุณาอ่านคู่มือประกอบการลงทุน …
ว่างๆ ลองไปดูใน Amazon นะครับ แล้วหา TDD มีมากกว่า 500 เล่ม

แต่เหตุผลดังกล่าวที่อธิบายไปนั้น ไม่มีเหตุผลไหนที่ดีพอ ที่จะทำให้คุณไม่ลองพยายามทำตามแนวคิด TDD เลย
มันอาจจะเป็นวิธีการที่ทรงพลัง ช่วยให้คุณต่อสู้กับสิ่งที่คุณคุ้นเคย
ช่วยสร้าง code ที่ดูแลรักษาได้ง่ายขึ้น
ช่วยให้คุณมั่นใจในการทำ regression ระบบ เนื่องจากคุณมี unit test ที่น่าเชื่อถือ …

คนเรามักมีเหตุผลร้อยแปด มาพูดเพื่อปฏิเสธการทำสิ่งที่อยู่นอก confort zone ของเรา
ดังนั้นก่อนที่จะปฏิเสธ TDD ลองลงมือทำมันก่อน แล้วค่อยตัดสินใจดีไหม ?

… แล้วทำไมคุณไม่ลองทำ TDD กันสักตั้งล่ะ … กลัวอะไรกันอยู่หรอ !!!

ปล. หลายๆ ที่เริ่มเอา TDD,  Test coverage มาตั้ง KPIs
ซึ่งแนวคิดนี้เหมือนจะดีนะ เพราะว่า ทุกๆ คนจะได้เขียน test ที่ทดสอบ code
แต่ถ้าเอามาตั้ง เพื่อเป็นการบังคับ และไม่มีการเตรียมพร้อมที่ดี
ทำให้เกิดการต่อต้าน โดยที่แต่ละคนอาจจะไม่เห็นด้วย แต่พูดออกมาไม่ได้
ผลที่ตามมาคือ การดื้อเงียบ แต่สามารถทำให้ได้ตาม KPIs นะเออ

เมื่อมามองในแง่คุณภาพแล้วจะไม่ได้ เพราะว่าทำให้มันได้ตาม KPIs เท่านั้น
ผลที่ได้ก็คือ มี test ก็เหมือนไม่มี ไร้ซึ่งคุณภาพ
เพราะฉะนั้น ระวังมันจะกลายเป็นดาบสองคม
แล้วยิ่งทำให้คนเกลียดหรือไม่เข้าใจ TDD มากยิ่งขึ้น

Reference Websites
What’s wrong with TDD
The Cost of Test Driven Development
Empirical Studies Show Test Driven Development Improves Quality
How to unit test “un-testable” code (in a nutshell)

Tags: