È meglio documentare le funzioni nel file header o nel file sorgente?


86

Nei linguaggi che distinguono tra un file "source" e "header" (principalmente C e C ++), è meglio documentare le funzioni nel file header:

( rubato dal CCAN )

/**
 * time_now - return the current time
 *
 * Example:
 *  printf("Now is %lu seconds since epoch\n", (long)time_now().tv_sec);
 */
struct timeval time_now(void);

o nel file sorgente?

(rubato da PostgreSQL)

/*
 * Convert a UTF-8 character to a Unicode code point.
 * This is a one-character version of pg_utf2wchar_with_len.
 *
 * No error checks here, c must point to a long-enough string.
 */
pg_wchar
utf8_to_unicode(const unsigned char *c)
{
...

Nota che alcune cose sono definite solo nell'intestazione, come le strutture, le macro e le static inlinefunzioni. Sto solo parlando di cose che sono dichiarate in un file header e definite in un file sorgente.

Ecco alcuni argomenti che mi vengono in mente. Mi sto impegnando per documentare nel file sorgente, quindi i miei argomenti "Pro-header" potrebbero essere piuttosto deboli.

Pro-intestazione:

  • L'utente non ha bisogno del codice sorgente per vedere la documentazione.
    • La fonte potrebbe essere scomoda o addirittura impossibile da acquisire.
    • Ciò mantiene ulteriormente l'interfaccia e l'implementazione.

Pro-source:

  • Rende l'intestazione molto più breve, offrendo al lettore una visione a volo d'uccello del modulo nel suo insieme.
  • Associa la documentazione di una funzione alla sua implementazione, rendendo più facile vedere che una funzione fa quello che dice di fare.

Quando rispondi, ti preghiamo di diffidare delle argomentazioni basate su quali strumenti e "IDE moderni" possono fare. Esempi:

  • Pro-header: la piegatura del codice può aiutare a rendere più navigabili le intestazioni commentate nascondendo i commenti.
  • Pro-source: cscope 's Find this global definitionfunzione vi porta al file di origine (in cui la definizione è) piuttosto che il file di intestazione (in cui la dichiarazione è).

Non sto dicendo di non fare simili argomenti, ma tieni presente che non tutti sono a proprio agio con gli strumenti che usi come sei.


La stessa domanda può applicarsi a Pascal / Delphi dove non abbiamo file sorgente e di intestazione, ma sezioni di interfaccia e implementazione.
Jan Doggen,

Risposte:


96

La mia opinione...

  • Documentare come utilizzare la funzione nel file di intestazione o in modo più vicino alla dichiarazione.

  • Documenta come funziona la funzione (se non è ovvio dal codice) nel file sorgente o, più precisamente, vicino alla definizione.

Per quanto riguarda il colpo d'occhio nell'intestazione, non hai necessariamente bisogno della documentazione che si chiude - puoi documentare gruppi di dichiarazioni contemporaneamente.

In linea di massima, il chiamante dovrebbe essere interessato a errori ed eccezioni (se solo così possono essere tradotti mentre propaga attraverso gli strati di astrazione), quindi questi dovrebbero essere documentati vicino alle dichiarazioni pertinenti.


13
+1 - ovvero documentare l'interfaccia nell'intestazione. I dettagli di Gory su come e perché nella fonte.
quick_now

2
Per le intestazioni delle librerie in cui non è disponibile alcuna fonte, è possibile aggiungere condizioni pre e post, ecc ... per aiutare con i test. Inoltre aggiungi O (n) prestazioni se ha senso, in modo che gli utenti della biblioteca possano scegliere saggiamente.
Patrick Hughes,

Naturalmente, a volte la dichiarazione e la definizione sono la stessa cosa.
Deduplicatore

@Deduplicator - quando le stesse regole portano ancora alla cosa giusta anche nel caso speciale, perché fare eco a quelle regole per ogni caso speciale? Sicuramente un deduplicatore non dovrebbe volerlo?
Steve314

1
@Deduplicator - ovviamente questa è una logica fortemente ripensata per non aver seguito il tuo consiglio, ma ci sto tenendo duro.
Steve314

34

Se hai intenzione di utilizzare uno strumento come Doxygen (nota nel primo esempio, che assomiglia davvero a un commento Doxygen perché inizia con /**) allora non importa davvero - Doxygen guarderà attraverso l'intestazione e i file sorgente e troverà tutti i commenti per generare la documentazione.

Tuttavia, sarei più propenso a inserire i commenti della documentazione nelle intestazioni, dove sono le dichiarazioni. I tuoi clienti avranno a che fare con le intestazioni per interfacciarsi con il tuo software, le intestazioni sono ciò che includeranno nei loro file di origine ed è lì che guarderanno prima per vedere come appare la tua API.

Se ad esempio guardi la maggior parte delle librerie Linux, il tuo sistema di gestione dei pacchetti Linux ha spesso un pacchetto che contiene solo i binari della libreria (per utenti "normali" che hanno programmi che necessitano della libreria) e hai un pacchetto "dev" che contiene le intestazioni per la libreria. Il codice sorgente non viene normalmente fornito direttamente in un pacchetto. Sarebbe davvero ingombrante se dovessi ottenere il codice sorgente di una libreria da qualche parte per ottenere la documentazione dell'API.


2
+1 - a condizione che anche se usi Doxygen, ciò non significa che non leggerai mai direttamente dalla fonte. Le annotazioni Doxygen sono talvolta utili anche come pattern standard per cui grep, ed è utile se l'annotazione che trovi è vicina al codice che descrive.
Steve314,

1
@ Steve314 ofcourse Non ho detto che non avresti mai voluto guardare il codice sorgente di alcune librerie, ma non sarebbe il primo posto in cui potresti cercare l'aspetto dell'API e come usarlo.
Jesper,

Vorrei anche raccomandare di mantenere tutto ciò che riguarda l'API nell'intestazione (o almeno nell'intestazione o nella fonte), poiché eviterebbe potenziali incoerenze durante l'aggiornamento della documentazione in un posto e non nell'altro.
jopasserat,

12

Abbiamo risolto questo problema (circa 25 anni fa) creando un gruppo di #define (ad esempio pubblico, privato, ecc. Che si sono risolti in <nulla>) che potrebbero essere utilizzate nel file sorgente e scansionate da uno script awk (horrors !) per generare automaticamente i file .h. Ciò significa che tutti i commenti vivevano nel sorgente e venivano copiati (quando appropriato) nel file .h generato. So che è piuttosto vecchia scuola, ma ha semplificato enormemente questo tipo di documentazione in linea.


1
hmm so che questo stile di cose può essere utile, ma dal mio punto di vista ho sempre trovato quel tipo di documentazione decisamente fastidiosa ...
osirisgothra,

1
Per parafrasare Donald Rumsfeld (un uomo che non mi è piaciuto), "Tu programmi con gli strumenti che hai, non con gli strumenti che vorresti avere." Ogni lingua con cui ho lavorato negli ultimi 40+ anni ha avuto almeno una verruca importante (se non di più). La nostra soluzione a) ha funzionato, b) ha utilizzato gli strumenti esistenti al momento, c) facendoci passare il nostro tempo a ottenere codice che genera entrate dalla porta.
Peter Rowell,

Anche se probabilmente non opterei per questo, è un modo interessante per gestire i commenti nelle intestazioni. Le intestazioni generate sarebbero nel controllo versione? o questo è un processo di rilascio per rendere la fonte ridistribuibile? (ma non utilizzato dagli sviluppatori)
ideasman42

Oh, ho visto di recente lo stesso modello in un progetto iniziato nel ≥ 2000 ed erano così orgogliosi della loro intelligente invenzione ...
5gon12eder

3
Nel nostro caso non abbiamo tenuto nessuno dei file generati sotto controllo della versione poiché erano facilmente e direttamente (ri) derivati ​​da file tracciati.
Peter Rowell,

9

Supponendo che questo sia codice all'interno di un progetto più ampio (in cui gli sviluppatori si sposteranno spesso tra sorgente e intestazioni) , e fornendo questo non è una libreria / middleware, dove altri potrebbero non avere accesso alla fonte, ho trovato che funziona migliore...

  • Intestazioni:
    abbassa i commenti di 1-2 righe, solo se sono necessari.
    A volte sono utili anche i commenti sopra un gruppo di funzioni correlate.
  • Fonte:
    documentazione sull'API direttamente sopra la funzione (testo normale o doxygen, se si preferisce) .
  • Conservare i dettagli dell'implementazione, rilevanti solo per uno sviluppatore che modifica il codice nel corpo della funzione.

Il motivo principale di ciò è mantenere i commenti vicini al codice, ho notato che i documenti nelle intestazioni tendono a non sincronizzarsi con le modifiche al codice più spesso (ovviamente non dovrebbero, ma lo hanno fatto nel nostro progetto su almeno) . Inoltre gli sviluppatori possono aggiungere documentazione nella parte superiore delle funzioni quando apportano alcune modifiche, anche se ci sono documenti di intestazione ... da qualche altra parte. Causare raddoppi o informazioni utili solo per trovarsi in una delle stringhe di documenti.

Ovviamente puoi scegliere una convenzione e assicurarti che tutti gli sviluppatori seguano, ho appena trovato la convenzione sopra la più naturale e causa meno problemi da mantenere.


Infine, per i progetti di grandi dimensioni, c'è un'inclinazione a non apportare piccole correzioni in un'intestazione quando si sa che causerà la ricompilazione di potenzialmente 100 o 1000 file quando altri aggiornano il controllo della versione, rallentando anche gli errori di bisettrice.


5

Secondo la mia opinione (piuttosto limitata e parziale), sono un modo di pensare in codice pro-source. Quando faccio bit e pezzi in C ++, di solito modifico il file header una volta e poi non torno più a guardarlo.

Quando inserisco la documentazione nel file sorgente, la vedo sempre quando modifico o leggo i codici. Immagino sia un'abitudine.

Ma sono solo io ...


1
Non funziona molto bene se hai solo una libreria compilata e il file di intestazione. In tal caso, più informazioni nell'intestazione sono buone perché sono l'unica documentazione dell'interfaccia che hai.
quick_now

potresti generare documentazione con doxygen - lo prende anche dai file .c. In questo modo è possibile distribuire facilmente la documentazione con le librerie compilate. Ma il problema sarebbe con IDE in grado di analizzare i file di intestazione e darti la documentazione durante l'utilizzo della funzione ... Ma forse potrebbe risolvere alcuni script di distribuzione che
copierebbero i

5

I commenti non sono documentazione. La documentazione per una funzione potrebbe in genere essere 2K di testo, possibilmente con diagrammi, vedere ad esempio la documentazione per le funzioni in Windows SDK. Anche se il tuo commento al documento lo consente, renderai illeggibile il codice che contiene il commento. Se si desidera produrre documentazione, utilizzare un elaboratore di testi.


aggiornamento, è molto più facile documentare in questi giorni (con cose come Qt creator là fuori) documentare semplicemente il modo doxygen (o clone), ad esempio, in qtc basta premere il tasto / alcune volte prima del commento e metà del il lavoro è fatto per te. A causa di cose del genere, dubito che le persone vorranno passare a un elaboratore di testi solo per documentare il loro codice. Lo facevo, garantito, nel 2005, ma non lo farei mai ora. Anche l'uso di un editor HTML sembra ora abbastanza arcaico.
Osirisgothra,

@osirisgothra Doxygen: la "documentazione" può essere facile da fare, e certamente produce molti LOC scritti rapidamente, ma il valore della "documentazione" prodotta rimane discutibile nella stragrande maggioranza dei casi. I commenti di Doxygen non sono né una buona documentazione (quasi tutti i dettagli cruciali mancano in modo genarile), né sono buoni commenti (tendono a ripetere ciò che è già evidente dalla firma). Penso che nbt abbia ragione nel dire che la documentazione reale non è meglio mescolata con il codice perché è dannosa per la leggibilità del codice. Andrà comunque fuori sincrono, non c'è proiettile d'argento per quello.
cmaster

4

Se gli stakeholder del tuo codice sorgente (diciamo, una piccola biblioteca) sono costituiti da "utenti" (colleghi sviluppatori che useranno le funzionalità della tua biblioteca senza essere coinvolti nella sua implementazione) e "sviluppatori" (tu e altri sviluppatori che implementeranno la biblioteca) , quindi inserisci le "informazioni degli utenti" nell'intestazione e la "nota di implementazione" nell'origine.

Per quanto riguarda il desiderio di non modificare i file di intestazione più di quanto sia assolutamente necessario - suppongo che se la tua libreria non è "in un folle flusso di cambiamenti", che "l'interfaccia" e la "funzionalità" non cambieranno molto, e nemmeno i commenti dell'intestazione cambiano troppo frequentemente. D'altra parte, i commenti sul codice sorgente dovranno essere mantenuti sincronizzati ("nuovi") con il codice sorgente.


0

Il punto centrale dell'utilizzo di doxygen è che si genera documentazione e la si rende accessibile altrove. Ora tutta quella documentazione nelle intestazioni è solo spazzatura che rende più difficile individuare rapidamente la dichiarazione di funzione richiesta e forse i suoi sovraccarichi. Un commento di copertina è massimo che dovrebbe andare lì, ma anche questa è una cattiva pratica. Causa se si modifica la documentazione nell'origine, ricompilare tale origine e ricollegarla. Ma se metti i documenti nell'intestazione non vuoi davvero cambiare una minima cosa lì dentro, perché innescherà una parte significativa della ricostruzione del progetto.


1
questo non sembra offrire nulla di sostanziale rispetto ai punti formulati e spiegati nelle precedenti 7 risposte
moscerino

1
@gnat dalle precedenti 7 risposte solo uno è a favore del codice rispetto alle intestazioni. E quello sta dando argomentazioni totalmente diverse.
Slava,
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.