Software Design

Good Comment, Bad Comment?

เขียน comment code อย่างไรให้ดีมีคุณค่า ไม่ใช่แค่ภาระ

การออกแบบซอฟต์แวร์ที่ดีควรมี 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
tsx
1// 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
tsx
1// 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
tsx
1// 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 ที่ไม่ได้เกี่ยวกับงานโดยตรง แต่ก็ยังไม่มีเวลาเข้าไปแก้ ณ ตอนนั้น แต่ก็ไม่อยากให้ลืมกันไป เราก็ควรทำอะไรสักอย่างเพื่อนเตือนคนที่จะมาต่อจากนี้ เพื่อไม่ให้ตรงหลุมเดียวกับคุณ

ตัวอย่าง

tsx
1// 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 เราก็ควรลบเช่นเดียวกัน

tsx
1function getX() {
2  // return X 👈 delete it
3  return X
4}
5

แต่บางครั้งมันไม่ได้ตรงไปตรงแบบตัวอย่างด้านบน

tsx
1function 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 ทำอยู่

tsx
1function 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 ที่ดีคือเครื่องหมายของโปรแกรมเมอร์ที่ใส่ใจและเห็นอกเห็นใจผู้อื่น มันไม่เพียงช่วยให้ทีมทำงานง่ายขึ้น แต่ยังช่วยให้ตัวเราในอนาคตสามารถกลับมาอ่านและทำความเข้าใจโค้ดของตัวเองได้อย่างรวดเร็วและมีความสุขด้วย 😀

Enjoyed this post?

Get the latest bite-sized content delivered to your inbox.

We respect your privacy. Unsubscribe at any time.

Contents