Codice di fantasia breve commentato vs. codice di facile comprensione più lungo non commentato - quale è preferito?


18

A volte un algoritmo può essere scritto in due modi:

  • Il modo breve e elegante; o
  • Il modo più lungo e di facile comprensione.

Ad esempio, ecco un modo più lungo e più semplice di copiare una stringa sourcein destin C:

*dest = *source;
while (*source != '\0') {
    source++;
    dest++;
    *dest = *source;
} (true);

Ed ecco un modo breve e di fantasia.

// Copy string source to dest
while (*dest++ = *source++);

Ho sempre sentito e letto che il codice di fantasia dovrebbe essere evitato e tendo ad essere d'accordo. E se prendessimo in considerazione i commenti? Supponiamo che, come negli esempi sopra, abbiamo un codice non commentato, più lungo e presumibilmente più facile da capire, e un codice ben commentato, breve e di fantasia? Il codice non di fantasia è ancora preferito?

EDIT: Molti hanno commentato i nomi delle variabili, quindi ho modificato il codice di esempio in modo da non considerarlo un fattore quando preferisco all'altro. Ho provato a rimuovere la doppia assegnazione nel primo esempio, ma ciò ha reso il codice meno leggibile.

Forse questo non era il migliore degli esempi perché molti trovano il codice "elaborato" più leggibile e comprensibile del codice più lungo. L'idea era di avere un codice più lungo che fosse molto più facile da capire di un codice molto breve ma complicato.

EDIT2: Ecco un nuovo esame che ho ricevuto da SO :

Versione fantasia commentata:

//direct formula for xoring all numbers from 1 to N
int Sum = (N & (N % 2 ? 0 : ~0) | ( ((N & 2)>>1) ^ (N & 1) ) );

Versione lunga non commentata:

int Sum = 0;
for (int i = 1; i < N; ++i)
{
   Sum ^= i; //or Sum = Sum ^ i;
}

2
@gablin: "bene" è una parola, ma è un aggettivo con un significato un po 'diverso da "buono" e non è più ampiamente usato (almeno negli Stati Uniti). La forma avverbio di "buono" è "bene" come in "codice ben commentato".
John M Gant,

@Giovanni: Ah sì, certo. Ho aggiornato la domanda di conseguenza. Grazie.
gablin,

2
In che modo la "fantasia" è breve? Questo è un pezzo di codice C da manuale che chiunque afferma di conoscere C dovrebbe essere in grado di leggere senza problemi. Terseness non significa "fantasia".
JBR Wilkinson,

@JBRWilkinson: Come ho detto nella parte modificata della domanda, questo esempio non è buono poiché la versione "fantasiosa" apparentemente non è poi così fantasiosa. L'obiettivo era di avere un modo breve ma non comprensibile con i commenti e quindi un modo più lungo ma molto più leggibile senza commenti.
gablin,

@gablin: la modifica compromette le risposte correnti.
Maniero,

Risposte:


28

Preferirei generalmente estrarre il codice di fantasia nel suo metodo ..

Invece di commentare il codice elaborato, il nome del metodo dovrebbe essere tutto ciò che serve per chiarire le cose.

char *copy_string(char *s, const char *t) {    
    while (*s++ = *t++); 
    return s;
}

3
Ottimo punto La fatturazione del codice autonomo è molto meglio dei commenti. Il compilatore sa come incorporarlo se necessario.
dbkk,

Ah sì, è un ottimo modo per rendere obsoleto il commento. Ma nonostante ciò, preferiresti sempre il codice di fantasia al codice più lungo?
gablin,

In generale si. Sento che metodi brevi e ben definiti rendono il codice più facile da leggere e mantenere. La complessità inserita nei propri metodi rende il riutilizzo più accessibile e evidente. Ci sono sempre delle eccezioni, alla fine dipende sempre dal codice.
Mongus Pong,

Sicuramente la tua funzione dovrebbe essere chiamata "strcpy"?
JBR Wilkinson,

C'è un errore in quel pezzo di codice. Cosa viene restituito? Cosa doveva essere restituito? Basta renderlo un metodo vuoto e finirlo;)
Christian Mann,

10

Sono tutto per la versione più lunga. Il problema con la versione breve del codice, oltre a essere più difficile da leggere per alcuni programmatori, è che il più delle volte è più difficile individuare gli errori semplicemente guardandolo.

Ho un esempio di vita reale. Nel nostro prodotto avevamo il seguente frammento di codice:

if (++someCounter < MAX_VALUE) {
    // Do something that has to be done only MAX_VALUE times
}

Questo codice sembra perfettamente ragionevole a prima vista, ma dopo un lungo periodo di tempo questo contatore trabocca e rompe la condizione (nello scenario di vita reale abbiamo schiacciato il sistema di produzione dei nostri clienti con un OOM). Questo codice è un po 'meno "sofisticato", ma è chiaro che fa quello che dovrebbe fare:

if (someCounter < MAX_VALUE) {
    ++someCounter;
    // Do whatever it is we came here for
}

E potresti dire che lo sviluppatore che ha scritto questo codice non era abbastanza buono (il che non è vero, era un ragazzo piuttosto brillante), ma penso che se la tua tecnica di codifica richiede di essere esperto di super-duper programmando GOD in per ottenere il codice giusto, stai facendo qualcosa di sbagliato. Il tuo codice dovrebbe essere il più sicuro possibile per il tuo bene e per chiunque debba mantenere questo codice dopo di te (che potrebbe non essere intelligente come te).

Quindi, sono tutto per semplicità e chiarezza.

Modifica: Oh, e per quanto riguarda i commenti - non importa. Molte persone non leggeranno comunque i commenti ( http://www.javaspecialists.co.za/archive/Issue039.html ) e coloro che non capiranno il tuo codice senza commenti, non lo capiranno abbastanza bene con loro in modo che può mantenerlo. L'obiettivo è aiutare le persone a capire che un determinato codice è "corretto", i commenti non possono essere d'aiuto.


1
"schiacciato il sistema di produzione del nostro cliente" - che è piuttosto male: -S

"Il problema con la versione breve del codice, oltre ad essere più difficile da leggere per alcuni programmatori" - qualsiasi pezzo di codice può essere difficile "per alcuni programmatori" da leggere. Devi solo trovare programmatori abbastanza stupidi. Non ridurre il codice al minimo denominatore.
quant_dev,

@quant_dev: al contrario, "Il debug è due volte più difficile della scrittura del codice in primo luogo. Pertanto, se si scrive il codice nel modo più intelligente possibile, non si è, per definizione, abbastanza intelligenti da eseguire il debug." - Brian W. Kernighan
Michael Borgwardt,

@MichaelBorgwardt Non applicarei il detto di Kernighan alla cieca in ogni possibile situazione. L'esempio dei PO è una funzione scritta "nel modo più intelligente possibile" (o vicino ad essa) e tuttavia dovrebbe essere abbastanza facile eseguire il debug, se è necessario un debug. D'altra parte, gli oneliner complicati possono essere molto intelligenti, ma sarà sicuramente ancora più difficile eseguire il debug. (Inoltre: Kernighan presume che le abilità di codifica = abilità di debug. Non debba essere il caso. Ho eseguito correttamente il debug del codice che non avrei potuto scrivere.)
quant_dev

6

Preferirei generalmente la versione più lunga. Due motivi principali vengono in mente:

  • È probabile che più persone lo capiscano con meno sforzo (supponendo che non sia un esempio "standard" come questa copia di stringa).
  • È possibile inserire punti di interruzione su singole dichiarazioni e passare a un debugger.

Per il meglio di entrambi i mondi, avvolgi il codice in una funzione, il cui nome fa il commento per te:

void copy_string(char *s, char *t)
{
    *s = *t;
    while (*t != '\0') {
        t++;
        s++;
        *s = *t;
    }
}

L'unico motivo per non farlo sarebbe se le prestazioni fossero un problema e la profilazione mostrasse davvero che le funzioni generali fossero significative.


1
Non è per quello che è in linea?
Antsan,

In effetti, sebbene l'inline sia accompagnato da una sua parte di problemi, come dover esporre il corpo della funzione in file header. I compilatori moderni non incorporano automaticamente le cose per te dove sono comunque sensibili?
Paul Stephenson,

4

Qualunque sia il più chiaro. Spesso è un frammento di codice compatto e facile da capire che non richiede un commento ... come il tuo secondo esempio.

Generalmente frammenti di codice più brevi sono più facili da capire in quanto c'è meno per il lettore da tenere in testa alla volta. Ovviamente, c'è un limite quando il codice viene eccessivamente offuscato e non intendo che si debba tagliare la chiarezza che migliora lo spazio bianco.

I commenti non devono mai indicare ciò che è ovvio dal codice, che fa semplicemente leggere due volte la stessa cosa al lettore. Per me il primo frammento richiede un chiarimento. Perché lo sviluppatore non ha utilizzato un do...whileciclo per rimuovere i duplicati del *s = *t;compito? Devo analizzare più codice per rendermi conto che sta implementando una copia di stringa. Un commento sarebbe più utile su questo codice più lungo che sul codice più breve.

Il commento sul secondo frammento è quasi ridondante in quanto il ciclo while è praticamente idiomatico, ma dice cosa fa il codice a un livello superiore rispetto al codice stesso che lo rende un commento utile.


Lo sviluppatore (me) non ha usato do ... whilesemplicemente perché non ci ho pensato quando ho scritto la domanda. Grazie per la segnalazione. ^^ Il secondo frammento può essere ovvio per te, ma certamente non è per me.
gablin,

4

Il problema è che non esiste una definizione chiara short fancy codepoiché dipende molto dal livello del programmatore. Mentre alcune persone non hanno problemi a comprendere while(*s++ = *t++);un'espressione, altre lo faranno.

Personalmente trovo il più while(*s++ = *t++);perfettamente leggibile e il più lungo più difficile da leggere. Altri potrebbero non essere d'accordo però.

Indipendentemente da ciò, si tratta solo di usare il buon senso. La leggibilità dovrebbe sicuramente essere una priorità, ma c'è un punto in cui il codice più lungo diventa meno leggibile quando diventa più lungo. La verbosità spesso riduce la leggibilità dalla mia esperienza.


Mi rattrista che un tema di molte di queste risposte sia "gli sviluppatori potrebbero non riconoscere il modo standard di scrivere strcpy () in C"
AShelly,

Non dovrebbe - non significa che non ci siano più buoni programmatori, piuttosto che a) non insegniamo più molto C e b) che la forza di C sia anche la sua debolezza - in questo mentre quel ciclo è comprensibile per uno praticato in C è anche piuttosto arcano e in un mondo che cerca di scrivere un codice sicuro abbastanza spaventoso per quello che implica su cosa si può fare in C
Murph

Quindi ci troviamo con un'altra sfida alle nostre attività quotidiane. Necessità di indovinare il livello generale di comprensione del linguaggio dei nostri colleghi diretti in modo che le nostre revisioni del codice rimangano costruttive. Non cadere in battaglie di cui è l'espressione "corretta", più pulita dell'intento.
frogstarr78,

2

Non sono d'accordo con la maggior parte delle altre risposte qui - penso (almeno in questo caso) che il codice più breve sia migliore. Contrariamente a quanto asserito, il codice più lungo non è "più semplice", almeno per un lettore. Semmai, sembra che tu abbia fatto tutto il possibile per renderlo più lungo, anche se rende il codice più difficile da capire e / o sicuro del corretto funzionamento.

In particolare, avendo l'assegnazione del primo byte della stringa al di fuori del ciclo, separata dall'assegnazione per gli altri byte, significa che bisogna fare molta più attenzione nella lettura per assicurarsi che tutti i byte siano copiati correttamente. La sequenza di azioni di base nella versione più breve è molto più facile da verificare. Il suo unico vero problema è nella formattazione: quando hai un corpo del loop intenzionalmente vuoto, è meglio chiarirlo, qualcosa del tipo:

while (*dest++ = *source++)
    ;

o anche:

while (*dest++ = *source++)
    ; /* no body */

Alcune persone preferiscono invece usare le parentesi graffe:

while (*dest++ = *source++)
    {}

Indipendentemente dalla formattazione esatta che preferisci, sono stati fatti abbastanza errori con cose come:

if (x>y);
     x = z;

... che è importante essere sicuri che 1) sia ovvio ciò che è effettivamente controllato da qualsiasi controllo di flusso, e 2) è ovvio che il codice è stato scritto sapendo cosa era controllato da esso, quindi qualcuno che lo legge non perde tempo a provare per capire se hanno appena trovato un bug.


Sì, a posteriori di questo esempio particolare, la versione "fantasia" è probabilmente più leggibile della versione più lunga. Se potessi pensare a un esempio migliore, lo farei, ma al momento non ci riesco. Ma non ho "fatto del mio meglio" per allungarlo - è così che avrei scritto una copia di stringa, almeno inizialmente. Potrebbe non essere l'approccio migliore, ma non è stato reso più lungo del necessario dalle intenzioni.
gablin,

2
Keep it simple, stupid!

Assicurati che qualsiasi altro programmatore possa capire cosa fa il tuo codice, e ancora meglio se è a colpo d'occhio (è qui che nomi e commenti positivi entrano in gioco).

Il kung-fu di fantasia e l'assemblaggio incoccato sono fantastici nel nome dell'ottimizzazione (forse non necessaria e prematura), ma quando anche tu non riesci a capire il codice che hai scritto quando ci si imbatte in un bug due mesi dopo .. Qual era il punto? Ti costerà tempo e fatica.

Mi riferisco spesso allo Zen di Python in queste situazioni. In particolare:

Explicit is better than implicit.
Simple is better than complex.

1

Non scrivere codice di fantasia nel software di produzione. So che è bello poterlo effettivamente scrivere, ed è più breve. Scrivere codice elaborato aumenta significativamente il valore "WTF / minuto", in altre parole diminuisce la qualità.

testo alternativo


1

Naturalmente dipende interamente dalle circostanze. ma in generale, trovo che questa sia una buona regola empirica:

Il debug è due volte più difficile della scrittura del codice in primo luogo. Pertanto, se si scrive il codice nel modo più intelligente possibile, per definizione non si è abbastanza intelligenti da eseguire il debug.

~ Brian Kernighan


più lungo ma più significativo, persino elegante , rispetto all'acronimo KISS più compatto ~ spero che l'ironia non sia persa; p
violetta313

0

Nella mia esperienza, la più grande vittoria in termini di breve codice di fantasia tende a utilizzare la ricorsione piuttosto che l'iterazione. È anche una delle cose più difficili da capire a colpo d'occhio sul codice, a meno che tu non stia lavorando nel tipo di linguaggio in cui tutto è comunque ricorsivo. Lo preferirei ancora per l'eleganza e la velocità di sviluppo che offre, ma cerco di assicurarmi che abbia commenti dettagliati se sembra che saranno opachi per i futuri manutentori o il mio sé futuro.


0

Sto iniziando a non fidarmi mai dei commenti. Troppo spesso, i commenti non vengono aggiornati quando il codice viene aggiornato e sono ampiamente obsoleti o rappresentano regole dei clienti / gestori che non sono più pertinenti.

È arrivato al punto in alcuni casi in cui i commenti non corrispondono nemmeno al codice che stanno descrivendo.

Se devo scegliere tra breve / fantasia e più / più facile da capire, allora scelgo sempre quest'ultima a meno che non v'è una davvero buona ragione.


0

La leggibilità e la manutenibilità sono fondamentali e il tuo secondo esempio (ovvero il più lungo) è molto più di entrambi. Ma perché limitarti a due opzioni? Anche il codice più lungo è troppo complesso (IMHO) per non annotarlo ulteriormente. Lo metterei in un metodo a sé stante con Javadoc appropriato (o qualsiasi altra cosa) e un nome di metodo adatto.

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.