Software Design during Wartime

บริษัท A...

เริ่มต้นจากการเป็น start-up พวกเค้าเขียน code เร็วมาก แทบไม่มี process อะไรเลย เขียนเสร็จสามารถ push code และ deploy production ได้ทันที เค้ามีลูกค้าจำนวนหนึ่ง ลูกค้าสามารถ request feature กับทีมได้โดยตรง ภายใน 3-4 วันลูกค้าก็ได้ใช้งาน feature ที่ต้องการ

เวลาผ่านไป พวกเค้าเริ่มมีลูกค้ามากขึ้นเนื่องจากมี feature ที่หลากหลาย ตอบโจทย์ แต่ระบบเริ่มซับซ้อน มันเริ่มแสดงปัญหามากขึ้น ระบบทำงานช้า มี bug และเมื่อ release ของใหม่หรือ bug fix ก็มักจะ break feature เดิม นอกจากนั้น feature request ก็ใช้เวลาหลายสัปดาห์หรือหลายเดือนกว่าจะทำสำเร็จ นั่นยิ่งทำให้ลูกค้าเก่าเริ่มไม่พอใจ แต่ก็ยังมีลูกค้าใหม่เข้ามาเรื่อยๆ

ทีมทำงานใต้ความกดดันที่สูงมาก พวกเค้านึกเสียใจว่าควรจะออกแบบระบบให้ดีตั้งแต่แรกเพื่อป้องกันไม่ให้เกิดปัญหานี้อีก พวกเค้าหาคนเก่งที่มีประสบการณ์เข้ามาเพิ่ม หา Architect ที่จะช่วยบอกพวกเค้าได้ว่าจะต้องทำอย่างไรถึงจะไม่มีปัญหาซ้ำแบบเดิม พวกเค้าเพิ่ม process มา control ในหลายจุดเพื่อป้องกันไม่ให้เกิดปัญหากับ feature ของลูกค้า การทำงานต้องมี document มีการ review และ approve แต่นั่นยิ่งทำให้ทีมงานต้องใช้เวลามากยิ่งขึ้นกว่าจะ release feature ให้ลูกค้าได้

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

บริษัท B...

พวกเค้าเป็นกลุ่มคนที่มีประสบการณ์ พวกเค้าทำ product แบบเดียวกับบริษัท A แต่พวกเค้าเลือกที่จะเริ่มออกแบบให้ระบบมีความยืดหยุ่นสูงตั้งแต่ต้น พวกเค้าเชื่อมั่นในประสบการณ์ที่มีในอุตสาหกรรมนี้ พวกเค้าใช้เวลาไปเกือบ 1 ปีในการ design และพัฒนาระบบที่พวกเค้าคิดว่าดีที่สุด ยืดหยุ่นที่สุดและสามารถตอบโจทย์ลูกค้าได้ แต่ในระหว่าง 1 ปีนั้น บริษัท A ปล่อย feature ต่างๆ มากมายที่ดูเหมือนไม่ผ่านการออกแบบมาเลย

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

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

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

บริษัท C...

พวกเค้าเป็นกลุ่มคนที่มีประสบการณ์และทำ product คล้ายกับ 2 บริษัทก่อนหน้า พวกเค้ารู้ว่าลูกค้ามีความต้องการที่หลากหลายและเปลี่ยนแปลงตลอดเวลา พวกเค้ารู้ว่าความเร็วเป็นของปีศาจ แต่พวกเค้าก็ฉลาดและระวังไม่ให้ตัวเองมีจุดจบเหมือนบริษัท A

พวกเค้าเลือกที่จะเขียน code ในระดับที่ “พอรับได้” มี process น้อยที่สุด แทบไม่มีเอกสารอะไรเลยถ้าไม่จำเป็นจริงๆ พวกเค้า design ผ่านการคุยกันสั้นๆ แล้วไปลองทำ พวกเค้าสามารถ push code และ deploy production ได้ทันทีเพื่อให้ลูกค้าได้ทดลองใช้และเก็บ feedback มาปรับปรุงเพิ่ม รอบการ release feature ของพวกเค้าคือหลักวัน ไม่ใช่หลักสัปดาห์, เดือน, หรือไตรมาส

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

...สุดท้ายพวกเค้าก็เป็นผู้นำอันดับ 1 ในตลาด ทุกคนต่างสงสัยว่าพวกเค้าทำได้อย่างไร

Wartime mindset

ผมอ่านหนังสือเล่มหนึ่งที่พูดถึงเรื่องนี้ เค้าเปรียบเทียบการสร้างสะพานสำหรับประชาชน vs สะพานสำหรับสงครามให้เข้าใจว่า การสร้างสะพานสำหรับประชาชนมักจะใช้เวลาหลายปีในการสร้างเนื่องจากเป้าหมายคือสะพานที่มีอายุใช้งานยาวนานที่สุด แต่เมื่อเทียบกับสะพานสำหรับสงคราม ถึงแม้ว่าจะต้องให้รถถังขับผ่านซึ่งมีน้ำหนักบรรทุกมากกว่าสะพานสำหรับประชาชน แต่เป้าหมายการออกแบบของมันไม่ใช่อายุยาวนาน แต่เป็นความเร็วในการสร้างโดยยังต้องรองรับน้ำหนักของรถถังได้ มันอาจจะสามารถสร้างเสร็จได้ในเวลา 5-10 วันและถูกใช้งานแค่ 1-3 ปีแล้วเลิกใช้ไป ไม่ใช่ 50-100 ปี ดังนั้น ทั้งแนวคิด วัสดุ รูปทรง การออกแบบ กระบวนการทำงาน ทั้ง 2 แบบมีความแตกต่างกันโดยสิ้นเชิง

การออกแบบและพัฒนา software ก็จะต้องเลือก technology ที่ทำให้เราสามารถ release software ได้ง่ายและเร็วด้วยเช่นกัน ลองนึกถึงการ update feature บน web application ผ่าน cloud server vs การส่ง CD/DVD ให้ลูกค้าเอาโปรแกรมไป install ในเครื่อง laptop เอง ทั้ง 2 วิธีใช้เวลาในการ release ต่างกันหลายเท่าตัว

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

Post hoc design

การที่เราจะทำได้อย่างบริษัท C นั้นไม่ใช่การไม่ออกแบบอะไรเลย แต่มันคือการออกแบบภายหลัง (Post hoc design)

เรามักเสียเวลาประชุมว่าจะใช้ technology อะไร จะทำบน architecture อะไร จะใช้ pattern ไหนในการเขียน code และยังรวมถึงการ discuss ว่า UI/UX จะเป็นอย่างไร จะมีกี่ปุ่ม จะใช้สีอะไร จะเลือก wording ไหน สิ่งเหล่านี้เป็นสิ่งจำเป็นแต่ยังไม่สำคัญจนกว่าเราจะปล่อย product/feature ให้ลูกค้าใช้งานและคอย observe ว่ามันตอบโจทย์หรือไม่

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

ดังนั้นในช่วงแรกของ new product หรือ new feature ทุกๆ วันมีความสำคัญ ดังนั้นทีมจะต้องเลือก “ความเร็ว” ในการปล่อย feature ไม่ใช่ “ความยั่งยืน” เพื่อให้เราค้นหา “feature-market fit” ได้เร็วที่สุด อย่างไรก็ตามทีมยังต้องคงความสามารถทั้งหมดของ software ไว้ให้ได้ ระบบห้ามพัง ห้ามทำให้ feature เดิมมีปัญหา

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

การทำ post hoc design & development ให้ยั่งยืนไม่ใช่การเปลี่ยนภาษา programming เปลี่ยน database หรือเปลี่ยน architecture ใหม่ทั้งหมดใหม่ แต่เป็นเพียงการ clean up ความเละเทะที่เราได้ทำไปในช่วงแรกและ enhance ระบบเพื่อให้เราทำ feature ถัดไปของลูกค้าได้ด้วยความเร็วเท่าเดิม (ถ้าไม่มี feature ถัดไปก็ยังไม่ต้อง enhance)

Reversible vs Irreversible decision

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

ยกตัวอย่างเช่น เราทำ mobile application ให้ลูกค้าใช้งานโดยให้ mobile application เชื่อมต่อกับฐานข้อมูลบน server โดยตรง ถึงแม้ว่าเราสามารถใช้ mobile developer 1 คนทำ feature เชื่อมฐานข้อมูลและปล่อย feature ได้เร็วในครั้งแรก แต่การแก้ไข feature ในครั้งถัดมานั้นยากมากๆ ทำให้ feature เดิมพัง เพราะไม่สามารถเพิ่ม/แก้ไข database column ได้ ไม่สามารถทำให้ mobile version เก่ากับใหม่ทำงานร่วมกันได้ ซึ่งไม่ใช่ “ความเร็ว” ในแบบที่ Wartime ต้องการ

อีกตัวอย่างคือการทำ native mobile app vs cross platform ในช่วงแรกเราอาจเลือกทำ cross platform ไปก่อนเพื่อรีบหา feature-market fit แต่เมื่อพบแล้ว เราจะเริ่มรู้ว่าจุดไหนมีปัญหาหรือไม่ตอบโจทย์ พัฒนา feature ยาก maintain ยากก็มา enhance เฉพาะหน้านั้นๆ

หรือการเขียน code ที่มีช่องโหว่ร้ายแรง ทำให้เกิด data leak หรือกระทบกับ financial ของบริษัทอย่างใหญ่หลวงก็เป็นสิ่งที่ต้องระวัง

การถกเถียงในเรื่อง code style หรือ variable naming หรือ monolith vs microservice หรือ SQL vs NoSQL เป็นเรื่องที่ยังไม่สำคัญ เราทำอะไรก็ได้ที่ทำได้เร็วเพื่อ release feature ให้ไว จากนั้นค่อยมา enhance เพิ่มในช่วงที่ feature เริ่มนิ่งได้

บางคนอาจสงสัยว่าการตัดสินใจเรื่องเหล่านี้ถ้าไม่เลือกตั้งแต่แรก มันจะแก้ไขยากและสร้างปัญหาในอนาคตหรือเปล่า แน่นอนว่ามีโอกาสที่จะสร้างปัญหาเมื่อมี feature-market fit เมื่อมีลูกค้าเยอะขึ้นและระบบเริ่มซับซ้อน แต่ทีมที่มี Wartime mindset จะต้องกลับมาปรับปรุงระบบให้ยั่งยืนในทันทีตลอดเวลา พวกเค้ารู้ว่า design ที่ดีคือ design ที่มีลูกค้าใช้งานจริง ทำงานได้ตามที่คาดหวังไว้ พวกเค้าเปลี่ยน technology ก็ต่อเมื่อพบว่ามันเป็นตัวถ่วงในด้านความเร็วในการปล่อย feature


Wartime Software Development ไม่ใช่ script kiddy ที่เขียน code เร็วแต่ขาดประสบการณ์ แต่เป็นเทคนิค กระบวนการและประสบการณ์มากมายที่ทำทุกอย่างเพื่อเน้นไปที่​ “ความเร็ว” บนพื้นฐานของ Software ที่ต้องทำงานได้ตามความคาดหวังของลูกค้าตลอดเวลา

พวกเขาทำสิ่งเหล่านี้เท่าที่จำเป็นในทันทีที่ได้ส่งมอบ feature ที่ตอบโจทย์ลูกค้าสำเร็จ – เขียน automate test เท่าที่จำเป็นทันทีที่ feature ตอบโจทย์ลูกค้า – clean up ทุกอย่างและ refactor code เท่าที่จำเป็นทันทีที่ feature ตอบโจทย์ลูกค้า – เขียน document เท่าที่จำเป็นทันทีที่ feature ตอบโจทย์ลูกค้า – automate business process เท่าที่จำเป็นทันทีที่ feature ตอบโจทย์ลูกค้า – สรุปบทเรียนในทุกด้านทันทีที่ feature ตอบโจทย์ลูกค้า พวกเขาใช้เวลาไม่มากในการทำสิ่งเหล่านี้เพื่อความ “ยั่งยืน” แล้วจึงเริ่มทำ feature ถัดไปที่ตอบโจทย์ลูกค้า