การออกแบบซอฟต์แวร์ที่ดีควรมี comment เยอะหรือน้อย? เป็นคำถามที่ถกเถียงกันตลอดมา ฝั่งหนึ่งบอกว่า "Code must be self-documenting!" ในขณะที่อีกฝั่งเชื่อว่า comment ช่วยให้เข้าใจ code ได้ง่ายขึ้น
ถ้าถามผมเมื่อก่อน ผมคงอยู่ฝั่ง "comment น้อย" เพราะมองว่า code ควรอธิบายตัวมันเองได้ แต่มุมมองนั้นอาจยังไม่ครบทุกด้าน
คำตอบไม่ใช่แค่ "เยอะ" หรือ "น้อย" แต่อยู่ที่ "คุณค่า" ที่ comment นั้นมอบให้ หัวใจสำคัญคือ: comment ควรอธิบาย "Why" (ทำไม) ไม่ใช่ "What" (ทำอะไร) เพราะตัว code ควรจะบอก "What" ได้ด้วยตัวมันเองอยู่แล้ว
แล้ว comment แบบไหนล่ะที่เรียกว่า "ดี" และมีคุณค่า?
Good Comment 👍
เขียนในสิ่งที่โค้ดบอกไม่ได้ "Why"
เขียนสิ่งที่แค่ code อย่างเดียวก็ตอบไม่ได้
ถ้ามีจังหวะที่บอกว่า มี comment นี้ดีกว่าไม่มี เช่นให้ value อะไรบางอย่าง เช่น ถ้าอยู่ในวงการ fin tech ก็จะมีศัพท์เฉพาะทาง หรือวิธีการคำนวณพิเศษ ถ้าเรามี code ที่ช่วยให้เราไม่ต้องเสียเวลาอ่าน 15-30 นาที เอาจบง่าย ๆ 30 วินาที หรือ 1 นาที ก็น่าจะดีนะ
เขียนเพื่อคนอื่น
เหมือนกันถ้าเราย้ายไปอยู่ในวงการแพทย์ ก็จะมีศัพท์เฉพาะของวงการแพทย์ เราที่เขียน software ก็ไม่ใช่ทุกคนที่จะรู้เรื่องนี้เท่ากันหมด บางทีเราอยู่ในวงการนี้จนจำศัพท์เฉพาะได้กว่า 80% แล้ว แต่ไม่ใช่สำหรับทุกคน
“ให้เราลองใส่หมวกเป็นคนอื่น” เป็นเพื่อนในทีม หรือแม้กระทั่งคนที่จะมาร่วมงานกับเราในอนาคต
ถ้าเป็นคนนั้นเขาจะถามอะไรนะ แล้วมีตรงไหนที่อธิบายสิ่งนี้หรือยัง? ถ้าเราไม่เขียนไว้ซักที่ สิ่งที่อาจจะเกิดคือ เราเนี่ยแหละที่ต้องไปอธิบายทุกครั้งที่มีใครเกิดสงสัย อยากถาม จะดีกว่าไหมถ้าเราไม่จำเป็นต้องอธิบายทุกรอบ หรืออธิบายน้อยลงกว่าเดิมเพราะเพื่อนร่วมงานไปก่อนมาก่อน และ feedback ให้กันถ้าหากว่า comment ยังอธิบายไม่เคลียร์พอ
เขียนบอกเจตนา
เขียนเพื่อบอกว่าคนอื่นว่าเขา ควรจะมาอ่านไฟล์นี้เมื่อไหร่ แล้วไฟล์นี้มีความสำคัญอย่างไร
ตัวอย่าง
-
แทนที่จะบอกแค่ว่าเป็น adapter สำหรับ stripe
// Adapter for the Stripe API. -
ลองเปลี่ยนเป็นบอกว่า สิ่งนี้มีไปเพื่ออะไร
// Acts as an Anti-Corruption Layer for all interactions with the Stripe API. // Its purpose is to translate our internal payment models into the format // required by Stripe, completely isolating the rest of the application // from specific Stripe implementation details.
เขียนไปทำไม
ไม่ใช่ทุกครั้งที่เราจะถูกใจคนอื่น LGTM 😅 ตลอด บางวันก็เป็นวันที่เหนื่อย วันที่ล้า code ก็อาจจะเขียนได้ไม่ดี
หรือเป็น code ที่เจอ deadline driven
ตัวอย่าง
- TODO
tsx1// TODO: This is a temporary fix to meet the sprint deadline. 2// We should refactor this to use the new UserEvent service instead of direct DB calls. 3// See ticket: JIRA-123 4
- trade-off
tsx1// This logic is duplicated from the Admin panel. I know it's not DRY, 2// but creating a shared library would have delayed the launch by a week. 3// A follow-up task has been created to address this: TICKET-456. 4
- performance concerns
tsx1// This nested loop could be an O(n^2) performance bottleneck with large datasets. 2// I couldn't think of a better way on the spot, but we should investigate 3// using a HashMap for an O(n) lookup instead. 4
เขียนเพื่อเป็นคำเตือน ⚠️
บางครั้งเราก็เจอ defect ที่ไม่ได้เกี่ยวกับงานโดยตรง แต่ก็ยังไม่มีเวลาเข้าไปแก้ ณ ตอนนั้น แต่ก็ไม่อยากให้ลืมกันไป เราก็ควรทำอะไรสักอย่างเพื่อนเตือนคนที่จะมาต่อจากนี้ เพื่อไม่ให้ตรงหลุมเดียวกับคุณ
ตัวอย่าง
tsx1// FRAGILE: This logic assumes the API endpoint /api/v1/documents 2// always returns the 'primary' document as the first element in the array. 3// If the API's sorting behavior changes, this will silently assign the wrong document. 4// We should explicitly find the document where doc.isPrimary === true instead. 5const primaryDoc = api.fetchDocuments(user.id)[0]; 6
Bad Comment 👎
อย่าเขียนในสิ่งที่โค้ดบอกอยู่แล้ว “What”
ไม่เขียนสิ่งที่โค้ดบอกอยู่
ถ้าเจอ comment ที่บอกแบบเดียวกับที่โค้ดทำ ลบดีกว่า
treat เหมือน code เลย ถ้าเราเจอ duplicate code เรายังอยากลบเลย
comment ซ้ำกับ code เราก็ควรลบเช่นเดียวกัน
tsx1function getX() { 2 // return X 👈 delete it 3 return X 4} 5
แต่บางครั้งมันไม่ได้ตรงไปตรงแบบตัวอย่างด้านบน
tsx1function getConfigurationFor(user) { 2 if (user && user.hasProfile) { 3 // ... 4 // ... many line of codes build specific user config 5 // ... 6 } else { 7 // no user profile, return default config 8 return getSystemDefaultConfiguration(); 9 } 10} 11
เราจำเป็นต้องจัดรูปให้เข้าเงื่อนไขข้างบน คือ comment บอกแบบเดียวกับสิ่งที่ code ทำอยู่
tsx1function getConfigurationFor(user) { 2 if (!user || !user.hasProfile) { 3 // no user profile, return default config 👈 delete it 4 return getSystemDefaultConfiguration(); 5 } 6 7 // ... 8 // ... many line of codes build specific user config 9 // ... 10} 11
สรุป
มอง Comment ให้เหมือนโค้ด
การเขียน comment ก็เหมือนการเขียน code มันต้องการการดูแลและปรับปรุงอยู่เสมอ comment ที่ถูกทิ้งไว้จนเก่าและไม่ตรงกับ code ปัจจุบัน อาจสร้างความเสียหายได้มากกว่าการไม่มี comment เลย
comment ที่ดีคือเครื่องหมายของโปรแกรมเมอร์ที่ใส่ใจและเห็นอกเห็นใจผู้อื่น มันไม่เพียงช่วยให้ทีมทำงานง่ายขึ้น แต่ยังช่วยให้ตัวเราในอนาคตสามารถกลับมาอ่านและทำความเข้าใจโค้ดของตัวเองได้อย่างรวดเร็วและมีความสุขด้วย 😀