จงทำสิ่งที่เรียบง่ายที่สุดเท่าที่เป็นไปได้
(seangoedecke.com)- ในการออกแบบซอฟต์แวร์ การเลือก “สิ่งที่เรียบง่ายที่สุดเท่าที่เป็นไปได้” อยู่เสมอเป็นคำแนะนำที่ได้ผล
- การออกแบบระบบที่ยอดเยี่ยมมักไม่ได้ดูยิ่งใหญ่อลังการ แต่แก้ปัญหาได้ด้วยองค์ประกอบให้น้อยที่สุดเท่าที่จำเป็น
- เมื่อตามหาวิธีแก้ที่เรียบง่าย สามารถยึดหลัก YAGNI(You Aren't Gonna Need It) เป็นปรัชญาหลักในการออกแบบ โดยค่อย ๆ ขยายเมื่อมีความต้องการใหม่เกิดขึ้นจริงเท่านั้น
- แม้จะมีข้อถกเถียงเรื่องนิยามของ “ความเรียบง่าย” แต่ระบบที่มีคอมโพเนนต์น้อย การเชื่อมต่อภายในหลวม และมีเสถียรภาพ คือสิ่งที่ใกล้เคียงความเรียบง่ายที่สุด
- การหมกมุ่นกับความสามารถในการขยายระบบมากเกินไปทำให้โค้ดเบสขาดความยืดหยุ่น ดังนั้นการออกแบบที่เรียบง่ายและยึดตามความต้องการจริงจึงได้เปรียบกว่าในระยะยาว
การแสวงหาสิ่งที่เรียบง่ายที่สุดเท่าที่เป็นไปได้
เมื่อต้องออกแบบระบบซอฟต์แวร์ สิ่งสำคัญคือการทำ “สิ่งที่เรียบง่ายที่สุดเท่าที่เป็นไปได้” แนวทางนี้ใช้ได้กับแทบทุกสถานการณ์ ไม่ว่าจะเป็นการแก้บั๊ก การดูแลรักษาระบบเดิม หรือการออกแบบสถาปัตยกรรมใหม่ วิศวกรจำนวนมากมักใฝ่ฝันถึงระบบ “ในอุดมคติ” ที่จัดระเบียบดี ขยายได้แทบไม่สิ้นสุด และกระจายโครงสร้างอย่างสวยงาม แต่ในความเป็นจริง การทำความเข้าใจระบบปัจจุบันอย่างลึกซึ้งก่อน แล้วเลือกวิธีแก้ที่ง่ายที่สุด มักได้ผลมากกว่า
ความเรียบง่ายที่มักถูกประเมินต่ำไป
- การออกแบบระบบต้องอาศัยความสามารถในการใช้เครื่องมือหลากหลาย เช่น app server, proxy, database, cache, queue เป็นต้น
- ยิ่งเป็นวิศวกรระดับจูเนียร์ ยิ่งอยากใช้หลายเทคโนโลยีเพื่อสร้างโครงสร้างที่ซับซ้อน แต่ความชำนาญที่แท้จริงกลับอยู่ที่การตัดสิ่งไม่จำเป็นออก
- การออกแบบซอฟต์แวร์ที่ยอดเยี่ยมมักดูธรรมดาเสียจนให้ความรู้สึกว่า ปัญหานั้นแก้ได้ง่ายกว่าที่คิด
- ตัวอย่างเช่น Unicorn และ Rails REST API อาศัยความสามารถพื้นฐานของ Unix เพื่อให้ได้ โครงสร้างน้อยที่สุด พร้อมรับประกันคุณสมบัติหลักต่าง ๆ (การแยกส่วน การขยายระบบ การกู้คืน ฯลฯ) จึงถือว่าเป็นการออกแบบที่ยอดเยี่ยม
วิธีคิดในการทำให้เรียบง่าย
- ตัวอย่างเช่น เมื่อเพิ่มฟีเจอร์ rate limiting ให้กับแอปพลิเคชัน Golang อาจใช้ external storage อย่าง Redis ได้ แต่ถ้ายังไม่จำเป็นจริง ก็อาจลองวิธีที่เรียบง่ายกว่าก่อน เช่น การนับในหน่วยความจำ
- หากวิธีที่เรียบง่ายเพียงพอ ก็สามารถเลื่อนการเพิ่มโครงสร้างพื้นฐานที่หนักออกไปก่อนได้
- ทำให้สามารถค่อย ๆ พัฒนาขยายระบบได้เมื่อมีความต้องการใหม่เกิดขึ้นจริงเท่านั้น
- นี่คือแนวทางที่ให้หลัก YAGNI เป็นลำดับความสำคัญสูงสุดในการออกแบบ
กับดักของความเรียบง่ายและข้อจำกัดในโลกจริง
1. ปรากฏการณ์ Big Ball of Mud
- หากพยายามแก้ทุกความต้องการแบบเฉพาะหน้า ก็เสี่ยงที่โค้ดเบสจะกลายเป็น “ก้อนโคลนขนาดใหญ่(big ball of mud)” ที่ซับซ้อนและดูแลรักษายาก
- แต่การแก้แบบฉาบฉวย (hack) ไม่ใช่ความเรียบง่าย ตรงกันข้าม มันเพิ่มความซับซ้อนให้การทำความเข้าใจและการบำรุงรักษา
- การจะหาวิธีแก้ที่เรียบง่ายจริง ๆ ต้องเปรียบเทียบหลายแนวทางและทำ วิศวกรรมอย่างเป็นระบบ อย่างแท้จริง
2. นิยามของความเรียบง่าย
- ไม่ใช่เรื่องง่ายที่จะเห็นตรงกันว่า “ความเรียบง่าย” คืออะไร
- โดยทั่วไป ระบบที่เรียบง่ายคือระบบที่มี ชิ้นส่วนที่เคลื่อนไหว(องค์ประกอบการทำงาน) น้อย, การเชื่อมต่อระหว่างคอมโพเนนต์หลวม, และ มีอินเทอร์เฟซที่ชัดเจน
- ตัวอย่างจริง: Unix process และ Unicorn ไม่ได้แชร์หน่วยความจำกัน จึงมีความเรียบง่ายสูง และเมื่อเทียบกับ Puma หรือ Redis ก็มีการเชื่อมโยงภายในต่ำกว่า
- เมื่อเลือกได้ยาก ให้มองว่า สิ่งที่ต้องดูแลรักษาน้อยกว่า คือสิ่งที่เรียบง่ายกว่า
3. คำวิจารณ์ต่อการหมกมุ่นกับ scalability
- “วิธีที่เรียบง่าย” อาจไม่เหมาะกับทราฟฟิกขนาดใหญ่
- แต่การออกแบบให้ซับซ้อนล่วงหน้าเพื่อรองรับการขยายขนาดอย่างรุนแรงในอนาคต ส่วนใหญ่มักเป็นความพยายามที่ไร้ประโยชน์
- โค้ดส่วนใหญ่ในความเป็นจริง แค่เตรียมรับทราฟฟิกที่เพิ่มขึ้นราว 2–5 เท่าก็เพียงพอ และหากเกินกว่านั้น การค่อยรับมือเมื่อเกิดปัญหาจริงย่อมสมเหตุสมผลกว่า
- การออกแบบที่ยึด scalability มากเกินไปทำลายความยืดหยุ่นของโค้ด การแยกโครงสร้างมากเกินความจำเป็นกลับทำให้การพัฒนาฟังก์ชันบางอย่างยากขึ้น และอาจต้องจัดการ transaction ที่ซับซ้อนตามมาด้วย
บทสรุป
- เมื่อเวลาผ่านไป ผู้เขียนยิ่งมองโลกในแง่ร้ายน้อยลงต่อความสามารถในการคาดการณ์ความต้องการของระบบในอนาคต
- ในการทำงานจริง แค่การทำความเข้าใจสถานะปัจจุบันของระบบให้ถูกต้องก็ยากมากพออยู่แล้ว และนี่คืออุปสรรคหลักที่ขัดขวางการออกแบบที่ดี
- การพัฒนาซอฟต์แวร์มีแนวทางใหญ่ ๆ อยู่สองแบบ
- ออกแบบโดยคาดการณ์ความต้องการในอนาคต
- ทำซ้ำกับ สิ่งที่เรียบง่ายที่สุดเท่าที่เป็นไปได้ โดยยึดตามความต้องการปัจจุบัน
- แนวทางหลังมีประสิทธิภาพกว่าจริง และการยึด YAGNI กับแนวคิดที่เน้นความเรียบง่ายจะนำไปสู่การออกแบบที่ดีในระยะยาว
ภาคผนวก: ที่มาของคำศัพท์และการถกเถียงใน Hacker News
- ต่อความเห็นที่ว่าสถาปัตยกรรมแบบเรียบง่ายจะยิ่งหมดความหมายเมื่อระบบมีขนาดใหญ่ขึ้น ผู้เขียนกลับยืนยันว่า ยิ่งเป็นระบบขนาดใหญ่ โครงสร้างที่เรียบง่ายยิ่งสำคัญกว่าเดิม (เพื่อรับมือกับความซับซ้อนจากปฏิสัมพันธ์ระหว่างฟีเจอร์)
- วลี “Do the simplest thing that could possibly work” ถูกบัญญัติขึ้นโดย Ward Cunningham และ Kent Beck
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ฉันคิดว่าแนวทางแบบนี้ใช้ได้ดีกับโดเมนที่เรียบง่าย แต่ถึงอย่างนั้นหลังจากทำงานในบริษัทเทคขนาดใหญ่มานานก็ยังรู้สึกประหลาดใจกับความซับซ้อนที่ต้องรองรับอยู่เสมอ แม้แต่ปัญหาทางธุรกิจที่ดูง่ายที่สุดก็อาจใช้เวลามากกว่าหนึ่งปีกว่าจะแก้ได้ หรือพังบ่อยจาก edge case จำนวนมากและปัญหาเรื่องสเกล คนที่ชูเรื่องความเรียบง่ายอาจไม่เคยมีประสบการณ์กับระบบขนาดใหญ่ ต่อให้ดูโค้ดเบสอายุ 10 ปี ก็ยังมีสิ่งที่ต้องคำนึงถึงมากเกินไปจนการ rewrite มักล้มเหลวอยู่บ่อย ๆ เหมือนอุปมา Chesterton's Fence ถ้าไม่รู้เหตุผลที่บางสิ่งมีอยู่ ก็ต้องมีปัญญาพอที่จะไม่ลบมันทิ้งส่งเดช
ฉันคิดว่านี่เป็นความเข้าใจผิดแบบคลาสสิกที่เกิดจากวิศวกรซอฟต์แวร์สื่อสารกันไม่ดี จุดของบทความตามชื่อเลยคือให้ทำ "สิ่งที่ง่ายที่สุดเท่าที่จะเป็นไปได้" สำหรับปัญหาที่ซับซ้อน ความซับซ้อนเป็นสิ่งหลีกเลี่ยงไม่ได้ แต่ความหมายคือให้ระวังความผิดพลาดที่ทำให้มันซับซ้อนเกินจำเป็น ไม่ได้แปลว่าต้องหลีกเลี่ยงความซับซ้อนทั้งหมด แต่ต้องระวังนิสัยที่ชอบทำให้เรื่องเกินความจำเป็น
อย่างที่ชี้ไว้ ความซับซ้อนอาจไม่ได้มาจากตัวโดเมนเองเสมอไป แต่อาจเป็นปัญหาที่เกิดจากการออกแบบซอฟต์แวร์ที่ไม่ดี ถ้าเต็มไปด้วย dependency และ side effect ก็แปลว่าการแยก concerns กับการจัดการ coupling ทำได้ไม่ดี การ refactor จะแทบเป็นไปไม่ได้ และถ้าวัฒนธรรมองค์กรไม่ดีขึ้น ระหว่าง refactor ก็จะมีแต่ปัญหาใหม่ถูกแปะเพิ่มเข้าไปเรื่อย ๆ ถึงอย่างนั้น แค่การแยก concerns และการประกอบแบบเรียบง่ายก็ยังช่วยแก้ปัญหาซับซ้อนได้ แม้จะยาก แต่ถ้า senior developer มีมุมมองนี้อย่างมั่นคง โอกาสสำเร็จก็จะสูงขึ้น
มีคนพูดถึงว่าผู้เขียนเป็น staff engineer ของ GitHub ดังนั้นฉันคิดว่าคนนี้ก็น่าจะมีประสบการณ์กับระบบขนาดใหญ่เพียงพอ
ระบบ legacy อยู่ตามขอบต่าง ๆ ในระบบจริงก็เหมือนกัน ยิ่งจำนวนมิติในปริภูมิหลายมิติเพิ่มขึ้น จุดต่าง ๆ ก็ยิ่งกระจุกตัวอยู่บนผิวขอบ และผู้ใช้จริงส่วนใหญ่ก็มักทำงานอยู่ใกล้ขีดจำกัดของระบบ สิ่งที่รองรับ edge ทั้งหมดเหล่านี้ได้ดีที่สุดก็คือระบบเก่าแก่ที่มีอยู่เดิมนั่นเอง
ที่ทำงานก่อนหน้านี้ ความซับซ้อนส่วนใหญ่เกิดจากความพยายาม refactor หรือปรับปรุงที่ล้มเหลว ถูกยกเลิกกลางทาง หรือทำไม่เสร็จ ฉันมักสงสัยว่าถ้าป้องกันสิ่งเหล่านี้ได้ตั้งแต่ต้น เราจะได้รับมอบระบบที่เรียบง่ายกว่านี้หรือเปล่า ไม่ได้หมายความว่าไม่ควร refactor หรือปรับปรุงเลย แต่คิดว่าควรวางแผนให้ครอบคลุม use case 100% อย่างชัดเจน และต้องมีงบกับ milestone พร้อม เพื่อให้แน่ใจว่าจะค่อย ๆ ปรับปรุงได้จริง
อยากให้มีการระบุที่มาของวลี "สิ่งที่ง่ายที่สุดเท่าที่จะเป็นไปได้" ให้ชัดเจนหน่อย วลีนี้เป็นหลักการที่ Ward Cunningham ผู้คิดค้น wiki และ Kent Beck ใช้กันบ่อยช่วงปลายยุค 80 ตอนที่ทำงานร่วมกัน ทั้งคู่คอยเตือนกันถึงหลักการนี้ระหว่างเขียนโค้ด และต่อมากลายเป็นหัวข้อสำคัญในการพูดและการเขียน อย่างตัวอย่างประตูปิดที่บทความนี้ยกมา มันดูเรียบง่าย แต่ "ความเรียบง่าย" นั้นก็เปลี่ยนไปตามสถานการณ์ บทความนี้ก็พูดถึงจุดนั้นเหมือนกัน คือการหาวิธีแก้ที่เรียบง่ายไม่ได้เรียบง่ายเสมอไป พวกเขาก็รู้ตัวว่าวิธีนี้อาจทิ้งหนี้เทคนิคไว้ แต่ลำดับความสำคัญคือทำให้โค้ดทำงานก่อน ส่วนตัวฉันอยากให้บทความนี้พูดถึงมุมของหนี้เทคนิคมากกว่านี้อีกหน่อย
หลังจากนั้น Kent Beck ก็ทำให้ Extreme Programming กลายเป็นแนวทางอย่างเป็นทางการ ซึ่งเป็นชุดของแนวปฏิบัติที่ช่วยให้ระบบเรียบง่ายค่อย ๆ วิวัฒน์ได้ตามการเปลี่ยนแปลงของ requirement
ฉันเคยได้ยินวลีนี้จากเพื่อนร่วมงานและเห็นเขาใช้เป็นเหมือนคติประจำชีวิต แต่ไม่รู้เลยว่า Ward Cunningham เป็นต้นฉบับ พอคำนี้ถูกใช้แพร่หลายมากจนไม่มีใครรู้ว่าใครเป็นคนคิด นั่นก็ดูเหมือนเป็นเกียรติสูงสุดแบบหนึ่ง
น่าสนใจที่มีการพูดถึง Wiki ที่ทำงานเก่าของฉันใช้ Lotus Notes จัดการโปรเจกต์ ซึ่งมีประโยชน์มากเพราะมันไฮไลต์ให้เห็นเลยว่าเอกสารถูกเปลี่ยนเมื่อไร โปรเจกต์ถัดมาใช้แต่ Wiki อย่างเดียว แต่กลับมองไม่ออกเลยว่าเอกสารไหนเปลี่ยนไปบ้าง จนแทบใช้งานอะไรไม่ได้ มันเรียบง่ายก็จริง แต่เรียบง่ายเกินไปจนใช้งานจริงไม่สะดวก
ตลอดอาชีพที่ผ่านมา เรื่องที่ถกเถียงกันมากที่สุดคือคำจำกัดความของคำว่า "ใช้งานได้" ประโยคที่ว่า "แค่ใช้งานได้ ไม่ได้แปลว่ามันไม่ได้พัง" เป็นสิ่งที่คนที่เคยซ่อมอะไรด้วยมือตัวเองจะเข้าใจได้ทันที ช่างซ่อมมักยอมใช้เครื่องมือที่พังซ่อมแบบขอไปทีก่อนจะตัดสินใจเปลี่ยน แต่ดูเหมือนนักพัฒนาจะไม่ค่อยรู้สึกถึงความจำเป็นของการ "ต้องซ่อมให้ถูกต้อง"
ช่วงที่ยากที่สุดในอาชีพของฉันคืออยู่ในบริษัทที่มีทีมหนึ่งชอบทำ prototype ทีมนี้จะทำแค่ proof of concept อย่างรวดเร็ว เดโมให้ผู้บริหารดู แล้วก็ปล่อยขึ้นระบบทันที จากนั้นผู้บริหารก็เข้าใจผิดว่าถ้าทำเสร็จเร็วขนาดนี้ก็น่าจะ deploy ได้เลย แต่พอทีมที่ต้องรับช่วงต่อเปิดโค้ดดู ก็พบว่าสิ่งจำเป็นอย่าง end-to-end security, validation, error handling และอื่น ๆ หายไปหมด สุดท้ายต้องสร้างใหม่ตั้งแต่ต้น และผู้บริหารก็เข้าใจผิดอีกว่าทีม deploy กำลังทำอะไรให้ซับซ้อนเกินเหตุ
ฉันเคยเห็นคำพูดที่น่าประทับใจจากที่ไหนสักแห่งว่า "ไม่พอที่โปรแกรมจะทำงานได้ มันต้องทำงานได้ด้วยเหตุผลที่ถูกต้อง" ซึ่งโดยแก่นแล้วก็คือข้อความเดียวกัน
บทสนทนาแบบนี้สำคัญมากในเชิงวิชาชีพ ระบบหนึ่งอาจเรียกว่า "ทำงานได้" ในความหมายที่มันให้ผลลัพธ์ตามต้องการ แต่ในแง่ความน่าเชื่อถือหรือค่าใช้จ่าย มันก็อาจยังถือว่าล้มเหลวอยู่ดี
สำหรับงานที่ฉันทำ ความหมายของคำว่า "ทำงานได้" ขึ้นอยู่กับว่านายจ้างจะให้เอาทรัพยากรของฉันคือเวลาไปลงกับอะไร ถ้าเป็นสถานการณ์ที่ใช้เวลาเพื่อปรับปรุงคุณภาพได้ ฉันก็จะพยายามทำให้ดีที่สุด แต่ถ้าพวกเขาต้องการแค่ให้ถึงเป้าหมายหรือเช็ก checklist ให้ครบ ฉันก็จะทำงานให้สอดคล้องกับนั้น ฉันคิดว่าผลลัพธ์ย่อมเป็นไปตามสิ่งที่ถูกวัด ดังนั้นฉันให้คำแนะนำได้ แต่คนตัดสินใจไม่ใช่ฉัน
ความย้อนแย้งของคำแนะนำแบบนี้คือ คนที่นำไปใช้ได้ดีจริง ๆ มักเป็นผู้เชี่ยวชาญที่มีประสบการณ์มากอยู่แล้ว เช่น จะรู้ได้อย่างไรว่าสิ่งไหนคือ "สิ่งที่ง่ายที่สุด" หรือจะตัดสินอย่างไรว่ามันใช้ได้จริง ไม่นานมานี้ฉันทำ XLSX importer เอง แล้วพลาดเรื่องการจัดการ XML namespace เพราะดันสมมติว่า Excel จะใช้แต่ default namespace เสมอ พอทีหลังได้รับไฟล์ที่ใช้ namespace แบบอื่นก็พังทันที ถ้าจะทำแบบง่าย ๆ ก็แค่ลบ prefix ทิ้งแล้วประมวลผล แต่เพื่ออนาคตของตัวเอง ฉันเลยใช้เวลา 4 ชั่วโมงเขียน parser ใหม่ทั้งชุดให้รองรับ namespace อย่างถูกต้อง การจะทำ "สิ่งที่ง่ายที่สุด" จริง ๆ ไม่ได้ง่ายขนาดนั้น และยิ่งมีประสบการณ์ก็ยิ่งตัดสินได้ดีขึ้น แต่พอมีประสบการณ์ถึงระดับนั้นแล้ว ก็รู้สึกเหมือนไม่จำเป็นต้องมีคำแนะนำแบบนี้อีกแล้วเหมือนกัน
ฉันคิดว่าในตัวบทความก็พูดถึงเหตุผลที่คำแนะนำนี้นำไปใช้ได้ยากอยู่แล้ว แก่นสำคัญคือ "ถ้าจะหาวิธีแก้ที่เรียบง่ายที่สุด คุณต้องพิจารณาหลายแนวทาง และสุดท้ายก็ต้องใช้ความคิดแบบวิศวกรรม"
ที่บริษัทเราใช้หลักว่า "อย่าเพิ่มโค้ดไปในทิศทางที่ผิด" ต่อให้เป็นการ implement แค่บางส่วน ก็ต้องเขียนในแนวทางที่ต่อยอดภายหลังได้ดี นี่คือ KISS แต่ไม่ยอมรับทางลัดเด็ดขาด
ฉันตัดสินความเรียบง่ายจาก "สิ่งที่เปลี่ยนผ่านได้ง่ายที่สุด" บริการเดี่ยวที่ไม่พึ่ง abstraction หรือ infrastructure ซับซ้อนมากนัก สุดท้ายมักเปลี่ยนผ่านได้ง่ายกว่า คนที่เข้ามาอ่านก็เข้าใจได้ทันที และทั้งการส่งต่องานกับการ debug ก็ทำได้สะดวกกว่า แต่ถ้าจำเป็นต้องมี abstraction ก็ใส่ และถ้าจำเป็นต้องมี infrastructure ก็เพิ่ม สิ่งสำคัญคือ เวลาส่งมอบโค้ด ฉันจะคิดเสมอว่าโครงสร้างนี้อธิบายได้ง่ายที่สุดหรือยัง เมื่อก่อนฉันเคยพยายามทำทุกอย่างให้เป็น abstraction แยกตาม service ตั้งค่าได้หมด และแทบไม่มีโค้ดเลย แต่ในทางปฏิบัติการเปลี่ยนผ่านและการส่งต่องานล้มเหลวโดยสิ้นเชิง ตอนนี้เลยทำให้โครงสร้างซับซ้อนเฉพาะเมื่อจำเป็นจริง ๆ และให้ค่าเริ่มต้นเป็นความเรียบง่ายที่เข้าใจได้ทันที ซึ่งสุดท้ายก็เป็นประโยชน์ทั้งต่อการ onboarding คนใหม่ การแก้บั๊ก และการเปลี่ยนผ่านจริง
AI vibecoding ก็คล้ายกัน ยิ่งมีประสบการณ์และ know-how มากขึ้น ก็ยิ่งเลือก task ที่เหมาะสมและบริหาร agent ได้ง่ายขึ้น
ดูเหมือนหลายคนจะพลาดประเด็นที่ว่า "สิ่งที่ง่ายที่สุด" ไม่ได้หมายถึงทางลัดหรือการอุดรูรั่วเฉพาะหน้า วิธีที่เรียบง่ายยิ่งต้องอาศัยการคิดและความเข้าใจระบบมากขึ้น ซึ่งนั่นก็เป็นจุดที่บทความเกริ่นไว้ หลายคนดูเหมือนจะเห็นแค่พาดหัวแล้วก็ระบายความไม่พอใจของตัวเองออกมา
โดยทั่วไปพอได้ยินหลักการหรือคำกล่าวหนักแน่นแบบนี้ ฉันจะเริ่มระแวงทันที ถ้าใครพูดเรื่องการพัฒนาซอฟต์แวร์เหมือนมีคำตอบสากลตายตัว มักแปลว่าเขาไม่ได้รู้อะไรมากนัก บทสรุปของนักพัฒนาที่มีประสบการณ์จริงคือ ซอฟต์แวร์เป็นเรื่องยากและต้องระมัดระวัง ไม่มีคำตอบสารพัดประโยชน์ ต้องมีทั้งความคิดที่เปิดกว้างและความใส่ใจ
ความเรียบง่าย หรืออีกด้านหนึ่งของความซับซ้อน เป็นเกณฑ์ที่แทบจะสำคัญที่สุดเวลาเปรียบเทียบทางเลือกในการออกแบบซอฟต์แวร์ เพราะสุดท้ายมนุษย์ต้องเป็นคนวางแผน เห็นพ้อง ลงมือทำ และบำรุงรักษา แต่การตัดสินว่าอะไรเรียบง่ายนั้นยากมาก และวิศวกรระดับเฉลี่ยของอุตสาหกรรมก็ไม่น่าเชื่อถือพอในเรื่องนี้ แถมคำว่า "ความเรียบง่าย" เองก็กลายเป็นคำฮิตที่ไร้ความหมายไปแล้ว มักถูกใช้แค่เพื่อโต้กลับว่่า "อันนี้ง่ายกว่า" แม้กับข้อเสนอที่ดีจริง ๆ หัวหน้าทีมควรจับประเด็นพวกนี้ให้ได้ แต่ทุกวันนี้ความสามารถของหัวหน้าทีมดูน่าไว้วางใจได้น้อยลงเรื่อย ๆ เลยยิ่งลำบาก
ในบทความก็มีประโยคที่น่าประทับใจอยู่เหมือนกันว่า ปรมาจารย์ที่แท้จริงรู้ว่าเมื่อไรควร "ทำน้อยลง" ไม่ใช่ "เพิ่มเข้าไป" เหมือนฉากที่มือใหม่เคลื่อนไหวเยอะแยะดูหวือหวา แต่ปรมาจารย์ขยับน้อยและใช้เพียงหมัดเดียวที่ตัดสินทุกอย่าง
ตอนอ่านบทความ ตอนแรกฉันก็หงุดหงิดนิดหน่อย แต่คิดว่ามันจับแก่นของการลองผิดลองถูกได้ดีว่า "ทางลัด" จะเพิ่มความซับซ้อนอีกรูปแบบหนึ่งเข้าไป ปัญหาคือเมื่อหลักการแบบนี้ถูกใช้เกินเลยเหมือนเป็นคำสั่งจากผู้บริหาร จนพยายามตอบปัญหาที่ซับซ้อนด้วยวิธีที่ง่ายเกินไป ทำให้ถ่ายทอดความรู้ยาก และสุดท้ายเหลือแต่งานเก็บกู้ที่ซับซ้อนกว่าเดิม ในทางกลับกัน เหตุที่อะไร ๆ ซับซ้อนเกินจำเป็นก็มักมาจากการทนอยู่กับการแก้เฉพาะหน้าและทางลัดซ้ำ ๆ จนวันหนึ่งพยายามรวบจัดการทีเดียวแล้วดันเลยเถิดเกินไปอีก สุดท้ายนักพัฒนาต้องเข้าไปมีส่วนร่วมในการประชุมอย่างจริงจังเพื่อชี้นำให้เกิดการตัดสินใจที่ฉลาดตั้งแต่แรก
ฉันไม่คิดว่านี่ถึงขั้นเป็นสัญญาณอันตราย เพราะความซับซ้อนที่ไม่จำเป็นเพิ่มขึ้นทุกวัน จึงจำเป็นต้องมีคนคอยย้ำให้รักษาความเรียบง่ายไว้ นักออกแบบ ผู้จัดการผลิตภัณฑ์ แม้แต่ลูกค้าและสถาปนิกเองก็มักมีสัญชาตญาณจะเพิ่มความซับซ้อนเข้าไป
ฉันเห็นด้วยกับข้อโต้แย้งของคุณ แต่ก็อยากชี้ว่าท้ายที่สุดแล้วมันมักกลับไปจบที่ "ทุกอย่างคือ trade-off" หรือ "ไม่มีของฟรี" อยู่ดี หลักการทั่วไปทั้งหลายเป็นการสรุปประสบการณ์ภาคสนามจำนวนมาก จึงตัดทิ้งไปเสียหมดไม่ได้ ปัญหาคือเมื่อคอนเซปต์ที่ใช้งานได้จริงค่อย ๆ กลายเป็นข่าวลือเกินจริงหรือเป็นลัทธิ จนสุดท้ายเหลือแค่การถกเถียงเรื่องชื่อโฟลเดอร์
จากการสร้างระบบ 0-1 หลายระบบในสตาร์ตอัปช่วง Seed ถึง Series C ฉันซึมซับหลักการหนึ่งมาอย่างลึกซึ้งว่า "ความเรียบง่ายคือความแข็งแกร่ง" ทั้งการออกแบบเริ่มต้นและการปรับปรุงระบบเดิม ล้วนเผลอออกแบบเกินความจำเป็นได้ง่าย ความต้องการของลูกค้าพัฒนาอยู่ตลอด และต่อให้พยายามคาดการณ์ความต้องการในอนาคตอย่างไร สุดท้ายก็ย่อมพลาดอยู่ดี ฉันคิดว่าความเรียบง่ายไม่ได้แค่ลดข้อผิดพลาด แต่ยังเป็นฐานให้เปลี่ยนโครงสร้างได้ง่ายด้วย ควรเตรียม X, Y, Z ที่เป็นไปได้ไว้ แต่ยังคงมุ่งไปที่การสร้าง "สิ่งที่ง่ายที่สุด" เพื่อเผื่อทางเลือกและการขยายในอนาคต ความซับซ้อนย่อมเพิ่มข้อจำกัดโดยหลีกเลี่ยงไม่ได้ และยิ่งกองสะสมตามเวลา สแต็กก็ยิ่งอ่อนแอลง
ฉันคิดว่าต้องเคยลองออกแบบ "ระบบในอุดมคติ" มาระดับหนึ่งก่อน ถึงจะไปถึง "สิ่งที่ง่ายที่สุด" ได้ การสร้างระบบที่อ่านง่ายและเปลี่ยนแปลงได้ง่ายต้องอาศัย know-how มากเหมือนกัน แม้แต่การปรับปรุงที่ "เรียบง่าย" อย่างแท้จริงก็มาจากประสบการณ์และความเข้าใจอย่างลึกซึ้ง
นี่สอดคล้องกับ Gall's law ตามทฤษฎีนี้ ระบบที่ซับซ้อนและทำงานได้จริง มักเริ่มจากระบบง่าย ๆ ก่อน แล้วค่อย ๆ เพิ่มความซับซ้อนเข้าไป ระบบที่ถูกทำให้ซับซ้อนตั้งแต่ต้นมักไปไม่รอด เพราะฉะนั้นควรสร้างระบบที่ง่ายที่สุดก่อน แล้วค่อยเพิ่มความซับซ้อนตาม requirement
ฉันเห็นด้วยกับเจตนาของบทความ แต่คิดว่าการมาถึงของ cloud infrastructure ทำให้คำจำกัดความของ "ความเรียบง่าย" เปลี่ยนไป ในอดีตมันเหมือนเป็นการเลือกระหว่าง "ง่ายแต่ไม่ scalable" กับ "ซับซ้อนแต่ scalable" แต่ตอนนี้ไม่ใช่แบบนั้นแล้ว โซลูชัน rate-limiting แบบ in-memory อาจง่ายบนเซิร์ฟเวอร์เครื่องเดียว แต่พอมีแค่สองเซิร์ฟเวอร์ก็กลายเป็นปัญหา distributed state ทันที ในทางกลับกัน managed service อย่าง DynamoDB หรือ ElastiCache กลับทำหน้าที่เป็นแหล่งความจริงหนึ่งเดียวได้ไม่ว่าจะมีโหนดเดียวหรือ 1000 โหนด และลดความซับซ้อนได้มาก ถ้ามองจากแนวคิดว่า "ระบบที่เรียบง่ายย่อมแข็งแรงกว่า" การใช้ managed service ก็อาจเรียบง่ายกว่าในระดับพื้นฐานด้วยซ้ำ เพราะช่วยลบปัญหาซ้ำ ๆ อย่างข้อมูลสูญหายหรือการจัดการ distributed state ไปได้ ดูเหมือนว่าทุกวันนี้นิยามของ "สิ่งที่ง่ายที่สุด" ได้เปลี่ยนมาเป็นการใช้ managed service อย่างชาญฉลาดแทนการดูแลเอง และปัจจุบันการเลี่ยง external dependency ไม่ได้ช่วยลดความซับซ้อนเสมอไป ตรงกันข้าม การ leverage ระบบที่แยกออกมาและผ่านการพิสูจน์แล้วอย่างมีประสิทธิภาพกลับช่วยประหยัดทั้งเวลาและค่าใช้จ่ายมากกว่า
ฉันเห็นด้วยกับคำกล่าวที่ว่า "ทำให้มันง่ายที่สุดเท่าที่จะทำได้ แต่อย่าทำให้ง่ายไปกว่านั้น" ฉันพยายามยึดหลักนี้อยู่เสมอ แต่ก็สงสัยตลอดว่าตัวเองพลาดโอกาสลดความซับซ้อนที่ไม่จำเป็นเพราะไม่รู้เทคโนโลยีใหม่ ๆ หรือว่าทุกคนรอบตัวต่างหากที่กำลังตกหลุมความซับซ้อนโดยไม่จำเป็น มันยากจะรู้ว่าเครื่องมือใหม่ใช้ได้จริงหรือไม่ถ้าไม่เคยลองในโปรเจกต์จริง และในทางกลับกัน ฉันก็เคยเห็นว่าการยัดเครื่องมือใหม่เข้าโปรดักชันเพียงเพื่อการเรียนรู้ของตัวเองนั้นสร้างภาระให้ทีมมากแค่ไหน
ฉันกำลังเจอฝันร้ายคล้ายกันอยู่ เพราะหัวหน้าที่เหนือขึ้นไปชอบซอฟต์แวร์ใหม่ล่าสุดเสมอ ทำให้ต้องคอยประเมินเครื่องมือที่อาจไม่มีประโยชน์ชัดเจนสำหรับงานจริงอยู่เรื่อย ๆ แถมยังคาดหวังให้สำรวจเรื่องแบบนี้ทุกสัปดาห์โดยไม่เกี่ยวกับผลงานด้วย เลยกดดันมาก
ในความเป็นจริง ฉันคิดว่าควรทำให้มันใช้งานได้ก่อนด้วยวิธีที่ง่ายที่สุดเท่าที่มี แม้ต้องทำด้วยมือก็ได้ แล้วค่อยเพิ่มฟังก์ชันเต็มรูปแบบเมื่อถึงเวลาจำเป็น ต่อให้ตอนแรกเสียเวลาไปกับการทำทุกอย่างให้เป็นระบบอัตโนมัติหรือทำเป็นเครื่องมือ แล้วภายหลังพบว่ามันไม่จำเป็น อย่างน้อยประสบการณ์ที่ทำให้รู้ชัดว่าทำไมจึงจำเป็นหรือไม่จำเป็นก็ยังมีคุณค่ากว่า
ความรู้สึกนี้คุ้นมาก ฉันเองก็เห็นด้วยกับบทความแนวนี้อยู่เสมอและพยายามนำความเรียบง่ายไปใช้ แต่ก็มักสับสนว่ามันคือความฉลาดและความเป็นรูปธรรมจริง ๆ หรือแค่ประสบการณ์และทักษะของฉันยังไม่พอ
เพราะเรื่องนี้เอง ฉันจึงพยายามระวังอย่างมากไม่ให้ตกไปสู่ "การพัฒนาเพื่อเรซูเม่"