บทที่ 4: Pragmatic Paranoia — ความระแวงแบบนักปฏิบัติ
3 min readภาพรวม
Tip 36: You Can't Write Perfect Software — คุณไม่มีทางเขียนซอฟต์แวร์ที่สมบูรณ์แบบได้
ยอมรับความจริงนี้ — แล้วเปลี่ยนมันให้เป็นข้อได้เปรียบ นักปฏิบัติไม่ไว้ใจโค้ดของคนอื่น และที่สำคัญ — ไม่ไว้ใจโค้ดของตัวเองด้วย สร้างระบบป้องกันความผิดพลาดของตัวเอง
Topic 23: Design by Contract — การออกแบบด้วยสัญญา
Tip 37: Design with Contracts — ออกแบบด้วยสัญญา
DBC (Design by Contract) มาจาก Bertrand Meyer และภาษา Eiffel — เป็นเทคนิคที่ระบุว่า function หรือ method จะทำอะไรภายใต้เงื่อนไขอะไร โดยใช้สามองค์ประกอบ:
| องค์ประกอบ | ความหมาย |
|---|---|
| Preconditions | สิ่งที่ต้องเป็นจริงก่อนเรียกใช้ routine — เป็นหน้าที่ของผู้เรียก |
| Postconditions | สิ่งที่ routine รับประกันว่าจะเป็นจริงหลังจากทำงานเสร็จ |
| Class Invariants | เงื่อนไขที่เป็นจริงเสมอตั้งแต่เกิดจนตายของ object |
ปรัชญาของ DBC: "Be strict in what you will accept before you begin, and promise as little as possible in return."
Semantic Invariants: ข้อกำหนดที่ไม่สามารถละเมิดได้ เช่น "จะไม่มีทางที่ transaction จะถูก apply ซ้ำสองครั้ง" — ต้องเป็นส่วนหนึ่งของความหมายของระบบ ไม่ใช่แค่นโยบายที่เปลี่ยนได้
Topic 24: Dead Programs Tell No Lies — โปรแกรมที่ตายแล้วไม่โกหก
Tip 38: Crash Early — พังให้เร็ว
เมื่อโค้ดพบว่าสิ่งที่ "เป็นไปไม่ได้" เพิ่งเกิดขึ้น — โปรแกรมของคุณไม่สามารถทำงานต่อไปได้อย่างน่าเชื่อถืออีกแล้ว การทำงานต่ออาจทำให้เขียนข้อมูลเสียหายลง database จริง ๆ หรือสั่งเครื่องซักผ้าหมุนรอบที่ 20 ติดต่อกัน
แนวคิดจาก Erlang/Elixir: "Defensive programming is a waste of time. Let it crash!" — ใช้ supervisors จัดการ failure — เมื่อ process ล้ม supervisor จะ restart หรือ clean up ให้ — สร้าง supervisor trees
อย่า: catch exception ทั้งหมดแล้ว re-raise — มันเพิ่มความซับซ้อนและ coupling โดยไม่จำเป็น แต่ให้: ปล่อยให้ exception propagate ตามธรรมชาติ
Topic 25: Assertive Programming — การเขียนโปรแกรมแบบ assert
Tip 39: Use Assertions to Prevent the Impossible — ใช้ assertions เพื่อป้องกันสิ่งที่เป็นไปไม่ได้
ทุกครั้งที่คุณคิดว่า "แต่นี่มันไม่มีทางเกิดขึ้นแน่นอน" — ให้เพิ่มโค้ดเพื่อตรวจสอบมัน Assertions ตรวจสอบสิ่งที่ควรจะเป็นจริงเสมอ — ไม่ใช่การจัดการ error ปกติ
ข้อควรระวัง:
- Assertions ต้องไม่มี side effects — การตรวจสอบไม่ควรเปลี่ยน state ของระบบ
- เปิด assertions ทิ้งไว้ใน production — การปิด assertions ตอน deploy คือการเดินไต่ลวดโดยไม่มีตาข่าย เพราะคุณเคยเดินผ่านมาแล้วในการซ้อม
- ปิดเฉพาะ assertions ที่กระทบ performance จริง ๆ
"Use Assertions in Production, Win Big Money" — startup ทำ network devices ที่เปิด assertions ทิ้งไว้ใน production ได้ feedback จากผู้ใช้จริงจนซอฟต์แวร์เสถียรมาก และถูกซื้อกิจการด้วยราคาหลายร้อยล้าน
Topic 26: How to Balance Resources — การจัดการทรัพยากร
Tip 40: Finish What You Start — ทำสิ่งที่เริ่มให้เสร็จ
Tip 41: Act Locally — กระทำเฉพาะที่
function หรือ object ที่ allocate resource ควรเป็นผู้ deallocate มัน — เปิดไฟล์ที่ไหน ปิดที่นั่น
รูปแบบที่ถูกต้อง:
thing = allocate_resource()
begin
process(thing)
finally
deallocate(thing)
end
ผิด: allocate อยู่ใน try block — ถ้า allocate ล้มเหลว finally จะพยายาม deallocate สิ่งที่ไม่มีอยู่
กฎการซ้อน allocations:
- deallocate ในลำดับย้อนกลับกับที่ allocate
- allocate ชุดทรัพยากรเดียวกันในลำดับเดียวกันเสมอ — ลดโอกาส deadlock
เมื่อ balance ไม่ได้ (เช่น dynamic data structures): กำหนด semantic invariant ว่าใครรับผิดชอบ deallocation — และต้องทำให้ชัดเจน สื่อสารให้รับรู้ และทำอย่างสม่ำเสมอ
Topic 27: Don't Outrun Your Headlights — อย่าวิ่งเร็วกว่าไฟหน้า
Tip 42: Take Small Steps—Always — ก้าวเล็ก ๆ เสมอ
Tip 43: Avoid Fortune-Telling — หลีกเลี่ยงการทำนายอนาคต
ไฟหน้ารถมีระยะส่องสว่างจำกัด — ถ้าคุณขับเร็วกว่าระยะที่มองเห็น คุณจะชนก่อนที่จะเบรกทัน ในการพัฒนาซอฟต์แวร์ "ไฟหน้า" ของเราก็จำกัดเช่นกัน — เรามองเห็นอนาคตได้แค่หนึ่งหรือสองก้าว ไม่กี่ชั่วโมงหรือไม่กี่วัน
Feedback คือ speed limit ของคุณ: unit tests, REPL results, user demos — ทุกอย่างที่ยืนยันหรือหักล้างการกระทำของคุณ
สิ่งที่เสี่ยงต่อการ "ทำนายอนาคต":
- ประมาณวันเสร็จเป็นเดือนล่วงหน้า
- ออกแบบเผื่อการ maintain ในอนาคตไกลเกินไป
- เดาความต้องการของผู้ใช้ในอนาคต
- เดาความพร้อมของเทคโนโลยีในอนาคต
Black Swans (Nassim Taleb): เหตุการณ์ที่หายากแต่ส่งผลกระทบมหาศาล — ไม่มีใครเดาได้ (Motif vs OpenLook ในยุค 90s — ถามผิดคำถาม ไม่มีใคร "ชนะ" เพราะ browser-based web มากลบทุกอย่าง)
แทนที่จะพยายามออกแบบให้สมบูรณ์แบบสำหรับอนาคต — ทำให้โค้ดของคุณ replaceable — ออกแบบให้ทิ้งโค้ดเก่าแล้วใส่โค้ดใหม่ที่เหมาะสมกว่าเข้าไปได้ง่าย