Các ví dụ về ý kiến ​​cho bạn biết tại sao thay vì làm thế nào hoặc những gì? [đóng cửa]


78

Trước hết, trong câu hỏi này, tôi muốn tránh xa cuộc bút chiến về việc nhận xét mã nguồn là tốt hay xấu. Tôi chỉ đang cố gắng để hiểu rõ hơn ý nghĩa của mọi người khi họ nói về những bình luận cho bạn biết TẠI SAO, CÁI GÌ hay CÁCH NÀO.

Chúng ta thường thấy các hướng dẫn như "Nhận xét sẽ cho bạn biết TẠI SAO; bản thân mã sẽ cho bạn biết CÁCH". Thật dễ dàng để đồng ý với tuyên bố ở mức độ trừu tượng. Tuy nhiên, mọi người thường bỏ điều này như một giáo điều, và rời khỏi phòng mà không cần giải thích thêm. Tôi đã thấy điều này được sử dụng ở rất nhiều nơi và bối cảnh khác nhau, có vẻ như mọi người có thể đồng ý với câu khẩu hiệu, nhưng dường như họ đang nói về những điều khác nhau hoàn toàn.

Vì vậy, trở lại câu hỏi: nếu bình luận nên cho bạn biết TẠI SAO, đây là lý do TẠI SAO chúng ta đang nói về? Đây có phải là lý do tại sao đoạn mã đó tồn tại ở nơi đầu tiên? Đây có phải là những gì mà đoạn mã nên làm? Tôi thực sự sẽ đánh giá cao nếu ai đó có thể đưa ra một lời giải thích rõ ràng, và sau đó thêm một số ví dụ tốt (ví dụ xấu không thực sự cần thiết, nhưng được tự do thêm chúng để tương phản).

Có rất nhiều câu hỏi về việc bình luận là tốt hay xấu, nhưng không ai trả lời câu hỏi cụ thể về những ví dụ tốt về những bình luận nói với bạn TẠI SAO.


36
Đôi khi các ý kiến ​​tốt nhất giải quyết TẠI SAO KHÔNG. Tôi đã từng gặp một đoạn mã phức tạp trông giống như nó có thể dễ dàng đơn giản hóa. Nhận xét giải thích tại sao sự đơn giản hóa rõ ràng đó không hoạt động trong trường hợp cụ thể này (vì nhà phát triển ban đầu đã thử nó).
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. Nếu mọi người cung cấp một ví dụ hợp lệ, thì tất cả họ đều là câu trả lời đúng. Định dạng của trang web này là để tạo điều kiện cho quá trình hỏi đáp trong đó không phải tất cả các câu trả lời đều được tạo ra như nhau.
David Kaczynski

Điểm tốt, @ david-kaczynski. Bạn có đề nghị gì?
rick

1
Ngoài đỉnh đầu, tôi không thể nghĩ ra cách nào để diễn đạt câu hỏi sao cho một ví dụ hoặc chiến thuật tổng quát có thể là câu trả lời "tốt nhất". Có một phần trò chuyện của p.se: chat.stackexchange.com/rooms/21/the-whiteboard , nhưng có lẽ sẽ có một diễn đàn tốt hơn cho câu hỏi của bạn. Nói một cách công bằng, có vẻ như câu hỏi của bạn đang nhận được phản hồi tích cực từ cộng đồng ở đây, vì vậy có lẽ không đáng lo ngại. Lời khuyên tốt nhất tôi có thể đưa ra cho việc tìm kiếm các ví dụ về các bình luận hữu ích là duyệt các kho git công cộng phổ biến.
David Kaczynski

Câu trả lời:


62

Ví dụ phổ biến nhất và đặc biệt nhất là các bình luận xung quanh các cách giải quyết khác nhau. Ví dụ: cái này:

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"

Bạn chắc chắn sẽ tìm thấy nhiều ví dụ hơn trong các nguồn Git và Linux; cả hai dự án đều cố gắng tuân theo quy tắc này.

Tôi cũng khuyên bạn nên tuân theo quy tắc này thậm chí nghiêm ngặt hơn với nhật ký cam kết . Đối với nhận xét mã có thể xảy ra là bạn sửa mã, nhưng quên cập nhật nhận xét. Với số lượng mã trong dự án thông thường, nó được đảm bảo xảy ra sớm hay muộn. Mặt khác, nhật ký cam kết được gắn với thay đổi cụ thể và có thể được gọi lại bằng chức năng "chú thích" / "đổ lỗi" của hệ thống kiểm soát phiên bản. Một lần nữa Git và Linux có một số ví dụ tốt.

Nhìn ví dụ vào cam kết này . (không sao chép ở đây, nó quá dài). Nó có bốn đoạn chiếm gần như toàn bộ trang (và một chút trên màn hình) mô tả chính xác những gì sai và tại sao nó sai và hơn là tiếp tục và sửa đổi tất cả các dòng SIX. Họ sử dụng những bình luận như thế này cho hai mục đích:

  1. Tất cả các thay đổi đã gửi được xem xét và nhật ký cam kết là những gì phải giải thích về thay đổi cho người đánh giá.
  2. Khi tìm thấy lỗi, các nhật ký có liên quan được truy xuất bằng cách sử dụng "pickaxe" hoặc "đổ lỗi" để tránh hoàn nguyên hành vi không chính xác trước đó.

(lưu ý: tôi mất tối đa 10 phút duyệt ngẫu nhiên git repo để đưa ra hai ví dụ này, vì vậy chắc chắn sẽ dễ dàng tìm thấy nhiều hơn ở đó)


29

Một nhận xét cho bạn biết lý do giải thích lý do đằng sau mã - ví dụ:

// 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;
    }
}

Một bình luận cho bạn biết làm thế nào giải thích những gì mã làm.

// 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;
    }
}

Sự khác biệt là một người bảo trì có thể nhìn vào cái đầu tiên và nói, "Ồ, vậy cái này có thể đã lỗi thời!" Trong trường hợp thứ hai, nhà bảo trì cho biết có một nhận xét không cho bạn biết bất cứ điều gì mà bản thân mã không tiết lộ (giả sử tên biến tốt).

Đây là một ví dụ thực tế về nhận xét tại sao, từ một số mã iOS tôi đã làm việc ở nơi chúng tôi cần để có địa chỉ cổng (hoặc đoán hợp lý cho nó). Tôi có thể vừa để lại những bình luận có nội dung như "Khởi tạo ổ cắm nhận", nhưng điều đó sẽ chỉ cho người bảo trì (hoặc tương lai tôi) biết chuyện gì đang xảy ra, chứ không phải tại sao tôi phải thực hiện công cụ lạ này để lấy địa chỉ cổng vào địa điểm đầu tiên.

/*
 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
Ví dụ đầu tiên quá dài dòng và bao gồm phần lớn "làm thế nào". Nó chỉ nói "Cập nhật <hình vẽ> từ temp <doodlead> để người dùng có thể <foo> an toàn bất cứ khi nào." Phần còn lại là tầm thường để ngụ ý từ mã này hoặc mã. Ngoài ra "giới thiệu câu chuyện cổ tích" trong bốn đoạn đầu của ví dụ cuối là hoàn toàn vô nghĩa. Tôi sẽ rời khỏi "Viva la kydge!"; thật buồn cười và cuối cùng Nhưng sự khởi đầu chỉ là quá nhiều từ người ta phải tìm hiểu kỹ trước khi đi đến lời giải thích thực tế.
Jan Hudec

@JanHudec Điều chỉnh theo phản hồi của bạn. Nhìn về phải không?
thegrinner

15
Một trong những điều tốt đẹp về ví dụ thứ hai là nó không chỉ giải thích tại sao mã hoạt động theo một cách cụ thể, mà còn giải thích tại sao các lựa chọn thay thế hợp lý khác không được thực hiện. Điều này làm cho mã dễ bảo trì hơn nhiều, vì anh chàng tiếp theo đọc mã và nghĩ, "Tại sao tôi không thể phân tích cú pháp bảng định tuyến?" chỉ có thể đọc bình luận. Hơn nữa, một người nào đó đưa ra một lý do chính đáng để thay đổi mã sẽ tự tin hơn rằng an toàn để làm như vậy. Mặt khác, một người bảo trì sẽ sợ rằng bất kỳ thay đổi nào sẽ thất bại trong kịch bản (chưa biết) đã truyền cảm hứng cho bùn.
Brian

18

Tôi muốn bắt đầu câu trả lời của mình bằng một trích dẫn của Jeff Atwood trong bài đăng trên Blog của anh ấy Mã cho bạn biết làm thế nào, Nhận xét cho bạn biết lý do :

loại bình luận tốt nhất là những bình luận bạn không cần

Ông cũng nói rằng:

Trước tiên bạn nên cố gắng làm cho mã của bạn đơn giản nhất có thể để hiểu mà không cần dựa vào các nhận xét như một cái nạng. Chỉ tại điểm mà mã không thể được làm cho dễ hiểu hơn, bạn mới nên bắt đầu thêm nhận xét.

Tôi hoàn toàn đồng ý và tại thời điểm này tôi phải thêm rằng trước khi tôi có thể bắt đầu làm cho mã đơn giản nhất có thể, tôi làm cho mã hoạt động và sau đó bắt đầu tái cấu trúc. Vì vậy, trong lần chạy đầu tiên trước khi tái cấu trúc thêm lý do tại sao các bình luận giúp ích rất nhiều.

Ví dụ: nếu sử dụng 3 vòng lặp lồng nhau với hàm băm 2 chiều để điền vào bảng các ngày trong tuần trong khi phân tích dữ liệu, rất dễ để mất dấu vết của những gì đã được thực hiện bởi ai đó hoặc thậm chí chính bạn nếu không xem xét trong vài tuần và đột nhiên tái cấu trúc.

[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.

Phần trên là một ví dụ về cách 3 vòng lặp lồng nhau sẽ hoạt động trước khi tái cấu trúc.
Ngoài ra, giải thích một số điều kiện chi nhánh có thể giúp hiểu mã tốt hơn nhiều với những gì người ta đã nghĩ trong quy trình:

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

Ngay cả mã đơn giản và rõ ràng hoạt động tốt với ý kiến. Chỉ để làm cho mọi thứ rõ ràng hơn một chút, rõ ràng hơn hoặc dễ hiểu hơn cho các đồng nghiệp và thậm chí cho chính bạn trong việc duy trì phần mềm.

Chắc chắn xp tuyên bố có mã tự giải thích, nhưng nhận xét một dòng có gây tổn thương không?

Tôi cũng thấy các quy tắc sau từ blog này rất hữu ích:

  • Hiểu tài liệu trước khi viết
  • Viết như thể khán giả của bạn là một học sinh lớp bốn
  • Hãy suy nghĩ về cách độc giả có thể hiểu sai về bạn

Bất cứ ai phải quay lại mã của riêng họ hoặc ai đó elses hoặc thậm chí mã kế thừa đều biết rằng đó có thể là một vấn đề đau đầu. Vì vậy, thay vì lười biếng hoặc cố gắng trở thành một lập trình viên uber trong việc không bình luận bất cứ điều gì hoặc rất ít, tại sao không tạo ra một bugger của riêng bạn hoặc một số người nghèo, người phải duy trì mã của bạn, cuộc sống tương lai dễ dàng hơn nhiều bằng cách tuân theo các quy tắc được trích dẫn.

Ngoài ra, nhiều phần mô tả lập trình bị nghi ngờ trong quá trình đánh giá và không hiểu tại sao một số phần được viết như chúng ngay cả khi một số phần mã là quan trọng để chương trình hoạt động do lỗi chính được tìm thấy vì mã được sử dụng trong nhiều năm . Vì vậy, để không làm bạn chán nản hoàn toàn với một tl; dr gần với một trích dẫn cuối cùng từ acmqueue :

Tài liệu trước, rõ ràng và rộng rãi là yếu tố chính trong việc tạo ra phần mềm có thể tồn tại và thích nghi. Tài liệu theo tiêu chuẩn cao sẽ giảm thời gian phát triển, giúp công việc tốt hơn và cải thiện điểm mấu chốt. Thật khó để yêu cầu nhiều hơn thế từ bất kỳ kỹ thuật.


8
Trong ví dụ thứ hai của bạn, người ta có thể loại bỏ các bình luận hoàn toàn bằng cách tái cấu trúc: factDayFuture = pad IfSingleDigitDate (factDayFuture); Điều này là tầm thường, nhưng một ví dụ mạnh mẽ hơn sẽ được hưởng lợi từ phương pháp này.
Chris Cudmore

4
Tôi đã có thể chuyển điều kiện vào phương pháp là tốt. - Một lần nữa, không phải vì một cái gì đó quá tầm thường, nhưng nó cho phép tôi bỏ qua suy nghĩ về việc đệm logic hoàn toàn. Tôi sẽ không thay thế ví dụ ban đầu của bạn, vì đó là một câu trả lời tốt hơn cho câu hỏi. Đó là nhiều hơn một lưu ý phụ, khám phá các lựa chọn thay thế khác.
Chris Cudmore

1
Quảng cáo "Chắc chắn xp tuyên bố có mã tự giải thích, nhưng nhận xét một dòng có bị tổn thương không?": Nhận xét là tốt, nhưng cũng có nguy cơ bình luận quá mức. Mỗi dòng bình luận là một thứ mà ai đó có thể quên cập nhật khi họ thay đổi mã.
Jan Hudec

1
Một cách tốt hơn để nói điều này là "Loại bình luận tốt nhất là sự vắng mặt của nhu cầu bình luận". Những bình luận không cần thiết (nhưng dù sao cũng được viết) không phải là những bình luận tốt.
Kaz

1
Điều thú vị là mã tham chiếu int directionCode = (x > oldX) ? DIRECTIONCODE_RIGHT : (x > oldX) ? DIRECTIONCODE_LEFT : DIRECTIONCODE_NONE;bị lỗi. Chắc chắn là nên ... (x < oldX) ? DIRECTIONCODE_LEFT : DIRECTIONCODE_NONE;. Ý kiến ​​bình luận tốt - mã xấu.
chux

8

Tôi có xu hướng giảm nhận xét cho các tham chiếu trong đó một chức năng / mã nhất định được giải thích kỹ hơn hoặc để giải thích tại sao một cách lập trình nhất định được chọn.

Xem xét rằng các lập trình viên khác có kỹ năng tương tự sử dụng hoặc đọc mã của bạn, điều quan trọng là nhận xét nếu bạn sử dụng một cách khác so với dự kiến ​​để đạt được một cái gì đó. Vì vậy, bạn có thể giải thích trong một nhận xét tại sao bạn chọn cách này.

Chẳng hạn, nếu bạn có thể sử dụng hai cảm biến khác nhau trên thiết bị Android và một trong số chúng không phù hợp với nhu cầu của bạn, bạn có thể giải thích trong nhận xét tại sao bạn chọn cảm biến khác.

Vì vậy, "tại sao" nên đưa ra một lý do cho các lựa chọn của bạn.


5
Tài liệu tham khảo là một ví dụ tuyệt vời. // Phương thức này sử dụng thuật toán furshclingeheimer để sắp xếp lại foobit. Xem http: // ...
Chris Cudmore

8

Nhận xét sẽ cho bạn biết những gì mã không, không nhất thiết phải bị xóa bởi TẠI SAO , CÁCH , hoặc . Nếu bạn có tên tốt và có chức năng phân định tốt, hoàn toàn có khả năng mã có thể cho bạn biết chính xác những gì đang diễn ra. Ví dụ:

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);
}

Mã này thực sự không cần bình luận. Tên hàm và kiểu làm cho nó dễ hiểu.

Tuy nhiên, đôi khi, có thể khó hoặc không thể thực sự tạo ra mã thông thạo như trên. Ví dụ: đoạn mã tiếp theo là để tìm một điểm ngẫu nhiên thống kê trên một hình cầu. Toán học là khá mờ đục, do đó, một bình luận với một liên kết để giải thích là để giúp kể CÁCH nó hoạt động. Điều này có thể được bọc trong một chức năng để nói nó mà không cần một lời nhận xét nếu cần nhiều hơn một lần, nếu không tiêu đề liên kết cũng giúp trong bộ phận đó.

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));

Một ví dụ khác khi các bình luận cho bạn biết những gì mã không phải là để giải thích một quyết định. Trong ví dụ tiếp theo, mã không khóa một biến không phải luồng cục bộ bên trong một đoạn mã được xâu chuỗi. Có một lý do cho điều này và bình luận giải thích TẠI SAO . Nếu không có bình luận, nó có thể được coi là một lỗi, hoặc thậm chí không được chú ý.

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)
    {
        ...
    }
    ...
}

Có lẽ, có thể được cải thiện để nói tại sao đối tượng ngẫu nhiên không được tạo bên trong vòng lặp song song ở vị trí đầu tiên. Nếu không có lý do, nó cũng có thể khiến ai đó xuất hiện và nhận ra rằng toàn bộ ý tưởng là ngu ngốc và là một nơi tốt để tái cấu trúc.


Có hợp lý để mô tả mã là không cần bình luận khi các bình luận đi trước WriteTextchứ không phải là //?

1
Như tôi đã nói trong câu trả lời, các bình luận là không cần thiết ngay cả khi không có câu lệnh in, tuy nhiên tôi đã chỉnh sửa nó để xóa các câu lệnh in để làm cho điểm rõ ràng hơn.
Chewy Gumball

5

Có thể hữu ích để nhận ra các loại "tại sao" khác nhau - đáng chú ý nhất là:

  • Những lý do mà mã có vẻ quá phức tạp sẽ không hoạt động nếu được đơn giản hóa (ví dụ: một kiểu chữ dường như không cần thiết có thể cần thiết để đảm bảo mã hoạt động trong một số trường hợp góc).

  • Lý do một số thao tác đơn giản đặc biệt có vẻ nguy hiểm thực sự an toàn (ví dụ: "Thói quen tìm nạp dữ liệu của chúng tôi sẽ báo cáo một mục vật phẩm giả quá khứ là ít hơn bất kỳ thứ gì khác và mục sau đó là lớn hơn; bất kỳ mục nào nên sắp xếp trước một thứ tự khác, trong một chuỗi tăng dần hoặc giảm dần nhất quán, sẽ có ít nhất một mục nữa (có thể là giả) theo sau nó ").

Trong nhiều trường hợp, một nhận xét về loại thứ hai trong một phần của mã có thể "khớp" với một nhận xét về loại thứ nhất trong một loại khác (ví dụ: "Trong khi nó xuất hiện chuỗi hoạt động này có thể được đơn giản hóa, thói quen Fitz dựa vào Wongle không bị Woozled cho đến sau khi Bandersnatch bị thổi bay. ")


2

Đừng quên, nếu bạn đang viết một chương trình, bạn không chỉ gõ ngẫu nhiên, bạn đang làm điều đó bởi vì bạn có một mô hình về những gì bạn muốn , cho dù đó là trong một tài liệu chính thức hay chỉ trong đầu bạn. Công cụ trong đầu của bạn giống như phần mềm / dữ liệu trong máy tính (và có khả năng chứa lỗi).

Ai đó đang đọc mã của bạn có thể không có mô hình đó trong đầu, vì vậy các bình luận có thể phục vụ để cho họ biết mô hình đó là gì và mã liên quan đến nó như thế nào. Tôi nghĩ đó là những gì có nghĩa là "tại sao". Chắc chắn là tốt để làm cho bản thân mã tự giải thích nhất có thể, nhưng điều đó không phải lúc nào cũng đủ tốt. Thí dụ:

// 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);

Trên hết, mô hình thay đổi theo thời gian và những thay đổi đó phải được chuyển sang mã. Vì vậy, các ý kiến ​​không chỉ cần nói "tại sao" một cái gì đó trong mã, mà còn quan trọng như thế nào để thay đổi nó để đáp ứng với những thay đổi mô hình dự đoán. Thí dụ:

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

Tôi nghĩ rằng mục đích cho ý kiến ​​đôi khi bị bỏ qua.


2
Câu hỏi là hỏi ví dụ. Bạn có thể thêm một ví dụ để làm cho câu trả lời này hữu ích hơn?
Bryan Oakley

2
Đoạn mã đầu tiên trông giống như một ví dụ kinh điển về việc giải thích "cái gì" với tôi. Không phải đó là một bình luận xấu, nhưng tôi không nghĩ nó trả lời câu hỏi của OP.

@Jon: Nếu bình luận không có ở đó, người đọc có thể thấy những gì đang xảy ra, nhưng không biết tại sao.
Mike Dunlavey

1
@MikeDunlavey: Tôi không đồng ý. Tôi vẫn không biết - tại sao bạn muốn vị trí ô lục giác gần nhất? Là gì mục đích của nhận vị trí này? Nó có ảnh hưởng gì không nếu tôi xóa hai dòng này?

2

Không phải tất cả các nhận xét của tôi thuộc loại 'tại sao', nhưng nhiều ý kiến ​​là như vậy.
Đây là những ví dụ từ một tệp nguồn (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.

Lưu ý rằng (của tôi) tại sao các bình luận thường đi trước mã sẽ thực hiện nó (do đó kết thúc bằng dấu hai chấm).

Tôi có một số ý kiến ​​chỉ giải thích những gì đang xảy ra, ví dụ: khi một quy trình có nhiều bước có một nhóm logic (và mã không được tái cấu trúc để hiển thị điều đó một cách tự động), tôi sẽ bình luận như sau:

// Step 1. Initialization

1

Tôi hiểu TẠI SAO là lý do tại sao bạn làm điều gì đó theo một cách có thể kỳ lạ hoặc có thể phi logic, do hoàn cảnh nhất định đòi hỏi nó phải được thực hiện. Các CÁCH thể được nhìn thấy trong mã riêng của mình, bất kể như thế nào kỳ quặc đó là, ngay cả khi các mã làm cho không có "cảm giác". Các có lẽ là nói tốt nhất trong phần đầu của tài liệu lớp / chức năng. Vì vậy, điều đó khiến bạn thêm vào TẠI SAO , nơi bạn giải thích bất cứ điều gì không có trong CÁCH và CÁI GÌ và những cách đặc biệt bạn cần thực hiện do những lý do ngoài tầm kiểm soát của bạn.

Tất nhiên không phải lúc nào cũng vậy, bên ngoài vùng đất của kỳ lân và cầu vồng ...

LÀM SAO:

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

GÌ:

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

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

TẠI SAO:

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

5
Làm thế nào để trả lời câu hỏi này?
gnat

1
Để trích dẫn OP: "Vì vậy, hãy quay lại câu hỏi: nếu bình luận nên nói với bạn TẠI SAO, đây là lý do TẠI SAO chúng ta đang nói về điều gì?", Và tôi đã trả lời câu hỏi đó: TẠI SAO được nói đến là lý do cho sự tồn tại của đoạn mã đã cho.
Juha Untinen

1
Câu hỏi đặc biệt yêu cầu ví dụ một vài lần. Bạn có thể thêm một ví dụ cho câu trả lời này để làm cho nó hữu ích hơn không?
Bryan Oakley

1
Tôi không nghĩ một trong hai ý kiến ​​này thực sự hữu ích. Nếu chữ ký của hàm của bạn là critters.dance(), thì bình luận chỉ lặp lại điều hiển nhiên và "Chúng tôi không thể làm cho nó hoạt động với bất kỳ cách nào khác mà chúng tôi đã thử" là hoàn toàn không có ích. Ngoài ra, nói rằng "chúng tôi sẽ gọi phương thức cho từng đối tượng" đang lặp lại những gì mã nói rất rõ ràng.
Brendan Long

1

Tôi đã học cách LUÔN viết bình luận trong các tiêu đề C ++ (vì không phải lúc nào hàm này cũng rõ ràng, mặc dù tên này cho một gợi ý hay) đặc biệt là nếu bạn chuyển API cho các nhà phát triển khác hoặc sử dụng công cụ cho autodoc như doxygen.

Vì vậy, với tôi một nhận xét điển hình trông giống như

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

Lần duy nhất tôi sử dụng TẠI SAO các bình luận là những thứ khó nắm bắt và đôi khi ngay cả với lập trình viên, như "ĐỪNG CHẠM VÀO NÀY! Bởi vì ..." hoặc "CHƯƠNG TRÌNH S CR RÚT TIỀN NẾU TUYỆT VỜI ..."

Cách giải quyết, hack và hành vi lạ đủ tiêu chuẩn TẠI SAO trong mắt tôi ...

Một ví dụ rất hay và thậm chí vui nhộn là "cách giải quyết" này đối với một số mã sai lầm được viết bởi một người tên Richard, một người khác đã gói nó và giải thích lý do tại sao trong các bình luận ... https://stackoverflow.com/a/184673/979785

Thật không may, có một vài lần, bạn buộc phải quấn bull **** vì bạn không thể chạm vào bản gốc, vì "nó luôn như vậy" hoặc bạn không có quyền truy cập hoặc ... tốt, bạn không có thời gian để sửa bản gốc cho mục đích không thực sự đủ điều kiện cho chi phí chung.


7
Ngoại trừ câu hỏi là về ý kiến , không phải tài liệu . Chúng thực sự là những thứ khác nhau ( documentationthẻ rất đáng tiếc nhưng vẫn không áp dụng cho câu hỏi).
Thomas

Vâng, thực tế là, trong nhận xét ngôn ngữ bản địa và nhận xét tài liệu của tôi được sử dụng thay thế cho nhau và vì vậy với thẻ tôi giả sử nó có thể áp dụng cho câu hỏi này. Đó thực sự là một lý do để downvote?
AnyOneElse

2
Câu hỏi hỏi một vài lần cho các ví dụ về lý do tại sao bình luận, nhưng ví dụ duy nhất bạn đưa vào là một bình luận . Mọi người lướt qua các câu trả lời cho các ví dụ có thể bị đánh lừa bởi ví dụ của bạn. Bạn có thể cho một ví dụ về một lý do tại sao bình luận?
Bryan Oakley

mặc dù tôi đã nói rằng có rất ít TẠI SAO trong mã của tôi và tôi đã đặt tên cho hai ví dụ: EDITED ... đây là một liên kết, điều đó chắc chắn đủ điều kiện cho TẠI SAO
AnyOneElse

@AnyOneElse Tôi không downvote. Nó đã ở đó trước khi tôi đến.
Thomas

0

Mã được cho là để xác định kế hoạch thực hiện. Bằng cách đó, người theo dõi chương trình (hoặc trình biên dịch) có thể tìm ra phải làm gì và làm như thế nào. Những gì được chia thành các bước mà người theo dõi chương trình có thể làm theo. Các bước nguyên thủy là như thế nào.

Ý định của coder là một vấn đề khác. Trong mã đơn giản, rõ ràng, đơn giản, ý định là rõ ràng. Bất kỳ người đọc thành thạo hợp lý nào của con người sẽ đi đến mục đích của một khối mã, chỉ bằng cách đọc mã. Hầu hết các mã nên đọc như thế này.

Đôi khi, mối quan hệ giữa ý định và kế hoạch là tối nghĩa. Mã tiết lộ những gì và làm thế nào, nhưng không phải tại sao. Đó là khi ý kiến ​​tiết lộ ý định là đáng giá. Ý định của lập trình viên là tại sao.


3
Câu hỏi hỏi một vài lần cho các ví dụ. Bạn có thể thêm một ví dụ cho câu trả lời của bạn để làm cho nó hữu ích hơn không?
Bryan Oakley

0

Có vấn đề này ngay bây giờ lội qua các thủ tục và quan điểm được lưu trữ đối với một mô hình dữ liệu phức tạp và hơi phức tạp.

Chúng tôi có (rất nhiều) các lựa chọn như "Trường hợp khi x.account không phải là null và x.address trong (chọn địa chỉ từ fedex) sau đó x.account khác y.account end" và năng suất được dự kiến ​​mặc dù không có thời gian tại tất cả để đọc tất cả các mã nguồn. Và ví dụ này có vẻ hợp lý, nhưng nó vẫn không thể hiểu được.

Các ý kiến ​​giải thích tại sao nếu trong fedex thì x và nếu không thì y - sẽ làm sáng tỏ toàn bộ hệ thống và khi chúng ta đọc đủ chúng, chúng ta bắt đầu hiểu. Và điều này đã được đơn giản hóa và có hàng trăm hoặc hàng ngàn câu nói tương tự. Trái tim tôi tỏa sáng nồng nhiệt đối với bất cứ ai mà nhà phát triển tử tế từ năm 2007 là người đưa ra những lý do đó.

Vì vậy, yeah, mô hình dữ liệu phức tạp phức tạp và veiws lông và thủ tục được lưu trữ với nhiều đường dẫn được đặt tên hợp lệ, xin vui lòng cho tình yêu của Gd cho chúng tôi biết lý do tại sao.


0

Tôi chỉ viết bình luận này; đó là một ví dụ cụ thể về việc giải thích tại sao một dòng mã là nó và đặc biệt là tại sao tôi thay đổi nó.

Phương pháp này kiểm tra dữ liệu được lưu trữ và đánh giá xem liệu nó có hoàn thành cho đến ngày hôm nay ở một đầu hay không và qua ngày bắt đầu ở đầu kia.

// 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)
    ...

Như bạn có thể đoán, toán tử lớn hơn mức lớn hơn hoặc bằng. Nhận xét giải thích tại sao giá trị cũ có ý nghĩa và tại sao giá trị mới tốt hơn. Nếu bất cứ ai nhìn vào điều này trong tương lai, họ sẽ thấy rằng việc sử dụng ">" không phải là một sự giám sát, mà là một sự tối ưu hóa. Sau đó, họ có thể thay đổi hoặc rời khỏi nó, dựa trên nhu cầu tại thời điểm đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.