Consistency (ความสอดคล้อง) เป็นเครื่องมือที่ทรงพลังในการลดความซับซ้อนของระบบและทำให้พฤติกรรมของมันชัดเจนยิ่งขึ้น ถ้าระบบมีความสอดคล้องกัน นั่นหมายความว่าสิ่งที่คล้ายกันจะถูกทำในวิธีที่คล้ายกัน และสิ่งที่แตกต่างกันจะถูกทำในวิธีที่แตกต่างกัน ความสอดคล้องสร้าง leverage ทางความคิด: เมื่อคุณเรียนรู้แล้วว่าสิ่งหนึ่งถูกทำอย่างไรในที่หนึ่ง คุณสามารถใช้ความรู้นั้นเพื่อทำความเข้าใจที่อื่นที่ใช้แนวทางเดียวกันได้ทันที ถ้าระบบไม่ได้ถูก implement อย่างสอดคล้องกัน นักพัฒนาจะต้องเรียนรู้เกี่ยวกับแต่ละสถานการณ์แยกกัน ซึ่งจะใช้เวลามากกว่า

ความสอดคล้องช่วยลดข้อผิดพลาด ถ้าระบบไม่มีความสอดคล้องกัน สองสถานการณ์อาจดูเหมือนเหมือนกันทั้งที่จริงแล้วแตกต่างกัน นักพัฒนาอาจเห็น pattern ที่ดูคุ้นเคยและตั้งสมมติฐานที่ไม่ถูกต้องจากประสบการณ์เดิมกับ pattern นั้น ในทางกลับกัน ถ้าระบบมีความสอดคล้องกัน สมมติฐานที่ตั้งจากสถานการณ์ที่ดูคุ้นเคยจะปลอดภัย ความสอดคล้องทำให้นักพัฒนาทำงานได้เร็วขึ้นและมีข้อผิดพลาดน้อยลง

17.1 Examples of consistency (ตัวอย่างของความสอดคล้อง)

Consistency สามารถนำไปใช้ได้ในหลายระดับในระบบ ต่อไปนี้คือตัวอย่างบางส่วน

Names. Chapter 14 (บทที่ 14) ได้กล่าวถึงประโยชน์ของการใช้ชื่ออย่างสอดคล้องกันไปแล้ว

Coding style. ปัจจุบันเป็นเรื่องปกติที่องค์กรพัฒนาจะมี style guides ที่จำกัดโครงสร้างของโปรแกรมเกินกว่ากฎที่ compiler บังคับใช้ สไตล์ไกด์สมัยใหม่ครอบคลุมประเด็นต่าง ๆ เช่น การย่อหน้า การวาง curly braces ลำดับการประกาศตัวแปร การตั้งชื่อ การเขียน comment และข้อจำกัดเกี่ยวกับฟีเจอร์ของภาษาที่ถือว่า อันตราย สไตล์ไกด์ทำให้โค้ดอ่านง่ายขึ้นและสามารถลดข้อผิดพลาดบางประเภทได้

Interfaces. Interface ที่มีหลาย implementation ก็เป็นอีกตัวอย่างหนึ่งของความสอดคล้อง เมื่อคุณเข้าใจ implementation หนึ่งของ interface แล้ว implementation อื่น ๆ ก็จะเข้าใจได้ง่ายขึ้น เพราะคุณรู้อยู่แล้วว่ามันต้องมีฟีเจอร์อะไรบ้าง

Design patterns. Design patterns คือโซลูชันที่ได้รับการยอมรับโดยทั่วไปสำหรับปัญหาทั่วไปบางอย่าง เช่น แนวทาง model-view-controller สำหรับการออกแบบ user interface ถ้าคุณสามารถใช้ design pattern ที่มีอยู่แล้วในการแก้ปัญหา การ implement จะดำเนินไปได้เร็วขึ้น มีแนวโน้มที่จะใช้งานได้มากขึ้น และโค้ดของคุณจะเข้าใจง่ายขึ้นสำหรับผู้อ่าน Design patterns ได้ถูกกล่าวถึงในรายละเอียดเพิ่มเติมใน Section 19.5 (หัวข้อ 19.5) .

Invariants. Invariant คือคุณสมบัติของตัวแปรหรือโครงสร้างที่เป็นจริงเสมอ ตัวอย่างเช่น data structure ที่เก็บข้อความหลายบรรทัดอาจบังคับใช้ invariant ที่ว่าแต่ละบรรทัดต้องลงท้ายด้วยอักขระ newline Invariants ช่วยลดจำนวนกรณีพิเศษที่ต้องพิจารณาในโค้ด และทำให้ง่ายต่อการให้เหตุผลเกี่ยวกับพฤติกรรมของโค้ด

17.2 Ensuring consistency (การรักษาความสอดคล้อง)

การรักษาความสอดคล้องเป็นเรื่องยาก โดยเฉพาะเมื่อมีคนจำนวนมากทำงานในโปรเจกต์เป็นเวลานาน คนในกลุ่มหนึ่งอาจไม่รู้เกี่ยวกับข้อตกลงร่วมที่ตั้งขึ้นในอีกกลุ่มหนึ่ง ผู้มาใหม่ไม่รู้กฎ พวกเขาจึงละเมิดข้อตกลงโดยไม่ตั้งใจ และสร้างข้อตกลงใหม่ที่ขัดแย้งกับของเดิม ต่อไปนี้คือเคล็ดลับบางประการสำหรับการสร้างและรักษาความสอดคล้อง:

Document. สร้างเอกสารที่แสดงรายการข้อตกลงร่วมที่สำคัญที่สุด เช่น แนวปฏิบัติเกี่ยวกับ coding style วางเอกสารไว้ในที่ที่นักพัฒนามีแนวโน้มจะเห็น เช่น จุดที่สังเกตเห็นได้ชัดบน project Wiki สนับสนุนให้คนที่เข้ามาใหม่ในกลุ่มอ่านเอกสาร และสนับสนุนให้คนเดิมทบทวนเอกสารเป็นครั้งคราว มีสไตล์ไกด์หลายฉบับจากหลายองค์กรที่ถูกเผยแพร่บนเว็บ ลองเริ่มต้นจากหนึ่งในนั้น

สำหรับข้อตกลงร่วมที่เจาะจงเฉพาะที่มากขึ้น เช่น invariants ให้หาจุดที่เหมาะสมในโค้ดเพื่อบันทึกไว้ ถ้าคุณไม่เขียนข้อตกลงร่วมลงไป คนอื่นก็ไม่น่าจะปฏิบัติตาม

Enforce. ถึงจะมี documentation ที่ดี นักพัฒนาก็ยังจำข้อตกลงทั้งหมดได้ยาก วิธีที่ดีที่สุดในการบังคับใช้ข้อตกลงคือการเขียน tool ที่ตรวจสอบ การละเมิด และทำให้แน่ใจว่าโค้ดจะ commit ไปยัง repository ไม่ได้ถ้าไม่ผ่าน checker เครื่องมือตรวจสอบอัตโนมัติทำงานได้ดีเป็นพิเศษกับข้อตกลงทาง syntax ระดับต่ำ

หนึ่งในโปรเจกต์ล่าสุดของฉันมีปัญหาเกี่ยวกับอักขระลงท้ายบรรทัด นักพัฒนาบางคนทำงานบน Unix ซึ่งลงท้ายบรรทัดด้วย newline ส่วนบางคนทำงานบน Windows ซึ่งปกติจะลงท้ายบรรทัดด้วย carriage-return ตามด้วย newline เมื่อนักพัฒนาจากระบบหนึ่งแก้ไขไฟล์เล็กน้อยที่ถูกแก้ไขก่อนหน้านี้บนอีกระบบหนึ่ง editor บางครั้งก็จะแทนที่อักขระลงท้ายบรรทัดทั้งหมดด้วยอักขระที่เหมาะสมกับระบบนั้น ทำให้ดูเหมือนว่าทุกบรรทัดในไฟล์ถูกแก้ไข ซึ่งทำให้ยากต่อการติดตามการเปลี่ยนแปลงที่มีความหมาย เราสร้างข้อตกลงว่าไฟล์ควรมีแค่ newline เท่านั้น แต่มันยากที่จะทำให้แน่ใจว่า tool ทุกตัวที่นักพัฒนาแต่ละคนใช้ปฏิบัติตามข้อตกลงนั้น ทุกครั้งที่มีนักพัฒนาใหม่เข้ามาในโปรเจกต์ เราจะพบปัญหาอักขระลงท้ายบรรทัดมากมายในช่วงที่นักพัฒนาคนนั้นกำลังปรับตัวเข้ากับข้อตกลง

ในที่สุดเราแก้ปัญหานี้ด้วยการเขียนสคริปต์สั้น ๆ ที่ทำงานอัตโนมัติก่อนที่จะ commit การเปลี่ยนแปลงไปยัง source code repository สคริปต์ตรวจสอบไฟล์ทั้งหมดที่ถูกแก้ไขและยกเลิกการ commit ถ้าไฟล์ใดมี carriage return สคริปต์ยังสามารถรันด้วยตนเองเพื่อซ่อมแซมไฟล์ที่เสียหายโดยการแทนที่ลำดับ carriage-return/newline ด้วย newline วิธีนี้กำจัดปัญหาได้ทันที และยังช่วยฝึกนักพัฒนาใหม่ด้วย

Code reviews เป็นอีกโอกาสหนึ่งในการบังคับใช้ข้อตกลงและให้ความรู้แก่นักพัฒนาใหม่เกี่ยวกับข้อตกลง ยิ่งผู้ตรวจสอบโค้ดจู้จี้จุกจิกมากเท่าไหร่ ทุกคนในทีมก็จะเรียนรู้ข้อตกลงได้เร็วขึ้นเท่านั้น และโค้ดก็จะสะอาดขึ้น

When in Rome ... ข้อตกลงที่สำคัญที่สุดคือนักพัฒนาทุกคนควรปฏิบัติตามสุภาษิตโบราณที่ว่า "When in Rome, do as the Romans do" เมื่อทำงานในไฟล์ใหม่ ให้มองไปรอบ ๆ ว่าโค้ดที่มีอยู่แล้วมีโครงสร้างอย่างไร ตัวแปรและเมธอด public ทั้งหมดถูกประกาศก่อน private หรือไม่? เมธอดเรียงตามลำดับตัวอักษรหรือไม่? ตัวแปรใช้ "camel case" อย่างใน firstServerName หรือ "snake case" อย่างใน first_server_name ? เมื่อคุณเห็นอะไรก็ตามที่ดูเหมือนว่าอาจจะเป็นข้อตกลง ให้ปฏิบัติตาม เมื่อตัดสินใจเกี่ยวกับการออกแบบ ให้ถามตัวเองว่ามีแนวโน้มไหมที่มีการตัดสินใจแบบเดียวกันนี้ที่อื่นในโปรเจกต์ ถ้ามีให้หาตัวอย่างที่มีอยู่แล้วและใช้แนวทางเดียวกันในโค้ดใหม่ของคุณ

Don't change existing conventions. อย่าพยายาม "ปรับปรุง" ข้อตกลงที่มีอยู่ การมี "ไอเดียที่ดีกว่า" ไม่ใช่เหตุผลที่พอเพียงที่จะทำให้เกิดความไม่สอดคล้อง ไอเดียใหม่ของคุณอาจดีกว่าจริง แต่มูลค่าของความสอดคล้องเหนือความไม่สอดคล้องนั้นเกือบจะมากกว่ามูลค่าของแนวทางหนึ่งเหนืออีกแนวทางหนึ่งเสมอ ก่อนที่จะทำให้เกิดพฤติกรรมที่ไม่สอดคล้องกัน ให้ถามตัวเองสองคำถาม หนึ่ง คุณมีข้อมูลใหม่ที่สำคัญที่สนับสนุนแนวทางของคุณซึ่งไม่มีตอนที่ข้อตกลงเดิมถูกตั้งขึ้นหรือไม่? สอง แนวทางใหม่ดีกว่ามากจนคุ้มค่าที่จะใช้เวลาอัปเดตทุกจุดที่ใช้แบบเดิมหรือไม่? ถ้าองค์กรของคุณเห็นพ้องว่าคำตอบของทั้งสองคำถามคือ "ใช่" ก็ลงมือปรับปรุงได้เลย เมื่อคุณทำเสร็จแล้ว ก็ไม่ควรมีร่องรอยของข้อตกลงเดิมหลงเหลืออยู่ อย่างไรก็ตาม คุณยังเสี่ยงที่นักพัฒนาคนอื่นจะไม่รู้เกี่ยวกับข้อตกลงใหม่ และอาจนำแนวทางเดิมกลับมาใช้ในอนาคต โดยรวมแล้ว การทบทวนข้อตกลงที่ตั้งไว้แล้วนั้นแทบจะไม่ใช่การใช้เวลาของนักพัฒนาที่คุ้มค่าเลย

17.3 Taking it too far (การยึดติดมากเกินไป)

Consistency ไม่ได้หมายความแค่ว่าสิ่งที่คล้ายกันควรทำในวิธีที่คล้ายกันเท่านั้น แต่สิ่งที่แตกต่างกันก็ควรทำในวิธีที่แตกต่างกันด้วย ถ้าคุณยึดติดกับ consistency มากเกินไปและพยายามบังคับสิ่งที่แตกต่างกันให้ใช้แนวทางเดียวกัน เช่น การใช้ชื่อตัวแปรเดียวกันสำหรับสิ่งที่แตกต่างกันจริง ๆ หรือการใช้ design pattern ที่มีอยู่กับงานที่ไม่เข้ากับ pattern นั้น คุณจะสร้างความซับซ้อนและความสับสน Consistency จะให้ประโยชน์ก็ต่อเมื่อนักพัฒนามั่นใจว่า "ถ้ามันดูเหมือน x มันก็เป็น x จริง ๆ"

17.4 Conclusion (บทสรุป)

Consistency เป็นอีกตัวอย่างหนึ่งของ investment mindset มันต้องใช้ความพยายามเพิ่มเติมเล็กน้อยเพื่อรักษาความสอดคล้อง: ทำงานเพื่อตัดสินใจเกี่ยวกับข้อตกลงร่วม ทำงานเพื่อสร้างเครื่องมือตรวจสอบอัตโนมัติ ทำงานเพื่อมองหาสถานการณ์ที่คล้ายกันเพื่อเลียนแบบในโค้ดใหม่ และทำงานในการตรวจสอบโค้ดเพื่อให้ความรู้แก่ทีม ผลตอบแทนจากการลงทุนนี้คือโค้ดของคุณจะชัดเจนมากขึ้น นักพัฒนาจะสามารถเข้าใจพฤติกรรมของโค้ดได้เร็วและแม่นยำขึ้น และสิ่งนี้จะช่วยให้พวกเขาทำงานได้เร็วขึ้น โดยมีบั๊กน้อยลง