Ask HN: โค้ดเบสที่ดีที่สุดสำหรับเรียนรู้การออกแบบซอฟต์แวร์คืออะไร?
(news.ycombinator.com)- กำลังพยายามพัฒนาทักษะด้านการออกแบบซอฟต์แวร์ และมีคนแนะนำให้ลองศึกษาจากโค้ดเบสที่ออกแบบมาดีซึ่งมีอยู่แล้ว
- จึงสงสัยว่า ในบรรดาโค้ดเบสที่เข้าถึงได้สาธารณะ มีอะไรบ้างที่ถือเป็นมาตรฐานระดับทองของการออกแบบซอฟต์แวร์
1. โค้ดเบสที่แนะนำ
- โปรเจ็กต์ขนาดใหญ่/ตัวแทนสำคัญ
- Git, Postgres, CPython
- "lieutenants model" ของ Linux Kernel
- UNIX v6, BSDs
- เฟรมเวิร์ก/ไลบรารี
- Spring Framework
- Laravel
- ไลบรารีมาตรฐานของ Rust
- Codemirror 6
- ระบบ/เซิร์ฟเวอร์
- เกม/กรณีพิเศษ
- สื่อการสอน/แหล่งเรียนรู้
- xv6 (คลาส OS ของ MIT)
- pytudes (Peter Norvig)
- อื่น ๆ
- Monocypher (ไลบรารีเข้ารหัสลับ)
- อิมพลีเมนเทชันของภาษา Tcl
2. การอ่านโค้ด vs การเรียนจากเอกสาร/การออกแบบ
- ข้อจำกัดของการดูแต่โค้ด
- โค้ดเบสแสดงให้เห็นการอิมพลีเมนต์ แต่ซ่อนเจตนาในการออกแบบและการแลกเปลี่ยนข้อดีข้อเสียไว้
- ความสำคัญของเอกสารการออกแบบ
- บันทึกการตัดสินใจอย่าง ADR (Architectural Decision Records), Rust RFCs, Python PEPs มีประโยชน์ต่อการเรียนรู้การออกแบบมากกว่า
- การเขียนเอกสารออกแบบด้วยตัวเองก็อาจเป็นการฝึกที่ดีได้
- หนังสือ·เอกสารแนะนำ
- The Architecture of Open Source Applications
- Code Reading (Spinellis)
- Beautiful Code (O’Reilly, ISBN-10: 0596510047)
- หนังสือเกี่ยวกับ Refactoring / Legacy Code
3. แนวคิดการเรียนรู้ที่เน้นการลงมือปฏิบัติ
- ประสบการณ์และการลองผิดลองถูก
- การออกแบบเป็นสิ่งที่เรียนรู้ได้จากการเจอปัญหาซ้ำ ๆ และเรียนรู้วิธีหลีกเลี่ยงมัน
- แค่อ่านโค้ดอย่างเดียวไม่ทำให้เกิดการเรียนรู้ ต้องลงมือเขียนเองและแก้ปัญหาจากความล้มเหลวจึงจะได้เรียนรู้
- การเรียนรู้ตามความสนใจ
- การสร้างโปรเจ็กต์ที่ตัวเองสนใจจะทำให้เรียนรู้ได้ลึกกว่า
- ต้นทุนของความล้มเหลวที่ต่ำ
- ซอฟต์แวร์มีต้นทุนของความล้มเหลวต่ำกว่าวิศวกรรมกายภาพ จึงเหมาะกับการเรียนรู้ผ่านการลองและการพลาด
4. ข้อถกเถียงเรื่องธรรมชาติของวิศวกรรมซอฟต์แวร์
- แนวคิดว่ายังเป็นวิศวกรรมที่ไม่สุกงอม
- ถ้ามีวิศวกรห้าคนแล้วได้คำตอบต่างกันห้าแบบ นั่นอาจเป็นหลักฐานว่ามันยังไม่สุกงอมในฐานะวิศวกรรม
- มุมมองว่าเอื้อต่อการทดลอง
- ซอฟต์แวร์มีข้อจำกัดน้อย จึงมีวิธีแก้ได้หลากหลาย และไม่ได้มีคำตอบตายตัวแบบวิศวกรรมกายภาพ
- เส้นแบ่งระหว่างศิลปะกับวิศวกรรม
- การออกแบบอาจเป็นกิจกรรมเชิงศิลปะที่มีองค์ประกอบด้านสุนทรียะ แต่ในแง่ของการตอบโจทย์การใช้งานก็เป็นวิศวกรรม
- ซอฟต์แวร์อยู่กึ่งกลางระหว่างความยืดหยุ่นแบบศิลปะและความเคร่งครัดแบบวิศวกรรม
5. วิธีเรียนรู้ทางเลือกอื่น
- วิเคราะห์โค้ดที่แย่
- ไม่ใช่แค่โค้ดที่ออกแบบดีเท่านั้น การ ลองแก้โค้ดเบสที่ย่ำแย่ ก็ให้ผลการเรียนรู้สูงมาก
- เรียนจากโค้ดเบสของตัวเอง
- หลายคนมองว่าโค้ดเบสภายในทีมเป็นแหล่งเรียนรู้ที่ได้ประโยชน์มากที่สุด
- แต่ถ้าโค้ดของทีมคุณแย่ ก็อาจต้องดูตัวอย่างภายนอกควบคู่กันไป
- การเรียนรู้ตามโดเมน
- การอ่านโค้ดเบสที่คล้ายกับปัญหาที่คุณอยากแก้ เป็นวิธีที่ได้ผลที่สุด
อินไซต์สำคัญ
- โค้ดเบสที่ออกแบบดีมีประโยชน์ แต่ การเรียนรู้ต้องควบคู่ไปกับการเข้าใจเจตนาการออกแบบและการลองผิดลองถูก
- มากกว่าการอ่านโค้ด สิ่งสำคัญคือ เอกสารการออกแบบและบันทึกการตัดสินใจ
- โปรเจ็กต์คุณภาพสูงที่เป็นตัวแทนสำคัญ (Git, Postgres, CPython, Rust std ฯลฯ) มีคุณค่าสูงในการเรียนรู้
- ไม่ใช่แค่โค้ดดีเท่านั้น การเรียนรู้จาก โค้ดที่แย่และโค้ดของตัวเอง ก็มีความเป็นรูปธรรมมากกว่าในระยะยาว
สรุปความคิดเห็นเด่น
คำแนะนำโค้ดเบสเด่น ๆ (CraigJPerry)
- Postfix mail server
- มีสถาปัตยกรรมที่เน้นความปลอดภัย และแสดงโครงสร้างคล้าย microservices ได้ตั้งแต่ก่อนแนวคิดนี้จะเป็นที่นิยม
- ถ้า microservices สมัยใหม่เน้นการกระจายงานในองค์กรขนาดใหญ่ Postfix ถูกออกแบบเพื่อ ความปลอดภัยและความเรียบง่าย
- Spring Framework
- สะท้อนวัฒนธรรมที่ใส่ใจความต้องการของนักพัฒนา Java ในองค์กรอย่างลึกซึ้ง
- เป็นตัวอย่างของการออกแบบที่ยึดผู้ใช้เป็นศูนย์กลาง
- Git
- ถ้าเข้าใจแนวคิด object database (blob, tree, commit) และ references แล้ว ส่วนที่เหลือคือการขยายต่อยอดอย่างค่อยเป็นค่อยไป
- ถูกยกเป็นตัวอย่างของการออกแบบที่ ขยายจากแนวคิดหลักอย่างสม่ำเสมอ
- Varnish
- เป็น reverse proxy ประสิทธิภาพสูง และยังเป็นโค้ดเบสที่จัดวางได้ดีจนใช้เป็นสื่อการเรียนรู้ได้
- Linux Kernel Lieutenants Model
- แม้จะไม่ใช่โค้ดเบส แต่ก็น่าศึกษาในฐานะ โมเดลการจัดการซอฟต์แวร์ขนาดใหญ่
- สิ่งเหล่านี้ไม่ใช่เพียง “โค้ดที่ออกแบบดี” แต่เป็น กรณีตัวอย่างที่การตัดสินใจด้านการออกแบบทิ้งความประทับใจไว้อย่างชัดเจน
เน้นการเรียนจากโค้ดเบสในงานจริง (crystal_revenge)
- คุณค่าการเรียนรู้สูงสุดมักมาจาก โค้ดเบสของทีมตัวเอง
- คุณจะได้เห็นทั้งทางเลือกที่ดีและไม่ดีผ่านกระบวนการเชื่อมโยงที่ สับสนและยุ่งเหยิง ระหว่างความต้องการจริงกับการอิมพลีเมนต์
- ข้อจำกัดในโลกจริงที่ใหญ่ที่สุดคือ แรงกดดันด้านเวลา และหัวใจสำคัญคือการเรียนรู้สมดุลระหว่างการออกแบบในอุดมคติกับความเป็นจริง
- ซอฟต์แวร์ที่ดีคือซอฟต์แวร์ที่ แก้ปัญหาความต้องการของผู้ใช้ได้ และประสบการณ์ที่ทำซ้ำจะช่วยให้เรียนรู้การออกแบบที่เพิ่มโอกาสสำเร็จ
ลิงก์ไปยังการถกเถียงและแหล่งข้อมูลเก่า (sprobertson)
- หัวข้อนี้ถูกพูดถึงใน HN หลายครั้งแล้ว
โค้ด vs เอกสารการออกแบบ (alphazard)
- โค้ดเบสเป็นเพียง ผลลัพธ์ของการอิมพลีเมนต์ ไม่ใช่ตัวการออกแบบเอง
- สำหรับการเรียนรู้การออกแบบ การ เขียนเอกสารการออกแบบ มีประสิทธิภาพมากกว่า
- เอกสารควรชัดเจนพอที่คนอื่นจะนำไปอิมพลีเมนต์ได้ตรงตามนั้น
- การลิสต์ทางเลือกและบันทึกว่าเหตุใดจึงไม่เลือกแต่ละทาง เป็น หลักฐานของการพิจารณาด้านการออกแบบ
- นักออกแบบที่ดีคือคนที่พิจารณา พื้นที่ของทางเลือกที่กว้างกว่า และเลือกจุดที่เหมาะสม
เน้นการเข้าใจทั้งระบบ (RossBencina)
- กระบวนการทำความเข้าใจทั้งโค้ดเบสมีคุณค่ามาก
- ไม่ใช่แค่ดูโค้ดที่ออกแบบดี แต่ยังเป็นการฝึกมอง ภาพรวมของระบบ
- การใช้ไดอะแกรมอย่าง UML เพื่อมองเห็นความสัมพันธ์จะช่วยได้
- แนวทางการเรียนรู้:
- การอ่านโค้ดของซอฟต์แวร์ที่คล้ายกับสิ่งที่คุณกำลังพัฒนาอยู่จะได้ผลดี
- แนะนำให้เริ่มจากโค้ดในโดเมนที่คุ้นเคยอยู่แล้ว (เว็บเฟรมเวิร์ก, เว็บเซิร์ฟเวอร์, Python standard library, VSCode ฯลฯ)
- ช่วงแรกควรเริ่มจากโปรแกรมเล็ก ๆ และโดเมนที่คุ้นเคย
เกณฑ์ของการออกแบบที่ดี (mamcx)
- การออกแบบที่ดีคือ เป้าหมายและแนวคิด ส่วนโค้ดเบสแสดงให้เห็น ระดับของการอิมพลีเมนต์มันออกมา
- การออกแบบที่ดีไม่ใช่แค่คำอธิบายอย่าง “เร็ว” หรือ “ปลอดภัย” แต่ต้องมี การพิจารณาอย่างเป็นรูปธรรมและการบันทึก trade-off
- ตัวอย่าง: Erlang, Pascal ยุคแรก, และการออกแบบของ RDBMS หลายตัว แสดงลักษณะนี้ได้ชัด
- ไลบรารีมาตรฐานของ Rust เน้นความปลอดภัยและความสม่ำเสมอ และทั้งโค้ดกับเอกสารก็สะท้อนสิ่งนี้ได้ดี จึงเป็นแหล่งเรียนรู้ที่ยอดเยี่ยม
การตัดสินใจด้านการออกแบบที่มองไม่เห็น (ben30)
- เมื่อดูโค้ดเบสที่ออกแบบดี ส่วนที่สำคัญที่สุดมักเป็นสิ่งที่มองไม่เห็น
- การตัดความซับซ้อนออก, การหลีกเลี่ยง abstraction ที่ไม่จำเป็น, การปฏิเสธบางแพตเทิร์น คือ การตัดสินใจผ่านสิ่งที่ไม่เลือกทำ ซึ่งสำคัญมาก
- วิธีเสริมคือใช้ ADR (Architectural Decision Records)
- เพื่อบันทึกทางเลือก เหตุผลที่ไม่เลือก และเหตุผลของทางเลือกที่เลือกไว้ ให้บริบทคงอยู่
- ช่วยทั้งผู้ดูแลในอนาคตและเครื่องมือ AI ได้มาก
- เวลาเรียนรู้ จึงควรดูไม่ใช่แค่โค้ด แต่รวมถึง โปรเจ็กต์ที่มีเอกสารการตัดสินใจด้านการออกแบบอย่าง ADR, RFC, PEP ควบคู่กันด้วย
5 ความคิดเห็น
ผมเคยอ่านโค้ดอยู่หลายรอบหลังจากได้ดูบทสัมภาษณ์ที่ Evan You (ผู้สร้าง Vue.js และ Vite) บอกว่า express.js ของ TJ Holowaychuk ถูกออกแบบมาได้สะอาดและสวยงามมาก ถึงจะยังไม่เข้าใจภาพรวมทั้งหมด แต่โดยรวมแล้วให้ความรู้สึกว่าโค้ดไม่ได้ซับซ้อน และเขียนไว้เฉพาะลอจิกที่จำเป็นอย่างกระชับและสะอาดมาก
มีคอมเมนต์กำกับไว้อย่างดีด้วย แม้จะเป็นโค้ดเมื่อ 10 ปีก่อน แต่ก็ช่วยให้เข้าใจ type inference หรือรูปแบบ DTO ได้ง่าย
จะอ้างอิงบทความปี 2009 จากบล็อกที่เต็มไปด้วยคอมเมนต์สแปมเนี่ยนะ..
ความคิดเห็นจาก Hacker News
ไม่แน่ใจว่ามีแค่ฉันคนเดียวหรือเปล่า แต่ฉันรู้สึกว่าวิธีที่ได้ผลที่สุดคือเจอปัญหาจริงซ้ำ ๆ แล้วค่อยเรียนรู้ด้วยตัวเองว่าจะหลบเลี่ยงมันอย่างไร พอทำไปเรื่อย ๆ ก็จะเริ่มจำลองในหัวได้เองว่าต่อไปอาจเกิดปัญหาอะไรขึ้นบ้าง และสุดท้ายสิ่งที่เรียกว่าการออกแบบก็คือการตัดสินใจอย่างรอบคอบเกี่ยวกับ trade-off ต่าง ๆ เช่น คาดการณ์ปัญหาในอนาคตหลายแบบล่วงหน้าแล้วหลีกเลี่ยงมัน จะยอมลงแรงแค่ไหนเพื่อเลี่ยงปัญหาแต่ละอย่าง หรือการออกแบบครั้งเดียวจะแก้ได้หลายปัญหาหรือไม่
ฉันก็เหมือนกัน วิธีแบบ "ทำแบบฝึกหัด" หรือ "ศึกษาจาก codebase" ไม่ค่อยเหมาะกับฉัน ฉันเรียนรู้ได้เองตามธรรมชาติเมื่อได้สร้างสิ่งที่ตัวเองสนใจจริง ๆ พร้อมกับพยายามทำให้ตัวอย่างที่ทำมีความถูกต้องและละเอียดรอบคอบ แต่บางครั้งก็ยังรู้สึกว่าฝีมือตัวเองยังไม่พอ ถ้าฉันอ่านโค้ดได้ลื่นไหลเหมือนอ่านหนังสือแล้วมองเห็นการทำงานของมันในหัวได้ การเรียนก็น่าจะสนุกขึ้นมาก
สิ่งที่ผมรู้สึกเมื่อได้ยินว่าต้องเรียนจากการชนปัญหาซ้ำ ๆ คือวงการซอฟต์แวร์เอ็นจิเนียริ่งยังไม่เป็นผู้ใหญ่พอ ลองนึกดูว่าถ้าสร้างสะพานหรือบ้านแบบนั้น หรือฝึกศัลยแพทย์แบบนั้น มันจะอันตรายแค่ไหน เมื่อเวลาผ่านไปมาตรฐานหรือบรรทัดฐานคงจะชัดเจนขึ้น แต่ตอนนี้ทุกอย่างยังลื่นไหลมาก เอาวิศวกรซอฟต์แวร์ห้าคนมานั่งรวมกันแล้วให้โจทย์เดียวกัน นอกจากจะได้คำตอบที่ต่างกันลิบลับห้าวิธีแล้ว ยังอาจเถียงกันหนักมากว่าแบบไหนถูกต้อง ผมไม่คิดว่าทัศนคติแบบ "เห็นปุ๊บก็รู้ว่าอันนี้ดี" เพียงอย่างเดียวจะถือเป็นวิศวกรรมที่แท้จริงได้
ฉันเองก็เรียนรู้อย่างต่อเนื่องด้วยวิธีนี้มาตลอดจนถึงตอนนี้ และก็คงทำต่อไป การเรียนจาก production code จริงน่าจะเป็นความท้าทายใหม่สำหรับฉัน ไม่รู้ว่าจะคุ้มค่าแค่ไหน แต่ก็น่าจะสนุกแน่ ๆ
ผมว่ามันคล้ายกับการหัดขับรถด้วยการขึ้นรถครั้งแรกแล้วชน จากนั้นค่อยทบทวนตัวเองเพื่อให้ครั้งหน้าขับไม่ชน ในความเป็นจริงเราต้องใช้ทั้งสองวิธี เวลาขับบนถนนทั่วไปเรามักไม่ค่อยเจอสถานการณ์ที่เกินขีดจำกัดจึงเอามาใช้ตรง ๆ ได้ยาก แต่ถ้าเป็นการแข่งรถ การรู้ให้ชัดว่าขีดจำกัดที่แท้จริงอยู่ตรงไหนเป็นเรื่องจำเป็น แน่นอนว่าผมไม่ได้คิดว่าเราต้องทำงานเหมือนเป็นการแข่งขันกีฬา แต่ถ้าไม่อ่านหนังสือและไม่ศึกษาเลย มันจะใช้เวลานานมากแบบสุด ๆ และยังมีอุบัติเหตุกับความพังไม่รู้จบด้วย ดังนั้นผมอยากบอกว่าให้อ่านไปเรื่อย ๆ ตอนนี้คุณอาจยังไม่รู้สึกว่าจำเป็น แต่วันหนึ่งเมื่อมีประสบการณ์มากขึ้น ความรู้นั้นจะต้องได้ใช้แน่นอน และคุณจะไม่ตกใจเหมือนครั้งแรกที่ต้องเรียนรู้ว่าลงเขาควรใช้เอนจินเบรกและเปลี่ยนเกียร์ต่ำ
นี่แหละคือประเด็นสำคัญ
พอได้ยินคำถามนี้ สิ่งแรกที่นึกถึงคือ "codebase ของทีมคุณเอง" ไม่มีวิธีไหนที่มีประสิทธิภาพในการเรียนรู้การออกแบบซอฟต์แวร์ไปกว่าการเข้าใจอย่างลึกซึ้งว่าทำไมวิธีแก้ที่ดีและวิธีแก้ที่แย่สำหรับปัญหาจริงจึงถูกเลือกใช้ ซอฟต์แวร์โดยเนื้อแท้คือชั้นกลางอันซับซ้อนที่เชื่อมระหว่างความต้องการของผู้ใช้กับการทำงานของเครื่องจักร ถ้าความสับสนวุ่นวายนี้ไม่มีอยู่ มันก็คงถูกทำให้เป็นอัตโนมัติไปแล้วและเราอาจไม่ต้องมีซอฟต์แวร์เลยด้วยซ้ำ ซอฟต์แวร์เป็นสิ่งที่ถ้ามัวแต่ไล่ตามอุดมคติมากเกินไป มักจะนำไปสู่การตัดสินใจที่แย่ได้บ่อย สิ่งที่ช่วยลดการลองผิดลองถูกจริง ๆ คือการเข้าใจว่า "ทำไมแรงกดดันแบบนี้จึงทำให้เกิดการเลือกแบบนั้น" พร้อมกันนั้นก็ต้องเรียนรู้วิธีการเชิงปฏิบัติที่ทำให้ทำงานได้เร็วและมีประสิทธิภาพ ความท้าทายใหญ่ที่สุดในโลกจริงคือข้อจำกัดด้านเวลา เรื่องนี้แทบไม่ถูกพูดถึงในทฤษฎีการออกแบบซอฟต์แวร์ แต่ในความเป็นจริงคุณแทบจะทำงานภายใต้แรงกดดันให้ส่งโค้ดเร็วที่สุดเสมอ และบ่อยครั้งก็ไม่มีเวลาพอจะทำในแบบที่อยากทำหรือแบบที่ดีที่สุด ซอฟต์แวร์ที่ดีคือซอฟต์แวร์ที่แก้ความต้องการจริงของผู้ใช้ได้ ในอนาคตย่อมมีแนวทางการออกแบบที่ทำให้การลงมือทำสำเร็จได้บ่อยขึ้น และวิธีที่ดีที่สุดในการค้นหามันก็คือพิจารณาโค้ดที่ตัวเองเขียนจริงอย่างลึกซึ้ง
ถ้าผู้ถามรู้สึกว่าซอฟต์แวร์ของทีมตัวเองเละเทะเลยอยากขอคำแนะนำจากข้างนอก แบบนั้นควรทำอย่างไร? หรือถ้าเป็นแค่นักศึกษามหาวิทยาลัยที่ถามล่ะ?
ฉันไม่เคยคิดมาก่อนว่าเวลาที่ต้องใช้ในการ implement ก็อาจเป็นตัวชี้วัดคุณภาพของการออกแบบได้เหมือนกัน แต่ฟังดูสมเหตุสมผลมาก ฉันเองก็เรียนรู้อะไรมหาศาลจาก codebase ของทีมตัวเองอยู่เหมือนกัน ส่วนใหญ่คือเรียนรู้จากสิ่งที่ดีในงานออกแบบที่ยอดเยี่ยม และในส่วนที่ไม่ดีพอก็ต้องไปค้นเพิ่มใน Google แล้วเรียนรู้ต่อไป
แม้จะเป็นข้อมูลเมื่อหลายปีก่อนแล้ว แต่มีชุดบทความ "The Architecture of Open Source Applications" ที่ผู้นำโครงการโอเพนซอร์สหลายคนร่วมเขียนไว้ และอ่านออนไลน์ได้ฟรี
https://aosabook.org/en/index.html
คำถามนี้ถูกถามมาหลายครั้งแล้ว เลยรวบรวมลิงก์อ้างอิงไว้ให้
ซอร์สโค้ดของ Yanderedev
ฉันคงยังไม่มีคุณสมบัติมากพอจะบอกว่าคำตอบที่ถูกคืออะไร แต่เมื่อประมาณ 15 ปีก่อนฉันอ่านหนังสือชื่อ "Code Reading" แล้วชอบมาก มันตรงกับหัวข้อนี้พอดี
https://www.spinellis.gr/codereading/
สารบัญ: https://www.spinellis.gr/codereading/toc.html
เหมือนจะมีหนังสืออีกเล่มที่ชื่อคล้ายกัน แต่จำได้ไม่แน่ว่าคือเล่มไหน
ในทางปฏิบัติ codebase มักสะท้อนการ implement มากกว่าการออกแบบ ตัวอย่างเช่น ต่อให้ย้ายไปเขียนใหม่ทั้งหมดในอีกภาษาหนึ่ง การออกแบบก็อาจยังคงเดิมได้ ผมแนะนำให้ฝึกเขียน design document ไม่ต้องกังวลว่าหน้าตาเอกสารควรเป็นอย่างไร และไม่จำเป็นต้องยึดติดกับ template สิ่งสำคัญที่สุดคือคนอื่นต้องหยิบเอกสารนี้ไปแล้ว implement ตามได้ และตัวเอกสารเองยังทำหน้าที่เป็น "ร่องรอยของการพิจารณา" ได้ด้วย แค่บันทึกให้ชัดเจนว่าคุณเลือกแนวทางไหน มีทางเลือกอะไรอีกบ้าง และทำไมจึงไม่เลือกทางนั้น การยอมรับและเปรียบเทียบทางเลือกไว้ล่วงหน้าจะช่วยให้ผู้อ่านเชื่อได้ว่าคุณคิดมารอบด้านแล้ว สิ่งที่นักออกแบบระบบที่ "ดี" ทำคือมองพื้นที่การออกแบบให้กว้างกว่าคนอื่น และมองหาจุดที่ดีได้อย่างสม่ำเสมอ เลือกปัญหามาสักหนึ่งอย่าง ทดลองสำรวจพื้นที่การออกแบบหลายแบบ แล้วอธิบายว่าแบบไหนดีกว่าเพราะอะไร พร้อมบันทึกทั้งหมดไว้
จุดเริ่มต้นควรเป็นคำถามว่า "ปัญหาที่ฉันอยากแก้คืออะไร?" จากนั้นหา codebase ที่แก้ปัญหานั้นได้ แล้ววิเคราะห์อย่างจริงจังว่าเขา implement กันอย่างไร ต้องจำไว้เสมอว่าการออกแบบที่ดีผูกติดอย่างใกล้ชิดกับบริบทของโดเมนเฉพาะ ผมคิดว่า Internal Model Principle ของ Wonham ก็ใช้กับโค้ดได้เหมือนกัน ตัวอย่างเช่น ผมเคยอยากแก้ปัญหาเรื่อง unit test สำหรับ embedded target จึงไปวิเคราะห์โอเพนซอร์สโปรเจ็กต์ที่เกี่ยวข้อง และพิจารณาอย่างวิพากษ์ว่าทำไมโค้ดแต่ละส่วนจึงถูกเขียนแบบนั้น ตอนนี้ผมก็กำลังสร้างโซลูชันของตัวเองไปพร้อมกับย้อนกลับไปดูโค้ดก่อนหน้าเหล่านั้นเป็นระยะ ๆ และยิ่งเข้าใจโดเมนของตัวเองลึกขึ้นก็ยิ่งเรียนรู้อะไรได้มากขึ้น
จากประสบการณ์ของผม (ทำซอฟต์แวร์มา 30 ปี ทำงานด้านสถาปัตยกรรมมา 25 ปี และจบปริญญาโทด้าน system architecture จาก MIT) สิ่งที่เรียกว่า design ที่ "ดี" แบบนามธรรมจริง ๆ แล้วไม่มีอยู่ มีแต่ design ที่แย่ชัดเจนซึ่งนำไปสู่ผลลัพธ์ที่ไม่ดี แต่เกณฑ์ของคำว่า "ดี" เปลี่ยนไปตามบริบท สิ่งที่คุณกำลังสร้าง ข้อกำหนดอย่างความปลอดภัยหรือ security และเหนือสิ่งอื่นใดคือทีมที่ต้อง implement มันกับโครงสร้างของทีมนั้น ล้วนมีผลมากที่สุด ถ้าเป็นทีมที่มีแต่จูเนียร์ ดีไซน์ที่ประณีตมากอาจถูกตีความผิดจนพังได้ ผมคิดว่าตามกฎของ Conway โครงสร้างของทีมพัฒนาสะท้อนออกมาเป็นซอฟต์แวร์โดยตรง
สิ่งหนึ่งที่ฉันตระหนักชัดขึ้นเรื่อย ๆ ระหว่างเรียนรู้ software design คือมันไม่มีคำตอบสารพัดประโยชน์ ถ้ามีแบบนั้นก็คงดีมาก บางครั้งการต้องเลือกคำตอบที่เหมาะที่สุดท่ามกลางสถาปัตยกรรมและ paradigm ที่หลากหลายก็ชวนอึดอัดเหมือนกัน ถึงอย่างนั้น ถ้าสะท้อน requirement ให้ถูกต้อง ตัวเลือกก็จะลดลงมาก ตอนนี้ฉันทำงานกับ embedded system ที่ให้ความสำคัญกับ safety เป็นพิเศษ และสภาพแวดล้อมนี้เองที่ทำให้ฉันต้องตัดสินใจบางอย่างซึ่งในสถานการณ์อื่นอาจไม่มีวันใช้เลย
ท้ายที่สุดแล้วแก่นสำคัญคือหลีกเลี่ยงแค่ทางประนีประนอมที่เหลวไหลจริง ๆ และเมื่อมองภาพกว้างก็พยายามไม่เลือกตัวเลือกที่แย่ที่สุด ประสบการณ์ในงานภาคสนามทำให้รู้สึกเสมอว่า มันไม่ใช่การแสวงหา architecture ที่ดีที่สุด แต่เป็นการต่อสู้อย่างต่อเนื่องเพื่อ "หลีกเลี่ยงการตัดสินใจที่แย่โดยพื้นฐาน"
ผมเคยทำรายการแนะนำแบบง่าย ๆ ไว้เมื่อก่อน ซึ่งตอนนี้ก็ยังใช้ได้อยู่
https://medium.com/@012parth/what-source-code-is-worth-studying-8755f88f8de5
มีหลุมพรางอยู่ตรงกลาง..
หรือว่าเป็นซอร์สโค้ดของ Yanderedev... 555