ความสอดคล้อง (Consistency)

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

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

17.1 ตัวอย่างของความสอดคล้อง

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

ชื่อ (Names) Chapter 14 ได้อภิปรายประโยชน์ของการใช้ชื่อในลักษณะที่สอดคล้องกัน

รูปแบบการเขียนโค้ด (Coding style) เป็นเรื่องปกติในปัจจุบันสำหรับองค์กรพัฒนาซอฟต์แวร์ที่มี style guides ที่จำกัด structure ของ program เกินกว่ากฎที่บังคับใช้โดย compilers Modern style guides จัดการกับปัญหาหลากหลาย เช่น indentation, curly-brace placement, order of declarations, naming, commenting, และข้อจำกัดในคุณลักษณะภาษาที่ถือว่าอันตราย Style guidelines ทำให้โค้ดอ่านง่ายขึ้นและสามารถลดข้อผิดพลาดบางประเภท

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

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

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

17.2 การสร้างความสอดคล้อง

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

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

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

บังคับใช้ (Enforce) แม้ว่าจะมีเอกสารที่ดี แต่ก็ยากสำหรับนักพัฒนาที่จะจำข้อตกลงทั้งหมด วิธีที่ดีที่สุดในการบังคับใช้ข้อตกลงคือการเขียน tool ที่ตรวจสอบความผิดพลาด และให้แน่ใจว่าโค้ดไม่สามารถ commit ไปยัง repository ได้ เว้นแต่จะผ่านการตรวจสอบ Automated checkers ทำงานได้ดีโดยเฉพาะสำหรับข้อตกลง syntactic ระดับต่ำ

หนึ่งในโปรเจ็กต์ล่าสุดของผม มีปัญหากับตัวอักษร line termination บางนักพัฒนาทำงานบน Unix โดยบรรทัดจะลงท้ายด้วย newlines คนอื่นทำงานบน Windows โดยบรรทัดปกติจะลงท้ายด้วยการส่งคืนคาร์เรจตามด้วย newline หากนักพัฒนาในระบบหนึ่งทำการแก้ไขเล็กน้อยในไฟล์ที่แก้ไขก่อนหน้านี้ในระบบอื่น บรรณาธิการบางครั้งจะแทนที่ line terminators ทั้งหมดด้วยตัวที่เหมาะสมสำหรับระบบนั้น สิ่งนี้ทำให้ดูเหมือนว่าทุกบรรทัดของไฟล์ได้รับการแก้ไข ซึ่งทำให้ยากต่อการติดตามการเปลี่ยนแปลงที่มีความหมายจริง เราสถาปนาข้อตกลงว่าไฟล์ควรมี newlines เท่านั้น แต่ยากที่จะให้แน่ใจว่าทุก tool ที่ใช้โดยนักพัฒนาแต่ละคนปฏิบัติตามข้อตกลง ทุกครั้งที่นักพัฒนาคนใหม่เข้าร่วมโปรเจ็กต์ เราจะประสบปัญหา line termination หลายประการในขณะที่นักพัฒนาคนนั้นปรับตัวให้เข้ากับข้อตกลง

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

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

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

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

17.3 ไปไกลเกินไป

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

17.4 บทสรุป

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