Jeg har ikke tal på hvor mange gange, jeg har hørt udviklere efterlyse flere kommentarer i koden, men uden at have lavet en egentlig undersøgelse, er min fornemmelse, at jeg har set langt flere dårlige end gode kommentarer i min tid som udvikler. Derfor er det ikke just nærliggende for mig at efterspørge flere kommentarer. Nærmest tværtimod.
Lad mig dog slå fast, at jeg bestemt anerkender værdien af kommentarer i de tilfælde, hvor de faktisk tilfører koden værdi. I alle de andre tilfælde gør de ofte mere skade end gavn. Lad os se lidt på, hvad der adskiller de brugbare kommentarer fra de ubrugelige.
Eksempler
Problemerne med kommentarer er mange, så lad os se på nogle af dem. Min liste er næppe udtømmende (lad os endelig få flere skrækeksempler), men blot et udsnit af de brugsmønstre, vi sikkert alle er stødt på fra tid til anden. Det første eksempel er banalt og synes ikke at gøre den store skade:
// reset counter
cnt = 0;
Men lad os ikke lægge ud med at tale om skade. Lad os i stedet spørge: Hvilken værdi tilfører denne kommentar koden? Ingen. Den fortæller mig godt nok, at udvikleren har været for doven eller måske ikke har evnet at omdøbe sin variabel til Counter eller noget mere sigende. At forklare at værdien bliver nulstillet, når den sættes til nul, er en lige så overflødig oplysning som at tvillinger kommer i par. Kommentaren giver os altså ikke mere information end vi snildt kunne have udtrykt i selve koden, så undgå gentagelsen. DRY gælder også for kommentarer.
Det største problem ved denne slags kommentarer er desværre, at de ofte kommer i hobetal. Hvis udvikleren af en eller anden grund tror, at de faktisk er til gavn, bliver den slags ligegyldigheder strøet ud over det hele. Det gør koden længere uden at gøre noget som helst positivt for læsbarheden. Det er spild af alles tid.
En afart af ovenstående er, når kommentarer bruges til at forklare værdier. Det kan være ved tildeling som ovenfor eller ved kald af metoder. Eksempel:
// payout occurs every 3 weeks
Payout(3);
Brug dog en konstant i stedet for en kommentar, så er der tilmed chance for, at den kan bruges igen.
Lærebog i C#
Lad være med at skrive kommentarer, der forklarer, hvad forskellige sprogkonstruktioner gør. Antag at læseren kender sproget. Skulle det ikke være tilfældet, er kommentarer alligevel ikke løsningen på det problem.
Beskrivelser af forskellige sprogkonstruktioner findes allerede en masse, så lad være med at forsøge at gøre koden til en referencemanual.
// TODO
Nogen vil måske mene, at vi her bevæger os ind i grænselandet mellem det ubrugelige og det brugbare, for hensigten med TODO-kommentarerne er naturligvis at gøre opmærksom på, at der er noget, der ikke er fulgt helt til dørs. Det er reelt nok, og jeg anvender selv TODO i min kode, mens jeg arbejder, men det er ikke i orden at checke kode ind med TODO-kommentarer.
Med mindre I bruger jeres repository til at planlægge arbejdsopgaver, er det jo et fjollet sted at registrere nye opgaver. Opret et work item, en incident, en change request eller hvad I nu kalder den slags og sørg for at få beskrevet, hvad der mangler, så I har en chance for at få fulgt op på det. Kildetekst er ikke særlig brugbar som projektstyringsværktøj.
Mange TODO-kommentarer er tilmed frygtelig indforståede. Jeg faldt over nedenstående under et code review for et stykke tid siden:
// TODO major hack!!!
Hvad forventes læseren at tænke her? Er nedenstående et major hack? I så fald hvordan og hvorfor? Mangler der er major hack her? Til hvad? Er der noget, der ikke virker? Det er bare ikke acceptabelt at gøre den slags.
Kommentarer som overskrifter
En hyppig anvendt fremgangsmåde er at bruge kommentarer som overskrifter for dele af koden. Udviklere, der anvender denne form for kommentarer, har ofte metoder, der er lange, men hvor kommentarerne formodes at give det gyldne overblik.
Således finder vi som regel kommentarer i stil med ”her initialiseres nødvendige strukturer”, ”her udregnes”, ”her udskrives”, ”her gemmes data” og så videre. Bagtanken er naturligvis, at læseren skal kunne tilegne sig et overblik ved at kigge ned over koden. Ideen er sympatisk men ikke særlig veludført.
Hvis en stump kode gør noget, vi kan sætte en fornuftig overskrift på, er det så ikke nærliggende, at denne funktionalitet eventuelt kan genbruges? Det gør kommentarer ikke det mindste for at fremme.
Et andet, større problem er, at ideen antager, at vi altid ser på koden i sin nuværende form, men hvad med de situationer, hvor vi virkelig har brug for at finde ud af, hvad der sker som f.eks. under fejlsøgning? Får vi en exception, er de velmenende kommentarer jo desværre ikke en del af vores stack trace. Her vil navnet på en kæmpe metode og et offset være ulig meget mindre værd end navnet på en lille, specifik undermetode.
I begge tilfælde er det meget mere anvendelig at skifte overskrifterne ud med metodekald. Måske endda metodekald på nye typer for derved at undgå, at hver type laver mere end en ting. Lav de enkelte blokke som metoder. Det giver korte metoder, der er lette at overskue og en god hierarkisk opdeling af opgaverne. Visual Studio gør det tilmed let at opdele metoder på denne måde via Extract Method. Ja, det giver flere metoder og flere kald, men kode, der er let at læse og vedligeholde, er altså uendelig meget mere værd end kompliceret kode, der måske kører en mikroskopisk brøkdel hurtigere.
De få tilfælde
Hvornår er det så okay at bruge kommentarer? Det korte svar er: ikke særlig ofte. Hver gang vi skal til at skrive en kommentar, bør vi i hvert fald lige tænke over, om der ikke er en bedre måde at udtrykke os i koden. Hvis kommentaren forsøger at lappe et hul, så lap hullet i stedet for at beskrive det. Hvis kommentaren forsøger at forklare kompleks kode, så skriv koden om, så den bliver forståelig. Hvis kommentaren forklarer en rodet struktur, så ryd op.
I mine øjne er kommentarer i kildeteksten kun brugbare, når de fortæller læseren noget, der ikke umiddelbart kan læses ud af koden. Forskellen på god og dårlig kode kendes som bekendt på antallet af WTF?!-udbrud hos læseren. Hvis læseren blot sidder og nikker og tænker, ”ja ja ja”, ”det giver mening”, ”sådan ville jeg også have lavet det”, er vi på rette spor.
Er vi tvunget væk fra dette spor, kan kommentarer være en hjælp til læseren. Det kan f.eks. være i tilfælde, hvor vi er nødt til at vælge en ikke oplagt løsning af hensyn til performance eller på grund af fejl, vi ikke har mulighed for at udbedre. Forklar læseren hvorfor det uventede giver mening i netop denne situation.
Klassebiblioteker
Et andet område, hvor kommentarer kan være anvendelige, er ved beskrivelse af offentlige typer og metoder i et klassebibliotek.
Det er fint med kommentarer, der forklarer intentionerne med og brugen af en type eller et interface (altså hvad og ikke hvordan), men det giver ikke rigtig nogen merværdi at få at vide, at et parameter ved navn filename indikerer navnet på en fil. Hvis læseren ikke kan læse navnet, er der ingen grund til at tro, at han kan læse kommentaren. Brug i stedet kræfterne på at vælge gode navne til metoder og argumenter og dokumenter så ideer og facetter, der ikke let kan læses ud af koden.
Der er ingen grund til at dokumentere alt blot for at kunne sige, at vi har dokumenteret. Kommentarer koster også tid og ressourcer at vedligeholde, så der er ingen grund til at skrive flere af dem end nødvendig. Ligesom kode kan kommentarer indeholde fejl, og fejlagtige kommentarer er som regel værre end ingen kommentarer. Hvis vi skriver få, meningsfyldte kommentarer, er det lettere at vedligeholde koden, end hvis vi på mekanisk vis forsøger at kommentere alt i detaljer.
God artikel. Jeg er helt enig. Med hensyn til TODO kommentarer foretrækker jeg at bruge #warning da disse er mere “in your face” og man har dermed større tendens til ikke at glemme dem.
Tim Ottinger kalder af samme grund kommentarer for undskyldninger – “Undskyld at jeg ikke i stedet skrev noget læsbar kode!”: http://www.butunclebob.com/ArticleS.TimOttinger.ApologizeIncode
Jeg er ikke enig med Tim Ottinger i, at kommentarer altid er noget skidt. Vi kan komme langt med gode navne, men navne er ikke prosa, og derfor er der grænser for, hvad vi kan udtrykke på den måde. At skabe overblik løser sig derfor sjældent ved blot at vælge gode navne.
Udmærket skriv
Jeg er absolut enig i langt det meste, dog studsede jeg lige over TODO. Jeg syntes TODO kan bruges til at kommunikere en masse til teamet; “her nåede jeg ikke at blive færdig”, “min intention var…, men jeg gjorde sådan her istedet”.
Jeg har selv skrevet og læst meget TODO, og de gange hvor en teammember har udtrykt manglende kendskab, har jeg taget fat i vedkommende og vi har haft en fed snak om at løse problemstillingen mere elegant
Samtidigt bruger jeg også TODO’s til at udtrykke, “jeg kom hertil og det virker nu så du kan teste!!, men det skal laves om til at trække på rigtige data” (og ja jeg har hørt om Mock-frameworks *G*)
Jeg synes du har meget fokus på “kæmpestore metoder” , men de bør bare refactors ik sandt
Min primære anke ved TODOs er, at hvis man bruger dem som noget, man skal vende tilbage til ved en anden lejlighed, er der langt bedre muligheder. I begrænset omfang er TODO da fint, men de er lidt lige som post-it – gode til små beskeder, men ikke det bedste planlægningsværktøj og ej heller egnede som dokumentation.
Mht store metoder, er vi enige. De bør splittes op i flere mindre. Desværre ser jeg alt for mange, alt for lange metoder i vores kodebase.
Nu har jeg ikke læst hele din post, men det korte svar til hvordan man skriver kode kommentare og en regel der er nem at huske for alle:
“Skriv ikke HVAD du gør, men HVORFOR du gør det”
Det er som om du antager at bare koden er velskrevet, navngivningen er perfekt osv., så kan man forstå hvad der sker.
Det hjælper selvfølgelig
Men hvis domæneområdet er kompliceret, bør man kommentere om hvilke forretningsregler, konventioner, approksimationer m.m. der gøren koden korrekt.
Det kan sagtens være indlysende klart /hvad/ koden gør, men ikke /hvorfor/. Det må være kommentarens fornemeste opgave: Forklar hvorfor!
@Mads: Hvorfor er bestemt bedre end hvad, men når det er sagt, er der mange hvorfor-oplysninger, jeg gerne er fri for. Skriv hvorfor du gør noget, der ikke er indlysende.
@Jesper: Nej, jeg antager ikke noget om koden. Min pointe er at det er bedre at bruge tiden på at ændre navne til det bedre end at dekorere med kommentarer. Som jeg også skriver i indlægget og i min kommentar til Mark, så er der områder, hvor kommentarer hjælper. Desværre er min erfaring, at det er sjældent der, man finder kommentarer.
Jeg er uenig. Dårlig kode med mange fejl glimrer altid ved, at der ingen kommentarer er, udover “I am naughty here..”, “fix this later” osv. Når du skriver “jeg har set langt flere dårlige end gode kommentarer i min tid som udvikler” tror jeg i virkeligheden, at du har LAGT MÆRKE TIL langt flere dårlige kommentarer end gode. Jamen, så slet dem dog og kom videre, og lad der ikke gå burkadebat i den.
Jeg bruger kommentarer for at gøre det nemmere at forstå min egen kode i fremtiden. Den fremtid, hvor jeg ikke har siddet med hovedet dybt begravet i problemstillingen i flere uger, og mener at det kan enhver da forstå.
Reglerne er:
1) Skriv god kode.
2) Skriv ikke dårlig kode.
3) Skriv gode kommentarer.
4) Skriv ikke dårlige kommentarer.
4 simple regler – sværere er det ikke at blive en god programmør
Brian, har du læst kapitlet om kommentarer i Code Complete 2? Det er glimrende, og afbalanceret.
Han kalder en type kommentarer for “intent comment”, dvs. “A comment at the level of intent explains the purpose of a section of code. Intent comments operate more at the level of the problem than at the level of the solution”.
Det er nogenlunde det jeg mener med /hvorfor/-kommentarer. Det fantastiske ved Code Complete er, at den altid prøver at finde empirisk belæg for om noget virker eller ej. Og her nævner han:
A six-month study conducted by IBM found that maintenance
programmers “most often said that understanding the original
progammer’s intent was the most difficult problem”
@Jesper: Jeg har læst Code Complete, men det er lang tid siden, så jeg har ikke citatet i frisk erindring.
Jeg tror, vi taler forbi hinanden. Jeg er helt med på at kommentarer kan være brugbare, og det var bestemt min intention, at det også skulle fremgå af teksten.
Så lad os være enige om, at kommentarer kan være brugbare, og lad mig så vende spørgsmålet: Hvilken kategori falder størstedelen af de kommentarer, du har set, i? Er det “intent comments” eller “label the mess”?
@Jens: Det er ikke klart for mig, hvad du er uenig med mig i.
Jeg lægger jo ikke skjul på, at der ikke ligger nogen reel undersøgelse til grund for min påstand om forholdet mellem antallet af gode og dårlige kommentarer. Muligvis lægger jeg mere mærke til de dårlige, som du påpeger. Det vil jeg ikke afvise, men antallet af dårlige kommentarer er ikke pointen.
Pointen er, at der er gode og dårlige kommentarer, og derfor giver det ikke mening blot at efterlyse flere kommentarer. Jeg forsøger så desuden at give mit bud på, hvad der er gode og dårlige kommentarer.
Din opskrift på hvordan man bliver en god udvikler er underholdende, men ikke operationel før du definerer hvad god og dårlig kode samt gode og dårlige kommentarer er. Jeg har givet et bud på sidstnævnte.
“… men uden at have lavet en egentlig undersøgelse, er min fornemmelse, at jeg har set langt flere dårlige end gode kommentarer i min tid som udvikler.”
Tja, jeg kunne sige det samme om kode generelt. Jeg er helt enig i, at simple kommentarer kan være en “code-smell” og f.eks. bør erstattes med en refaktoring, som trækker den kommenterede kode ud i en metode med samme navn som kommentaren. Anatgelser kan f.eks. dokumeneteres med Asserts i stedet for kommentarer.
Der hvor kommentarer får deres værdi, er når de beskriver hvorfor, og ikke hvad. Kommentarer der dokumenterer kontrakter, såsom kravene til input parametre og hvilke garantier der gives for retur værdier, exceptions og tilstande på det kaldte objekt er i mine øjne vigtige. Det gør, at brugeren af koden kan bure et tooltip for at se kontrakten og ikke behøver at læse den kaldte kode.
Jeg er enig med Morten i refaktoreringsvinklen. I eksemplet nævnes:
// reset counter
cnt = 0;
Det burde netop ligge i en metode der hedder (gæt) ResetCounter. Generelt mener jeg altid man bør høre en alarmklokke ringe i baghovedet hvis man føler trang til at skrive oventående kommentar.
@Rasmus: ENIG! Sådan skal det gøres – før jeg læste ”Clean Code: A Handbook of Agile Software Craftsmanship” forstod jeg det ikke når folk snakkede om ”selvforklarende kode”, men efter at have læst kapitlet om kommentarer (det er kapitel 4) – ”Clean Code” er et must for alle udviklere som bør have bogen liggende tilgængeligt (det kan anbefales at benytte bogen som det nogen kalder ”lokumslæsning” – så kan man dagligt blive mindet om god kodestil).
@Brian: Eksemplet med // reset counter er super godt, for jeg uenig i din udlægning: jeg tror ikke han mener at forklare at værdien nulstilles, men at den ”stilles tilbage” – det er jo ikke givet at en counter starter på 0 og jeg tror det var den helt specielle information udvikleren ville fastholde med kommentaren:
// reset counter
cnt = -12;
Nu giver det mere mening – ikk’?
Netop derfor ville Rasmus funktion ResetCounter også øge læsbarheden, for den ville fjerne den støj (kilde til fejl læsning) der følger af at læse kommentaren og koden sammen – det næste der så kunne dukke op var en unittest der Assert’er at cnt == CounterStart efter ResetCounter er kaldt.