Come semplificare la comprensione di una base di codice di grandi dimensioni


104

Supponiamo che stia sviluppando un progetto relativamente grande. Ho già documentato tutte le mie classi e funzioni con Doxygen, tuttavia, ho avuto l'idea di mettere un "note del programmatore" su ogni file di codice sorgente.

L'idea alla base è quella di spiegare in parole povere come funziona una classe specifica (e non solo perché come fanno molti commenti). In altre parole, per dare agli altri programmatori una visione diversa di come funziona una classe.

Per esempio:

/*
 * PROGRAMMER'S NOTES:
 *
 * As stated in the documentation, the GamepadManager class 
 * reads joystick joystick input using SDL and 'parses' SDL events to
 * Qt signals.
 *
 * Most of the code here is about goofing around the joystick mappings.
 * We want to avoid having different joystick behaviours between
 * operating systems to have a more integrated user experience, since
 * we don't want team members to have a bad surprise while
 * driving their robots with different laptops.
 *
 * Unfortunately, we cannot use SDL's GamepadAPI because the robots
 * are interested in getting the button/axes numbers, not the "A" or
 * "X" button.
 *
 * To get around this issue, we created a INI file for the most common 
 * controllers that maps each joystick button/axis to the "standard" 
 * buttons and axes used by most teams. 
 *
 * We choose to use INI files because we can safely use QSettings
 * to read its values and we don't have to worry about having to use
 * third-party tools to read other formats.
 */

Sarebbe un buon modo per rendere più semplice un grande progetto per i nuovi programmatori / collaboratori per capire come funziona? Oltre a mantenere uno stile di codifica coerente e un'organizzazione di directory "standard", ci sono "standard" o raccomandazioni per questi casi?


32
Diavolo, no. Se il tuo codice è illeggibile, la documentazione non sarà di aiuto.
Telastyn,

35
@jeffo - il problema è che prendere il tempo per farlo può succedere una volta. Il tempo per mantenere leggibile il codice avviene nel tempo. Sono stato in luoghi con questo tipo di documentazione, fatto quando il progetto era giovane o quando Joe il perfezionista era ancora nella squadra. Poi è stato abbandonato e i commenti sono rimasti, non più accurati.
Telastyn,

25
Almeno a un livello superiore, una descrizione in prosa fuori codice di ciò che fa un progetto, come funziona e quali compromessi sono stati fatti nell'architettura è inestimabile. Questo tipo di documento è un must per i nuovi arrivati prima che facciano un tour del codice. Ci sono molte stronzate sulla mia metodologia-è-troppo-radicale-per-doc-documenti intorno alla rete, e mentre è vero che un documento arco iniziale e un documento arco in evoluzione non si allineano, è necessaria una descrizione in prosa per chiunque di afferrare rapidamente una base di codice grande, non banale. Ecco un esempio (scarso): zxq9.com/erlmud/html/001-002_architecture.html
zxq9

11
@Telastyn: questo non ha nulla a che fare con la leggibilità o meno del codice (e spero che lo sia). Documentare la logica del design è assolutamente importante.
Razze di leggerezza in orbita

7
@Telastyn: Sì, forse. Personalmente lo scriverei in un documento autonomo. Ma i blocchi di commenti nella parte superiore dei file di origine non sono poi così male.
Razze di leggerezza in orbita

Risposte:


139

Questo e spettacolare. Vorrei che più sviluppatori di software si prendessero il tempo e gli sforzi per farlo. It:

  • Dichiara in parole povere cosa fa la classe (cioè la sua responsabilità),
  • Fornisce utili informazioni supplementari sul codice senza ripetere testualmente ciò che il codice dice già,
  • Delinea alcune delle decisioni di progettazione e perché sono state prese, e
  • Evidenzia alcuni dei gotcha che potrebbero accadere alla prossima persona che legge il tuo codice.

Purtroppo, molti programmatori cadono nel campo di "se il codice è scritto correttamente, non dovrebbe essere documentato". Non vero. Esistono molte relazioni implicite tra classi di codice, metodi, moduli e altri artefatti che non sono evidenti dalla sola lettura del codice stesso.

Un programmatore esperto può creare con cura un design con un'architettura chiara e facilmente comprensibile che è ovvio senza documentazione. Ma quanti programmi del genere hai effettivamente visto?


15
E perché il "Mese dell'uomo mitico" diventa una profezia che si autoavvera, nessuno si è preso il tempo di scrivere tutto questo per il nuovo sviluppatore quando era fresco di mente e il progetto non è rimasto indietro.
JeffO

3
Sono d'accordo con ogni punto che fai qui. Non mi piace il termine usato dall'OP nel suo post how a class works. Questo cambia con il tempo e la manutenzione. Sebbene il mio team non metta quanto sopra nella fonte. Manteniamo un wiki con le decisioni e copiamo la discussione del canale lento sulle decisioni di progettazione in un documento (Forniamo un collegamento dal sommario delle decisioni e la conclusione alle note non elaborate in modo da non dover ricodificare le vecchie decisioni). Tutto fatto ordinatamente in github (quindi è tutto in un unico posto).
Martin York,

1
Il mio unico problema è applicarlo a livello globale. Questa classe è abbastanza complessa, con alcuni gotcha disponibili, chiaramente è davvero utile (anche se alla fine hai a che fare con Comment Rot). Quando una classe è più ovvia, il commento può essere un po 'superfluo.
Deworde,

1
"Un programmatore esperto può creare con cura un design con un'architettura chiara e facilmente comprensibile che sia ovvia senza documentazione. Ma quanti programmi simili hai effettivamente visto" Mentre questo è vero, la qualità della documentazione non è mai migliore della qualità di il codice. Un codice ben progettato tende ad avere una buona, seppur inutile, documentazione. Il codice scarsamente progettato ha commenti come "incremento x di 1"
deworde

3
Sono assolutamente d'accordo con questa risposta, e se trovassi qualcosa di simile all'esempio del PO nel codice, sarei così felice. Solo una singola aggiunta: prendi in considerazione l'aggiunta di una data al tuo commento, solo per dare un suggerimento a eventuali lettori sulla freschezza della descrizione e aggiornala ogni volta che aggiorni il testo.
Svalorzen,

36

La chiave per lavorare con un codebase di grandi dimensioni non è dover leggere l'intero codebase per apportare una modifica. Per consentire a un programmatore di trovare rapidamente il codice che sta cercando, il codice dovrebbe essere organizzato e l'organizzazione apparente. Cioè, ogni unità logica nel codice, dall'eseguibile, dalla libreria, dallo spazio dei nomi, fino alla singola classe dovrebbe avere una chiara responsabilità. Vorrei quindi non solo documentare i file di origine, ma anche le directory in cui risiedono.

Le note del programmatore forniscono anche informazioni sulle decisioni di progettazione. Sebbene queste possano essere informazioni preziose, le separerei dalla dichiarazione di responsabilità (per consentire al lettore di scegliere se desidera leggere le responsabilità della classe o la sua logica progettuale) e spostarla il più vicino possibile alla fonte che descrive per quanto possibile, per massimizzare la possibilità che la documentazione venga aggiornata quando il codice è (la documentazione è utile solo se possiamo fidarci della sua precisione - la documentazione obsoleta può essere peggiore di niente!).

Detto questo, la documentazione dovrebbe rimanere ASCIUTTA, ovvero non ripetere le informazioni che avrebbero potuto essere espresse in codice o che erano già state descritte altrove (frasi come "come indicato nella documentazione" sono un segnale di avvertimento). In particolare, i futuri manutentori saranno solo abili nel linguaggio di programmazione del progetto in quanto sono in inglese; parafrasando l'implementazione nei commenti (che vedo del tutto troppo spesso quando le persone sono orgogliose della loro documentazione) non ha alcun vantaggio e probabilmente divergerà dall'implementazione, in particolare se la documentazione non è vicina al codice che descrive.

Infine, la struttura della documentazione dovrebbe essere standardizzata in tutto il progetto in modo che tutti possano trovarla (è un casino reale di documenti di Peter nel tracker dei bug, Sue nel wiki, Alan nel readme e John nel codice sorgente ...) .


La tua prima frase è esattamente come la vedo io. Basi di codice di grandi dimensioni dovrebbero essere composte come un numero di componenti più piccoli in cui un nuovo programmatore può cambiarne uno in modo affidabile senza mettere in pericolo nessuno degli altri.
Jon Chesterfield,

1
spostalo il più vicino possibile alla fonte che descrive, per massimizzare la possibilità che la documentazione venga aggiornata quando il codice è . Questa è un'esperienza preziosa.
laike9m,

ASCIUGARE come linea guida per la documentazione è un ottimo punto! Ciò imposta automaticamente la messa a fuoco corretta e proibisce i commenti notoriamente odiosi "// increment x di 1".
Hans-Peter Störr,

13

Non sarei d'accordo che questo sia un ottimo approccio, principalmente dovuto a

  1. Quando si esegue il refactoring del progetto, si spostano i metodi, la documentazione si interrompe.

  2. Se la documentazione non viene aggiornata correttamente, si creerà più confusione che aiuto nella comprensione del codice.

Se si dispone di unit test per ciascun metodo / test di integrazione per ciascun modulo, si tratterebbe di una autocompensazione più gestibile e più facile da comprendere rispetto ai commenti sul codice.

Sì, avere una struttura di directory adeguata sicuramente aiuterà.


+1 per i test è il modo migliore per comprendere una base di codice. Test unitari, test di integrazione, test di accettazione raccontano la storia di come dovrebbe funzionare l'applicazione e come dovrebbe essere usata.
BZink

7

Personalmente sono un fan di un documento di design di alto livello - preferibilmente scritto PRIMA di qualsiasi codice - che offre una panoramica del design e un elenco di classi e risorse. Un design top-down semplifica notevolmente le cose: il tuo potrebbe essere "motore di gioco -> hardware -> controller -> joystick"; quindi, un nuovo programmatore ha detto che "aggiustare il pulsante 'a' sul 'controller xyz" avrebbe almeno saputo dove iniziare a cercare.

Troppe lingue moderne tendono a suddividere il codice in centinaia di piccoli file, quindi solo trovare il file corretto può essere una sfida anche per un progetto moderato.


16
20 anni fa tutto il mio codice era in un unico enorme file. Ora è in migliaia di piccoli file e file di test. C'è una buona ragione per questo e riflette 20 anni di sviluppo software (l'ecosistema generale, non le mie conoscenze). Waaay troppo a lungo per un commento però.
Michael Durrant,

4
ah, il vecchio metodo a cascata di scrivere una Verità unica, comprensiva, immutabile, prima ancora che il codice inizi e rende impossibile deviare nell'attuazione da detta Verità.
jwenting

2
@jwenting: non devi andare così lontano. Ma è ancora bene avere una certa idea di che cosa si sta costruendo.
Robert Harvey,

1
Certamente senza il monito su come scomporre correttamente questo e dove infrangere le regole, avrai molto rapidamente un documento che è obsoleto o una macina. "Devo aggiungere una nuova classe; a Documanto, il Behemoth che mangia tempo!"
Deworde,

2
@deworde: l'ho letto come "troppo pigro per conservare la documentazione".
Robert Harvey,

6

Se la base di codice è grande, provo a fornire un documento di progettazione che mappi gli elementi chiave della sua progettazione e implementazione . L'intenzione qui non è quella di dettagliare nessuna delle classi utilizzate, ma fornire una chiave per codificare e il pensiero che è andato nella progettazione. Fornisce un contesto generale al sistema, ai suoi componenti e alla sua applicazione.

Le cose da includere nel documento di progettazione sono;

  • Architettura dell'applicazione
  • Struttura del codice logico
  • Flussi di dati
  • Modelli chiave utilizzati e motivazione dietro il loro utilizzo
  • Struttura del codice sorgente
  • Come costruirlo (questo offre informazioni sulle dipendenze implicite e sulla struttura del codice fisico)

A seguito di ciò, la documentazione per le classi e le funzioni / i metodi dovrebbero essere completate come appropriato . In particolare l'API pubblica; dovrebbe essere chiaro quali sono i seguenti in tutti i casi;

  • presupposti
  • effetti
  • invarianti
  • Condizioni di eccezione (genera)

+1 Meglio che descrivere ogni classe, in quanto non sarà più aggiornato di un progetto generale.
Lode

4

La regola più importante che ho trovato per facilitare ai nuovi sviluppatori la comprensione di una base di codice è che l' accordo perfetto è costoso.

Se i nuovi sviluppatori devono comprendere perfettamente il sistema su cui stanno lavorando, ciò impedisce tutte le opportunità di apprendimento sul lavoro. Penso che le note del programmatore siano un ottimo inizio, ma andrei oltre. Prova a scrivere codice che, se avvicinato di nuovo, consentirebbe a uno sviluppatore di capire cosa stanno facendo al volo, piuttosto che richiedere loro di imparare prima di farlo. Piccole cose come asserzioni per casi che conosci non possono mai accadere, insieme a commenti che spiegano perché l'asserzione è valida, fanno molto. Lo stesso vale per la scrittura di codice che non riesce con garbo anziché segfault se si fa qualcosa di sbagliato.


La mia regola è che i commenti dovrebbero riguardare PERCHÉ , non COME . Il codice descrive COME.
user11393

3

Ho visto grandi classi con documentazione e dopo aver letto la documentazione non ho idea di cosa dovrebbe essere utile questa classe e perché qualcuno la userebbe! E allo stesso tempo, avevo bisogno di alcune funzionalità ed ero assolutamente sicuro che ci doveva essere una classe per gestirla, e non riuscivo a trovarla da nessuna parte - perché non c'era documentazione che mi guidasse da ciò di cui avevo bisogno alla classe facendolo.

Quindi la prima cosa che vorrei nella documentazione è solo qualche frase su cosa fa una classe e perché vorrei usarla. I commenti nella domanda originale stanno andando abbastanza bene al riguardo. Dopo aver letto questi commenti, se avessi un joystick che non funziona bene perché non riesco a interpretare i valori forniti, saprei quale codice controllare.


0

Simile a quello che ha detto @meriton, suddividere il codice in componenti separati. Ancora meglio, suddividere la base di codice in pacchetti separati (JAR, gemme, uova, qualunque cosa) per rendere ancora più chiaro il modo in cui i componenti sono separati. Se c'è un bug, uno sviluppatore deve solo trovare il pacchetto in cui si trova il bug e (si spera) risolverlo solo lì. Per non parlare del fatto che è più semplice eseguire unit test e sfruttare la gestione delle dipendenze.

Un'altra soluzione: ridurre la base di codice. Meno codice c'è, più è facile da capire. Rifattorizzare il codice inutilizzato o duplicato. Utilizzare tecniche di programmazione dichiarativa . Questo richiede sforzo, ovviamente, e spesso non è possibile o pratico. Ma è un obiettivo degno. Come ha scritto Jeff Atwood: Il miglior codice non è affatto un codice


-1

Per sistemi complessi può valere la pena non solo documentare ogni file, ma anche le loro interazioni e gerarchia, e come le strutture del programma e perché.

Ad esempio, un motore di gioco è in genere piuttosto complesso ed è difficile decidere cosa si chiama cosa dopo centinaia di strati di astrazione. Potrebbe valere la pena creare un file come "Architecture.txt" per spiegare come e perché il codice è strutturato in questo modo e perché c'è quel livello di astrazione dall'aspetto inutile lì.


-7

Ciò può essere in parte dovuto al fatto che è difficile per un singolo programmatore scriverlo, poiché ogni individuo comprende solo la propria parte del progetto.

A volte puoi ottenere queste informazioni dalle note del project manager, ma questo è tutto ciò che otterrai, poiché raramente riscrivono le loro note in questo formato.


7
Se guardi github troverai molti progetti che hanno questo tipo di nota in un file README.md. È diventato così tanto parte della cultura di git in generale e i progetti javascript in particolare per la maggior parte delle persone non useranno una libreria che non ha questo tipo di documentazione di alto livello. Quindi non è vero che "nessun programmatore lo scriverebbe" poiché devi solo guardare qualcosa come jQuery o socket.io e trovare programmatori che scrivano tali cose. Inoltre è diventata una cultura che i file README non accurati generano segnalazioni di bug.
Slebetman,

1
Ciò non sembra rispondere alla domanda, che era alla ricerca di motivi per cui lo stile di documentazione proposto avrebbe funzionato o meno, e anche di standard di documentazione.
user52889

5
Se hai un team di programmatori che lavora su un prodotto e ogni programmatore capisce solo il codice specifico su cui ha lavorato, non solo il tuo team è incredibilmente disfunzionale con un fattore di bus assurdo, ma uno mette in dubbio la qualità del codice. Come si fa a integrare il codice in un prodotto senza comprendere il resto del codice nello stesso sistema ??!?
Razze di leggerezza in orbita
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.