Monthly Archives: February 2011

Huge part of Software development is about Learning

ไม่นานมานี้ ได้ฟัง presentation Scaling Up by Scaling Down: Successful Agile Adoption in the Large by Focusing on the Individual ในช่วงต้น เค้าชี้ให้เห็นว่า ส่วนที่สำคัญมาก ส่วนหนึ่งของ software development คือ การเรียนรู้ 

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

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

ไม่ว่าจะเป็นการเรียนรู้เทคโนโลยี การเรียนรู้ problem domain การเรียนรู้เพื่อนร่วมงาน และอื่นๆ อีกมากมาย เป็นส่วนสำคัญที่ใหญ่มากๆ ตลอดการพัฒนา

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

My view of TDD

ได้โอกาสกล่าวถึง practice ที่ผมชอบที่สุด และใช้บ่อยที่สุดในชีวิตทำงานช่วงนี้ TDD (Test-drive development)

เค้าว่ากันว่า TDD เป็น practice ของคนที่ไม่เก่ง คนที่มักจะทำอะไรผิดพลาด ถ้าคุณมีความสามารถมากพอ ที่จะเขียน code ออกมารวดเดียวใช้งานได้ คุณอาจจะมองว่า TDD เป็นกระบวนการขัดขวาง flow ในการทำงานของคุณ แต่ผมมักจะผิดพลาดครับ

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

TDD คือ อะไร มีขั้นตอนตามตำราอย่างไร ผมขอไม่กล่าวถึง แนะนำให้ติดตาม series ของพี่ @roofimon ทาง code-66 เองละกัน

ส่วน blog นี้ผมจะขอกล่าวถึง motivation ของ TDD ในมุมมองของผม และเล่าถึง TDD ที่ผมทำอยู่ทุกๆ วันเป็นอย่างไร

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

แนะนำว่าถ้าจะลอง TDD ควรศึกษามาก่อนระดับหนึ่ง พอจะเริ่มใช้ให้ใช้ให้เต็ม stream เริ่มกับ project ใหม่ของท่านตั้งแต่เริ่มน่าจะสะดวกที่สุด เพราะการทำ TDD ครึ่งๆ กลางๆ มีความเป็นไปได้สูงมากที่ท่านจะได้รับประสบการณ์ที่ไม่ดีกับไป

“ผมคิดว่าใช้ TDD แล้วได้อะไร”

  • Focus ปัญหาที่ต้องการได้ง่ายขึ้น ก่อนจะลงมือเขียนโปรแกรมอะไร เราจำเป็นต้องคิดก่อนว่าเราจะเขียนทำไม การเขียน test ก่อน เทียบเท่ากับการจดสิ่งที่เราต้องทำออกมาก่อนเริ่มลงมือทำนั่นเอง
  • รู้ว่าโปรแกรมที่เขียน ถูกหรือผิดอย่างรวดเร็ว ความสำคัญของเรื่องนี้ เกี่ยวกับเรื่อง high feedback ที่ผมเขียนไว้ครับ
  • Loosely coupling software ถ้าท่านเขียน unit test อย่างถูกวิธีท่านจะได้ โปรแกรมที่ไม่มีความผูกพันธ์ระหว่าง unit (class, component) สูงเกินไปนัก (เพราะถ้าสูงแสดงว่าท่านไม่ได้เขียน unit test แล้ว) ซึ่งเป็นผลให้เวลาท่านแก้อะไรกับส่วนไหน ก็จะกระทบกับส่วนอื่นๆ ไม่มากนัก
  • ป้องกัน overengineer และ premature optimization โปรแกรมเมอร์อย่างเราๆ มักมองข้าม shot เห็นปัญหาข้างหน้าที่จะเกิดขึ้น 3 ชั้นได้ แต่ความจริงคือ สำหรับโปรแกรมเมอร์ที่มีประสบการณ์ไม่เพียงพอ มันมักจะผิด การทำอะไรในสิ่งที่ไม่ได้ใช้ ยิ่งถ้าเป็นส่วนที่ใช้พลังงานไปเยอะ จะทำให้เราเซ็งและเสียกำลังใจไปมาก
  • ความมั่นใจว่า software ยังทำงานได้ และรับรู้ถึงปัญหาในส่วนของโปรแกรมที่เคยทำงานได้แล้วมันพังได้อย่างรวดเร็ว ด้วย test ที่เราเขียนไว้ก่อนจะเริ่มลงมือ code ถ้าเขียน test after เราอาจจะเขียนไม่ครอบคลุม ขี้เกียจเขียน
  • กล้าที่จะแก้ไขโปรแกรม requirement มักเปลี่ยน, วิธีที่ดีมักไม่มาในครั้งแรก, ความมั่นใจในการจะแก้ไข code ในมุมมองของผม เป็นสิ่งที่จำเป็นมากต่อการพัฒนา software ขนาดใหญ่และใช้เวลานาน
  • มีตัวอย่างการรัน code สำหรับคนอื่นที่มาดูโปรแกรมของเรา จาก test นั่นเอง (ถ้าไปใช้ BDD ก็จะได้ excutable specs มาอีกต่างหาก)
  • ลดภาระของสมอง จากหลายๆ เหตุผลด้านบน ทำให้ท่านย้ายหลายสิ่งที่เดิมทีเคยทำด้วยสมอง มาไว้ที่ test

“ผมทำ TDD อย่างไร”

  1. เขียน Acceptance test (black box, user view point to whole component) ของ function ที่กำลังจะทำ
  2. เขียน unit test (white box, isolating) จากจุดที่ทำให้ acceptance test ไม่ผ่าน
  3. เขียน code ให้ test ผ่าน
  4. วนกลับไปทำ 2-3 เพิ่มจนกว่า 1 จะผ่าน แล้วก็เขียน 1 อันต่อไป
  5. ผม refactoring เรื่อยๆ ไม่ค่อยได้ทำตาม practice เท่าไหร่ อาจจะเป็นเพราะใช้ TDD มาซักระยะ trick มันอยู่ที่ พยายามอย่าทำอะไรค้างเอาไว้ ไม่ว่าจะแก้อะไรต้องรีบกลับมาทำให้ test รันผ่านไว้เสมอ แล้วจะดีเอง
  6. เวลาเจอ bug อะไร ทั้งเจอเอง หรือมีคนอื่นเจอ ควรจะมี test ไม่ว่าจะเป็น acceptance หรือ unit คลุม bug ตรงส่วนนั้นไว้เสมอ ก่อนจะลงมือแก้ เพื่อที่มันจะไม่เกิดซ้ำ

“ปัญหาของ TDD”

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

Importances of Rapid Feedback

ผมไม่ได้เป็นกูรู Agile อาจจะอธิบายเรื่องนี้ได้ไม่ดีเท่าไหร่ แต่คอนเซปหนึ่งที่สัมผัสได้จาก practice เกือบทั้งหมดของ Agile ที่เคยผ่านหูผ่านตามา คือ การเน้นที่ Rapid Feedback

ไม่ว่าจะเป็น TDD, Continuous Integration/Deployment ที่พยายามให้เราเห็นผลกระทบหลังจากการเปลี่ยนแปลง code ทันที หรือที่แฝงๆ อยู่ใน practice อื่นๆ เช่น Stand-up meeting (คุยกันบ่อยๆ ทำให้อัพเดตการเปลี่ยนแปลงของเพื่อนร่วมทีมได้เร็ว), Iterative development (ทำให้งานเป็นชิ้นเล็กๆ จบในตัวเอง เห็นผลชัดเจน)

เรื่องเกี่ยวกับ rapid feedback เรื่องหนึ่งที่น่าสนใจ ผมได้ฟังมาจากพี่ @juacompe ใน session เรื่อง Seeking Hyper Productivity ที่ Opendream คือ เค้าบอกว่าการที่มีนักเล่นเกมส์เก่งๆ ได้ แต่ในชีวิตจริงไม่สามารถสร้างคนที่เก่งขนาดนั้นได้ เพราะเกมส์เป็นสิ่งที่มี rapid feedback สูงกว่าชีวิตจริงมาก

หลังๆ นี้ ในงานที่ทำอยู่รู้สึกว่าหลายๆ ปัญหาจะไม่เกิดขึ้นหรือเกิดขึ้นมีความเสียหายเบากว่านี้ หากเรามี feedback ที่เร็วกว่านี้ ที่เห็นชัดๆ และคิดว่าเป็นกันบ่อยๆ คือ การเขียนโปรแกรมไปแล้ว ไม่ได้ใช้ เพราะรู้ในภายหลังว่าใช้ไม่ได้ หรือเข้าใจอะไรบางส่วนผิด หรือ overengineer เขียน feature ที่ไม่เคยได้ถูกใช้

สำหรับบริษัทที่มีพนักงานจำนวนไม่เยอะมาก การทำให้พนักงานสามารถ focus สิ่งที่สร้าง value ได้ เป็นสิ่งสำคัญมาก ถ้าเป็นทีมที่พัฒนา End-user application ผมว่าควรให้ user experiences นำทุกๆสิ่ง ไม่ว่าจะเป็น infrastructures, tools, frameworks หรือแม้กระทั่ง platform เลยทีเดียว เพราะจะเป็นจุดที่ตอบคำถามได้ว่าเราสมควรทำอะไรไม่สมควรทำอะไรบ้าง

แต่ไม่ว่าอย่างไร ผมคิดว่ามันเป็นไปได้ยากมากที่เราจะ design อะไรแล้ว ไม่ต้องมีการแก้อีก เพราะในการทำ project มักจะมีปัญหาที่มองไม่เห็น ณ ตอนที่เราเริ่มคิด และทำๆไปก็จะมี requirement change อยู่เสมอๆ (ในจุดนี้ผมก็ยังไม่ค่อยเข้าใจว่า ทำไมกับกิจการอื่น เช่น การโยธา ถึงเป็นไปได้ แต่กลับมีปัญหากับทางซอฟต์แวร์)

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

การทำให้เกิด rapid feedback นั้น ต้องพยายามทำอยู่ตลอดเวลา บางทีมพัฒนาซอฟต์แวร์แบบเน้น Prototyping ซึ่งผมมองว่าได้รับ feedback เร็วๆแค่บางส่วน เพราะในความจริงแล้ว ถึงแม้จะผ่าน prototype phase ไปแล้ว ก็ใช่ว่าจะไม่มีปัญหาแอบแฝงอยู่อีก ยิ่งกับ application บางประเภทมี scope ที่กว้าง บางทีมหั่นส่วน prototype ใหญ่เกิดไป ทำ prototype ไปซักพักก็รู้สึกว่าใหญ่เกิน เลิกทำไปอีก

ปัญหาที่สำคัญของการพยายามทำให้เกิด rapid feedback คือ การทำให้เกิด feedback นั้นก็มี cost เมื่อเราต้องการ focus feedback จากบางสิ่ง เราต้องยอมทำสิ่งอื่นง่ายๆ ในระดับพอใช้ได้ เพื่อที่จะได้ประกอบกันเป็นภาพรวม แต่งานทำอะไรง่ายๆ นั้น หลายๆครั้ง หลายๆคน อาจจะมองว่าต้องใช้ทรัพยากร และเวลามากเกินไป ที่จะทำมาแล้วสุดท้ายก็ต้องไปทำใหม่ ไม่ได้ใช้อยู่ดี

และบางครั้งการพยายามสร้าง feedback อาจจะทำให้เกิดความรู้สึกเหมือนเรากำลังเมินเฉยกับปัญหาบางอย่าง ที่เห็นอยู่กับตา แต่ไม่เกี่ยวกับสิ่งที่เราต้องการ feedback ณ ตอนนี้ เราเลือกที่จะพัฒนาโดยไม่ใส่ใจปัญหานั้นๆ ไปก่อน ซึ่งก็ตอบได้ยากว่าเราจะพัฒนาได้ยืดหยุ่นเพียงพอที่จะนำปัญหาที่เราเคยเห็นมาต่อเติมในภายหลังจากที่เราได้รับ feedback จากสิ่งที่ต้องการได้หรือไม่

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