บทที่ 2: A Pragmatic Approach — แนวทางการทำงาน
3 min readภาพรวม
บทนี้รวบรวมหลักการออกแบบและแนวทางที่ใช้ได้ในทุกระดับของการพัฒนาซอฟต์แวร์ — ตั้งแต่การออกแบบที่ดี ไปจนถึงการประมาณเวลา ครอบคลุม 8 หัวข้อที่เป็นรากฐานของงานซอฟต์แวร์
Topic 8: The Essence of Good Design — แก่นของการออกแบบที่ดี
Tip 14: Good Design Is Easier to Change Than Bad Design — การออกแบบที่ดีเปลี่ยนแปลงง่ายกว่าการออกแบบที่แย่
หลักการ ETC (Easier To Change): ทุกครั้งที่ต้องตัดสินใจระหว่างทางเลือกหลายทาง — ให้ถามว่า "ทางเลือกไหนทำให้เปลี่ยนแปลงง่ายกว่าในอนาคต?" หลักการนี้เป็นรากฐานของหลักการอื่น ๆ ทั้งหมด — DRY ก็ดีเพราะทำให้เปลี่ยนแปลงง่าย, decoupling ก็ดีเพราะทำให้เปลี่ยนแปลงง่าย และอื่น ๆ
Topic 9: DRY — The Evils of Duplication — ความชั่วร้ายของการซ้ำซ้อน
Tip 15: DRY — Don't Repeat Yourself — อย่าทำซ้ำ
DRY ไม่ใช่แค่เรื่องการไม่ copy-paste โค้ด — แต่มันคือหลักการที่ว่า ทุกชิ้นของความรู้ (knowledge) ต้องมีหนึ่งตัวแทนที่เป็น single, unambiguous, authoritative representation ในระบบ เมื่อความรู้ชิ้นหนึ่งเปลี่ยน — คุณต้องเปลี่ยนที่เดียวเท่านั้น
ประเภทของ Duplication:
- Imposed duplication: นักพัฒนารู้สึกว่าไม่มีทางเลือก — สภาพแวดล้อมบังคับ
- Inadvertent duplication: นักพัฒนาไม่รู้ว่ากำลังทำซ้ำ — มักเกิดจากการออกแบบที่ผิดพลาด
- Impatient duplication: ความขี้เกียจ — copy-paste เพราะ "เร็วกว่า"
- Interdeveloper duplication: หลายคนในทีมเขียนสิ่งเดียวกันซ้ำ — สื่อสารกันไม่พอ
วิธีแก้: ทำให้ reuse ง่าย, เขียน documentation ที่หาได้ง่าย, สื่อสารในทีม, ใช้ code reviews
Topic 10: Orthogonality — ความเป็นอิสระต่อกัน
Tip 16: Make It Easy to Reuse — ทำให้ reuse ได้ง่าย
Tip 17: Eliminate Effects Between Unrelated Things — กำจัดผลกระทบระหว่างสิ่งที่ไม่เกี่ยวข้องกัน
แนวคิดยืมมาจากเรขาคณิต: เส้น orthogonal สองเส้นตัดกันที่จุดเดียวและเป็นอิสระต่อกัน ในซอฟต์แวร์ — สอง component เป็น orthogonal ถ้าการเปลี่ยนแปลงในอันหนึ่งไม่มีผลต่ออีกอัน การออกแบบแบบ orthogonal ทำให้ productivity สูงขึ้น (เพราะ component เล็ก ๆ reuse ได้ง่าย) และลดความเสี่ยง (ถ้ามีปัญหาจะถูกแยกอยู่ในบริเวณเล็ก ๆ)
เทคนิค: แยก UI ออกจาก database, แยก business logic ออกจาก infrastructure, ใช้ global data ให้น้อยที่สุด, หลีกเลี่ยง function ที่มี side effects
Topic 11: Reversibility — การย้อนกลับได้
Tip 18: There Are No Final Decisions — ไม่มีการตัดสินใจที่เป็นที่สุดท้าย
ไม่มีใครรู้ว่าอนาคตจะเป็นอย่างไร — ดังนั้นอย่าตัดสินใจอะไรแบบ irreversible หากเป็นไปได้ให้ออกแบบให้สามารถเปลี่ยนใจได้ในภายหลัง การตัดสินใจเล็ก ๆ ในระบบที่ซับซ้อนอาจนำไปสู่ผลลัพธ์ที่ไม่คาดคิด (เหมือน butterfly effect) — ดังนั้นเก็บตัวเลือกของคุณให้เปิดกว้าง
Topic 12: Tracer Bullets — กระสุนติดตามวิถี
Tip 20: Use Tracer Bullets to Find the Target — ใช้ tracer bullets เพื่อหาเป้าหมาย
Tracer bullets คือกระสุนที่จุดไฟให้เห็นวิถีตอนยิง — ในซอฟต์แวร์หมายถึงการสร้างระบบที่ทำงานได้แบบ end-to-end แต่มีฟังก์ชันน้อยที่สุดก่อน แล้วค่อยเพิ่มฟีเจอร์ทีละส่วน Tracer code ไม่ใช่ prototype ที่ใช้แล้วทิ้ง — แต่มันคือ skeleton ของระบบจริงที่จะถูกใช้งานต่อไป
ข้อดี: ผู้ใช้เห็นของที่ทำงานได้เร็ว, นักพัฒนามีโครงสร้างให้ทำงาน, มี integration platform, มีของให้ demo, และวัดความคืบหน้าได้ดี
Tracer bullets vs Prototypes: Prototypes สร้าง disposable code เพื่อเรียนรู้ — tracer bullets สร้าง production code แบบบาง ๆ
Topic 13: Prototypes and Post-it Notes — ต้นแบบ
Tip 21: Prototype to Learn — สร้าง prototype เพื่อเรียนรู้
Prototypes ใช้เพื่อวิเคราะห์และลดความเสี่ยง — สร้างเพื่อตอบคำถามเฉพาะทางโดยไม่สนใจรายละเอียดอื่น ๆ สิ่งที่สร้าง prototype ได้: architecture, ฟีเจอร์ใหม่, external data structure, third-party tools, performance issues, UI design
สิ่งที่ละเลยได้ใน prototype: correctness, completeness, robustness, style
สำคัญ: ทำให้ทุกคนเข้าใจชัดเจนว่าโค้ด prototype เป็น disposable — ไม่งั้น management อาจบังคับให้ deploy prototype ที่ทำจาก "balsa wood and duct tape" ขึ้น production
Topic 14: Domain Languages — ภาษาเฉพาะ domain
Tip 22: Program Close to the Problem Domain — เขียนโปรแกรมให้ใกล้เคียงกับ domain ของปัญหา
Domain languages มีสองแบบ:
- Internal: ฝังอยู่ในภาษา host (เช่น RSpec ใน Ruby, Phoenix router ใน Elixir) — ใช้พลังของภาษา host ได้เลย แต่ถูกจำกัดด้วย syntax ของภาษา
- External: ภาษาของตัวเองที่มี parser แยก (เช่น Cucumber, Ansible/YAML) — ไม่มีข้อจำกัดด้าน syntax แต่ต้องเขียน parser
คำแนะนำ: เริ่มจาก off-the-shelf external languages (YAML, JSON, CSV) ถ้าเป็นไปได้ — ถ้าไม่ ให้ใช้ internal domain language — external language ที่เขียนเองควรใช้เฉพาะเมื่อผู้ใช้แอปพลิเคชันจะเป็นคนเขียนภาษา
Topic 15: Estimating — การประมาณ
Tip 23: Estimate to Avoid Surprises — ประมาณเพื่อหลีกเลี่ยงความประหลาดใจ
Tip 24: Iterate the Schedule with the Code — ปรับตารางเวลาไปพร้อมกับการเขียนโค้ด
หน่วยของการประมาณ:
| ระยะเวลา | ใช้หน่วย |
|---|---|
| 1–15 วัน | วัน |
| 3–6 สัปดาห์ | สัปดาห์ |
| 8–20 สัปดาห์ | เดือน |
| 20+ สัปดาห์ | คิดหนักก่อนให้ตัวเลข |
กระบวนการประมาณ:
- เข้าใจสิ่งที่ถูกถาม — ขอบเขตคืออะไร?
- สร้างโมเดล — สร้าง mental model คร่าว ๆ
- แยกโมเดลเป็นส่วนประกอบ — หา parameters ของแต่ละ component
- กำหนดค่าให้แต่ละ parameter — parameter ที่มีผลแบบทวีคูณสำคัญที่สุด
- คำนวณผลลัพธ์ — ใช้ช่วงของค่า (range) แทนตัวเลขเดี่ยว
เทคนิค PERT: ประมาณแบบ optimistic, most likely, และ pessimistic — แล้วใช้สถิติคำนวณ
"Eating the Elephant": ประมาณเวลาโครงการด้วยการทำ incremental development — กินช้างทีละคำ — เพราะวิธีเดียวที่จะรู้ว่าโครงการใช้เวลานานแค่ไหนคือการได้ประสบการณ์จากการทำโครงการนั้น
เวลาถูกถามให้ประมาณ: ตอบว่า "I'll get back to you" — อย่าประมาณที่เครื่องทำกาแฟ