| Topic 10 | Orthogonality (หลักการความเป็นอิสระต่อกัน) |
|---|
Orthogonality เป็นแนวคิดที่สำคัญมากถ้าคุณอยากสร้างระบบที่ออกแบบง่าย สร้างง่าย เทสต์ง่าย และขยายต่อได้ง่าย แต่แนวคิดเรื่อง Orthogonality นี้กลับไม่ค่อยมีใครสอนกันตรง ๆ ส่วนใหญ่มันจะแฝงอยู่ในเทคนิคและวิธีการอื่น ๆ ที่คุณเรียนรู้มา ซึ่งถือเป็นเรื่องน่าเสียดาย เพราะทันทีที่คุณเรียนรู้จะนำหลักการ Orthogonality มาใช้โดยตรง คุณจะสังเกตเห็นคุณภาพของระบบที่คุณสร้างดีขึ้นอย่างเห็นได้ชัดเลยครับ
What Is Orthogonality? (Orthogonality คืออะไร?)
“Orthogonality” เป็นศัพท์ที่ยืมมาจากวิชาเรขาคณิต เส้นสองเส้นจะเรียกว่า orthogonal กันก็ต่อเมื่อมันตัดกันเป็นมุมฉาก เหมือนแกนทั้งสองของกราฟ ในทางเวกเตอร์ เราเรียกเส้นทั้งสองนี้ว่า independent (อิสระต่อกัน) เมื่อตัวเลข 1 บนแผนภาพเคลื่อนไปทางเหนือ มันจะไม่ทำให้ระยะห่างไปทางตะวันออกหรือตะวันตกเปลี่ยนไปเลย ส่วนตัวเลข 2 เคลื่อนไปทางตะวันออก แต่ไม่ได้เคลื่อนขึ้นเหนือหรือลงใต้
ในโลกของคอมพิวเตอร์ คำนี้ถูกนำมาใช้สื่อถึงความเป็นอิสระหรือการ decouple กัน สิ่งสองอย่างขึ้นไปจะถือว่า orthogonal กัน ถ้าการเปลี่ยนแปลงอย่างหนึ่งไม่ส่งผลกระทบต่ออีกอย่างเลย ในระบบที่ออกแบบมาดี โค้ดของฐานข้อมูล (database) จะ orthogonal กับ user interface นั่นคือคุณเปลี่ยน interface ได้โดยไม่กระทบฐานข้อมูล และสลับฐานข้อมูลได้โดยไม่ต้องแก้ interface เลยครับ
ก่อนที่เราจะไปดูข้อดีของระบบที่ orthogonal มาดูตัวอย่างระบบที่ไม่ orthogonal กันก่อนดีกว่าครับ
A Nonorthogonal System (ระบบที่ไม่ Orthogonal)
สมมติคุณกำลังนั่งเฮลิคอปเตอร์ชมวิว Grand Canyon อยู่ จู่ ๆ นักบินที่ดันไปกินปลาเป็นมื้อเที่ยง (ซึ่งเป็นความผิดพลาดที่เห็นได้ชัด) ก็ครางเสียงหง่าย ๆ แล้วสลบไป โชคดีที่เขาทิ้งให้คุณลอยตัวอยู่ที่ระดับ 100 ฟุตเหนือพื้นพอดี
โชคยังดีที่เมื่อคืนก่อนคุณเพิ่งอ่านหน้า Wikipedia เกี่ยวกับเฮลิคอปเตอร์มา คุณเลยรู้ว่าเฮลิคอปเตอร์มีตัวควบคุมหลัก ๆ อยู่สี่อย่าง cyclic คือคันบังคับที่คุณถือด้วยมือขวา ขยับมันแล้วเฮลิคอปเตอร์จะเคลื่อนไปในทิศทางที่สอดคล้องกัน มือซ้ายของคุณถือ collective pitch lever ดึงขึ้นแล้วจะเพิ่มมุมใบพัดทั้งหมด ทำให้เกิดแรงยก ที่ปลายคันโยกนี้มี throttle อยู่ และสุดท้ายคุณมี foot pedals สองอัน ที่ใช้ปรับแรงขับของใบพัดหาง ช่วยให้เฮลิคอปเตอร์หมุนตัวได้
“ง่ายจะตาย!” คุณคิดในใจ “แค่ค่อย ๆ กด collective pitch lever ลง เดี๋ยวก็ร่อนลงพื้นอย่างสวยงามแล้วกลายเป็นฮีโร่” แต่พอลองทำจริง ๆ คุณถึงได้รู้ว่าชีวิตมันไม่ได้ง่ายขนาดนั้น หัวเฮลิคอปเตอร์ทิ่มลง แล้วคุณก็เริ่มหมุนวนดิ่งลงไปทางซ้าย จู่ ๆ คุณก็พบว่าตัวเองกำลังบังคับระบบที่ทุกการควบคุมส่งผลกระทบข้างเคียงไปหมด กดคันโยกซ้ายลง คุณก็ต้องดึงคันบังคับขวากลับมาชดเชยพร้อมกดเหยียบขวาไปด้วย แต่การเปลี่ยนแปลงแต่ละอย่างนี้ก็ไปกระทบตัวควบคุมอื่น ๆ อีกต่อหนึ่ง จู่ ๆ คุณก็ต้องมาพะวงกับระบบที่ซับซ้อนสุด ๆ ที่ทุกการเปลี่ยนแปลงส่งผลกระทบต่อทุกอินพุตอื่น ๆ ไปหมด งานของคุณหนักมาก มือและเท้าต้องขยับตลอดเวลาเพื่อพยายามสร้างสมดุลให้กับแรงทั้งหมดที่มีปฏิสัมพันธ์กันอยู่
ตัวควบคุมของเฮลิคอปเตอร์นั้นไม่ orthogonal กันอย่างชัดเจนเลยครับ
Benefits of Orthogonality (ข้อดีของ Orthogonality)
อย่างที่ตัวอย่างเฮลิคอปเตอร์แสดงให้เห็น ระบบที่ไม่ orthogonal นั้นโดยธรรมชาติแล้วซับซ้อนกว่าในการเปลี่ยนแปลงและควบคุม เมื่อองค์ประกอบต่าง ๆ ของระบบพึ่งพากันอย่างแน่นหนา มันจะไม่มีสิ่งที่เรียกว่า “การแก้ไขเฉพาะจุด” อีกต่อไป
| Tip 17 | กำจัดผลกระทบระหว่างสิ่งที่ไม่เกี่ยวข้องกัน |
|---|
เราอยากออกแบบ component ที่ self-contained คือเป็นอิสระ และมีจุดประสงค์เดียวที่ชัดเจน (สิ่งที่ Yourdon กับ Constantine เรียกว่า cohesion ใน Structured Design: Fundamentals of a Discipline of Computer Program and Systems Design [YC79] ) เมื่อ component ต่าง ๆ แยกออกจากกันอย่างชัดเจน คุณจะรู้ว่าเปลี่ยนตัวหนึ่งได้โดยไม่ต้องกังวลเรื่องตัวอื่น ตราบใดที่คุณไม่ไปแก้ external interface ของ component นั้น คุณก็มั่นใจได้ว่าจะไม่ทำให้เกิดปัญหาลุกลามไปทั่วทั้งระบบครับ
การเขียนระบบแบบ orthogonal จะให้ประโยชน์หลัก ๆ สองอย่างกับคุณ คือ productivity ที่เพิ่มขึ้น และความเสี่ยงที่ลดลง
Gain Productivity (เพิ่ม Productivity)
-
การเปลี่ยนแปลงจะถูกจำกัดอยู่แค่จุดเดียว ทำให้เวลาที่ใช้พัฒนาและเทสต์ลดลง การเขียน component เล็ก ๆ ที่ self-contained นั้นง่ายกว่าการเขียนโค้ดก้อนใหญ่ก้อนเดียว component ง่าย ๆ สามารถออกแบบ เขียนโค้ด เทสต์ แล้วก็ปล่อยผ่านไปได้เลย—ไม่ต้อง คอยแก้โค้ดเดิมทุกครั้งที่เพิ่มโค้ดใหม่เข้ามา
-
แนวทางแบบ orthogonal ยังช่วยส่งเสริมการ reuse ด้วย ถ้า component มีหน้าที่รับผิดชอบที่ชัดเจนเฉพาะเจาะจง มันก็สามารถ เอาไปผสมกับ component ใหม่ ๆ ในรูปแบบที่คนเขียนตอนแรกไม่เคยคิดถึงมาก่อนได้ ยิ่งระบบของคุณ loosely coupled มากเท่าไหร่ ก็ยิ่งง่ายต่อการปรับโครงสร้างใหม่หรือ reengineer มันมากเท่านั้น
-
การรวม component ที่ orthogonal เข้าด้วยกันยังให้ประโยชน์ด้าน productivity แบบเนียน ๆ อีกอย่างหนึ่งด้วย สมมติว่า component หนึ่งทำได้
อย่างที่แตกต่างกัน และอีกตัวทำได้
อย่าง ถ้าทั้งสอง orthogonal กันแล้วเอามารวมกัน ผลลัพธ์จะทำได้
อย่าง แต่ถ้า component ทั้งสองไม่ orthogonal กัน ก็จะมีส่วนที่ทับซ้อนกัน และผลลัพธ์ที่ได้ก็จะน้อยลง คุณจะได้ functionality ต่อความพยายามที่ลงไปมากขึ้น เมื่อรวม component ที่ orthogonal เข้าด้วยกันครับ
Reduce Risk (ลดความเสี่ยง)
แนวทางแบบ orthogonal ช่วยลดความเสี่ยงที่มีอยู่ในการพัฒนาทุกแบบ
-
ส่วนของโค้ดที่มีปัญหาจะถูกแยกออกจากกัน ถ้า module ไหนป่วย มันก็มีโอกาสน้อยที่จะลามอาการไปยังส่วนอื่นของระบบ และยังง่ายต่อการตัดมันออกแล้วเปลี่ยนใส่ของใหม่ที่แข็งแรงกว่าเข้าไปแทนด้วย
-
ระบบที่ได้จะเปราะบางน้อยลง การเปลี่ยนแปลงหรือแก้ไขเล็ก ๆ น้อย ๆ ในจุดใดจุดหนึ่ง ปัญหาที่อาจเกิดขึ้นก็จะจำกัดอยู่แค่ในจุดนั้นเท่านั้น
-
ระบบที่ orthogonal มักจะถูกเทสต์ได้ดีกว่า เพราะออกแบบและรัน test บน component ของมันได้ง่ายกว่า
-
คุณจะไม่ผูกติดกับ vendor, product หรือ platform ใดตัวหนึ่งแน่นเกินไป เพราะ interface ที่เชื่อมกับ third-party component เหล่านี้จะถูกจำกัดอยู่แค่ในส่วนเล็ก ๆ ของงานพัฒนาทั้งหมดเท่านั้น
มาดูกันว่าคุณสามารถนำหลักการ orthogonality มาใช้กับงานของคุณได้ยังไงบ้างครับ
Design (การออกแบบ)
developer ส่วนใหญ่คุ้นเคยกับความจำเป็นในการออกแบบระบบให้ orthogonal อยู่แล้ว แม้ว่าอาจจะใช้คำอื่นอย่าง modular , component-based และ layered เพื่ออธิบายกระบวนการนี้ก็ตาม ระบบควรประกอบด้วยชุดของ module ที่ทำงานร่วมกัน โดยแต่ละตัวทำหน้าที่เป็นอิสระจากตัวอื่น บางครั้ง component เหล่านี้จะถูกจัดเป็น layer โดยแต่ละ layer ให้ระดับของ abstraction ที่ต่างกัน แนวทางแบบ layered นี้ เป็นวิธีที่ทรงพลังในการออกแบบระบบให้ orthogonal เพราะแต่ละ layer ใช้แค่ abstraction ที่ layer ด้านล่างมันมอบให้เท่านั้น คุณจึงมีความยืดหยุ่นสูงมากในการเปลี่ยน implementation เบื้องหลังโดยไม่กระทบโค้ด การทำ layering ยังช่วยลดความเสี่ยงที่จะเกิด dependency ที่ควบคุมไม่ได้ระหว่าง module ด้วย คุณจะเห็น layering ถูกแสดงเป็นไดอะแกรมบ่อย ๆ แบบนี้:
ภาพนี้แสดงการนำเสนอที่อยู่ (address representation) layer แรกคือ user interface layer ที่สองมีสามส่วนคือ database access, authorization และ business logic layer ที่สามแสดง application framework ซึ่งมีส่วนคือ standard libraries ส่วนสุดท้ายแสดง container services
มีวิธีทดสอบง่าย ๆ ว่าระบบออกแบบมาแบบ orthogonal หรือเปล่า เมื่อคุณ map component ต่าง ๆ ออกมาแล้ว ลองถามตัวเองดูว่า ถ้าฉันเปลี่ยน requirement ที่อยู่เบื้องหลังฟังก์ชันหนึ่งอย่างมาก จะมี module กี่ตัวที่ได้รับผลกระทบ? ในระบบที่ orthogonal คำตอบควรจะเป็น “หนึ่งตัว” [16] การย้ายปุ่มบน GUI panel ไม่ควรต้องไปแก้ database schema เลย การเพิ่ม context-sensitive help ก็ไม่ควรไปกระทบ billing subsystem เช่นกัน
ลองนึกถึงระบบที่ซับซ้อนสำหรับ monitor และควบคุมโรงต้มน้ำ (heating plant) ดู requirement เดิมต้องการแค่ graphical user interface แต่ต่อมามีการเปลี่ยน requirement ให้เพิ่ม mobile interface ที่ให้วิศวกร monitor ค่าสำคัญ ๆ ได้ด้วย ถ้าระบบออกแบบมาแบบ orthogonal คุณจะต้องแก้แค่ module ที่เกี่ยวกับ user interface เท่านั้นเพื่อรองรับสิ่งนี้ ส่วน logic เบื้องหลังในการควบคุมโรงต้มน้ำจะไม่ถูกกระทบเลย และถ้าคุณจัดโครงสร้างระบบอย่างระมัดระวัง คุณจะสามารถรองรับทั้งสอง interface ด้วย code base เดียวกันได้เลยด้วยซ้ำ
ลองถามตัวเองด้วยว่า design ของคุณ decouple จากการเปลี่ยนแปลงในโลกจริงมากแค่ไหน คุณใช้เบอร์โทรศัพท์เป็น identifier ของลูกค้าอยู่หรือเปล่า? แล้วถ้าบริษัทโทรศัพท์เปลี่ยน area code ล่ะจะเกิดอะไรขึ้น? postal code, เลขบัตรประชาชนหรือรหัส ประจำตัวของรัฐ, อีเมล และ domain ต่าง ๆ ล้วนเป็น identifier ภายนอกที่คุณควบคุมไม่ได้ และอาจเปลี่ยนได้ทุกเมื่อด้วยเหตุผล อะไรก็ได้ อย่าไปพึ่งพา property ของสิ่งที่คุณควบคุมไม่ได้เด็ดขาดครับ
Toolkits and Libraries (Toolkit และ Library)
ระวังให้ดีเวลาที่คุณนำ toolkit หรือ library จากภายนอกเข้ามาใช้ในระบบ ให้รักษาความ orthogonal ของระบบไว้ เลือกใช้เทคโนโลยีอย่างชาญฉลาด
เวลาที่คุณนำ toolkit เข้ามาใช้ (หรือแม้แต่ library จากเพื่อนร่วมทีมคนอื่น) ให้ถามตัวเองว่ามันบังคับให้โค้ดของคุณต้อง เปลี่ยนในจุดที่ไม่ควรจะต้องเปลี่ยนหรือเปล่า ถ้า scheme สำหรับ persist object นั้น transparent มันก็ orthogonal แต่ถ้ามันบังคับให้คุณต้องสร้างหรือเข้าถึง object ด้วยวิธีพิเศษบางอย่าง แสดงว่ามันไม่ orthogonal การแยกรายละเอียดแบบนี้ออกจากโค้ดของคุณยังมีข้อดีเพิ่มเติมคือทำให้เปลี่ยน vendor ในอนาคตได้ง่ายขึ้นด้วยครับ
ระบบ Enterprise Java Beans (EJB) เป็นตัวอย่างที่น่าสนใจของ orthogonality ในระบบที่เน้น transaction ส่วนใหญ่ โค้ดของแอปต้องกำหนดจุดเริ่มต้นและจุดจบของแต่ละ transaction เอง แต่กับ EJB ข้อมูลนี้ถูกแสดงออกมาแบบ declarative ผ่าน annotation ที่อยู่นอก method ที่ทำงานจริง โค้ดแอปตัวเดียวกันสามารถรันในสภาพแวดล้อม EJB transaction ที่ต่างกันได้โดยไม่ ต้องแก้อะไรเลย
ในแง่หนึ่ง EJB ก็เป็นตัวอย่างของ Decorator Pattern คือการเพิ่ม functionality ให้กับสิ่งต่าง ๆ โดยไม่ต้องไปแก้ตัวมันเอง สไตล์การเขียนโปรแกรมแบบนี้ใช้ได้กับแทบทุกภาษาโปรแกรมมิ่ง และไม่จำเป็นต้องมี framework หรือ library ด้วยซ้ำ แค่ต้องมีวินัยนิดหน่อยตอนเขียนโค้ดเท่านั้นเองครับ
Coding (การเขียนโค้ด)
ทุกครั้งที่คุณเขียนโค้ด คุณก็มีความเสี่ยงที่จะลดความ orthogonal ของแอปพลิเคชันลง ถ้าคุณไม่คอยสังเกตอยู่ตลอดเวลา ทั้งสิ่งที่คุณกำลังทำและบริบทที่ใหญ่กว่าของแอป คุณอาจจะเผลอไปสร้าง functionality ที่ซ้ำกับ module อื่นโดยไม่ตั้งใจ หรือแสดงความรู้เดิมซ้ำสองครั้งได้
มีเทคนิคหลายอย่างที่คุณใช้รักษาความ orthogonal ไว้ได้ครับ:
ทำให้โค้ดของคุณ Decouple กัน
เขียนโค้ดแบบ shy—คือ module ที่ไม่เปิดเผยอะไรที่ไม่จำเป็นให้ module อื่นเห็น และไม่ไปพึ่งพา implementation ของ module อื่น ลองใช้ Law of Demeter ดู ซึ่งเราจะพูดถึงใน Topic 28, Decoupling ถ้าคุณต้องการเปลี่ยน state ของ object ก็ให้ object นั้นเป็นคนทำให้คุณเอง วิธีนี้จะทำให้โค้ดของคุณยังคงแยกออกจาก implementation ของโค้ดอื่น และเพิ่มโอกาสที่คุณจะรักษาความ orthogonal ไว้ได้ครับ
หลีกเลี่ยง Global Data
ทุกครั้งที่โค้ดของคุณอ้างอิงถึง global data มันจะผูกตัวเองเข้ากับ component อื่น ๆ ที่แชร์ data นั้นด้วยทันที แม้แต่ global ที่คุณตั้งใจจะแค่อ่านอย่างเดียวก็ยังนำปัญหามาได้ (เช่น ถ้าอยู่ ๆ คุณต้องเปลี่ยนโค้ดให้รองรับ multithread) โดยทั่วไปแล้ว โค้ดของคุณจะเข้าใจง่ายและดูแลรักษาง่ายกว่า ถ้าคุณส่ง context ที่จำเป็นเข้าไปใน module อย่างชัดเจน ในแอปแบบ object-oriented context มักถูกส่งเป็น parameter ให้กับ constructor ของ object ส่วนโค้ดแบบอื่นคุณก็สร้าง structure ที่เก็บ context แล้วส่ง reference ของมันไปมาได้เหมือนกัน
Singleton pattern ใน Design Patterns: Elements of Reusable Object-Oriented Software [GHJV95] เป็นวิธีการันตีว่าจะมี instance ของ object จาก class หนึ่ง ๆ อยู่แค่ตัวเดียว หลายคนใช้ singleton object เป็นเหมือน global variable ประเภทหนึ่ง (โดยเฉพาะในภาษาอย่าง Java ที่ไม่รองรับแนวคิด global โดยตรงอยู่แล้ว) ระวังการใช้ singleton ให้ดี เพราะมันก็นำไปสู่การผูกโยง (linkage) ที่ไม่จำเป็นได้เหมือนกันครับ
หลีกเลี่ยงฟังก์ชันที่คล้ายกัน
บ่อยครั้งที่คุณจะเจอกลุ่มฟังก์ชันที่หน้าตาคล้ายกันไปหมด—อาจจะแชร์โค้ดส่วนต้นกับส่วนท้ายเหมือนกัน แต่ตรงกลางแต่ละตัว ใช้ algorithm ต่างกัน โค้ดที่ซ้ำกันแบบนี้คืออาการของปัญหาเชิงโครงสร้าง ลองไปดู Strategy pattern ใน Design Patterns เพื่อหา implementation ที่ดีกว่าดูครับ
ฝึกให้ตัวเองมีนิสัยคอยตั้งคำถามกับโค้ดของตัวเองอยู่เสมอ มองหาโอกาสที่จะจัดโครงสร้างใหม่เพื่อปรับปรุงโครงสร้างและความ orthogonal ของมัน กระบวนการนี้เรียกว่า refactoring และมันสำคัญมากจนเราต้องแยกไปพูดถึงเป็นหัวข้อเฉพาะเลย (ดู Topic 40, Refactoring )
Testing (การเทสต์)
ระบบที่ออกแบบและ implement แบบ orthogonal จะเทสต์ได้ง่ายกว่า เพราะการปฏิสัมพันธ์ระหว่าง component ของระบบถูกกำหนดไว้ อย่างชัดเจนและจำกัดขอบเขต ทำให้เทสต์ส่วนใหญ่ของระบบทำได้ในระดับ module เดี่ยว ๆ นี่คือข่าวดี เพราะการเทสต์ระดับ module (หรือ unit test) นั้นกำหนดและทำได้ง่ายกว่า integration test มาก อันที่จริงเราแนะนำให้เทสต์เหล่านี้รันอัตโนมัติเป็นส่วน หนึ่งของ build process ปกติเลยด้วยซ้ำ (ดู Topic 41, Test to Code )
การเขียน unit test นั้นก็เป็นบททดสอบความ orthogonal ที่น่าสนใจในตัวมันเองเหมือนกัน ต้องทำอะไรบ้างกว่าจะ build และรัน unit test ได้? คุณต้อง import โค้ดส่วนใหญ่ของระบบเข้ามาด้วยหรือเปล่า? ถ้าใช่ แสดงว่าคุณเจอ module ที่ decouple จากส่วนอื่นของระบบได้ไม่ดีนักแล้วละครับ
การแก้บั๊กก็เป็นโอกาสที่ดีในการประเมินความ orthogonal ของระบบทั้งระบบเหมือนกัน เวลาคุณเจอปัญหา ให้ประเมินดูว่าการแก้ไขนั้นจำกัดอยู่แค่จุดเดียวแค่ไหน คุณต้องแก้แค่ module เดียว หรือการเปลี่ยนแปลงกระจายไปทั่วทั้งระบบ? พอแก้เสร็จแล้ว มันแก้ปัญหาได้หมดจริงไหม หรือมีปัญหาอื่นโผล่ขึ้นมาแบบงง ๆ อีก? นี่เป็นโอกาสดีที่จะเอา automation เข้ามาช่วย ถ้าคุณใช้ version control system อยู่ (และคุณจะใช้แน่นอนหลังจากอ่าน Topic 19, Version Control ) ให้ tag การแก้บั๊กไว้ตอน check code กลับเข้าไปหลังเทสต์เสร็จ แล้วคุณก็รัน report รายเดือนเพื่อวิเคราะห์แนวโน้มของจำนวน source file ที่ได้รับผลกระทบจากการแก้บั๊กแต่ละครั้งได้
Documentation (เอกสารประกอบ)
อาจฟังดูแปลกใจ แต่ orthogonality ก็ใช้ได้กับเอกสารประกอบเหมือนกัน แกนของมันคือ content กับ presentation ถ้าเอกสารของคุณ orthogonal จริง ๆ คุณควรจะเปลี่ยนหน้าตาการแสดงผลได้อย่างสิ้นเชิงโดยไม่ต้องแตะ content เลย word processor มี style sheet และ macro ที่ช่วยเรื่องนี้ได้ ส่วนตัวเราเองชอบใช้ระบบ markup อย่าง Markdown มากกว่า เวลาเขียนเราจะโฟกัส แค่ content อย่างเดียว แล้วปล่อยให้ presentation เป็นหน้าที่ของเครื่องมือที่เราใช้ render มันครับ [17]
Living with Orthogonality (อยู่ร่วมกับ Orthogonality)
Orthogonality มีความเกี่ยวข้องอย่างใกล้ชิดกับ DRY principle DRY มุ่งลด duplication ภายในระบบ ในขณะที่ orthogonality มุ่งลดการพึ่งพากันระหว่าง component ของระบบ แม้มันจะเป็นคำที่ฟังดูเทอะทะไปหน่อย แต่ถ้าคุณใช้หลักการ orthogonality ควบคู่ไปกับ DRY principle อย่างใกล้ชิด คุณจะพบว่าระบบที่คุณพัฒนาจะยืดหยุ่นขึ้น เข้าใจง่ายขึ้น และ debug เทสต์ รวมถึงดูแลรักษาได้ง่ายขึ้นด้วยครับ
ถ้าคุณถูกดึงเข้าไปในโปรเจกต์ที่ทุกคนดิ้นรนสุดฤทธิ์เพื่อจะแก้อะไรสักอย่าง แล้วทุกการเปลี่ยนแปลงดูเหมือนจะทำให้อีกสี่อย่าง พังตามไปด้วย ให้นึกถึงฝันร้ายเรื่องเฮลิคอปเตอร์เอาไว้ โปรเจกต์นั้นก็คงไม่ได้ถูกออกแบบและเขียนโค้ดแบบ orthogonal นี่แหละครับ ถึงเวลาต้อง refactor แล้ว
แล้วถ้าคุณเป็นนักบินเฮลิคอปเตอร์ ก็อย่ากินปลาเชียวนะครับ….
Related Sections Include (หัวข้อที่เกี่ยวข้อง)
- Topic 3, Software Entropy
- Topic 8, The Essence of Good Design
- Topic 11, Reversibility
- Topic 28, Decoupling
- Topic 31, Inheritance Tax
- Topic 33, Breaking Temporal Coupling
- Topic 34, Shared State Is Incorrect State
- Topic 36, Blackboards
Challenges (โจทย์ท้าทาย)
-
ลองพิจารณาความแตกต่างระหว่างเครื่องมือที่มี graphical user interface กับ command-line utility เล็ก ๆ ที่เอามาผสมกันได้ ซึ่งใช้งานผ่าน shell prompt ดูสิ ชุดไหน orthogonal มากกว่ากัน แล้วทำไมถึงเป็นแบบนั้น? ชุดไหนใช้งานได้ง่ายกว่าสำหรับจุดประสงค์ที่มันถูกสร้างมาโดยตรง? ชุดไหนเอาไปผสมกับเครื่องมืออื่นเพื่อรับมือกับ โจทย์ใหม่ ๆ ได้ง่ายกว่า? แล้วชุดไหนเรียนรู้ได้ง่ายกว่ากัน?
-
C++ รองรับ multiple inheritance ส่วน Java ให้ class หนึ่ง implement หลาย interface ได้ ในขณะที่ Ruby มี mixin การใช้ feature เหล่านี้ส่งผลต่อ orthogonality ยังไงบ้าง? การใช้ multiple inheritance กับ multiple interface ส่งผลกระทบต่างกันไหม? แล้วการใช้ delegation กับการใช้ inheritance ต่างกันยังไง?
Exercises (แบบฝึกหัด)
แบบฝึกหัดที่ 1 ( คำตอบที่เป็นไปได้ )
สมมติคุณต้องอ่านไฟล์ทีละบรรทัด แล้วในแต่ละบรรทัดต้องแยกออกเป็น field ต่าง ๆ ชุด pseudo class definition ไหนต่อไปนี้น่าจะ orthogonal มากกว่ากัน?
| | class Split1 { |
|---|---|
| | constructor(fileName) # เปิดไฟล์เพื่ออ่าน |
| | def readNextLine() # เลื่อนไปยังบรรทัดถัดไป |
| | def getField(n) # คืนค่า field ลำดับที่ n ในบรรทัดปัจจุบัน |
| | } |
หรือ
| | class Split2 { |
|---|---|
| | constructor(line) # แยกบรรทัดออกเป็น field |
| | def getField(n) # คืนค่า field ลำดับที่ n ในบรรทัดปัจจุบัน |
| | } |
แบบฝึกหัดที่ 2 ( คำตอบที่เป็นไปได้ )
ความแตกต่างด้าน orthogonality ระหว่างภาษาแบบ object-oriented กับภาษาแบบ functional คืออะไร? ความแตกต่างเหล่านี้เป็นสิ่งที่ฝังอยู่ในตัวภาษาเองหรือแค่อยู่ในวิธีที่คนใช้ภาษานั้น ๆ กันแน่?