Jakie są przykłady komentarzy, które mówią ci, dlaczego zamiast jak i co? [Zamknięte]


78

Po pierwsze, w tym pytaniu chciałbym trzymać się z dala od polemiki dotyczącej tego, czy komentowanie kodu źródłowego jest dobre czy złe. Po prostu staram się lepiej zrozumieć, co ludzie mają na myśli, gdy mówią o komentarzach, które mówią DLACZEGO, CO I JAK.

Często widzimy wytyczne takie jak „Komentarze powinny WIEDZIEĆ DLACZEGO; sam kod powinien WIEDZIEĆ JAK”. Łatwo jest zgodzić się z tym stwierdzeniem na poziomie abstrakcyjnym. Jednak ludzie zwykle upuszczają to jak dogmat i wychodzą z pokoju bez dalszych wyjaśnień. Widziałem to używane w tak wielu różnych miejscach i kontekstach, że wygląda na to, że ludzie mogą zgodzić się na hasło, ale wydaje się, że mówią całkowicie o różnych sprawach.

Wróćmy zatem do pytania: jeśli komentarze powinny WAM powiedzieć, DLACZEGO, o co DLACZEGO mówimy? Czy to jest powód, dla którego ten fragment kodu istnieje? Czy to właśnie powinien robić ten fragment kodu? Byłbym naprawdę wdzięczny, gdyby ktoś mógł podać jasne wyjaśnienie, a następnie dodać kilka dobrych przykładów (złe przykłady nie są tak naprawdę potrzebne, ale można je dodać dla kontrastu).

Istnieje wiele pytań na temat tego, czy komentarze są dobre, czy złe, ale nikt nie odpowiada na konkretne pytanie, jakie są dobre przykłady komentarzy, które mówią DLACZEGO.


36
Czasami najlepsze komentarze odnoszą się do DLACZEGO NIE. Kiedyś napotkałem skomplikowany fragment kodu, który wyglądał, jakby można go było łatwo uprościć. W komentarzu wyjaśniono, dlaczego to oczywiste uproszczenie nie zadziałało w tym konkretnym przypadku (ponieważ pierwotny programista już go wypróbował).
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. Jeśli wszyscy podają prawidłowy przykład, wszystkie są poprawnymi odpowiedziami. Format tej witryny ma ułatwić proces pytań i odpowiedzi, w którym nie wszystkie odpowiedzi są sobie równe.
David Kaczyński

Dobra uwaga, @ David-Kaczyński. Co sugerujesz?
rick

1
Nie mogę wymyślić sposobu, aby sformułować pytanie, aby pojedynczy przykład lub ogólna taktyka mogła być „najlepszą” odpowiedzią. Istnieje część czatu p.se: chat.stackexchange.com/rooms/21/the-whiteboard , ale prawdopodobnie byłoby lepsze forum dla twojego pytania. Szczerze mówiąc, wygląda na to, że twoje pytanie otrzymuje pozytywną odpowiedź od społeczności tutaj, więc prawdopodobnie nie warto się martwić. Najlepszą radą, jaką mogę znaleźć, aby znaleźć przykłady użytecznych komentarzy, byłoby przeglądanie popularnych publicznych repozytoriów git.
David Kaczyński

Odpowiedzi:


62

Najczęstszym i najbardziej charakterystycznym przykładem są komentarze dotyczące różnych obejść. Na przykład ten:

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"

Na pewno znajdziesz więcej przykładów w źródłach Git i Linux; oba projekty starają się przestrzegać tej zasady.

Polecam również przestrzeganie tej zasady jeszcze bardziej surowo z dziennikami zatwierdzeń . W przypadku komentarzy do kodu może się zdarzyć, że naprawisz kod, ale zapomnij zaktualizować komentarz. Ilość kodu w zwykłym projekcie gwarantuje, że nastąpi to wcześniej czy później. Z drugiej strony dziennik zatwierdzeń jest powiązany z konkretną zmianą i można go przywołać za pomocą funkcji „adnotacji” / „obwiniania” systemu kontroli wersji. Znowu Git i Linux mają kilka dobrych przykładów.

Spójrz np. Na to zatwierdzenie . (nie kopiowanie tutaj, jest za długie). Ma cztery akapity zajmujące prawie całą stronę (i nieco przesadzone) opisujące, co dokładnie było nie tak i dlaczego było złe, a następnie ciągnie się i modyfikuje wszystkie duże SZEŚĆ linii. Używają takich komentarzy do dwóch celów:

  1. Wszystkie przesłane zmiany są sprawdzane, a dziennik zatwierdzania musi wyjaśnić recenzentowi zmianę.
  2. Po znalezieniu błędu odpowiednie dzienniki są pobierane przy użyciu „kilofu” lub „obwiniania”, aby uniknąć powrotu do wcześniejszego niepoprawnego zachowania.

(uwaga: wymyślenie tych dwóch przykładów zajęło mi co najwyżej 10 minut losowego przeglądania repozytorium git, więc z pewnością łatwiej byłoby znaleźć tam więcej)


29

Komentarz, który wyjaśnia, dlaczego wyjaśnia przyczyny kodu - na przykład:

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

Komentarz, który wyjaśnia, jak wyjaśnia działanie kodu.

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

Różnica polega na tym, że opiekun może spojrzeć na pierwszy i powiedzieć: „Och, więc to może być nieaktualne!” W drugim przypadku wspomniany opiekun ma komentarz, który nie mówi niczego, czego sam kod nie ujawnia (przy założeniu dobrych nazw zmiennych).

Oto prawdziwy przykład, dlaczego komentarz, z jakiegoś kodu iOS, nad którym pracowałem, gdzie potrzebowaliśmy uzyskać adres bramy (lub rozsądne przypuszczenie). Mogłem po prostu zostawić komentarze, które mówiły takie rzeczy jak „Zainicjuj gniazdo odbiorcze”, ale to tylko powiedziałoby opiekunowi (lub mnie w przyszłości), co się dzieje, a nie dlaczego musiałem robić tę dziwną kludge, aby uzyskać adres bramy w pierwsze miejsce.

/*
 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
Pierwszy przykład jest nadmiernie gadatliwy i zawiera wiele „jak”. Należy powiedzieć „Aktualizuj <doodads> z temp <doodad>, aby użytkownik mógł bezpiecznie <foo> go w każdej chwili.” Reszta jest trywialna, aby sugerować na podstawie tego lub kodu. Również „wprowadzenie do bajki” w pierwszych czterech akapitach ostatniego przykładu jest całkowicie bezcelowe. Zostawiłbym „Viva la kludge!”; to jest śmieszne i na końcu. Ale początek to po prostu zbyt wiele słów, które trzeba przekopać, zanim dojdzie się do właściwego wyjaśnienia.
Jan Hudec

@JanHudec Dostosowano zgodnie z Twoją opinią. Rozejrzyj się, prawda?
thegrinner

15
Jedną z fajnych rzeczy w drugim przykładzie jest to, że nie tylko wyjaśnia, dlaczego kod działa w określony sposób, ale także wyjaśnia, dlaczego nie zastosowano innych rozsądnych alternatyw. To sprawia, że ​​kod jest znacznie łatwiejszy w utrzymaniu, ponieważ następny facet, który czyta kod i myśli: „Dlaczego nie mogę po prostu przeanalizować tabeli routingu?” mogę po prostu przeczytać komentarz. Ponadto osoba, która ma pochodzić z uzasadnionych powodów, aby zmienić kod będzie bardziej przekonany, że jest to bezpieczne. W przeciwnym razie opiekun pozostawia obawy, że wszelkie zmiany zawiodą w (nieznanym) scenariuszu, który zainspirował kludge.
Brian

18

Chciałbym rozpocząć swoją odpowiedź cytatem napisanym przez Jeffa Atwooda w jego blogu Kod mówi wam jak, komentarze mówią wam dlaczego :

najlepszy rodzaj komentarzy to te, których nie potrzebujesz

Stwierdza również, że:

Najpierw powinieneś starać się, aby Twój kod był jak najprostszy do zrozumienia, nie polegając na komentarzach jako kuli. Dodawaj komentarze tylko w punkcie, w którym kod nie może być łatwiejszy do zrozumienia.

Całkowicie się zgadzam i w tym miejscu muszę dodać, że zanim zacznę upraszczać kod, sprawię, że kod będzie działał, a następnie zacznę refaktoryzację. Więc podczas pierwszego uruchomienia przed refaktoryzacją dodajmy, dlaczego komentarze bardzo pomagają.

Na przykład, jeśli używasz 3 zagnieżdżonych pętli z dwuwymiarowymi hashtabami, aby wypełnić tabelę dni tygodnia podczas analizowania danych, bardzo łatwo jest stracić kontrolę nad tym, co zostało zrobione przez kogoś lub nawet przez ciebie, jeśli nie spojrzysz na to przez kilka tygodni i nagle dokonujesz refaktoryzacji.

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

Górna część jest przykładem działania 3 zagnieżdżonych pętli przed refaktoryzacją.
Wyjaśnienie niektórych warunków rozgałęzienia może pomóc w lepszym zrozumieniu kodu dzięki temu, co myślałeś w tym procesie:

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

Nawet prosty i oczywisty kod działa dobrze z komentarzami. Żeby było trochę bardziej oczywiste, bardziej zrozumiałe lub łatwiejsze do zrozumienia dla kolegów, a nawet dla ciebie w utrzymaniu oprogramowania.

Pewnie xp twierdzi, że ma kod, który sam się wyjaśnia, ale czy komentarz w jednym wierszu boli?

Uważam również, że następujące zasady z tego bloga są bardzo pomocne:

  • Zrozum materiał zanim napiszesz
  • Pisz tak, jakby twoja publiczność była czwartą równiarką
  • Zastanów się, jak czytelnicy mogą cię źle interpretować

Każdy, kto musi wrócić do własnego kodu, kogoś innego, a nawet kodu starszego, wie, że może to być ból głowy. Więc zamiast być leniwym lub próbować być uber-koderem, nie komentując niczego lub bardzo mało, dlaczego nie uczynić swojego własnego lub jakiegoś biednego robala, który musi zachować twój kod, przyszłe życie o wiele łatwiej, przestrzegając podanych zasad.

Również wiele dokonanych decyzji programistycznych jest wątpliwych podczas przeglądów i nie zawsze jest jasne, dlaczego niektóre części zostały napisane tak, jak były, nawet jeśli niektóre sekcje kodu są niezbędne dla działania programu z powodu poważnego błędu wykrytego, ponieważ kod był używany przez lata . Aby nie zanudzić was wszystkich tl; dr zamknij ostatnią cytatem z acmqueue :

Wcześniejsza, przejrzysta i obszerna dokumentacja jest kluczowym elementem w tworzeniu oprogramowania, które przetrwa i dostosuje się. Dokumentowanie zgodnie z wysokimi standardami skróci czas opracowywania, poprawi pracę i poprawi wynik finansowy. Trudno prosić o więcej niż jakakolwiek technika.


8
W drugim przykładzie można całkowicie wyeliminować komentarze poprzez refaktoryzację: actualDayFuture = padIfSingleDigitDate (actualDayFuture); Jest to trywialne, ale bardziej solidny przykład skorzystałby z tego podejścia.
Chris Cudmore,

4
Wprowadziłbym również warunek do metody. - Znowu nie dla czegoś tak trywialnego, ale pozwala mi to całkowicie zignorować myślenie o logice wypełniania. Nie zastąpiłbym jednak twojego oryginalnego przykładu, ponieważ jest to lepsza odpowiedź na pytanie. To raczej dodatkowa uwaga, eksploracja innych alternatyw.
Chris Cudmore,

1
Reklama „Jasne, że xp stwierdza, że ​​kod sam się wyjaśnia, ale czy komentarz w jednym wierszu boli?”: Komentarze są dobre, ale istnieje również ryzyko nadmiernego komentowania. Każdy wiersz komentarza to taki, który ktoś może zapomnieć o aktualizacji po zmianie kodu.
Jan Hudec

1
Lepszym sposobem na powiedzenie tego jest: „Najlepszym rodzajem komentarza jest brak potrzeby komentarza”. Komentarze, które nie są potrzebne (ale i tak zostały napisane), nie są dobrymi komentarzami.
Kaz

1
Ciekawe, że w przywoływanym kodzie int directionCode = (x > oldX) ? DIRECTIONCODE_RIGHT : (x > oldX) ? DIRECTIONCODE_LEFT : DIRECTIONCODE_NONE;jest błąd. Z pewnością powinno być ... (x < oldX) ? DIRECTIONCODE_LEFT : DIRECTIONCODE_NONE;. Dobre pomysły na komentarze - zły kod.
chux,

8

Staram się redukować komentarze do odwołań, w których określona funkcjonalność / kod jest wyjaśniona dokładniej, lub wyjaśnić, dlaczego wybrano określony sposób programowania.

Biorąc pod uwagę, że inni programiści o podobnych umiejętnościach używają lub czytają Twój kod, ważne jest, aby skomentować, jeśli używasz innego niż oczekiwano sposobu osiągnięcia czegoś. Możesz więc w komentarzu wyjaśnić, dlaczego wybierasz ten sposób.

Na przykład, jeśli możesz użyć dwóch różnych czujników na urządzeniu z Androidem, a jeden z nich nie odpowiada Twoim potrzebom, możesz w komentarzu wyjaśnić, dlaczego wybrałeś drugi.

Zatem „dlaczego” powinno uzasadniać dokonane wybory.


5
Referencje są świetnym przykładem. // Ta metoda wykorzystuje algorytm furshclingeheimera do ronsteryzacji foobit. Patrz http: // ...
Chris Cudmore,

8

Komentarze powinny informować o tym, czego nie zawiera kod, niekoniecznie określany przez DLACZEGO , JAK i CO . Jeśli masz dobre nazwiska i dobrze określone funkcje, to całkiem możliwe, że kod dokładnie powie ci, co się dzieje. Na przykład:

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

Ten kod naprawdę nie wymaga komentarzy. Nazwy funkcji i typów ułatwiają ich zrozumienie.

Czasami jednak stworzenie płynnego kodu takiego jak powyższy może być trudne lub niemożliwe. Na przykład następny fragment kodu służy do znalezienia statystycznie losowego punktu na kuli. Matematyka jest dość nieprzejrzysta, więc komentarz z linkiem do objaśnienia ma pomóc WIEDZIEĆ, jak działa. Można to zawrzeć w funkcji, która mówi CO robi bez potrzeby komentowania, jeśli jest potrzebna więcej niż jeden raz, w przeciwnym razie tytuł linku również pomaga w tym dziale.

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

Innym przykładem, gdy komentarze mówią, czego nie robi kod, jest wyjaśnienie decyzji. W następnym przykładzie kod nie blokuje zmiennej nie-lokalnej w wątku kodu. Jest ku temu powód, a komentarz wyjaśnia DLACZEGO . Bez komentarza może to zostać uznane za błąd lub nawet nie zostać zauważone.

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

Być może można by usprawnić stwierdzenie, dlaczego losowy obiekt nie jest tworzony w pierwszej kolejności w pętli równoległej. Jeśli nie ma żadnego powodu, może również sprawić, że ktoś przyjdzie i zda sobie sprawę, że cały pomysł jest głupi i jest dobrym miejscem do refaktoryzacji.


Czy uzasadnione jest opisanie kodu jako niewymagającego komentarzy, gdy komentarze są poprzedzone znakiem WriteTextzamiast //?

1
Jak powiedziałem w odpowiedzi, komentarze nie są potrzebne, nawet jeśli nie było instrukcji drukowania, jednak edytowałem je, aby usunąć instrukcje drukowania, aby wyjaśnić sprawę.
Chewy Gumball

5

Pomocne może być rozpoznanie różnych rodzajów „dlaczego” - w szczególności:

  • Powody, dla których kod, który wydaje się zbyt skomplikowany, nie działałby, gdyby został uproszczony (np. Pozornie zbędny typecast może być konieczny, aby zapewnić działanie kodu w niektórych przypadkach narożnych).

  • Powody, dla których pewna szczególna prosta operacja, która wydaje się niebezpieczna, jest w rzeczywistości bezpieczna (np. „Nasza procedura pobierania danych zgłasza, że ​​element fikcyjny za ostatnim jest mniejszy niż cokolwiek innego, a element później jest większy; każdy element, który powinien zostać posortowany przed drugim, w spójnej kolejności rosnącej lub malejącej, będzie miał co najmniej jeszcze jeden (prawdopodobnie obojętny) element następujący po nim ”).

W wielu przypadkach komentarz drugiego typu w jednej części kodu może „pasować” do komentarza pierwszego typu w innym (np. „Chociaż wydaje się, że ta sekwencja operacji może być uproszczona, procedura Fitza opiera się na Wongle nie jest Woozled, dopóki Bandersnatch nie zostanie zlikwidowany. ")


2

Nie zapominaj, że pisząc program, nie piszesz tylko losowo, robisz to, ponieważ masz model tego, czego chcesz , czy to w oficjalnym dokumencie, czy tylko w twojej głowie. Rzeczy w twojej głowie są tak samo prawdziwe jak oprogramowanie / dane w komputerze (i równie dobrze mogą zawierać błędy).

Ktoś czytający Twój kod może nie mieć tego modelu w głowie, więc komentarze mogą mu powiedzieć, co to był model i jak kod się z nim odnosi. Myślę, że to właśnie oznacza „dlaczego”. Z pewnością dobrze jest, aby sam kod był jak najbardziej zrozumiały, ale to nie zawsze jest wystarczająco dobre. Przykład:

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

Ponadto model zmienia się w czasie i zmiany te należy przenieść do kodu. Komentarze muszą więc nie tylko powiedzieć „dlaczego” coś jest w kodzie, ale równie ważne, jak to zmienić w odpowiedzi na przewidywane zmiany modelu. Przykład:

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

Myślę, że cel komentarzy jest czasem zaniedbywany.


2
Pytanie dotyczy przykładów. Czy możesz dodać przykład, aby ta odpowiedź była bardziej przydatna?
Bryan Oakley,

2
Pierwsza część kodu wygląda dla mnie jak klasyczny przykład wyjaśniania „co”. Nie chodzi o to, że to zły komentarz, ale nie sądzę, że odpowiada na pytanie OP.

@Jon: Jeśli komentarza nie ma, czytelnik może zobaczyć, co się dzieje, ale nie ma pojęcia, dlaczego.
Mike Dunlavey

1
@MikeDunlavey: Nie zgadzam się. Nadal nie mam pojęcia - dlaczego chcesz najbliższej lokalizacji komórek heksagonalnych? Jaki jest cel uzyskania tej lokalizacji? Czy wpłynęłoby to na coś, gdybym usunął te dwa wiersze?

2

Nie wszystkie moje komentarze są typu „dlaczego”, ale wiele z nich jest.
Oto przykłady z jednego pliku źródłowego (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.

Zauważ, że (my) dlaczego komentarze zwykle poprzedzają kod, który to zrobi (stąd kończą się dwukropkiem).

Mam kilka komentarzy wyjaśniających tylko to, co się dzieje, np. Gdy proces ma wiele kroków, które mają logiczne grupowanie (a kod nie jest refaktoryzowany, aby pokazać to automatycznie), skomentuję:

// Step 1. Initialization

1

Rozumiem DLACZEGO powód, dla którego robisz coś w możliwie dziwny lub może nielogiczny sposób, z uwagi na okoliczności, które tego wymagają. JAK można zobaczyć w samym kodzie, bez względu na to, jak dziwne to jest, nawet jeśli kod nie ma „sens”. CO jest prawdopodobnie najlepiej powiedziano na początku dokumentacji klasy / funkcji. To pozostawia Cię z dodaniem DLACZEGO , gdzie wyjaśnisz wszystko, co nie jest zawarte w JAK i CO, a także szczególne sposoby, które musisz podjąć z powodów niezależnych od ciebie.

Oczywiście nie zawsze tak jest poza krajem jednorożców i tęcz ...

W JAKI SPOSÓB:

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

CO:

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

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

DLACZEGO:

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

5
Jak to odpowiada na zadane pytanie?
komar

1
Cytując OP: „Wróćmy zatem do pytania: jeśli komentarze powinny powiedzieć DLACZEGO dany fragment kodu.
Juha Untinen,

1
Pytanie kilka razy dotyczy konkretnych przykładów. Czy możesz dodać przykład do tej odpowiedzi, aby był bardziej przydatny?
Bryan Oakley,

1
Nie sądzę, aby którykolwiek z tych komentarzy był pomocny. Jeśli podpis twojej funkcji był critters.dance(), to komentarz po prostu powtarza to, co oczywiste, a „Nie mogliśmy zmusić go do działania w inny sposób, który próbowaliśmy” jest całkowicie nieprzydatny. Ponadto powiedzenie „wywołamy metodę dla każdego obiektu” bardzo wyraźnie powtarza ten kod.
Brendan Long

1

Nauczyłem się ZAWSZE pisać komentarze w plikach nagłówkowych C ++ (ponieważ nie zawsze jest jasne, CO robi funkcja, chociaż nazwa daje dobrą wskazówkę), zwłaszcza jeśli przekazujesz API innym programistom lub używasz narzędzia do autodoc, takiego jak doxygen.

Więc dla mnie typowy komentarz wygląda jak

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

Jedynym razem, kiedy użyłem DLACZEGO komentarzy, są rzeczy trudne do uchwycenia, a czasem nawet dla programisty, takie jak „NIE DOTKNIJ TEGO! Ponieważ ...” lub „PROGRAM ZOSTANIE ZAWIESZONY, JEŚLI LINIA JEST USUNIĘTA ...”

Obejścia, hacki i dziwne zachowania kwalifikują się do DLACZEGO kryteriów w moich oczach ...

Bardzo dobrym, a nawet przezabawnym przykładem jest to „obejście” jakiegoś pomieszanego kodu napisanego przez osobę o imieniu Richard, ktoś inny go zawinął i wyjaśnił dlaczego w komentarzach ... https://stackoverflow.com/a/184673/979785

Niestety zdarza się, że jesteś zmuszony owinąć byka ****, ponieważ nie możesz dotknąć oryginału albo dlatego, że „zawsze tak było”, albo nie masz dostępu, albo… no cóż, nie mam czasu, aby naprawić oryginał, ponieważ tak naprawdę nie kwalifikuje się do narzutu.


7
Tyle że pytanie dotyczy komentarzy , a nie dokumentacji . W rzeczywistości są to różne rzeczy ( documentationtag jest godny pożałowania, ale nadal nie dotyczy pytania).
Thomas

Przepraszam za to, że w moim ojczystym komentarzu i komentarzach do dokumentacji używa się zamiennie, więc przy tagu zakładałem, że dotyczy to również tego pytania. Czy to naprawdę powód, by głosować?
AnyOneElse,

2
Pytanie kilka razy pyta o przykłady, dlaczego komentarze, ale jedynym przykładem, który podajesz, jest komentarz jaki . Ludzie przeglądający odpowiedzi na przykłady mogą wprowadzać użytkownika w błąd. Czy możesz podać przykład, dlaczego komentarz?
Bryan Oakley,

chociaż powiedziałem, że w moim kodzie jest bardzo DLACZEGO, i wymieniłem dwa przykłady: EDYTOWANY ... oto link, który zdecydowanie kwalifikuje się do DLACZEGO
AnyOneElse

@AnyOneElse Nie głosowałem. Było tam, zanim przybyłem.
Thomas

0

Kod ma określać plan wykonania. W ten sposób obserwujący program (lub kompilator) może dowiedzieć się, co robić i jak to zrobić. To, co jest podzielone na etapy, które może śledzić programista. Prymitywne kroki to jak.

Cel kodera to inna sprawa. W prostym, jasnym i prostym kodzie zamiar jest oczywisty. Każdy rozsądnie biegły czytelnik ludzki dojdzie do celu bloku kodu, po prostu czytając kod. Większość kodów powinna czytać w ten sposób.

Czasami związek między intencją a planem jest niejasny. Kod ujawnia co i jak, ale nie dlaczego. Wtedy warto opowiedzić się o intencjach. Dlaczego programista zamierza.


3
Pytanie kilkakrotnie pyta o przykłady. Czy możesz dodać przykład do swojej odpowiedzi, aby był bardziej przydatny?
Bryan Oakley,

0

Mając teraz ten problem, przebijamy się przez procedury składowane i widoki w oparciu o złożony i nieco skomplikowany model danych.

Mamy (liczne) wymyślone selekcje, takie jak „Przypadek, gdy x.account nie ma wartości zerowej i x.adres w (wybierz adres z fedex), a następnie x.account inaczej y.account koniec” przez cały czas i oczekuje się produktywności, chociaż nie ma czasu na wszystko, aby przeczytać cały kod źródłowy. A ten przykład w pewnym sensie ma sens, ale wciąż jest nieprzenikniony.

Komentarze wyjaśniające, dlaczego jeśli w fedex to x, a jeśli nie to y - rzuca światło na cały system, a kiedy czytamy wystarczająco dużo z nich, zaczynamy to rozumieć. I to jest zbyt uproszczone i istnieją setki lub tysiące podobnych oświadczeń. Moje serce ciepło świeci w kierunku każdego, kto był twórcą z 2007 roku, który włożył te, dlaczego.

Tak, tak, złożone skomplikowane modele danych i owłosione żywioły oraz procedura przechowywana z wieloma ważnymi nazwanymi ścieżkami, proszę, z miłości do B-ga, powiedz nam dlaczego.


0

Właśnie napisałem ten komentarz; jest to konkretny przykład wyjaśnienia, dlaczego wiersz kodu jest tym, czym jest, a w szczególności dlaczego go zmieniłem.

Metoda sprawdza przechowywane dane i ocenia, czy są one kompletne do dnia dzisiejszego z jednej strony i do daty rozpoczęcia z drugiej strony.

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

Jak zapewne można się domyślać, operator większy niż był równy lub większy. Komentarz wyjaśnia, dlaczego stara wartość ma sens i dlaczego nowa wartość jest lepsza. Jeśli ktoś spojrzy na to w przyszłości, zobaczy, że użycie „>” nie jest przeoczeniem, ale optymalizacją. Następnie mogą to zmienić lub zostawić, w zależności od potrzeb w danym momencie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.