| Topic 11 | Reversibility (ความสามารถในการย้อนกลับ) |
|---|
ไม่มีอะไรอันตรายไปกว่าความคิดที่คุณมีอยู่เพียงความคิดเดียวอีกแล้ว
Emil-Auguste Chartier (Alain) , Propos sur la religion , 1938
วิศวกรมักชอบคำตอบเดียวที่เรียบง่ายสำหรับแก้ปัญหา ข้อสอบเลขที่ให้คุณประกาศได้อย่างมั่นใจเต็มร้อยว่า
นั้นสบายใจกว่าการเขียนเรียงความคลุมเครือ ๆ อุ่น ๆ เกี่ยวกับสาเหตุมากมายของการปฏิวัติฝรั่งเศสเยอะ ฝ่ายบริหารก็มักเห็นด้วย กับวิศวกร คำตอบเดียวที่เข้าใจง่ายมันเหมาะกับ spreadsheet และแผนโปรเจกต์มากกว่า
ถ้าโลกแห่งความเป็นจริงยอมให้ความร่วมมือแบบนั้นได้ก็คงดี! แต่น่าเสียดายที่แม้วันนี้
จะเท่ากับ
วันพรุ่งนี้มันอาจต้องกลายเป็น
และสัปดาห์หน้าอาจเป็น
ก็ได้ ไม่มีอะไรที่คงอยู่ตลอดไป—และถ้าคุณพึ่งพา fact อะไรสักอย่างหนักเกินไป คุณแทบจะการันตีได้เลยว่ามัน จะ เปลี่ยนแปลงแน่นอน
มีวิธี implement สิ่งหนึ่ง ๆ ได้มากกว่าหนึ่งแบบเสมอ และมักจะมี vendor ที่ให้บริการ third-party product มากกว่าหนึ่งเจ้าด้วย ถ้าคุณเข้าโปรเจกต์ไปพร้อมกับความคิดแคบ ๆ ว่ามีวิธีทำได้แค่ วิธีเดียว คุณอาจจะเจอเซอร์ไพรส์ที่ไม่น่าอภิรมย์เข้าให้ก็ได้ หลายทีมโปรเจกต์ต้องถูกบังคับให้ตาสว่างเมื่ออนาคตค่อย ๆ เผยตัวออกมา:
“แต่คุณบอกว่าเราจะใช้ database XYZ นี่! เราเขียนโค้ดโปรเจกต์นี้ไปแล้ว 85% จะเปลี่ยนตอนนี้ไม่ได้แล้วนะ!” programmer คนหนึ่งประท้วง “ขอโทษด้วย แต่บริษัทเราตัดสินใจจะ standardize ไปใช้ database PDQ แทน—สำหรับทุกโปรเจกต์เลย มันไม่ได้อยู่ในมือผมแล้วละ พวกเราต้องเขียนโค้ดใหม่กันหมด ทุกคนต้องมาทำงานวันเสาร์อาทิตย์จนกว่าจะแจ้งเปลี่ยนแปลง”
การเปลี่ยนแปลงไม่จำเป็นต้องโหดร้ายหรือฉับพลันขนาดนั้นเสมอไป แต่เมื่อเวลาผ่านไปและโปรเจกต์ของคุณคืบหน้าขึ้นเรื่อย ๆ คุณอาจพบว่าตัวเองติดอยู่ในสถานการณ์ที่ไปต่อไม่ได้ ทุกครั้งที่มีการตัดสินใจสำคัญ ทีมโปรเจกต์ก็จะยิ่งผูกมัดตัวเองเข้ากับ เป้าหมายที่แคบลงเรื่อย ๆ—เป็นความจริงเวอร์ชันที่แคบลงและมีตัวเลือกน้อยลง
พอถึงเวลาที่การตัดสินใจสำคัญ ๆ ถูกตัดสินใจไปหมดแล้ว เป้าหมายก็จะเล็กลงจนแค่มันขยับนิดเดียว หรือลมเปลี่ยนทิศ หรือ ผีเสื้อที่โตเกียวกระพือปีก คุณก็พลาดเป้าแล้ว [18] แถมอาจจะพลาดไปไกลมากด้วยซ้ำ
ปัญหาคือการตัดสินใจสำคัญ ๆ มักย้อนกลับได้ยาก
เมื่อคุณตัดสินใจใช้ database ของ vendor เจ้านี้ หรือ architectural pattern แบบนั้น หรือ deployment model แบบหนึ่ง คุณก็ผูกมัดตัวเองเข้ากับแนวทางที่ย้อนกลับไม่ได้แล้ว เว้นแต่จะยอมจ่ายราคาที่แพงมาก
Reversibility (ความสามารถในการย้อนกลับ)
หัวข้อหลายเรื่องในหนังสือเล่มนี้มุ่งช่วยให้คุณสร้างซอฟต์แวร์ที่ flexible และปรับตัวได้ ถ้าเรายึดตามคำแนะนำเหล่านั้น— โดยเฉพาะ DRY principle , decoupling และการใช้ external configuration —เราก็ไม่ต้องตัดสินใจแบบที่ย้อนกลับไม่ได้บ่อยเท่าไหร่ นี่เป็นเรื่องดี เพราะเราไม่ได้ตัดสินใจถูกที่สุดตั้งแต่ครั้งแรกเสมอไป บางทีเราก็ผูกมัดตัวเองกับเทคโนโลยีหนึ่งแล้วมาพบทีหลังว่าหาคนที่มีสกิลที่จำเป็นมาทำงานไม่พอ บางทีเราก็ล็อกกับ third-party vendor เจ้าหนึ่งแล้วเขาก็ดันถูกคู่แข่งซื้อกิจการไปพอดี requirement, ผู้ใช้ และฮาร์ดแวร์เปลี่ยนแปลงเร็วกว่าที่เราจะพัฒนา ซอฟต์แวร์ตามทันเสียอีก
สมมติว่าตอนต้นโปรเจกต์คุณตัดสินใจใช้ relational database จาก vendor A พอมาถึงช่วง performance testing ในภายหลัง คุณกลับพบว่า database ตัวนี้ช้าเกินไป แต่ document database จาก vendor B เร็วกว่า สำหรับโปรเจกต์แบบดั้งเดิมส่วนใหญ่ คุณคงซวยแน่ ๆ เพราะส่วนใหญ่แล้วการเรียกใช้ third-party product มักฝังปนอยู่ทั่วทั้งโค้ด แต่ถ้าคุณ abstract แนวคิดเรื่อง database ออกมาจริง ๆ—จนถึงจุดที่มันแค่ให้บริการ persistence เป็น service เท่านั้น—คุณก็จะมีความยืดหยุ่น ที่จะเปลี่ยนม้ากลางศึกได้
ในทำนองเดียวกัน สมมติว่าโปรเจกต์เริ่มต้นเป็นแอปแบบ browser-based แต่พอใกล้จบเกม ฝ่าย marketing ก็ตัดสินใจว่าจริง ๆ แล้ว อยากได้เป็น mobile app มากกว่า มันจะยากแค่ไหนสำหรับคุณ? ในโลกที่สมบูรณ์แบบ มันไม่ควรกระทบคุณมากนัก อย่างน้อยก็ในฝั่ง server คุณก็แค่ดึง HTML rendering ออกแล้วแทนที่ด้วย API เท่านั้นเอง
ความผิดพลาดอยู่ที่การสมมติว่าการตัดสินใจใด ๆ นั้นแน่นอนตายตัวเหมือนสลักลงบนหิน—และไม่เตรียมพร้อมรับมือกับเหตุการณ์ ไม่คาดฝันที่อาจเกิดขึ้น แทนที่จะสลักการตัดสินใจลงบนหิน ให้คิดว่ามันเหมือนตัวหนังสือที่เขียนลงบนทรายชายหาดมากกว่า คลื่นลูกใหญ่สามารถซัดเข้ามาลบมันทิ้งได้ทุกเมื่อ
| Tip 18 | ไม่มีการตัดสินใจใดที่เป็นที่สิ้นสุด |
|---|
Flexible Architecture (สถาปัตยกรรมที่ยืดหยุ่น)
ในขณะที่หลายคนพยายามรักษาให้ โค้ด ของตัวเองยืดหยุ่น คุณก็ต้องคิดถึงการรักษาความยืดหยุ่นในด้าน architecture, deployment และการผูกกับ vendor ด้วยเช่นกัน
เรากำลังเขียนสิ่งนี้อยู่ในปี 2019 นับตั้งแต่ต้นศตวรรษที่ผ่านมา เราเห็น server-side architecture ที่ถูกเรียกว่า “best practice” มาแล้วดังนี้:
- เครื่องเหล็กก้อนใหญ่ (mainframe)
- กลุ่มสหพันธ์ของเครื่องเหล็กก้อนใหญ่หลายเครื่อง
- คลัสเตอร์ที่ทำ load balancing บนฮาร์ดแวร์ commodity
- virtual machine บน cloud ที่รันแอปพลิเคชัน
- virtual machine บน cloud ที่รัน service
- เวอร์ชัน containerized ของสิ่งที่กล่าวมาข้างต้น
- แอปพลิเคชันแบบ serverless ที่รองรับด้วย cloud
- และสุดท้ายก็หนีไม่พ้นที่จะย้อนกลับไปใช้เครื่องเหล็กก้อนใหญ่สำหรับงานบางอย่างอีกครั้ง
ลองเพิ่มกระแสฮิตล่าสุดเข้าไปในลิสต์นี้ดูสิ แล้วมองมันด้วยความทึ่ง—มันเป็นปาฏิหาริย์จริง ๆ ที่มีอะไรทำงานได้เลยด้วยซ้ำ
แล้วคุณจะวางแผนรับมือกับความผันผวนของ architecture แบบนี้ได้ยังไง? คุณทำไม่ได้หรอกครับ
สิ่งที่คุณทำได้คือทำให้มันเปลี่ยนง่าย ซ่อน third-party API ไว้หลัง abstraction layer ของคุณเอง แยกโค้ดออกเป็น component ต่าง ๆ แม้สุดท้ายคุณจะ deploy มันรวมกันบน server เครื่องเดียวก็ตาม วิธีนี้ก็ยังง่ายกว่าการเอาแอปแบบ monolithic มาแยกทีหลัง เยอะ (พวกเรามีแผลเป็นเป็นหลักฐานยืนยันเรื่องนี้)
และแม้ว่านี่จะไม่ใช่ประเด็นเรื่อง reversibility โดยตรงนัก แต่ก็ขอฝากคำแนะนำสุดท้ายไว้อีกอย่างหนึ่งครับ
| Tip 19 | อย่าไล่ตามกระแสฮิต |
|---|
ไม่มีใครรู้หรอกว่าอนาคตจะเป็นยังไง โดยเฉพาะพวกเราเองก็ไม่รู้เหมือนกัน! ดังนั้นจงทำให้โค้ดของคุณ “rock-n-roll” ได้ คือ “rock on” เมื่อมันทำได้ และ “roll with the punches” เมื่อมันจำเป็นต้องทำ
Related Sections Include (หัวข้อที่เกี่ยวข้อง)
- Topic 8, The Essence of Good Design
- Topic 10, Orthogonality
- Topic 19, Version Control
- Topic 28, Decoupling
- Topic 45, The Requirements Pit
- Topic 51, Pragmatic Starter Kit
Challenges (โจทย์ท้าทาย)
-
ได้เวลามาเล่นกับกลศาสตร์ควอนตัมเล็กน้อยผ่านแมวของ Schrödinger กันครับ
สมมติว่าคุณมีแมวอยู่ในกล่องปิด พร้อมกับอนุภาคกัมมันตรังสีหนึ่งตัว อนุภาคนี้มีโอกาสพอดี 50% ที่จะแตกตัวออกเป็นสอง ถ้ามันแตก แมวจะตาย ถ้ามันไม่แตก แมวก็จะปลอดภัย ดังนั้นแมวตัวนี้ตายหรือเป็นกันแน่? ตามทฤษฎีของ Schrödinger คำตอบที่ ถูกต้องคือ ทั้งสองอย่าง (อย่างน้อยก็ตราบใดที่กล่องยังปิดอยู่) ทุกครั้งที่ปฏิกิริยาระดับ subnuclear เกิดขึ้นโดยมีผลลัพธ์ที่เป็นไปได้สองแบบ จักรวาลจะถูกโคลนออกมา ในจักรวาลหนึ่งเหตุการณ์นั้นเกิดขึ้น ในอีกจักรวาลหนึ่งมันไม่เกิด แมวมีชีวิตอยู่ในจักรวาลหนึ่ง และตายในอีกจักรวาลหนึ่ง คุณจะรู้ว่า คุณ อยู่ในจักรวาลไหนก็ต่อเมื่อเปิดกล่องเท่านั้น
ไม่แปลกเลยที่การเขียนโค้ดเผื่ออนาคตนั้นยากเย็นแสนเข็ญ
แต่ลองคิดถึงวิวัฒนาการของโค้ดในแนวทางเดียวกับกล่องที่เต็มไปด้วยแมวของ Schrödinger ดูสิ ทุกการตัดสินใจจะนำไปสู่ อนาคตอีกเวอร์ชันหนึ่ง โค้ดของคุณรองรับอนาคตที่เป็นไปได้กี่แบบ? แบบไหนมีโอกาสเกิดขึ้นมากกว่ากัน? แล้วมันจะยากแค่ไหน ที่จะรองรับมันเมื่อถึงเวลานั้นจริง ๆ?
คุณกล้าเปิดกล่องนั้นไหมล่ะครับ?