Commenti sul codice pulito e documentazione di classe


83

Sto discutendo con i miei nuovi colleghi in merito ai commenti. Entrambi amiamo il codice pulito e sto perfettamente bene con il fatto che i commenti al codice in linea dovrebbero essere evitati e che i nomi di classe e metodi dovrebbero essere usati per esprimere ciò che fanno.

Tuttavia, sono un grande fan dell'aggiunta di piccoli riassunti di classe che cercano di spiegare lo scopo della classe e ciò che è effettivamente rappresentato, in primo luogo in modo che sia facile mantenere il modello del principio di responsabilità singola . Sono anche abituato ad aggiungere riassunti di una riga ai metodi che spiegano cosa dovrebbe fare il metodo. Un esempio tipico è il metodo semplice

public Product GetById(int productId) {...}

Sto aggiungendo il seguente sommario del metodo

/// <summary>
/// Retrieves a product by its id, returns null if no product was found.
/// </summary

Credo che il fatto che il metodo restituisca null debba essere documentato. Uno sviluppatore che desidera chiamare un metodo non dovrebbe aprire il mio codice per vedere se il metodo restituisce null o genera un'eccezione. A volte fa parte di un'interfaccia, quindi lo sviluppatore non sa nemmeno quale codice sottostante è in esecuzione?

Tuttavia, i miei colleghi pensano che questo tipo di commenti siano " odori di codice " e che "i commenti siano sempre insuccessi" ( Robert C. Martin ).

C'è un modo per esprimere e comunicare questo tipo di conoscenza senza aggiungere commenti? Dato che sono un grande fan di Robert C. Martin, mi sto confondendo un po '. I riepiloghi sono gli stessi dei commenti e quindi sempre degli errori?

Questa non è una domanda sui commenti in linea.


38
Robert Martin ha detto "I commenti sono sempre fallimenti"? Bene, allora è un estremista marginale e dovrebbe essere preso con un pizzico di sale. (Sì, sono consapevole che scrive così per scopi retorici, per far passare il suo messaggio. Il mio punto è, anche tu dovresti .)
Kilian Foth,

18
I libri di zio Bob dovrebbero venire con un sacco di sale da 1 kg ...
AK_4

6
Se stai seguendo Robert Martin, la documentazione per il caso null dovrebbe essere un test. Cioè, dovresti avere un test che mostra nel qual caso il metodo può restituire null. In alternativa, poiché si tratta di Java, anche un'annotazione @Nullable sarebbe migliore del commento.
Martin Epsz,

15
@Bjorn Possiedo una copia di Clean Code e l'ho letto cover to cover più di una volta. Sì, lo zio Bob preferisce che il codice sia auto-documentante, ma ci sono molti esempi di commenti nel suo codice nel libro . Il punto è se ti senti obbligato a scrivere un commento, fai del tuo meglio per cambiare il codice piuttosto che aggiungere il commento, ma non rifiutare del tutto i commenti (anche i commenti in linea).

6
Il metodo dovrebbe essere chiamato TryGetById e il commento dovrebbe essere rimosso.
usr

Risposte:


116

Come altri hanno già detto, c'è una differenza tra i commenti sulla documentazione API e i commenti in linea. Dal mio punto di vista, la differenza principale è che un commento in linea viene letto accanto al codice , mentre un commento di documentazione viene letto accanto alla firma di tutto ciò che stai commentando.

Detto questo, possiamo applicare lo stesso principio DRY . Il commento dice la stessa cosa della firma? Diamo un'occhiata al tuo esempio:

Recupera un prodotto in base al suo ID

Questa parte ripete solo ciò che vediamo già dal nome GetByIdpiù il tipo restituito Product. Solleva anche la domanda quale sia la differenza tra "ottenere" e "recuperare", e che cosa porta il codice rispetto al commento ha su quella distinzione. Quindi è inutile e leggermente confuso. Semmai, si sta ostacolando in realtà utile, seconda parte del commento:

restituisce null se non è stato trovato alcun prodotto.

Ah! Questo è qualcosa che sicuramente non possiamo sapere con certezza solo dalla firma e fornisce informazioni utili.


Ora fai un ulteriore passo avanti. Quando le persone parlano di commenti come odori di codice, la domanda non è se il codice così com'è ha bisogno di un commento, ma se il commento indica che il codice potrebbe essere scritto meglio, per esprimere le informazioni nel commento. Ecco cosa significa "odore di codice", non significa "non farlo!", Significa "se lo stai facendo, potrebbe essere un segno che c'è un problema".

Quindi se i tuoi colleghi ti dicono che questo commento su null è un odore di codice, dovresti semplicemente chiedere loro: "Okay, come dovrei esprimerlo allora?" Se hanno una risposta fattibile, hai imparato qualcosa. In caso contrario, probabilmente ucciderà i loro reclami morti.


Per quanto riguarda questo caso specifico, in genere il problema null è ben noto per essere un problema difficile. C'è un motivo per cui le basi di codice sono disseminate di clausole di guardia, perché i controlli null sono un presupposto popolare per i contratti di codice, perché l'esistenza di null è stata definita un "errore da miliardi di dollari". Non ci sono molte opzioni praticabili. Uno popolare, tuttavia, trovato in C # è la Try...convenzione:

public bool TryGetById(int productId, out Product product);

In altre lingue, può essere idiomatico usare un tipo (spesso chiamato qualcosa di simile Optionalo Maybe) per indicare un risultato che può essere o meno presente:

public Optional<Product> GetById(int productId);

Quindi, in un certo senso, questa posizione anti-commento ci ha portato da qualche parte: abbiamo almeno pensato se questo commento rappresenta un odore e quali alternative potrebbero esistere per noi.

Se dovremmo effettivamente preferire questi sulla firma originale è un altro dibattito, ma almeno abbiamo opzioni per esprimere attraverso il codice piuttosto che commentare cosa succede quando non viene trovato alcun prodotto. Dovresti discutere con i tuoi colleghi quale di queste opzioni ritengono migliore e perché e, si spera, aiutare ad andare oltre le dichiarazioni dogmatiche sui commenti.


9
O l' Linqequivalente di Try..., ...OrDefaultche ritorna default(T)se la clausola porterebbe a un risultato vuoto.
Bart van Nierop,

4
Apprezzo molto la tua distinzione tra commenti di codice in linea e commenti di documentazione e gli esempi forniti :)
Rachel

2
I possibili valori di ritorno di una funzione dovrebbero essere evidenti dalla sua firma. Lo TryGetValueschema è un modo ragionevole per farlo in C #, ma la maggior parte dei linguaggi funzionali ha un modo migliore di rappresentare un valore mancante. Maggiori informazioni qui
AlexFoxGill

2
@BenAaronson: se si desidera avere un'interfaccia generica in grado di supportare la covarianza, è possibile utilizzare T TryGetValue(params, ref bool success)per qualsiasi tipo T o T TryGetValue(params), con null che indica un errore, per il tipo T vincolato in classe, ma il TryGetXXmodello che restituisce boolè incompatibile con la covarianza.
supercat

6
In Java 8, è possibile restituire un Optional<Product>per indicare che potrebbe non esserci un prodotto restituito dal metodo.
Wim Deblauwe,

102

La citazione di Robert C. Martin è fuori dal contesto. Ecco la citazione con un po 'più di contesto:

Niente può essere così utile come un commento ben posizionato. Nulla può ingombrare un modulo più di frivoli commenti dogmatici. Niente può essere così dannoso come un vecchio commento volgare che propaga menzogne ​​e disinformazione.

I commenti non sono come l'elenco di Schindler. Non sono "puro bene". In effetti, i commenti sono, nella migliore delle ipotesi, un male necessario. Se i nostri linguaggi di programmazione fossero abbastanza espressivi, o se avessimo il talento di usare in modo sottile quei linguaggi per esprimere il nostro intento, non avremmo bisogno di molti commenti, forse per niente.

L'uso corretto dei commenti è per compensare la nostra incapacità di esprimerci nel codice. Nota che ho usato la parola fallimento. Intendevo ciò. I commenti sono sempre errori. Dobbiamo averli perché non possiamo sempre capire come esprimerci senza di loro, ma il loro uso non è motivo di celebrazione.

Quindi quando ti trovi in ​​una posizione in cui devi scrivere un commento, riflettilo e vedi se non c'è modo di girare le tabelle ed esprimerti in codice. Ogni volta che ti esprimi nel codice, dovresti darti una pacca sulla spalla. Ogni volta che scrivi un commento, dovresti fare una smorfia e sentire il fallimento della tua capacità espressiva.

(Copiato da qui , ma la citazione originale è tratta da Clean Code: A Handbook of Agile Software Craftsrafts )

Come questa citazione sia ridotta in "I commenti sono sempre fallimenti" è un buon esempio di come alcune persone prenderanno una citazione ragionevole fuori dal contesto e la trasformeranno in stupido dogma.


La documentazione dell'API (come javadoc) dovrebbe documentare l'API in modo che l'utente possa utilizzarla senza dover leggere il codice sorgente . Quindi in questo caso la documentazione dovrebbe spiegare cosa fa il metodo. Ora puoi sostenere che "Recupera un prodotto dal suo ID" è ridondante perché è già indicato dal nome del metodo, ma le informazioni che nullpossono essere restituite sono sicuramente importanti da documentare, dal momento che questo non è affatto ovvio.

Se si desidera evitare la necessità del commento, è necessario rimuovere il problema sottostante (che è l'uso di nullcome valore di ritorno valido), rendendo l'API più esplicita. Ad esempio, è possibile restituire un tipo di Option<Product>tipo, quindi la firma del tipo stesso comunica chiaramente cosa verrà restituito nel caso in cui il prodotto non venga trovato.

Ma in ogni caso non è realistico documentare un'API completamente solo attraverso i nomi dei metodi e le firme dei tipi. Usa i doc-commenti per qualsiasi ulteriore informazione non ovvia che l'utente dovrebbe conoscere. Supponiamo che la documentazione API DateTime.AddMonths()nel BCL:

Il metodo AddMonths calcola il mese e l'anno risultanti, tenendo conto degli anni bisestili e del numero di giorni in un mese, quindi regola la parte del giorno dell'oggetto DateTime risultante. Se il giorno risultante non è un giorno valido nel mese risultante, viene utilizzato l'ultimo giorno valido del mese risultante. Ad esempio, 31 marzo + 1 mese = 30 aprile. La parte ora del giorno dell'oggetto DateTime risultante rimane la stessa di questa istanza.

Non puoi assolutamente esprimerlo usando solo il nome e la firma del metodo! Naturalmente la documentazione della tua classe potrebbe non richiedere questo livello di dettaglio, è solo un esempio.


I commenti in linea non sono neanche male.

I commenti negativi sono negativi. Ad esempio commenti che spiegano solo cosa si può vedere banalmente dal codice, l'esempio classico è:

// increment x by one
x++;

I commenti che spiegano qualcosa che potrebbe essere chiarito rinominando una variabile o un metodo o in altro modo ristrutturando il codice, sono odori di codice:

// data1 is the collection of tasks which failed during execution
var data1 = getData1();

Questi sono il tipo di commenti contro cui Martin rota. Il commento è un sintomo di una mancata scrittura di codice chiaro, in questo caso di utilizzare nomi autoesplicativi per variabili e metodi. Il commento in sé non è ovviamente il problema, il problema è che abbiamo bisogno del commento per capire il codice.

Ma i commenti dovrebbero essere usati per spiegare tutto ciò che non è ovvio dal codice, ad esempio perché il codice è scritto in un certo modo non ovvio:

// need to reset foo before calling bar due to a bug in the foo component.
foo.reset()
foo.bar();

Anche i commenti che spiegano cosa fa un pezzo di codice eccessivamente contorto sono un odore, ma la correzione non è di mettere fuorilegge i commenti, la correzione è la correzione del codice! In parole povere, il codice contorto avviene (si spera solo temporaneamente fino a un refactor) ma nessuno sviluppatore ordinario scrive un codice pulito perfetto la prima volta. Quando si verifica un codice contorto, è molto meglio scrivere un commento che spieghi cosa fa piuttosto che non scrivere un commento. Questo commento faciliterà anche il refactoring in seguito.

A volte il codice è inevitabilmente complesso. Può essere un algoritmo complicato o può essere il sacrificio del codice che limita la chiarezza per motivi di prestazioni. Ancora una volta sono necessari commenti.


13
C'è anche il caso in cui il tuo codice gestisce una situazione che è semplicemente complicata e nessun codice semplice può gestirla.
gnasher729,

6
Buon punto, gnasher. Questo sembra accadere spesso quando devi ottimizzare un pezzo di codice per le prestazioni.
Jacques B

9
Anche un commento in x++può essere buono se è qualcosa come "incrementare x di uno, avvolgendo se è UINT32_MAX"; chiunque conosca le specifiche del linguaggio saprebbe che l'incremento di un uint32_tinvolucro verrà eseguito, ma senza il commento non si potrebbe sapere se tale wrapping fosse una parte prevista dell'algoritmo implementato.
supercat

5
@ l0b0: spero che tu stia scherzando!
JacquesB,

9
@ l0b0 Non esiste un codice temporaneo. Il codice non viene mai refactored perché l'azienda è stata contenta del risultato e non approva i finanziamenti per risolverlo. Tra cinque anni, alcuni sviluppatori junior vedranno questo codice, non utilizzerai più WizBug 4.0 da quando lo hai sostituito con Bugtrocity v9, quindi "Bug123" non significa nulla per lui. Ora pensa che sia così come dovrebbe essere il codice permanente e continua a essere un terribile sviluppatore per tutta la sua carriera. Pensa ai bambini. Non scrivere codice temporaneo.
corsiKa

36

C'è una differenza tra commentare il tuo codice e documentare il tuo codice .

  • I commenti sono necessari per mantenere il codice in un secondo momento, ovvero modificare il codice stesso.

    I commenti possono effettivamente essere percepiti come problematici. Il punto estremo sarebbe dire che indicano sempre un problema, sia all'interno del tuo codice (codice troppo difficile da capire) sia all'interno della lingua (la lingua non è in grado di essere abbastanza espressiva; ad esempio, il fatto che il metodo non ritorni mai nullpotrebbe essere espresso tramite contratti di codice in C #, ma non c'è modo di esprimerlo tramite il codice, diciamo, in PHP).

  • È necessaria la documentazione per poter utilizzare gli oggetti (classi, interfacce) sviluppati. Il pubblico target è diverso: non sono le persone che manterranno il tuo codice e lo cambieranno di cui stiamo parlando qui, ma le persone che a malapena hanno bisogno di usarlo .

    Rimuovere la documentazione perché il codice è abbastanza chiaro è folle, poiché la documentazione è qui specificamente per rendere possibile l'uso di classi e interfacce senza dover leggere migliaia di righe di codice .


Sì, ma almeno una parte del punto di Martin è che con le moderne pratiche di sviluppo, i test sono la documentazione, non il codice stesso. Supponendo che il codice sia stato testato con un sistema di test in stile BDD, ad esempio specflow, i test stessi sono una descrizione direttamente leggibile del comportamento del metodo ("dato un database di prodotti quando GetById viene chiamato con l'id di un prodotto valido, quindi l'oggetto Product appropriato viene restituito [...] quando GetById viene chiamato con un ID prodotto non valido, quindi viene restituito null "o qualcosa del genere).
Jules,

13

Bene, sembra che il tuo collega legga libri, accetti ciò che dicono e applichi ciò che ha imparato senza pensare e senza considerare il contesto.

Il tuo commento su ciò che fa la funzione dovrebbe essere tale che puoi buttare via il codice di implementazione, ho letto il commento della funzione e posso scrivere il sostituto per l'implementazione, senza che nulla vada storto.

Se il commento non mi dice se viene generata un'eccezione o se viene restituito zero, non posso farlo. Inoltre, se il commento non dice voi se viene generata un'eccezione o se nullo viene restituito, quindi ovunque si chiama la funzione, è necessario assicurarsi che il codice funziona correttamente se viene generata un'eccezione o nullo viene restituito.

Quindi il tuo collega ha torto. E vai avanti e leggi tutti i libri, ma pensa da solo.

PS. Ho visto la tua linea "a volte fa parte di un'interfaccia, quindi non sai nemmeno quale codice è in esecuzione." Anche solo con le funzioni virtuali, non sai quale codice è in esecuzione. Peggio ancora, se hai scritto una classe astratta, non c'è nemmeno alcun codice! Quindi, se hai una classe astratta con una funzione astratta, i commenti che aggiungi alla funzione astratta sono l' unica cosa che un implementatore di una classe concreta deve guidare. Questi commenti possono anche essere l'unica cosa che può guidare un utente della classe, ad esempio se tutto ciò che hai è una classe astratta e una fabbrica che restituisce un'implementazione concreta, ma non vedi mai alcun codice sorgente dell'implementazione. (E, naturalmente, non dovrei essere a guardare il codice sorgente di un'implementazione).


Non ho commentato il codice per 10 anni. I commenti sono gonfia, immondizia. Al giorno d'oggi nessuno commenta il codice. Ci concentriamo su codice ben formato e denominato, piccoli moduli, disaccoppiamento, ecc. CHE rende il tuo codice leggibile non commenti. I test assicurano che se si elimina il codice, nulla va storto, non commenti. I test ti dicono come usi il codice che scrivi, come li chiami e perché sono lì in primo luogo. Sei troppo vecchia scuola, devi conoscere i test e pulire il codice amico mio.
Positivo

12

Esistono due tipi di commenti da considerare: quelli visibili alle persone con il codice e quelli utilizzati per generare documentazione.

Il tipo di commento a cui si riferisce lo zio Bob è il tipo che è visibile solo alle persone con il codice. Quello che sta sostenendo è una forma di SECCO . Per una persona che sta guardando il codice sorgente, il codice sorgente dovrebbe essere la documentazione di cui ha bisogno. Anche nel caso in cui le persone abbiano accesso al codice sorgente, i commenti non sono sempre negativi. A volte, gli algoritmi sono complicati o devi capire perché stai adottando un approccio non ovvio in modo che gli altri non finiscano per rompere il tuo codice se provano a correggere un bug o ad aggiungere una nuova funzionalità.

I commenti che stai descrivendo sono documentazione API. Queste sono cose che sono visibili alle persone che utilizzano l'implementazione, ma che potrebbero non avere accesso al codice sorgente. Anche se hanno accesso al tuo codice sorgente, potrebbero lavorare su altri moduli e non guardare il tuo codice sorgente. Queste persone troverebbero utile avere questa documentazione disponibile nel loro IDE mentre scrivono il loro codice.


Sinceramente non ho mai pensato che DRY si applicasse a code + commenti, ma ha perfettamente senso. Un po 'come nell'esempio "incremento X" nella risposta di @ JacquesB.

7

Il valore di un commento viene misurato nel valore delle informazioni che fornisce meno lo sforzo necessario per leggerlo e / o ignorarlo. Quindi se analizziamo il commento

/// <summary>
/// Retrieves a product by its id, returns null if no product was found.
/// </summary>

per valore e costo, vediamo tre cose:

  1. Retrieves a product by its idripete ciò che dice il nome della funzione, quindi ha un costo senza valore. Dovrebbe essere cancellato.

  2. returns null if no product was foundè un'informazione molto preziosa. Probabilmente riduce i tempi che altri programmatori dovranno guardare all'implementazione della funzione. Sono abbastanza certo che consente di risparmiare più lettura rispetto al costo di lettura che si presenta. Dovrebbe rimanere.

  3. Le linee

    /// <summary>
    /// </summary>
    

    non trasportare alcuna informazione. Sono puro costo per il lettore del commento. Possono essere giustificati se il tuo generatore di documentazione ne ha bisogno, ma in quel caso dovresti probabilmente pensare a un diverso generatore di documentazione.

    Questo è il motivo per cui l'uso di generatori di documentazione è un'idea discutibile: in genere richiedono molti commenti aggiuntivi che non contengono informazioni o ripetono cose ovvie, solo per il bene di un documento raffinato.


Un'osservazione che non ho trovato in nessuna delle altre risposte:

Anche i commenti che non sono necessari per comprendere / utilizzare il codice possono essere molto utili. Ecco un esempio:

//XXX: The obvious way to do this would have been ...
//     However, since we need this functionality primarily for ...
//     doing this the non-obvious way of ...
//     gives us the advantage of ...

Probabilmente molto testo, completamente inutile per capire / usare il codice. Tuttavia, spiega un motivo per cui il codice ha l'aspetto. Impedirà alle persone di guardare il codice, chiedersi perché non sia stato fatto in modo ovvio e iniziare a riformattare il codice fino a quando non si rendono conto del perché il codice è stato scritto in questo modo in primo luogo. E anche se il lettore è abbastanza intelligente da non passare direttamente al refactoring, deve comunque capire perché il codice ha l'aspetto che ha prima di rendersi conto che dovrebbe rimanere così com'è. Questo commento potrebbe letteralmente risparmiare ore di lavoro. Pertanto il valore è superiore al costo.

Allo stesso modo, i commenti possono comunicare le intenzioni di un codice, anziché solo come funziona. E possono dipingere il quadro generale che di solito si perde nei minimi dettagli del codice stesso. Come tale, hai ragione a essere a favore dei commenti di classe. Apprezzo di più i commenti di classe se spiegano l'intenzione della classe, come interagisce con le altre classi, come deve essere usata, ecc. Purtroppo, non sono un grande autore di tali commenti ...


2
Wow - cambia il tuo generatore di documenti perché richiede un paio di righe extra di HTML per l'analisi? Non.
corsiKa

2
@corsiKa YMMV, ma io preferirei un generatore di documentazione che riduca al minimo i costi nei commenti. Ovviamente, preferirei anche leggere un file di intestazione ben scritto piuttosto che una documentazione di Doxygen non sincronizzata con il codice attuale. Ma, come ho detto, YMMV.
cmaster

4
Anche se il nome di un metodo descrive brillantemente il suo scopo, ripetere tale scopo usando il linguaggio naturale può rendere più facile per qualcuno che lo legge associare tale scopo a qualsiasi avvertenza che segue. Una riaffermazione di ciò che è descritto nel nome sarà abbastanza breve che anche se il valore è basso, anche il costo sarà basso. Non sono quindi d'accordo con la prima parte del tuo post. +1, tuttavia, per la seconda parte. La documentazione di approcci alternativi che sono stati valutati e respinti può essere estremamente preziosa, ma raramente tali informazioni ricevono l'attenzione che merita.
supercat

GetByIdsolleva la domanda, cos'è id, e anche, ottieni cosa da dove. Il commento alla documentazione dovrebbe consentire all'ambiente di sviluppo di visualizzare la risposta a queste domande. A meno che non sia spiegato altrove nei commenti del documento del modulo, sarebbe anche un posto dove dire perché si dovrebbe ottenere l'ID comunque.
hyde,

Commenti soffiano, codice pulito (auto-descrittivo), TDD (ricevi spesso feedback e ricevi spesso feedback sul tuo design) e regole di test (ti danno fiducia e documentali)! TEST persone TEST. Nessuno qui ne parla. Svegliati
acquista Positivo il

4

Il codice non commentato è un codice errato. È un mito diffuso (se non universale) che il codice può essere letto più o meno allo stesso modo, per esempio, dell'inglese. Deve essere interpretato, e per qualsiasi altro ma il codice più banale che richiede tempo e fatica. Inoltre, ognuno ha un diverso livello di capacità sia nella lettura che nella scrittura di una determinata lingua. Le differenze tra gli stili e le capacità di codifica dell'autore e del lettore sono forti ostacoli all'interpretazione accurata. È anche un mito che tu possa derivare l'intenzione dell'autore dall'implementazione del codice. Nella mia esperienza, raramente è sbagliato aggiungere commenti extra.

Robert Martin et al. consideralo un "cattivo odore" perché potrebbe essere che il codice sia cambiato e i commenti no. Dico che è una buona cosa (esattamente nello stesso modo in cui un "cattivo odore" viene aggiunto al gas domestico per avvisare l'utente delle perdite). La lettura dei commenti fornisce un utile punto di partenza per l'interpretazione del codice effettivo. Se corrispondono, avrai una maggiore fiducia nel codice. Se differiscono, hai rilevato un odore di avvertimento e devi indagare ulteriormente. La cura per un "cattivo odore" non è quella di rimuovere l'odore ma di sigillare la perdita.


2
Dato che sei un autore intelligente e il testo è a beneficio di un pubblico intelligente; Disegna la linea usando il buon senso. Ovviamente, così com'è, l'esempio è stupido, ma ciò non vuol dire che potrebbe non esserci un'ottima ragione per chiarire con un commento il motivo per cui il codice include un i ++ a quel punto.
Vince O'Sullivan,

8
i++; // Adjust for leap years.
Vince O'Sullivan,

5
"Robert Martin et al. Lo considerano un" cattivo odore "perché potrebbe essere che il codice sia cambiato e i commenti no." Questa è solo una parte dell'odore. Il peggiore odore deriva dall'idea che il programmatore abbia deciso di non provare a scrivere il codice in un modo più descrittivo, e invece ha scelto di "sigillare la fuga" con un commento. La sua affermazione è che, anziché schiaffeggiare un commento "// aggiustare per gli anni bisestili", si dovrebbe probabilmente avere un metodo "AdjustForLeapYears ()" nel codice stesso (o qualcosa di simile). La documentazione viene fornita sotto forma di test che esercitano la logica dell'anno bisestile.
Eric King,

3
Vorrei prendere in considerazione l'aggiunta di una chiamata di metodo per sostituire una singola riga di codice con un overkill di commento, in particolare poiché il nome del metodo è in realtà solo un commento che etichetta un pezzo di codice e nessuna garanzia di una migliore accuratezza della documentazione. (Se quella linea si verificasse in due o più punti, l'introduzione di una chiamata di metodo sarebbe, ovviamente, esattamente la soluzione giusta.)
Vince O'Sullivan,

1
@Jay La ragione è che rendere esplicite le tue astrazioni (ad esempio introducendo metodi) è la regola. Non farlo perché potresti finire con un metodo che ha una riga è l'eccezione. Permettetemi di parafrasare la vera regola arbitraria: "Usa le strutture del tuo linguaggio di programmazione (in genere metodi e classi) per introdurre astrazioni, a meno che l'implementazione di tale astrazione non possa essere espressa come una riga di codice, in tal caso specifica l'astrazione nel linguaggio naturale aggiungendo un commento."
Eric

3

In alcune lingue (ad esempio F #) l'intero commento / documentazione può essere effettivamente espresso nella firma del metodo. Questo perché in F #, null non è generalmente un valore consentito se non specificamente consentito.

Ciò che è comune in F # (e anche in molti altri linguaggi funzionali) è che invece di null usi un tipo di opzione Option<T>che potrebbe essere Noneo Some(T). La lingua lo capirebbe e ti costringerebbe (o ti avvertirebbe se non lo fai) ad abbinarsi ad entrambi i casi quando provi ad usarlo.

Quindi ad esempio in F # potresti avere una firma simile a questa

val GetProductById: int -> Option<Product>

E quindi questa sarebbe una funzione che accetta un parametro (un int) e quindi restituisce un prodotto o il valore Nessuno.

E poi potresti usarlo in questo modo

let product = GetProduct 42
match product with
| None -> printfn "No product found!"
| Some p -> DoThingWithProduct p

E otterrai avvisi del compilatore se non corrispondi ad entrambi i casi possibili. Quindi non c'è modo di ottenere eccezioni di riferimento null lì (a meno che tu non ignori gli avvisi del compilatore ovviamente) e sai tutto ciò di cui hai bisogno solo guardando la firma della funzione.

Ovviamente, ciò richiede che il tuo linguaggio sia progettato in questo modo, cosa che molti linguaggi comuni come C #, Java, C ++ ecc. Quindi questo potrebbe non esserti utile nella tua situazione attuale. Ma è (si spera) bello sapere che ci sono lingue là fuori che ti permettono di esprimere questo tipo di informazioni in modo statico senza ricorrere a commenti ecc. :)


1

Ci sono alcune risposte eccellenti qui e non voglio ripetere quello che dicono. Vorrei aggiungere alcuni commenti. (Nessun gioco di parole previsto.)

Ci sono molte affermazioni che le persone intelligenti fanno - sullo sviluppo del software e su molti altri argomenti, suppongo - che sono ottimi consigli se compresi nel contesto, ma quali persone sciocche che escono dal contesto o si applicano in situazioni inadeguate o portano a estremi ridicoli.

L'idea che il codice dovrebbe essere auto-documentato è un'idea eccellente. Ma nella vita reale, ci sono limiti alla praticità di questa idea.

Un problema è che la lingua potrebbe non fornire funzionalità per documentare ciò che deve essere documentato in modo chiaro e conciso. Con il miglioramento dei linguaggi informatici, questo diventa sempre meno un problema. Ma non penso che sia completamente scomparso. Ai tempi in cui scrivevo in assembler, aveva molto senso includere un commento come "prezzo totale = prezzo degli articoli non tassabili più il prezzo degli articoli tassabili più il prezzo degli articoli tassabili * aliquota fiscale". Ciò che era esattamente in un registro in un dato momento non era necessariamente ovvio. Ci sono voluti molti passaggi per fare una semplice operazione. Ecc. Ma se stai scrivendo in un linguaggio moderno, un commento del genere sarebbe solo una riaffermazione di una riga di codice.

Mi annoio sempre quando vedo commenti come "x = x + 7; // aggiungi 7 a x". Come, wow, grazie, se avessi dimenticato cosa significhi un segno più che potrebbe essere stato molto utile. Il punto in cui potrei davvero essere confuso è sapere cos'è "x" o perché è stato necessario aggiungerne 7 in questo particolare momento. Questo codice potrebbe essere reso autocomponente dando un nome più significativo a "x" e usando una costante simbolica invece di 7. Come se avessi scritto "total_price = total_price + MEMBERSHIP_FEE;", probabilmente non è necessario affatto un commento .

Sembra bello dire che un nome di funzione dovrebbe dire esattamente cosa fa una funzione in modo che eventuali commenti aggiuntivi siano ridondanti. Ho ricordi affettuosi del tempo in cui ho scritto una funzione che controllava se un numero di articolo era nella nostra tabella degli articoli del database, restituendo vero o falso, e che ho chiamato "ValidateItemNumber". Sembrava un nome decente. Poi è arrivato qualcun altro e ha modificato quella funzione per creare anche un ordine per l'articolo e aggiornare il database, ma non ha mai cambiato il nome. Ora il nome era molto fuorviante. Sembrava che avesse fatto una piccola cosa, quando in realtà ha fatto molto di più. Successivamente qualcuno ha addirittura eliminato la parte relativa alla convalida del numero di articolo e lo ha fatto altrove, ma non ha ancora cambiato il nome. Quindi, anche se ora la funzione non ha nulla a che fare con la convalida dei numeri di articolo,

Ma in pratica, è spesso impossibile per un nome di funzione descrivere completamente ciò che fa la funzione senza che il nome della funzione sia lungo quanto il codice che costituisce quella funzione. Il nome ci dirà esattamente quali convalide vengono eseguite su tutti i parametri? Cosa succede a condizioni eccezionali? Spiegare ogni possibile ambiguità? Ad un certo punto il nome diventerebbe così lungo che diventa confuso. Accetterei String BuildFullName (nome stringa, nome stringa) come firma della funzione decente. Anche se ciò non spiega se il nome è espresso "primo ultimo" o "ultimo, primo" o qualche altra variazione, cosa fa se una o entrambe le parti del nome sono vuote, se impone limiti sulla lunghezza combinata e cosa fa se viene superato,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.