Screen Shot 2558-05-04 at 1.41.15 PM
ปัญหาที่นำมาเป็นโจทย์ในการฝึกคือ Counting code line
หรือการนับจำนวน Line of Code นั่นเอง
ซึ่งนำมาจาก Code Kata 13
แน่นอนว่า ปัญหานี้มีวิธีการแก้ไขหลากหลายมาก
มาเริ่มฝึกกันดีกว่า และมาดูว่าสุดท้ายแล้วได้ผลอย่างไร ?

Code Kata 13 :: Counting code line

ให้ทำการนับจำนวน Line of Code ของ code ภาษา Java
ตัวอย่างเช่น code ชุดนี้มี 3 บรรทัด

สรุปได้ว่า ควรจะนับเฉพาะบรรทัดที่

  • บรรทัดไม่ว่าง
  • ไม่ใช่ comment ทั้ง single line และ multiple line
  • และอื่นๆ อีกมากมาย

เมื่อเราเข้าใจปัญหาแล้ว จึงให้เริ่มเขียน code
ผ่านทาง Cyber Dojo กันเลย ได้ผลดังภาพ

Screen Shot 2558-05-04 at 7.59.40 AM

โดยจากทั้ง 4 คนที่แก้ไขปัญหานั้น
ใช้แนวคิด TDD (Test-Driven Development) นะ

มาดูกันว่าแนวคิดนี้มันสอน และ ให้อะไรเราบ้าง ?

เรื่องแรกเลยก็คือ Test case แรกนั่นเอง

ทุกคนจะต้องตัดสินใจว่า จะเริ่มต้นอย่างไรดี ?
ซึ่งทุกคนรู้ว่า จะต้องเริ่มจาก test case ที่ง่ายสุดๆ ก่อนสิ
จะได้แก้ไขง่ายๆ

คำถาม
แล้ว test case ง่ายๆ มันคืออะไรล่ะ ?
คำตอบ
จากดูการเริ่มต้นของแต่ละคน พบว่ามีอยู่ 3 กลุ่มคือ

  1. ใน test case แรก ทำการส่งชื่อไฟล์เข้าไป
  2. ใน test case แรก ทำการส่งข้อมูล code เข้าไป เป็น String
  3. ใน test case แรก ทำการส่ง Stream เข้าไป

ย้อนกลับไปดู Unit test ที่ดีสิ
หนึ่งในนั้นคือ เราต้องตัด dependency ออกไปให้หมดนะ
ซึ่งหนึ่งในนั้นก็คือ File system นั่นเอง
ดังนั้น ในการแก้ไขปัญหานี้เราไม่ต้องการ
ไปยุ่งกับ File system นะครับ

นั่นคือ ใน test case แรกให้ทำการส่งข้อมูลเป็น String เข้าไป
เพื่อทำการนับว่ามีจำนวนบรรทัดเท่าไร ?

เมื่อเริ่มต้นในแนวทางที่ดูดี แล้ว
ต่อไปเริ่มกระบวนการต่อไปดีกว่า

เดินไปข้างหน้าอย่างรวดเร็ว

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

  • 0 บรรทัด
  • 1 บรรทัด
  • 2 บรรทัด

จัดการกับพวก whitespace ต่างๆ ทั้งในบรรทัดเดียวกับ และ หลายๆ บรรทัด
และอื่นๆ อีกมากมาย

และอย่าลืมว่า เมื่อเราพัฒนา code ไปเรื่อยๆ
ทั้ง test code และ production code
จะพบว่ามี duplication code หรือ code ซ้ำๆ เยอะมาก
ดังนั้น ห้ามลืม Refactoring ใน TDD นะครับ
Write test -> Make it pass -> Refactoring and repeat

ผลที่ได้คือ code ที่มันน่าเกลียดๆ ?

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

แต่จะมาติดกับการแก้ไขปัญหา เรื่อง multiple line comment นั่นเอง
code ที่ออกมาจะอุดมไปด้วย if-else block ดังตัวอย่าง

คำถาม
ทำไม if-else มันเยอะจังนะ ?
คำตอบ
ก็มันเป็นวิธีการแก้ไขปัญหา ที่ง่ายสุดๆ แล้วไงล่ะ

แต่เมื่อปัญหามันซับซ้อนมากยิ่งขึ้น แล้ว
if-else มันจะนรกมากๆ เลยไหมนะ ?
ยิ่งใน test case ของ multiple line comment
ทำให้เราเพิ่มพวกตัวแปร flag เข้ามาใน code
ทำให้เราเพิ่มพวก if-else-if-else เข้ามาอีกเพียบ
นั่นคือ การเพิ่มความซับซ้อนเข้าไปใหญ !!
แต่ก็ยังทำกันอีกนะ …

ดังนั้น ลองหยุดคิดกันหน่อยดีไหม ว่าทำไมมันถึงได้ code เช่นนี้ออกมา
บางคนบอกว่า ถ้าเราทำตามแนวคิด TDD แล้ว
จะช่วยให้เราสร้างสิ่งต่างๆ ออกมาได้ง่าย
พร้อมกับการออกแบบที่เรียบง่าย
และสุดท้ายจะได้สิ่งที่ดีออกมา !!

แต่กลับลืมไปว่า
ผลลัพธ์จะออกมาดีไม่ได้เลย ถ้าขาดการคิด
แน่นอนว่า มันไม่ง่ายเลย

แนวคิด TDD นั้นเป็นแนวคิดที่ดีมากสำหรับการพัฒนา software
ช่วยทำให้เราคิด และ เปลี่ยนแนวทางการแก้ไขปัญหา
โดยที่เรายังมีความเชื่อมั่นว่า ภาพรวมของระบบยังทำไงได้

คำถาม
แต่ทำไม มันทำให้ code ที่ได้ มันแย่ล่ะ ?
ลองถามตัวเราเองสิว่า
มันยากไหม ที่จะต้องเพิ่ม feature ใหม่ๆ เข้ามา
เช่น การเพิ่ม test case สำหรับ multiple line comment เข้ามา ?
หรือใช้เวลานานไหม ? สำหรับการแก้ไขให้ code ทำงานได้ถูกต้อง

ดังนั้น สิ่งที่เรา และ ทีม ทำได้คือ
เราควรทำการ refactor code ที่มันมี if-else เยอะๆ กันนะ
แต่นั่นมันเป็นวิธีซ่อนความซับซ้อนไว้หรือไม่นะ ?

บางคนก็อาจจะบอกว่า
code ชุดนี้มันก็ทำงานได้ตามความต้องการนะ
ถึงจะ code จะดูไม่ดีนักก็ตาม

บางคนก็อาจจะบอกว่า
code มันดูแย่นะ if-else เยอะไปนะ
เราต้องการแนวทางใหม่ๆ
เราต้องการวิธีคิดใหม่ๆ
ใช่ไหมครับ ?

แล้วแนวทางใหม่ๆ มันคืออะไรล่ะ ?

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

แน่นอนว่า ทุกคนเข้าใจปัญหาอย่างแจ่มไปเลย
เพราะว่า แก้ไขปัญหามาได้ทุกคน
หรือทุกคนมีประสบการณ์มาแล้วนั่นเอง
ทำให้พูดกันได้ง่ายขึ้นเยอะ

คำถามที่น่าสนใจ จากการพูดคุยคือ
ทำไมเราต้องไปตรวจสอบด้วยล่ะ ?
ว่าแต่ละบรรทัด หรือ แต่ละส่วนมันคืออะไร ?
เช่น ว่างหรือไม่
เช่น comment หรือไม่

ทำไมเราต้องไปสนใจล่ะ?
ทั้งๆ ที่เราสนใจเพียงการนับบรรทัด หรือ Line of Code นะ
ดังนั้น เราทำการลบสิ่งที่เราไม่ต้องการออกไปเลยดีไหม ?
ซึ่งวิธีการแก้ไขต้องลดการใช้ if-else ด้วยนะ

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

หลังจากนั้นก็ทำการ refactor code ในแต่ละบรรทัด
ด้วยการ extract method ออกไป เพื่อให้ชื่อมันสื่อสารได้ชัดเจน

แต่มีคำถามที่น่าสนใจ ถามกันออกมาคือ
แบบนี้เราทำกำลัง Big Design Up Front (BDUF) หรือไม่ ?
แบบนี้มันซับซ้อนไปไหมนะ ?

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

มันแตกต่างจากวิธีการเดิมๆ
ที่ระบบมักจะถูกออกแบบ จากคนที่ไม่ได้ลงมือทำ
คนที่ออกแบบมักจะไม่เคยแก้ปัญหานั้นๆ
ทำให้มันเกิดปัญหาขึ้นมาหรือเปล่านะ !!

ดังนั้น
เราจะแก้ไขปัญหาได้อย่างไร ถ้าปราศจาคการเขียน code
เราจะแก้ไขปัญหาได้อย่างไร ถ้าปราศจาคการลงมือทำ
เราจะแก้ไขปัญหาได้อย่างไร ถ้าปราศจาคประสบการณ์
สุดท้ายมันทำให้เราได้สิ่งที่เราต้องการออกมา
นั่นคือ Emergent Design นั่นเอง

สรุปแล้วจากปัญหานี้ทำให้เรียนรู้ว่า

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

มาเขียน code กันเถอะครับ !!