it-swarm.it

Cosa è dimostrato come una buona lunghezza massima di una funzione?

La lunghezza della funzione influisce sulla produttività di un programmatore? In tal caso, qual è un buon numero massimo di righe per evitare la perdita di produttività?

Dal momento che si tratta di un argomento molto apprezzato, eseguire il backup del reclamo con alcuni dati.

47
Gaurav

Da quando mi sono imbarcato in questa folle racchetta nel 1970, ho visto esattamente un modulo che in realtà necessario essere più di una pagina stampata (circa 60 righe). Ho visto molti moduli più lunghi.

Del resto, ho scritto moduli più lunghi, ma di solito erano grandi macchine a stati finiti scritte come grandi dichiarazioni switch.

Parte del problema sembra essere che ai programmatori in questi giorni non viene insegnato a modulare le cose.

Anche gli standard di codifica che massimizzano lo spreco di spazio verticale sembrano essere parte del problema. (Ho ancora per incontrare un manager software che ha letto Gerald Weinberg " Psicologia della programmazione informatica ". Weinberg sottolinea che numerosi studi hanno dimostrato che la comprensione del programmatore è essenzialmente limitata a ciò che il programmatore può vedere in un dato istante. Se il programmatore deve scorrere o girare una pagina, la sua comprensione diminuisce in modo significativo: devono ricordare e astrarre.)

Rimango convinto che molti dei guadagni di produttività del programmatore ben documentati da [~ # ~] avanti [~ # ~] erano dovuti al sistema "blocco" FORTH per il codice sorgente: moduli erano fortemente limitati a un massimo assoluto di 16 righe di 64 caratteri. Potresti considerare il fattore all'infinito, ma tu non potresti in nessun caso scrivere una routine di 17 righe.

47
John R. Strohm

Qual è la taglia giusta, davvero?

Dipende dalla lingua che usi, ma in generale (e per i miei gusti personali):

  • Idealmente , meno di 25 righe.
  • Accettabilmente , meno di 35 righe.

Se è di più, allora è qualcosa che devo tornare più tardi e rielaborare.

Ma realisticamente , qualsiasi dimensione deve essere quando devi consegnare qualcosa e che ha più senso al momento sputarli in quel modo, fa a volte è ancora più facile per qualcuno rivederlo prima della spedizione. (ma ci torno ancora più tardi).

(Recentemente il mio team ha eseguito un programma sul nostro codebase: abbiamo trovato classe con 197 metodi e un altro con solo 3 metodi ma uno di questi era 600 linee. Gioco carino: qual è il peggio dei 2 mali?)


Ora per una risposta più zen ... In generale è considerata una buona pratica (TM) citare uno o due grandi uomini, quindi ecco qui:

Tutto dovrebbe essere reso il più semplice possibile, ma non più semplice. - A. Einstein

La perfezione si ottiene finalmente non quando non c'è più nulla da aggiungere, ma quando non c'è più nulla da togliere. - A. De Saint Exupéry


Addendum su stili di commento

Come aggiunta a questo, le tue funzioni dovrebbero avere nomi chiari che spiegano il loro intento. Per quanto riguarda i commenti, di solito non faccio commenti all'interno di una funzione:

  • commenti dicono "why?" ,
  • codice dice "come?" .

È sufficiente un blocco di commenti nella parte superiore di ogni funzione (che richiede una spiegazione). Se la tua funzione è piccola e i nomi delle funzioni sono abbastanza espliciti, dovresti semplicemente dire cosa vuoi ottenere e perché. Uso i commenti incorporati solo per i campi in alcune lingue o all'inizio del blocco per le funzioni che infrangono le regole della riga 25-35 se l'intento non è chiaro. Uso un commento a blocchi all'interno del codice quando si verifica una situazione eccezionale (un blocco catch in cui non è necessario o che si desidera fare qualcosa dovrebbe avere un commento che spiega perché, ad esempio).

Per ulteriori informazioni, leggi la mia risposta su Stile e raccomandazioni del codice di commento

31
haylem

A mio avviso, ogni funzione dovrebbe essere il più piccola possibile. Ogni funzione dovrebbe fare solo una cosa e farlo bene. Questo non risponde veramente alla domanda di massima lunghezza, ma sono più i miei sentimenti sulla lunghezza delle funzioni.

Per usare le parole di Zio Bob, "Estrai finché non riesci più ad estrarre. Estrai fino allo sfinimento."

12
Jason

Quale dovrebbe essere l'altezza massima di un edificio? Dipende da dove si trova la build o dall'altezza desiderata.
Puoi ottenere risposte diverse da persone diverse che provengono da città diverse.
Alcune funzioni di script e gestori di interruzione del kernel sono molto lunghi.

10
Huang F. Lei

Un metodo che funziona per me è: posso avere una parte di una funzione più lunga dare un nome che abbia un senso. Penso che la lunghezza di un metodo non sia così importante come una buona denominazione. Il metodo dovrebbe fare ciò che dice il nome, né più né meno. E dovresti essere in grado di dare un buon nome. Se non riesci a nominare bene il tuo metodo, probabilmente il codice non è buono messo insieme.

10
Mnementh

Finché deve essere per fare ciò che deve fare, ma non più.

10
Paul Nathan

Penso che ci sia un compromesso. Se disponi di molti metodi brevi, spesso è più difficile eseguirne il debug rispetto a un metodo lungo. Se devi saltare l'editor 20 o 30 volte diverse per tracciare una chiamata del metodo, sarà difficile tenerlo tutto nella tua testa. Nel frattempo, se esiste un metodo chiaro ben scritto, anche se è composto da 100 righe, è spesso più facile tenerlo in mente.

La vera domanda è perché gli elementi dovrebbero essere in diversi metodi e la risposta fornita sopra è il riutilizzo del codice. Se non stai riutilizzando il codice (o non lo sai), potrebbe essere logico lasciarlo in un unico metodo facile da seguire e, dato che devi riutilizzarlo, dividi le parti che devono riutilizzare usando in metodi più piccoli.

In realtà, parte del buon metodo di progettazione sta realizzando metodi funzionalmente coerenti (essenzialmente fanno una cosa). La lunghezza dei metodi non ha importanza. Se una funzione fa una cosa ben definita ed è di 1.000 righe, allora è un buon metodo. Se una funzione fa 3 o 4 cose ed è solo 15 linee, allora è un cattivo metodo ...

6
Cervo

Da Complessità ciclomatica (Wikipedia):

La complessità ciclomatica di una sezione del codice sorgente è il conteggio del numero di percorsi linearmente indipendenti attraverso il codice sorgente.

  • Ti consiglio di mantenere quel numero sotto i 10 in un unico metodo. Se arriva a 10, allora è il momento di ricodificare.

  • Ci sono strumenti che possono valutare il tuo codice e darti un numero di complessità ciclomatica.

  • Dovresti cercare di integrare questi strumenti nella tua pipeline di build.

  • Non inseguire letteralmente le dimensioni di un metodo, ma cerca di osservarne la complessità e le responsabilità. Se ha più di una responsabilità, allora è probabilmente una buona idea ripensare. Se la sua complessità ciclomatica aumenta, allora è probabilmente il momento di ricodificare.

  • Sono abbastanza certo che ci sono altri strumenti che ti danno un feedback simile, ma non ho ancora avuto la possibilità di esaminarlo.

5
CodeART

Per me, una funzione è la lunghezza che deve essere. Il più delle volte che lo divido è quando riuserò il codice.

Fondamentalmente, mi atterrò alla principale "alta coesione, basso accoppiamento" e non ci sono vincoli sulla lunghezza.

5
Ross

La domanda dovrebbe essere: quante cose dovrebbe fare una funzione. E di solito, è raro che tu abbia bisogno di 100 linee per fare "una" cosa. Ancora una volta dipende dal livello dal quale stai guardando il codice: l'hashing di una password è una cosa? O l'hashing e il salvataggio della password sono una cosa?

Direi, inizia con il salvataggio della password come una funzione. Quando ritieni che l'hash sia diverso e rifletti il ​​codice. Non sono un programmatore esperto in alcun modo, ma IMHO, l'intera idea delle funzioni inizia in piccolo è che più atomiche sono le tue funzioni, maggiori sono le possibilità di riutilizzo del codice, non dovendo mai fare la stessa modifica in più di un posto , eccetera.

Ho visto SQL stored procedure che si estendono su 1000 righe. Anche il numero di righe di stored procedure è inferiore a 50? Non lo so, ma rende la lettura del codice, inferno. Non solo devi continuare a scorrere su e giù, ma devi dare ad alcune righe di codice un nome come "this does validation1", "this update in the database", ecc. - un lavoro che il programmatore avrebbe dovuto fare.

5
Narayana

Trovo più facile tenere traccia di ciò che sto facendo se riesco a vedere l'intera funzione in una volta. Quindi ecco come preferisco scrivere funzioni:

  1. Abbastanza corto da adattarsi al mio monitor con un carattere ragionevole.
  2. Se deve essere più lungo del n. 1, abbastanza corto per stampare su un pezzo di carta con un carattere ragionevole.
  3. Se deve essere più lungo del n. 2, abbastanza corto per stampare 2 in 1 su un foglio di carta.

Raramente scrivo funzioni più lunghe di così. La maggior parte di questi sono gigantesche istruzioni switch C/C++.

5
Bob Murphy

Abbastanza corto per essere ottimizzato correttamente

I metodi dovrebbero essere così brevi da fare esattamente una cosa. Il motivo è semplice: in questo modo il tuo codice può essere ottimizzato correttamente.

In un linguaggio JIT come Java o C #, è importante che i tuoi metodi siano semplici in modo che il compilatore JIT possa produrre codice rapidamente. I metodi più lunghi e più complicati richiedono naturalmente più tempo JIT. Inoltre, i compilatori JIT offrono solo una manciata di ottimizzazioni e solo i metodi più semplici ne traggono vantaggio: questo fatto è stato anche messo in evidenza nel Effective C # di Bill Wagner.

In un linguaggio di livello inferiore, come C o C++, anche avere metodi brevi (forse una dozzina di righe) è importante perché in questo modo minimizzi la necessità di memorizzare variabili locali in RAM anziché in un registro. (Aka "Registrazione fuoriuscita"). Si noti tuttavia che in questo caso non gestito, il costo relativo di ciascuna chiamata di funzione può essere piuttosto elevato.

E anche in un linguaggio dinamico, come Ruby o Python, avere metodi brevi aiuta anche nelle ottimizzazioni del compilatore. In un linguaggio dinamico più una funzionalità è "dinamica", più è difficile Ad esempio, un metodo lungo che accetta una X e potrebbe restituire un Int, Float o String probabilmente eseguirà molto più lentamente di tre metodi separati che restituiscono ciascuno solo un singolo tipo, perché se il compilatore sa esattamente quale tipo la funzione tornerà, può anche ottimizzare il sito di chiamata della funzione (ad esempio, non controllando le conversioni di tipo).

4
Chris Smith

In genere, provo a mantenere i miei metodi/funzioni su ciò che si adatta allo schermo di un monitor 1680x1050. Se non si adatta, utilizzare i metodi/le funzioni di supporto per distribuire l'attività.

Aiuta la leggibilità sia su schermo che su carta.

4
Jason

Non pongo limiti fissi a nulla perché alcune funzioni implementano algoritmi intrinsecamente complessi e qualsiasi tentativo di renderli più brevi renderebbe le interazioni tra le nuove funzioni più brevi così complicate che il risultato netto non ridurrebbe la semplicità. Inoltre, non credo che l'idea che una funzione debba fare solo "una cosa" è una buona guida, poiché "una cosa" ad un alto livello di astrazione può essere "molte cose" ad un livello inferiore.

Per me, una funzione è decisamente troppo lunga se la sua lunghezza causa sottili violazioni di DRY in questo momento, ed estrarre parte della funzione in una nuova funzione o classe potrebbe risolverlo. Una funzione potrebbe essere troppo a lungo se questo non è il caso, ma una funzione o classe potrebbe essere facilmente estratta in modo da rendere il codice più modulare in un modo che potrebbe essere utile di fronte a cambiamenti prevedibili lungo la strada.

4
dsimcha

Dipende molto da cosa c'è nel codice.

Ho visto una routine di mille righe con cui non ho avuto problemi. Era un'enorme istruzione switch, nessuna opzione superava una dozzina di righe e l'unica struttura di controllo in ogni opzione era un singolo loop. In questi giorni sarebbe stato scritto con oggetti ma non era un'opzione allora.

Sto anche guardando 120 linee in un interruttore di fronte a me. Nessun caso supera 3 righe: una guardia, un incarico e l'interruzione. Sta analizzando un file di testo, gli oggetti non sono una possibilità. Qualsiasi alternativa sarebbe più difficile da leggere.

3
Loren Pechtel

Alla maggior parte dei compilatori non importa la lunghezza di una funzione. Una funzione dovrebbe essere funzionale, ma essere sia facile da capire, cambiare e riutilizzare per gli esseri umani. Scegli una lunghezza adatta a te.

2
LennyProgrammers

Forse la lunghezza della funzione non è una buona metrica. Cerchiamo di usare complessità ciclomatica , anche sui metodi, e uno dei futuri controlli del codice sorgente controlla che la complessità ciclomatica su classi e metodi deve essere inferiore a X.

Per i metodi, X è impostato su 30 ed è abbastanza stretto.

1
Antonio Bakula

La mia regola generale è che una funzione dovrebbe adattarsi allo schermo. Sono stati trovati solo tre casi che tendono a violare:

1) Funzioni di invio. Ai vecchi tempi questi erano comuni ma la maggior parte di questi sono sostituiti con l'eredità degli oggetti in questi giorni. Gli oggetti funzionano solo all'interno del tuo programma, quindi vedrai comunque funzioni di invio occasionali quando gestisci i dati che arrivano da altrove.

2) Funzioni che eseguono tutta una serie di passaggi per raggiungere un obiettivo e in cui i passaggi mancano di una buona suddivisione. Si finisce con una funzione che chiama semplicemente un lungo elenco di altre funzioni in ordine.

3) Come il n. 2 ma in cui i singoli passaggi sono così piccoli da essere semplicemente allineati anziché chiamati separatamente.

1
Loren Pechtel