ทำไมต้องเขียน Comment? สี่ข้ออ้างอิง
เอกสารประกอบในโค้ด (In-code documentation) มีบทบาทสำคัญในการออกแบบซอฟต์แวร์ Comment เป็นสิ่งจำเป็นเพื่อช่วยให้ Developer เข้าใจระบบและทำงานได้มีประสิทธิภาพ แต่บทบาทของ Comment ไปไกลกว่านี้ เอกสารประกอบยังมีบทบาทสำคัญในการสร้าง Abstraction โดยหากไม่มี Comment คุณจะไม่สามารถซ่อนความซับซ้อนได้ และจากมองต่อไป กระบวนการเขียน Comment หากทำอย่างถูกต้องจะช่วยปรับปรุงการออกแบบของระบบให้ดีขึ้นจริง ในทางกลับกัน การออกแบบซอฟต์แวร์ที่ดีจะสูญเสียคุณค่าส่วนใหญ่หากมีเอกสารประกอบที่ไม่ดี
น่าเสียดายที่มุมมองนี้ไม่เป็นที่ยอมรับของทั้งหมด ส่วนสำคัญของโค้ดในการทำงานจริงมี Comment เกือบไม่มีเลย Developer หลายคนคิดว่า Comment เป็นการเสียเวลา บางคนเห็นคุณค่าของ Comment แต่ไม่ว่าด้วยเหตุใด ก็ไม่เคยเขียนมัน โชคดีที่ทีม Development หลายทีมรู้จักคุณค่าของเอกสารประกอบ และดูเหมือนว่าจำนวนทีมเหล่านี้กำลังเพิ่มขึ้นเรื่อยๆ อย่างไรก็ตาม แม้ในทีมที่สนับสนุน Documentation เอง Comment ก็มักถูกมองว่าเป็นงานสมควร (drudge work) และ Developer หลายคนไม่เข้าใจวิธีการเขียนมัน ดังนั้น เอกสารประกอบที่ได้จึงมักเป็นคุณภาพปานกลางเพียงเท่านั้น เอกสารประกอบที่ไม่เพียงพอสร้างการลากจูงที่ใหญ่โตและไม่จำเป็นต่อการพัฒนาซอฟต์แวร์
ในบทนี้ผมจะอภิปรายข้ออ้างอิดสำหรับการหลีกเลี่ยงการเขียน Comment และเหตุผลว่าทำไม Comment จึงสำคัญจริงๆ บทที่ 13 จะอธิบายวิธีการเขียน Comment ที่ดี และบทต่างๆ อีกสองสามบทหลังจากนั้นจะพูดถึงประเด็นที่เกี่ยวข้อง เช่น การเลือกชื่อตัวแปรและวิธีการใช้เอกสารประกอบเพื่อปรับปรุงการออกแบบของระบบ ผมหวังว่าบทเหล่านี้จะโน้มน้าวใจคุณถึงสามสิ่ง: Comment ที่ดีสามารถสร้างความแตกต่างมากมายในคุณภาพโดยรวมของซอฟต์แวร์; มันไม่ยากที่จะเขียน Comment ที่ดี; และ (ซึ่งอาจเป็นเรื่องยากสำหรับการเชื่อ) การเขียน Comment สามารถสนุกได้จริง
เมื่อ Developer ไม่เขียน Comment พวกเขามักจะปกป้องพฤติกรรมของตัวเองด้วยข้ออ้างหนึ่งข้ออ้างหรือมากกว่านั้นดังต่อไปนี้:
- "โค้ดที่ดีจะมีการอธิบายตัวเอง"
- "ผมไม่มีเวลาที่จะเขียน Comment"
- "Comment จะหมดอายุและกลายเป็นสิ่งที่ทำให้เข้าใจผิด"
- "Comment ทั้งหมดที่ผมเห็นไม่มีค่าแต่อย่างใด ทำไมต้องพยายาม" ในส่วนต่อไปนี้ผมจะแก้ไขข้ออ้างแต่ละข้ออ้างตามลำดับ
12.1 โค้ดที่ดีจะมีการอธิบายตัวเอง
บางคนเชื่อว่าถ้าโค้ดเขียนได้ดี มันก็ชัดเจนมากจนไม่จำเป็นต้องมี Comment ปรศจน์ที่น่าเพลินใจนี้ เหมือนข่าวลือที่ว่าไอศกรีมดีต่อสุขภาพของคุณ: เราอยากจะเชื่อมันจริงๆ! น่าเสียดายที่มันไม่จริง เพื่อให้แน่ใจ มีบางสิ่งที่คุณสามารถทำได้เมื่อเขียนโค้ดเพื่อลดความจำเป็นสำหรับ Comment เช่น การเลือกชื่อตัวแปรที่ดี (ดู บทที่ 14) อย่างไรก็ตาม ยังมีจำนวนมหาศาลของข้อมูลการออกแบบที่ไม่สามารถแสดงออกมาในรูปของโค้ดได้ ตัวอย่างเช่น มีเพียงส่วนเล็กน้อยของ Interface ของ Class เช่น Signature ของ Method ที่สามารถระบุไดได้อย่างเป็นทางการในโค้ด ด้านที่ไม่เป็นทางการของ Interface เช่น คำอธิบายระดับสูงของสิ่งที่ Method แต่ละตัวทำหรือความหมายของผลลัพธ์ของมัน สามารถอธิบายได้เฉพาะในส่วน Comment เท่านั้น มีตัวอย่างอื่นๆ อีกหลายตัวอย่างของสิ่งที่ไม่สามารถอธิบายได้ในโค้ด เช่น เหตุผลสำหรับการตัดสินใจออกแบบที่เฉพาะเจาะจง หรือเงื่อนไขที่สมควรที่จะเรียก Method ที่เฉพาะเจาะจง
Developer บางคนแย้งว่าหากผู้อื่นต้องการทราบว่า Method ทำอะไร พวกเขาควรอ่านโค้ดของ Method: สิ่งนี้จะแม่นยำกว่า Comment ใดๆ เป็นไปได้ว่าผู้อ่านสามารถหักลบ Interface ที่เป็นนามธรรมของ Method ได้โดยการอ่านโค้ดของมัน แต่จะใช้เวลานาน และเจ็บปวดมาก นอกจากนี้ หากคุณเขียนโค้ดด้วยการคาดคะเนว่าผู้ใช้จะอ่าน Implementation ของ Method คุณจะพยายามทำให้ Method แต่ละตัวสั้นที่สุดเท่าที่จะเป็นไปได้ เพื่อให้อ่านได้ง่าย หากมีสิ่งใดที่ไม่ธรรมดา คุณจะแบ่งมันออกเป็นหลาย Method ที่เล็กกว่า สิ่งนี้จะส่งผลให้เกิด Method ตื้นๆ จำนวนมหาศาล นอกจากนี้ มันไม่ได้ทำให้โค้ดอ่านได้ง่ายขึ้นจริงๆ: เพื่อที่จะเข้าใจพฤติกรรมของ Method ระดับบนสุด ผู้อ่านอาจจำเป็นต้องเข้าใจพฤติกรรมของ Method ที่ซ้อนอยู่ สำหรับระบบขนาดใหญ่ มันไม่ใช่เรื่องปฏิบัติได้สำหรับผู้ใช้ที่จะอ่านโค้ดเพื่อเรียนรู้พฤติกรรม
ยิ่งไปกว่านั้น Comment ยังเป็นพื้นฐานของ Abstraction โปรดระลึกจาก บทที่ 4 ว่าเป้าหมายของ Abstraction คือการซ่อนความซับซ้อน: Abstraction คือมุมมองแบบง่ายของเอนทิตี ซึ่งรักษาข้อมูลที่จำเป็นแต่ละไว้รายละเอียดที่อาจไม่สนใจได้อย่างปลอดภัย หากผู้ใช้ต้องอ่านโค้ดของ Method เพื่อใช้มัน ก็ไม่มี Abstraction: ความซับซ้อนทั้งหมดของ Method ถูกเปิดเผย หากไม่มี Comment เท่าที่จะเป็นไปได้ของ Method คือ Declaration ของมัน ซึ่งระบุชื่อของมันและชื่อและประเภทของ Argument และผลลัพธ์ Declaration ขาดข้อมูลที่จำเป็นเกินไปมากจนจะไม่สามารถให้ Abstraction ที่มีประโยชน์ได้ด้วยตัวเอง ตัวอย่างเช่น Method ที่จะแยก Substring อาจมี Argument สองตัว start และ end ซึ่งบ่งชี้ถึงช่วงของตัวอักษรที่จะแยก จากการประกาศเพียงอย่างเดียว เป็นไปไม่ได้ที่จะบอกได้ว่า Substring ที่แยกออกมาจะรวม Character ที่บ่งชี้ด้วย end หรือสิ่งที่เกิดขึ้นหาก start > end Comment ช่วยให้เราสามารถจับข้อมูลเพิ่มเติมที่ Caller ต้องการ ดังนั้นจึงทำให้มุมมองแบบง่ายเสร็จสิ้นในขณะซ่อน Implementation Detail ยังเป็นสิ่งสำคัญที่ Comment นั้นเขียนด้วยภาษามนุษย์เช่น English: สิ่งนี้ทำให้มันมีความแม่นยำน้อยกว่าโค้ด แต่มันให้พลังในการแสดงออกมากขึ้น ดังนั้นเราจึงสามารถสร้าง Description ที่เรียบง่ายและสัญชาตญาณได้ หากคุณต้องการใช้ Abstraction เพื่อซ่อนความซับซ้อน Comment ถือว่าจำเป็น
12.2 ผมไม่มีเวลาที่จะเขียน Comment
เป็นเรื่องที่น่าอยากจะให้ Comment มีความสำคัญน้อยกว่างานพัฒนา Task อื่นๆ ด้วยการเลือกระหว่างการเพิ่ม Feature ใหม่และการจัดเอกสารประกอบของ Feature ที่มีอยู่ ดูเหมือนว่าตรรกะจะเลือก Feature ใหม่ อย่างไรก็ตาม โครงการซอฟต์แวร์เกือบทั้งหมดอยู่ภายใต้ความกดดันด้านเวลา และจะมีสิ่งต่างๆ ที่ดูเหมือนจะมีความสำคัญมากกว่าการเขียน Comment เสมอ ดังนั้น หากคุณอนุญาตให้เอกสารประกอบหลีกเลี่ยง คุณจะจบลงด้วยการไม่มีเอกสารประกอบ
ข้อโต้แย้งโต้เถียงกับข้ออ้างนี้คือจิตสำนึก Investment ที่กล่าวถึงใน หน้า 15 หากคุณต้องการโครงสร้างซอฟต์แวร์ที่สะอาด ซึ่งจะช่วยให้คุณทำงานได้อย่างมีประสิทธิภาพในระยะยาว คุณต้องใช้เวลาพิเศษบ้างในตอนแรกเพื่อสร้างโครงสร้างนั้น Comment ที่ดีสร้างความแตกต่างมหาศาลในความสามารถในการบำรุงรักษาของซอฟต์แวร์ ดังนั้นความพยายามที่ใช้ไปสำหรับพวกมันจะจ่ายคืนตัวเองอย่างรวดเร็ว นอกจากนี้ การเขียน Comment ไม่จำเป็นต้องใช้เวลามาก ถามตัวเองว่าคุณใช้เวลาพัฒนา (Development Time) เท่าไร พิมพ์โค้ด (ตรงข้ามกับการออกแบบ การ Compile การ Test เป็นต้น) สมมติว่าคุณไม่รวม Comment ใด ผมสงสัยว่าคำตอบมากกว่า 10% ตอนนี้ สมมติว่าคุณใช้เวลาเท่ากันพิมพ์ Comment และพิมพ์โค้ด: นี่ควรจะเป็น Upper Bound ที่ปลอดภัย ด้วยการสมมติฐานเหล่านี้ การเขียน Comment ที่ดีจะเพิ่มเวลาพัฒนาของคุณไม่เกินประมาณ 10% ผลประโยชน์ของการมี Documentation ที่ดีจะชดเชยค่าใช้จ่ายนี้อย่างรวดเร็ว
นอกจากนี้ Comment ที่สำคัญที่สุด จำนวนมากคือสิ่งที่เกี่ยวข้องกับ Abstraction เช่น เอกสารประกอบระดับบนสุดสำหรับ Class และ Method บทที่ 15 จะแย้งว่า Comment เหล่านี้ควรเขียนเป็นส่วนหนึ่งของกระบวนการออกแบบ และการเขียน Documentation นั้นเป็นเครื่องมือออกแบบสำคัญที่ปรับปรุงการออกแบบโดยรวม Comment เหล่านี้จ่ายคืนตัวเองทันที
12.3 Comment หมดอายุและกลายเป็นสิ่งที่ทำให้เข้าใจผิด
Comment บางครั้งหมดอายุ แต่สิ่งนี้ไม่จำเป็นต้องเป็นปัญหาใหญ่ในทางปฏิบัติ การรักษา Documentation ให้ทันสมัยไม่จำเป็นต้องใช้ความพยายามมหาศาล การเปลี่ยนแปลง Documentation ขนาดใหญ่จำเป็นเฉพาะเมื่อมีการเปลี่ยนแปลงโค้ดขนาดใหญ่ และการเปลี่ยนแปลงโค้ดจะใช้เวลามากกว่าการเปลี่ยนแปลง Documentation บทที่ 16 กล่าวถึงวิธีการจัดระเบียบ Documentation เพื่อให้สามารถรักษา Documentation ให้ทันสมัยหลังจากการปรับเปลี่ยนโค้ด (แนวคิดสำคัญคือการหลีกเลี่ยง Documentation ที่ซ้ำซ้อนและรักษา Documentation ให้ใกล้เคียงกับโค้ดที่สอดคล้องกัน) Code Review เป็นกลไกที่ยอดเยี่ยมสำหรับการตรวจจับและแก้ไข Comment ที่ล้าสมัย
12.4 ทั้งหมด Comment ที่ผมเห็นไม่มีค่า
ในสี่ข้ออ้างนี้ นี่คือสิ่งที่น่าจะมีข้อได้ที่สุด Developer Software ทั้งหมดเห็นว่า Comment ที่ไม่ให้ข้อมูลที่เป็นประโยชน์ และ Documentation ส่วนใหญ่ที่มีอยู่คือไม่ดีขนาดไหนแล้ว โชคดีที่ปัญหานี้สามารถแก้ไขได้; การเขียน Documentation ที่มั่นคง ไม่ยากเมื่อคุณรู้วิธี บทต่อไปนี้จะอธิบาย Framework สำหรับวิธีการเขียน Documentation ที่ดีและการรักษามันในช่วงเวลา
12.5 ประโยชน์ของ Comment ที่เขียนได้ดี
เมื่อพูดถึง (และ หวังว่าได้ปฏิเสธ) ข้อโต้แย้งต่อการเขียน Comment ตอนนี้ให้พิจารณาประโยชน์ที่คุณจะได้รับจาก Comment ที่ดี แนวความคิดโดยรวมเบื้องหลัง Comment คือการจับข้อมูลที่เป็นอยู่ในใจของผู้ออกแบบ แต่ไม่สามารถแสดงออกมาในรูปของโค้ด ข้อมูลนี้มีตั้งแต่รายละเอียดระดับต่ำ เช่น คุณสมบัติ Hardware ที่ท้ายกระบวนการทำให้โค้ดส่วนหนึ่งซับซ้อนเป็นพิเศษ จนถึงแนวคิดระดับสูง เช่น เหตุผลสำหรับ Class เมื่อ Developer อื่นมาทำการปรับเปลี่ยนในภายหลัง Comment จะช่วยให้พวกเขาทำงานได้รวดเร็วและแม่นยำยิ่งขึ้น หากไม่มี Documentation ผู้พัฒนาในอนาคตจะต้องรู้จักหรือเดาความรู้เดิมของผู้ออกแบบ; สิ่งนี้จะใช้เวลาเพิ่มเติม และมีความเสี่ยงของข้อบกพร่องหากผู้พัฒนาที่ใหม่เข้าใจผิดเจตนาของผู้ออกแบบเดิม Comment มีค่าแม้ในกรณีที่ผู้ออกแบบเดิมเป็นคนทำการเปลี่ยนแปลง: หากผ่านไปไม่กี่สัปดาห์นับจากครั้งสุดท้ายที่คุณทำงานในส่วนของโค้ด คุณจะลืมรายละเอียดจำนวนมากของการออกแบบเดิม
บทที่ 2 อธิบายวิธีสามประการที่มี Complexity ปรากฏตัวในระบบซอฟต์แวร์:
การขยาย Change (Change amplification): การเปลี่ยนแปลงที่ดูเหมือนง่าย ต้องใช้การแก้ไขโค้ดในหลายสถานที่
Cognitive load: เพื่อที่จะทำการเปลี่ยนแปลง ผู้พัฒนาต้องสะสมข้อมูลจำนวนมาก
Unknown unknowns: มันไม่ชัดเจนว่าโค้ดที่ต้องแก้ไข หรือข้อมูลที่ต้องพิจารณาเพื่อทำการเปลี่ยนแปลงเหล่านั้น
Documentation ที่ดีช่วยกับคำขอที่สองสองข้อในสามข้อเหล่านี้ Documentation สามารถลดปกรณ์ (Cognitive load) โดยการให้ข้อมูลที่ Developer ต้องการเพื่อทำการเปลี่ยนแปลงและโดยการทำให้ได้ง่ายสำหรับ Developer เพื่อเพิกเฉยต่อข้อมูลที่ไม่เกี่ยวข้อง หากไม่มี Documentation ที่เพียงพอ Developer อาจต้องอ่าน Code ของปริมาณมากในการสร้าง What ที่เป็นอยู่ในใจของผู้ออกแบบ Documentation นอกจากนี้ยังสามารถลด Unknown unknowns โดยการชี้แจงโครงสร้างของระบบ ดังนั้นจึงชัดเจนว่าข้อมูล Code ใดที่เกี่ยวข้องสำหรับการเปลี่ยนแปลงใดๆ
บทที่ 2 ชี้ให้เห็นว่าสาเหตุหลักของ Complexity คือ Dependency และ Obscurity Documentation ที่ดีสามารถชี้แจง Dependency และเติมช่องว่างเพื่อขจัด Obscurity
บทต่างๆ ไม่กี่บทต่อไปนี้จะแสดงให้คุณเห็นวิธีการเขียน Documentation ที่ดี พวกเขายังจะกล่าวถึงวิธีการรวม Documentation-writing เข้าไปในกระบวนการออกแบบเพื่อให้มันปรับปรุงการออกแบบของ Software ของคุณ