ตัวอย่างของความคิดเห็นที่บอกคุณว่าทำไมแทนที่จะเป็นอย่างไรหรืออะไร [ปิด]


78

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

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

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

มีคำถามมากมายเกี่ยวกับว่าความคิดเห็นดีหรือไม่ดี แต่ไม่มีใครตอบคำถามเฉพาะว่าอะไรเป็นตัวอย่างที่ดีของความคิดเห็นที่บอกคุณว่าทำไม


36
บางครั้งความคิดเห็นที่ดีที่สุดก็ไม่ใช่ที่อยู่ ฉันเคยพบรหัสที่ซับซ้อนเล็กน้อยซึ่งดูเหมือนว่ามันจะง่ายขึ้น ความคิดเห็นอธิบายว่าทำไมการทำให้เข้าใจง่ายที่เห็นได้ชัดไม่ทำงานในอินสแตนซ์นี้โดยเฉพาะ (เพราะนักพัฒนาดั้งเดิมได้ลองไปแล้ว)
Dan Pichelman

6
There are many questions on whether comments are good or bad, but no one that addresses the specific question of what are good examples of comments that tell you WHY. หากทุกคนมีตัวอย่างที่ถูกต้องนั่นเป็นคำตอบที่ถูกต้องทั้งหมด รูปแบบของเว็บไซต์นี้เพื่ออำนวยความสะดวกให้กับกระบวนการถาม - ตอบที่ไม่ได้สร้างคำตอบทั้งหมดเท่ากัน
David Kaczynski

จุดที่ดี @ david-kaczynski คุณแนะนำอะไร?
rick

1
จากด้านบนของหัวของฉันฉันไม่สามารถคิดวิธีที่จะวลีคำถามเพื่อให้ตัวอย่างเดียวหรือชั้นเชิงทั่วไปสามารถเป็นคำตอบที่ "ดีที่สุด" มีส่วนแชทของ p.se: chat.stackexchange.com/rooms/21/the-whiteboardแต่อาจมีฟอรัมที่ดีกว่าสำหรับคำถามของคุณ ในความเป็นธรรมดูเหมือนว่าคำถามของคุณได้รับการตอบรับเชิงบวกจากชุมชนที่นี่จึงอาจไม่คุ้มค่าที่จะกังวล คำแนะนำที่ดีที่สุดที่ฉันสามารถให้ได้ในการค้นหาตัวอย่างความคิดเห็นที่เป็นประโยชน์คือการเรียกดูที่เก็บ git สาธารณะยอดนิยม
David Kaczynski

คำตอบ:


62

ตัวอย่างที่พบบ่อยที่สุดและโดดเด่นที่สุดคือความคิดเห็นเกี่ยวกับวิธีแก้ไขต่างๆ ตัวอย่างเช่นอันนี้:

https://github.com/git/git/blob/master/compat/fopen.c :

/*
 *  The order of the following two lines is important.
 *
 *  FREAD_READS_DIRECTORIES is undefined before including git-compat-util.h
 *  to avoid the redefinition of fopen within git-compat-util.h. This is
 *  necessary since fopen is a macro on some platforms which may be set
 *  based on compiler options. For example, on AIX fopen is set to fopen64
 *  when _LARGE_FILES is defined. The previous technique of merely undefining
 *  fopen after including git-compat-util.h is inadequate in this case.
 */
#undef FREAD_READS_DIRECTORIES
#include "../git-compat-util.h"

คุณจะพบตัวอย่างเพิ่มเติมในแหล่ง Git และ Linux ทั้งสองโครงการพยายามปฏิบัติตามกฎนี้

ผมขอแนะนำที่จะปฏิบัติตามกฎนี้อย่างเคร่งครัดมากยิ่งขึ้นกับการบันทึกการกระทำ สำหรับความคิดเห็นของรหัสอาจเกิดขึ้นที่คุณแก้ไขรหัส แต่ลืมที่จะปรับปรุงความคิดเห็น ด้วยจำนวนรหัสในโครงการปกติจะรับประกันว่าจะเกิดขึ้นไม่ช้าก็เร็ว ในทางกลับกันบันทึกการกระทำจะเชื่อมโยงกับการเปลี่ยนแปลงเฉพาะและสามารถเรียกคืนได้โดยใช้ฟังก์ชัน "คำอธิบายประกอบ" / "ตำหนิ" ของระบบควบคุมเวอร์ชัน Git และ Linux อีกครั้งมีตัวอย่างที่ดี

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

  1. การเปลี่ยนแปลงที่ส่งทั้งหมดจะได้รับการตรวจสอบและบันทึกการกระทำเป็นสิ่งที่ต้องอธิบายการเปลี่ยนแปลงต่อผู้ตรวจสอบ
  2. เมื่อพบข้อผิดพลาดบันทึกที่เกี่ยวข้องจะถูกเรียกคืนโดยใช้ "pickaxe" หรือ "ตำหนิ" เพื่อหลีกเลี่ยงการย้อนกลับไปสู่พฤติกรรมที่ไม่ถูกต้องก่อนหน้านี้

(หมายเหตุ: ฉันใช้เวลามากที่สุด 10 นาทีในการค้นหาแบบสุ่มของ git repo เพื่อหาสองตัวอย่างนี้ดังนั้นจะแน่ใจได้ว่าจะหาได้ง่ายกว่านี้)


29

ความคิดเห็นที่จะบอกคุณว่าทำไมอธิบายถึงเหตุผลการใช้รหัส - ตัวอย่างเช่น:

// We need to sync the values if the temp <doodad> GUID matches one of the active <doodad>'s
// GUID, as the temp <doodad> has the most recent values according to the server and said 
// values might have changed since we added the <doodad>. We want a user to be able to <foo> 
// the <doodad> whenever, which means those values must be accurate.
for (doodad in doodads) {
    if ([doodad guid] == [tempDoodad guid]) {
        [doodad updateFromDoodad:tempDoodad];
        break;
    }
}

ความคิดเห็นที่บอกคุณว่าจะอธิบายสิ่งที่รหัสทำอย่างไร

// Loop through our <doodads> and check for a GUID match. If it matches, copy the new values
// on the <doodad> that matches 
for (doodad in doodads) {
    if ([doodad guid] == [tempDoodad guid]) {
        [doodad updateFromDoodad:tempDoodad];
        break;
    }
}

ความแตกต่างคือผู้ดูแลสามารถดูคนแรกและพูดว่า "โอ้นี่อาจจะล้าสมัย!" ในกรณีที่สองผู้ดูแลระบบกล่าวว่ามีความคิดเห็นที่ไม่ได้บอกอะไรเลยว่าโค้ดนั้นไม่เปิดเผย (สมมติว่าเป็นชื่อตัวแปรที่ดี)

นี่คือตัวอย่างชีวิตจริงของความคิดเห็นที่ว่าทำไมจากโค้ด iOS บางตัวที่ฉันทำงานในที่ที่เราต้องการเพื่อรับที่อยู่เกตเวย์ (หรือการคาดเดาที่สมเหตุสมผล) ฉันเพิ่งจะเหลือความคิดเห็นที่กล่าวถึงสิ่งต่าง ๆ เช่น "เริ่มต้นซ็อกเก็ตรับ" แต่ที่จะบอกผู้ดูแล (หรือในอนาคตฉัน) สิ่งที่เกิดขึ้นไม่ใช่ว่าทำไมฉันต้องทำกระบองแปลกนี้เพื่อรับที่อยู่เกตเวย์ใน ที่แรก.

/*
 We're going to do something really hacky here and use a custom partial
 implementation of traceroute to get our gateway IP address.

 [rant removed - irrelevant to the point]

 There's no good way to get at the gateway address of an iDevice
 right now. So, we have two options (per https://devforums.apple.com/message/644915#644915 ):
 1. Get at and parse the routing table (like netstat -rn, or route -n)
 2. Do a traceroute and grab the IP address for the first hop

 As far as I can tell, the former requires <sys/route.h> from the Mac OS X
 header files, which doesn't seem like a good idea to me. Also, there's a
 thread on the Apple Developer forums that seems to imply that header isn't
 in iOS for a reason (https://devforums.apple.com/message/774731#774731 ).

 So when we send our request with a TTL of one it will survive a single hop
 to the router and return, triumphant, with the router's IP address!

 Viva la kludge!

 PS: Original source was the below SO question, but I've modded it since then.
 http://stackoverflow.com/questions/14304581/hops-tracing-ttl-reciveform-on-ios/14304923#14304923
 */

// Default to using Google's DNS address. We used to try checking www.google.com
// if reachability reported we had internet, but that could still hang on routers
// that had no internet connectivity - not sure why.
const char *ip_addr = [kGoogleDNS UTF8String]; // Must be const to avoid undefined behavior
struct sockaddr_in destination,fromAddr;
int recv_sock;
int send_sock;

// ... more code follows

4
ตัวอย่างแรกคือ verbose มากเกินไปและรวมถึง "วิธี" มาก มันพูดเพียงแค่ "อัปเดต <doodads> จาก temp <doodad> เพื่อให้ผู้ใช้สามารถ <foo> ทุกครั้งที่ปลอดภัย" ส่วนที่เหลือเป็นเรื่องเล็กน้อยที่จะบ่งบอกถึงจากนี้หรือรหัส นอกจากนี้ "การแนะนำเรื่องเทพนิยาย" ในสี่ย่อหน้าแรกของตัวอย่างสุดท้ายนั้นไม่มีจุดหมายโดยสิ้นเชิง ฉันจะออกจาก "Viva la kludge!"; มันตลกและในที่สุด แต่จุดเริ่มต้นเป็นเพียงคำที่มากเกินไปที่เราต้องขุดผ่านก่อนที่จะไปถึงคำอธิบายที่แท้จริง
Jan Hudec

@JanHudec ปรับตามความคิดเห็นของคุณ ดูใช่มั้ย
thegrinner

15
หนึ่งในสิ่งที่ดีเกี่ยวกับตัวอย่างที่สองคือมันไม่เพียง แต่อธิบายว่าทำไมโค้ดทำงานในลักษณะเฉพาะ แต่ยังอธิบายว่าทำไมตัวเลือกอื่น ๆ ที่สมเหตุสมผลไม่ได้ถูกนำมาใช้ สิ่งนี้ทำให้โค้ดสามารถบำรุงรักษาได้มากขึ้นเนื่องจากคนต่อไปที่อ่านโค้ดและคิดว่า "ทำไมฉันไม่แยกวิเคราะห์ตารางเส้นทาง สามารถอ่านความคิดเห็นได้ นอกจากนี้คนที่ไม่มาด้วยเหตุผลที่ถูกต้องที่จะเปลี่ยนรหัสจะมีความมั่นใจมากขึ้นว่ามันปลอดภัยที่จะทำเช่นนั้น มิฉะนั้นผู้ดูแลจะถูกทิ้งให้กลัวว่าการเปลี่ยนแปลงใด ๆ จะล้มเหลวในสถานการณ์ (ไม่ทราบ) ซึ่งเป็นแรงบันดาลใจให้กระบอง
Brian

18

ฉันต้องการเริ่มต้นคำตอบของฉันด้วยคำพูดของ Jeff Atwood ในรหัสโพสต์บล็อกของเขาบอกคุณได้อย่างไรความเห็นบอกคุณทำไม :

ความคิดเห็นที่ดีที่สุดคือสิ่งที่คุณไม่ต้องการ

นอกจากนี้เขายังกล่าวว่า:

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

ฉันเห็นด้วยอย่างยิ่งและ ณ จุดนี้ฉันต้องเพิ่มสิ่งนั้นก่อนที่ฉันจะเริ่มสร้างรหัสได้ง่ายที่สุดเท่าที่จะเป็นไปได้ ดังนั้นในระหว่างการรันครั้งแรกก่อนที่จะทำการเพิ่มอีกครั้งทำไมความคิดเห็นช่วยได้มาก

ตัวอย่างเช่นหากใช้ลูปซ้อนกัน 3 วงพร้อมแฮชมิติ 2 มิติเพื่อเติมตารางวันธรรมดาขณะแยกวิเคราะห์ข้อมูลมันง่ายมากที่จะสูญเสียการติดตามสิ่งที่ทำโดยใครบางคนหรือแม้แต่ตัวคุณเองหากไม่ได้ดูสักสองสามสัปดาห์

[loop1]6oclock -> [loop2]Monday -> [loop3]stage 1 to 4
         -> tuesday-> stage 1 to 4
         ...
         -> Saturday -> stage 1 to 4
    7oclock -> Monday-> stage 1 to 4
        ....etc.

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

// added a zero before the actual day in order for the days always to be 2 digits long.
if( actualDayFuture < 10 ) 
{ 
     actualDayFuture = padIfSingleDigitDate(actualDayFuture); 
}

แม้แต่รหัสที่เรียบง่ายและชัดเจนก็ทำงานได้ดีกับความคิดเห็น เพียงเพื่อทำให้สิ่งต่าง ๆ ชัดเจนขึ้นชัดเจนขึ้นหรือเข้าใจง่ายขึ้นสำหรับเพื่อนร่วมงานและแม้แต่ตัวคุณเองในการบำรุงรักษาซอฟต์แวร์

แน่ใจว่า xp ระบุว่ามีโค้ดที่อธิบายตัวเองได้ แต่ความคิดเห็นหนึ่งบรรทัดทำร้ายหรือไม่?

ฉันพบว่ากฎต่อไปนี้จากบล็อกนี้มีประโยชน์มาก:

  • ทำความเข้าใจเนื้อหาก่อนที่จะเขียน
  • เขียนราวกับว่าผู้ชมของคุณเป็นนักเรียนระดับประถมสี่
  • คิดเกี่ยวกับวิธีที่ผู้อ่านอาจตีความคุณผิด

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

นอกจากนี้ยังมีข้อสงสัยเกี่ยวกับการเขียนโปรแกรมจำนวนมากที่เกิดขึ้นระหว่างการตรวจสอบและมันก็ไม่ชัดเจนเสมอไปว่าทำไมบางส่วนถูกเขียนเนื่องจากแม้ว่าบางส่วนของรหัสมีความสำคัญสำหรับโปรแกรมที่จะทำงานเนื่องจากข้อผิดพลาดใหญ่ ๆ . ดังนั้นเพื่อที่จะไม่ทำให้คุณเบื่อโดยสิ้นเชิงด้วย tl; dr ปิดด้วยคำพูดสุดท้ายจากacmqueue :

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


8
ในตัวอย่างที่สองของคุณคุณสามารถกำจัดความคิดเห็นทั้งหมดโดยการปรับโครงสร้างใหม่: actualDayFuture = padIfSingleDigitDate นี่เป็นเรื่องเล็กน้อย แต่ตัวอย่างที่แข็งแกร่งกว่าจะได้รับประโยชน์จากวิธีการนี้
Chris Cudmore

4
ฉันจะย้ายเงื่อนไขไปเป็นวิธีการเช่นกัน - อีกครั้งไม่ใช่สำหรับสิ่งเล็กน้อยดังนั้น แต่ฉันไม่สนใจความคิดเกี่ยวกับการขยายเหตุผลทั้งหมด ฉันจะไม่แทนที่ตัวอย่างดั้งเดิมของคุณเนื่องจากเป็นคำตอบที่ดีกว่าสำหรับคำถาม มันเป็นอีกด้านของการสำรวจทางเลือกอื่น ๆ
Chris Cudmore

1
โฆษณา "Sure xp ระบุว่ามีรหัสที่อธิบายตัวเอง แต่ความคิดเห็นหนึ่งบรรทัดทำร้ายหรือไม่": ความคิดเห็นดี แต่มีอันตรายจากการแสดงความคิดเห็นมากเกินไป ความคิดเห็นทุกบรรทัดเป็นสิ่งที่ใครบางคนอาจลืมอัปเดตเมื่อพวกเขาเปลี่ยนรหัส
Jan Hudec

1
วิธีที่ดีกว่าในการพูดแบบนี้คือ "ความคิดเห็นที่ดีที่สุดคือการขาดความคิดเห็น" ความคิดเห็นที่ไม่จำเป็น (แต่เขียนอยู่แล้ว) ไม่ใช่ความคิดเห็นที่ดี
Kaz

1
น่าสนใจว่ารหัสอ้างอิงมีint directionCode = (x > oldX) ? DIRECTIONCODE_RIGHT : (x > oldX) ? DIRECTIONCODE_LEFT : DIRECTIONCODE_NONE;ข้อผิดพลาด ... (x < oldX) ? DIRECTIONCODE_LEFT : DIRECTIONCODE_NONE;แน่นอนว่าควรจะเป็น แนวคิดข้อคิดเห็นที่ดี - รหัสไม่ถูกต้อง
chux

8

ฉันมักจะลดความคิดเห็นไปยังการอ้างอิงทั้งที่ฟังก์ชัน / รหัสบางอย่างมีการอธิบายอย่างละเอียดมากขึ้นหรือเพื่ออธิบายว่าทำไมเลือกวิธีการเขียนโปรแกรมบางอย่าง

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

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

ดังนั้น 'ทำไม' ควรให้เหตุผลกับตัวเลือกของคุณ


5
การอ้างอิงเป็นตัวอย่างที่ดี // วิธีนี้ใช้อัลกอริธึม furshclingeheimer เพื่อสร้างความเสียหายให้กับ foobit ดู http: // ...
Chris Cudmore

8

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

List<LightMap> maps = makeLightmaps(receivingModels);
TrianglePartitioner partition = new Octree(castingTriangles);
List<Photon> photons = firePhotons(lights, partition);

if (photons.Count > 0)
{
      PhotonPartitioner photonMap = new KDTree(photons);
      gatherPhotons(maps, photonMap, partition, lights);
}

รหัสนี้ไม่จำเป็นต้องแสดงความคิดเห็น ชื่อฟังก์ชั่นและประเภททำให้เข้าใจง่าย

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

double randomA = localGenerator.NextDouble();
double randomB = localGenerator.NextDouble();

//http://mathworld.wolfram.com/SpherePointPicking.html
double theta = 2 * Math.PI * randomA;
double phi = Math.Acos(2 * randomB - 1);

Vector3 randomDirection = new Vector3(Settings.ambientRayLength * (float)(Math.Cos(theta) * Math.Sin(phi)),
                                      Settings.ambientRayLength * (float)(Math.Sin(theta) * Math.Sin(phi)),
                                      Settings.ambientRayLength * (float)Math.Cos(phi));

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

Random random = new Random();
Parallel.For(0, maxPhotons, delegate(int photonIndex, ParallelLoopState state)
{
    ...
    //I don't actually care if this random number is unique between threads, threadsafty is not that big of a deal
    //  in this case and locking the random object could cause a lot of lock contention
    while (random.NextDouble() > reflectProbability)
    {
        ...
    }
    ...
}

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


มันมีเหตุผลที่จะอธิบายรหัสว่าไม่จำเป็นต้องแสดงความคิดเห็นเมื่อมีการแสดงความคิดเห็นนำหน้าWriteTextแทนที่จะเป็น//?

1
ดังที่ฉันได้กล่าวไว้ในคำตอบความคิดเห็นนั้นไม่จำเป็นแม้ว่าจะไม่มีคำสั่งพิมพ์ แต่ฉันได้ทำการแก้ไขเพื่อลบคำแถลงการพิมพ์เพื่อให้ชัดเจนยิ่งขึ้น
Chewy Gumball

5

มันอาจเป็นประโยชน์ในการรู้จัก "สาเหตุ" ชนิดต่าง ๆ - ที่สะดุดตาที่สุด:

  • เหตุผลที่รหัสที่ดูเหมือนซับซ้อนเกินไปจะไม่ทำงานหากลดความซับซ้อนลง (เช่น typecast ที่ดูไม่จำเป็นต้องใช้เพื่อให้แน่ใจว่ารหัสทำงานในบางกรณี)

  • เหตุผลที่การดำเนินการอย่างง่าย ๆ บางอย่างที่ดูอันตรายมีความปลอดภัยจริง ๆ (เช่น "รูทีนการดึงข้อมูลของเราจะรายงานรายการหุ่นจำลองที่ผ่านมาว่ามีน้อยกว่าอย่างอื่นและรายการหลังจากนั้นใหญ่กว่ารายการใด ๆ ที่ควรเรียงลำดับ ก่อนอื่นในลำดับที่เรียงขึ้นหรือลงที่สอดคล้องกันจะมีรายการอย่างน้อยหนึ่งรายการ

ในหลายกรณีความคิดเห็นของประเภทที่สองในส่วนหนึ่งของรหัสอาจ "จับคู่" กับความคิดเห็นของประเภทแรกในอีก (เช่น "ในขณะที่มันจะปรากฏขึ้นลำดับของการดำเนินการนี้จะง่ายจีน Fitz อาศัยประจำ Wongle ที่ไม่ถูก Woozled จนกระทั่งหลังจาก Bandersnatch ถูก Blarped ")


2

อย่าลืมว่าถ้าคุณเขียนโปรแกรมคุณไม่เพียงแค่พิมพ์สิ่งต่าง ๆ แบบสุ่มคุณกำลังทำอยู่เพราะคุณมีแบบจำลองของสิ่งที่คุณต้องการไม่ว่าจะเป็นในเอกสารทางการหรือในหัวของคุณ สิ่งที่อยู่ในหัวของคุณนั้นเหมือนของจริงเหมือนซอฟต์แวร์ / ข้อมูลในคอมพิวเตอร์ (และมีแนวโน้มที่จะมีข้อบกพร่อง)

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

// transform the x,y point location to the nearest hexagonal cell location
ix1 = (int)floor(0.5 + x + y/2);
iy1 = (int)floor(0.5 + y);

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

// to change to square cell locations, remove the "+ y/2" in the above code

ฉันคิดว่าวัตถุประสงค์ในการแสดงความคิดเห็นบางครั้งก็ถูกทอดทิ้ง


2
คำถามกำลังถามตัวอย่าง คุณสามารถเพิ่มตัวอย่างเพื่อให้คำตอบนี้มีประโยชน์มากกว่าหรือไม่
ไบรอัน Oakley

2
อันแรกของรหัสดูเหมือนเป็นตัวอย่างคลาสสิกของการอธิบาย "อะไร" สำหรับฉัน ไม่ใช่ว่ามันเป็นความคิดเห็นที่ไม่ดี แต่ฉันไม่คิดว่ามันจะตอบคำถามของ OP

@ จอน: หากความคิดเห็นไม่ได้อยู่ที่นั่นผู้อ่านสามารถดูสิ่งที่เกิดขึ้น แต่ไม่มีความคิดว่าทำไม
Mike Dunlavey

1
@ MikeDunlavey: ฉันไม่เห็นด้วย ฉันยังไม่มีความคิด - ทำไมคุณต้องการตำแหน่งเซลล์หกเหลี่ยมที่ใกล้ที่สุด อะไรคือวัตถุประสงค์ของการได้รับตำแหน่งนี้? จะมีผลอะไรหรือไม่ถ้าฉันลบสองบรรทัดนี้?

2

ไม่ใช่ความคิดเห็นของฉันทั้งหมดเป็นประเภท 'ทำไม' แต่มีอยู่มากมาย
นี่คือตัวอย่างจากไฟล์ต้นฉบับหนึ่ง (Delphi):

// For easier access to the custom properties:

function GetPrivate: Integer;   // It's an integer field in the external program so let's treat it like that here

// The below properties depend on the ones above or are calculated fields.
// They are kept up-to-date in the OnEventModified event of the TTSynchronizerStorage
// or in the ClientDataSet.OnCalcFields of the TcxDBSchedulerStorage.DataSource.DataSet
property IsModified       : Boolean   read GetIsModified   write SetIsModified;
property IsCatTT          : Boolean   read GetIsCatTT      write SetIsCatTT;
property IsSynced         : Boolean   read GetIsSynced     write SetIsSynced;

lLeftPos := pos(' - [',ASubject); // Were subject and [shiftnaam:act,project,cust] concatenated with a dash?

// Things that were added behing the ] we will append to the subject:

// In the storage the custom value must also be set for:
Self.SetCustomFieldValueByname(cCustFldIsCatTT,Result);

// When we show the custom fields in a grid, the Getters are not executed,
// because the DevEx code does not know about our class helpers.
// So we have two keep both properties synchronized ourselves:

// lNewMasterEvent was set to usUpdated, overwrite because we added:
if ARepair then
  lNewMasterEvent.CustUpdateStatus := usRecreated

// The source occurrence date may have bee changed. Using GetOriginalDate we can retrieve the original date,
// then use that for creating a target occurrence (and update its date):

lNewTTOccurrence.CustSyncEntryID := cSyncEntryID0;    // Backward compatibility with old sync methode

// Single event became recurring or vice versa; replace entire event

// In contradiction to CopySingleEventToTimeTell, CopyMasterEventToTimeTell does not have a ANewStatus parameter
// because master events are always added.

โปรดทราบว่า (ของฉัน) ทำไมความคิดเห็นมักจะนำหน้ารหัสที่จะทำ (ลงท้ายด้วยเครื่องหมายโคลอน)

ฉันมีความคิดเห็นอธิบายเฉพาะสิ่งที่เกิดขึ้นเช่นเมื่อกระบวนการมีหลายขั้นตอนซึ่งมีการจัดกลุ่มแบบลอจิคัล (และรหัสไม่ refactored เพื่อแสดงว่าโดยอัตโนมัติ) ฉันจะแสดงความคิดเห็นเช่น:

// Step 1. Initialization

1

ฉันเข้าใจว่าทำไมจึงเป็นเหตุผลว่าทำไมคุณถึงทำสิ่งที่แปลกหรือไร้เหตุผลเนื่องจากสถานการณ์ที่กำหนดทำให้ต้องทำเช่นนั้น วิธีสามารถมองเห็นได้ในรหัสของตัวเองไม่ว่าวิธีการที่แปลกก็คือแม้ว่ารหัสทำให้ไม่มี "ความรู้สึก" สิ่งที่อาจจะบอกที่ดีที่สุดในการเริ่มต้นของเอกสารชั้น / ฟังก์ชั่น เพื่อให้คุณเพิ่มWHYซึ่งคุณจะอธิบายอะไรที่ไม่รวมอยู่ใน HOW และ WHAT และวิธีแปลก ๆ ที่คุณต้องใช้เนื่องจากเหตุผลที่อยู่นอกเหนือการควบคุมของคุณ

แน่นอนว่าไม่ใช่กรณีนอกแผ่นดินยูนิคอร์นและสายรุ้ง ...

วิธีการ:

foreach($critters as $creature) {
   $creature->dance();
}

อะไร:

/* Dancing creatures v1.0
 * 
 * The purpose of this is to make all your critters do the funky dance.
 */

foreach($critters as $creature) {
  $creature->dance();
}

ทำไม:

// We had to store the items in an array of objects because of _____ (reason)
foreach($critters as $creature) {
   $creature->dance();
}

5
คำถามนี้ถามคำถามนี้อย่างไร
ริ้น

1
ในการอ้างถึง OP: "ดังนั้นกลับไปที่คำถาม: ถ้าความเห็นควรบอกคุณว่าทำไมนี่คือเหตุผลที่เรากำลังพูดถึงเรื่องนี้" และฉันตอบคำถามนั้น: ทำไมสิ่งที่พูดถึงคือเหตุผลของการดำรงอยู่ของ ชิ้นส่วนของรหัสที่ได้รับ
Juha Untinen

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

1
ฉันไม่คิดว่าความคิดเห็นเหล่านี้มีประโยชน์จริง ๆ หากลายเซ็นของฟังก์ชั่นของคุณเป็นcritters.dance()เช่นนั้นความคิดเห็นก็จะแสดงซ้ำอย่างชัดเจนและ "เราไม่สามารถทำให้มันทำงานด้วยวิธีอื่น ๆ ที่เราลองทำ" นั้นไม่ได้ช่วยอะไรเลย นอกจากนี้การพูดว่า "เราจะเรียกวิธีการสำหรับแต่ละวัตถุ" กำลังทำซ้ำสิ่งที่รหัสอย่างชัดเจนว่า
เบรนแดนลอง

1

ฉันเรียนรู้ที่จะเขียนข้อคิดเห็นใน C ++ headerfiles เสมอ (เนื่องจากมันไม่ชัดเจนว่าฟังก์ชั่นทำอะไรถึงแม้ว่าชื่อจะให้คำแนะนำที่ดี) โดยเฉพาะอย่างยิ่งถ้าคุณส่ง API ไปยังนักพัฒนาอื่น ๆ หรือใช้เครื่องมือสำหรับ autodoc เช่น doxygen

ดังนั้นสำหรับฉันความคิดเห็นทั่วไปดูเหมือนว่า

/*** Functionname
/*   What happens here
/*  [in] Params
/*  [out] params
/*** 

ครั้งเดียวที่ฉันใช้ทำไมความคิดเห็นเป็นสิ่งที่ยากต่อการเข้าใจและบางครั้งแม้แต่กับโปรแกรมเมอร์เช่น "อย่าแตะต้องสิ่งนี้เพราะ ... " หรือ "โปรแกรมจะล้มเหลวหากสายถูกลบ ... "

การแก้ปัญหาแฮ็กและพฤติกรรมแปลก ๆ มีคุณสมบัติตรงตามเกณฑ์ที่ทำไมในสายตาของฉัน ...

ตัวอย่างที่ดีและเฮฮามากคือ "วิธีแก้ไข" สำหรับรหัสที่เขียนโดยคนบางคนที่ชื่อ Richard ริชาร์ดคนอื่นห่อมันและอธิบายว่าทำไมในความคิดเห็น ... https://stackoverflow.com/a/184673/979785

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


7
ยกเว้นว่าเป็นคำถามที่เกี่ยวกับการแสดงความคิดเห็นไม่ได้เอกสาร พวกเขาเป็นสิ่งที่แตกต่างกันจริง ๆ ( documentationแท็กน่าเสียดาย แต่ก็ยังไม่สามารถใช้ได้กับคำถาม)
โทมัส

ขอโทษจริงที่ว่าในภาษาพื้นเมืองของฉันและความคิดเห็นเอกสารมีการใช้แทนกันและด้วยแท็กฉันคิดว่ามันใช้ได้สำหรับคำถามนี้เช่นกัน นั่นคือเหตุผลที่จะลงคะแนนเสียงจริงเหรอ?
AnyOneElse

2
คำถามจะถามสองสามครั้งเพื่อดูว่าทำไมความคิดเห็น แต่ตัวอย่างเดียวที่คุณรวมคือความคิดเห็นอะไร คนที่อ่านคำตอบตัวอย่างอาจเข้าใจผิดโดยตัวอย่างของคุณ คุณสามารถยกตัวอย่างของความคิดเห็นที่ว่าทำไม ?
ไบรอัน Oakley

แม้ว่าฉันจะบอกว่ามีน้อยมากทำไมในรหัสของฉันและฉันชื่อสองตัวอย่าง: แก้ไข ... นี่คือลิงค์ที่มีคุณสมบัติแน่นอนสำหรับ WHY
AnyOneElse

@ AnyOneElse ฉันไม่ได้ลงคะแนน มันอยู่ที่นั่นก่อนที่ฉันจะมาถึง
โทมัส

0

รหัสควรระบุแผนการดำเนินการ วิธีนั้นผู้ติดตามโปรแกรม (หรือคอมไพเลอร์) สามารถคิดได้ว่าจะทำอย่างไรและจะทำอย่างไร สิ่งที่แยกย่อยออกเป็นขั้นตอนที่ผู้ติดตามโปรแกรมสามารถติดตามได้ ขั้นตอนดั้งเดิมเป็นอย่างไร

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

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


3
คำถามถามตัวอย่างสองสามครั้ง คุณสามารถเพิ่มตัวอย่างในคำตอบเพื่อให้มีประโยชน์มากขึ้นได้ไหม?
ไบรอัน Oakley

0

มีปัญหานี้ในขณะนี้ลุยผ่านขั้นตอนการจัดเก็บและมุมมองกับรูปแบบข้อมูลที่ซับซ้อนและค่อนข้างซับซ้อน

เรามี (จำนวนมาก) เลือกเช่น "กรณีเมื่อ x.account ไม่ใช่โมฆะและ x.address ใน (เลือกที่อยู่จาก fedex) จากนั้น x.account อื่น y.account สิ้นสุด" ตลอดและคาดว่าจะได้ผลผลิตแม้ว่าจะไม่มีเวลา all เพื่ออ่านซอร์สโค้ดทั้งหมด และตัวอย่างนี้เรียงลำดับแบบสมเหตุสมผล แต่ก็ยังไม่อาจจำแนกได้

ความคิดเห็นที่อธิบายว่าทำไมถ้าใน fedex แล้ว x และถ้าไม่เช่นนั้น y - ฉายแสงให้ทั้งระบบและเมื่อเราอ่านพอแล้วเราก็เริ่มได้มัน และนี่ก็ง่ายกว่าและมีข้อความที่คล้ายกันนับร้อยหรือนับพันหัวใจของฉันเปล่งประกายอย่างอบอุ่นต่อผู้ที่ชื่นชอบประเภทจากปี 2007 คือใครที่ใส่สิ่งเหล่านั้นลงไปทำไม

ดังนั้นใช่รูปแบบข้อมูลที่ซับซ้อนและ veiws มีขนดกและขั้นตอนการจัดเก็บที่มีเส้นทางที่ถูกต้องหลายชื่อโปรดให้ Gd บอกเราว่าทำไม


0

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

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

// In principal, this should be ">=", as we may have data up to the account start
// date but not complete for that day; in practice, 98% of the time if we have
// data for the start date it *is* complete, and requerying it would be a waste
// of time.
while (endDate > accountStartDate)
    ...

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.