I metodi lunghi sono sempre sbagliati? [chiuso]


64

Quindi, guardando prima ho notato alcuni commenti sui metodi lunghi come cattiva pratica.

Non sono sicuro di essere sempre d'accordo sul fatto che i metodi lunghi siano cattivi (e vorrebbero le opinioni degli altri).

Ad esempio, ho alcune viste Django che eseguono un po 'di elaborazione degli oggetti prima di inviarli alla vista, un metodo lungo è 350 righe di codice. Ho scritto il mio codice in modo che si occupi dei parametri - ordinamento / filtro del queryset, quindi a poco a poco esegue alcune elaborazioni sugli oggetti restituiti dalla mia query.

Quindi l'elaborazione è principalmente aggregazione condizionale, che ha regole abbastanza complesse che non possono essere facilmente eseguite nel database, quindi ho alcune variabili dichiarate al di fuori del ciclo principale e quindi le ho alterate durante il ciclo.

variable_1 = 0
variable_2 = 0
for object in queryset :
     if object.condition_condition_a and variable_2 > 0 :
     variable 1+= 1
     .....
     ...    
     . 
      more conditions to alter the variables

return queryset, and context 

Quindi, secondo la teoria, dovrei scomporre tutto il codice in metodi più piccoli, in modo da avere il metodo di visualizzazione come massimo una pagina.

Tuttavia, avendo lavorato su varie basi di codice in passato, a volte trovo che renda il codice meno leggibile, quando è necessario passare costantemente da un metodo all'altro per capire tutte le sue parti, mantenendo il metodo più esterno nella tua testa.

Trovo che avendo un metodo lungo ben formattato, puoi vedere la logica più facilmente, poiché non viene nascosta nei metodi interni.

Potrei scomporre il codice in metodi più piccoli, ma spesso c'è un ciclo interno utilizzato per due o tre cose, quindi si tradurrebbe in codice più complesso o metodi che non fanno una cosa ma due o tre (in alternativa Potrei ripetere i loop interni per ogni attività, ma poi ci sarà un successo nelle prestazioni).

Quindi c'è un caso in cui i metodi lunghi non sono sempre male? C'è sempre un caso per i metodi di scrittura, quando saranno usati solo in un posto?

AGGIORNAMENTO: Sembra che abbia posto questa domanda oltre un anno fa.

Quindi ho rifattorizzato il codice dopo la risposta (mista) qui, diviso in metodi. È un'app di Django che recupera insiemi complessi di oggetti correlati dal database, quindi l'argomento test è fuori (probabilmente ci sarebbe voluto quasi tutto l'anno per creare oggetti rilevanti per i casi di test. Ho un tipo di "necessità fatte ieri" ambiente di lavoro prima che qualcuno si lamenti). Correggere i bug in quella parte del codice è ora leggermente più semplice, ma non così enormemente.

prima :

#comment 1 
bit of (uncomplicated) code 1a  
bit of code 2a

#comment 2 
bit of code 2a
bit of code 2b
bit of code 2c

#comment 3
bit of code 3

adesso:

method_call_1
method_call_2
method_call_3

def method_1 
    bit of (uncomplicated) code 1a  
    bit of code 2a

def method_2 
    bit of code 2a
    bit of code 2b
    bit of code 2c

def method_3
    bit of code 3

156
Tutti gli assoluti sono cattivi. Sempre.
Joachim Sauer,

30
Vedo l'argomento "Estrai metodi se riesci a riutilizzarli" abbastanza spesso (in questa o forme simili), ma non lo compro: se il metodo sta facendo più di una cosa, dovresti estrarre metodi da esso per leggibilità / manutenibilità anche se quei nuovi metodi sono chiamati da un solo punto nel tuo codice.
Joachim Sauer,

4
@gnat: wow, una sorta di allineamento manuale (tramite un preprocessore) nella fase di costruzione non sarebbe una soluzione migliore qui?
Joachim Sauer,

11
Uno dei migliori programmatori che conosco ha commentato che se si desidera davvero una misura, il numero di variabili locali è migliore della lunghezza effettiva. Stava lavorando a un complesso ottimizzatore di percorso in cui l'intestino era un metodo lungo diverse centinaia di righe, ma la quantità di stato (variabili locali) mantenuta era molto piccola.
Chuu,

2
I metodi lunghi non sono sempre male; ma sono qualcosa che dovresti sempre guardare e chiederti "è così male?"
Carson63000,

Risposte:


80

No, i metodi lunghi non sono sempre male.

Nel libro Codice completo , si misura che i metodi lunghi a volte sono più veloci e più facili da scrivere e non comportano problemi di manutenzione.

In effetti, ciò che è veramente importante è restare SECCHI e rispettare la separazione delle preoccupazioni. A volte, il calcolo è solo lungo da scrivere, ma in realtà non causerà problemi in futuro.

Tuttavia, dalla mia esperienza personale, i metodi più lunghi tendono a mancare di separazione delle preoccupazioni. In effetti, i metodi lunghi sono un modo semplice per rilevare che qualcosa potrebbe essere errato nel codice e che è necessaria particolare attenzione quando si esegue la revisione del codice.

EDIT: man mano che vengono fatti commenti, aggiungo un punto interessante alla risposta. Verificherei infatti anche le metriche di complessità per la funzione (NPATH, complessità ciclomatica o CRAP ancora migliore).

In effetti, raccomando di non controllare tali parametri su funzioni lunghe, ma di includere un avviso su di essi con strumenti automatizzati (come lo stile di controllo per java ad esempio) SU OGNI FUNZIONE.


41
+1: "No, i metodi lunghi non sono sempre cattivi" ma sono quasi sempre cattivi
Binary Worrier,

67
I corpi dei metodi lunghi sono un odore di codice classico : non è di per sé un problema, ma indica che probabilmente c'è un problema lì.
Joachim Sauer,

6
+1, ma consiglierei comunque di verificare la complessità ciclomatica del metodo lungo. Valori elevati indicano metodi che sono effettivamente impossibili da testare unità (e metodi lunghi sono molto raramente privi della logica del flusso di controllo).
Daniel B,

11
Uso i nomi dei metodi per ridurre al minimo i commenti. Il che a volte porta a cose come "getSelectedNodeWithChildren", ma il mio collega continua a dirmi che il mio codice è ben leggibile. Cerco anche di evitare le abbreviazioni, sono belle da scrivere, ma non così belle da leggere.
K ..

4
@ da_b0uncer Questa è anche una politica che seguo. È più difficile leggere il codice che scriverlo, quindi uno sforzo extra quando si scrive per rendere il codice più leggibile paga.
deadalnix,

55

La maggior parte del fuoco qui sembra essere intorno alla parola sempre . Sì, gli assoluti sono cattivi e l'ingegneria del software è quasi tanta arte quanto la scienza, e tutto il resto ... ma devo dire che per l'esempio che hai dato, il metodo sarebbe migliore se fosse diviso su. Questi sono gli argomenti che in genere userò per giustificare la suddivisione del metodo:

Leggibilità: non sono sicuro degli altri, ma non riesco a leggere rapidamente 350 righe di codice. Sì, se è il mio proprio codice, e posso fare molte ipotesi su di esso, ho potuto sfogliarlo molto rapidamente, ma questo è oltre il punto. Considera quanto più facile sarebbe leggere quel metodo, se consistesse in 10 chiamate ad altri metodi (ognuno con un nome descrittivo). In questo modo, hai introdotto una stratificazione nel codice e il metodo di alto livello fornisce una breve e dolce struttura al lettore per quanto riguarda ciò che sta succedendo.

Modifica: per metterlo sotto una luce diversa, pensaci in questo modo: come spiegheresti questo metodo a un nuovo membro del team? Sicuramente ha una struttura che puoi riassumere sulla falsariga di "bene, inizia facendo A, poi B, poi a volte C, ecc.". Avere una breve "panoramica" che chiama altri metodi rende evidente questa struttura. È estremamente raro trovare 350 righe di codice che non ne beneficiano; il cervello umano non è pensato per avere a che fare con liste lunghe centinaia di voci, le raggruppiamo.

Riusabilità: i metodi lunghi tendono ad avere una bassa coesione: spesso fanno più di una cosa. La bassa coesione è nemica del riutilizzo; se si combinano più attività in un solo metodo, finirà per essere riutilizzato in meno posti di quanto avrebbe dovuto essere.

Testabilità e coesione: ho menzionato la complessità ciclomatica in un commento sopra: è una buona misura di quanto sia complesso il tuo metodo. Rappresenta il limite inferiore del numero di percorsi univoci attraverso il codice, a seconda degli input (modifica: corretto secondo il commento di MichaelT). Significa anche che per testare correttamente il tuo metodo, devi avere almeno tanti casi di test quanti sono i tuoi numeri di complessità ciclomatica. Sfortunatamente, quando metti insieme pezzi di codice che non sono realmente dipendenti l'uno dall'altro, non c'è modo di essere sicuri di questa mancanza di dipendenza e la complessità tende a moltiplicarsi. Puoi pensare a questa misura come un'indicazione del numero di cose diverse che stai cercando di fare. Se è troppo alto, è tempo di dividere e conquistare.

Refactoring e struttura: i metodi lunghi sono spesso segni che manca una struttura nel codice. Spesso, lo sviluppatore non riusciva a capire quali fossero i punti in comune tra le diverse parti di quel metodo e dove si potesse tracciare una linea tra di loro. Comprendere che un metodo lungo è un problema e cercare di dividerlo in metodi più piccoli è il primo passo su una strada più lunga per identificare effettivamente una struttura migliore per l'intera faccenda. Forse devi creare una classe o due; alla fine non sarà necessariamente più complesso!

Penso anche che in questo caso, la scusa per avere un metodo lungo è "... alcune variabili dichiarate al di fuori del ciclo principale vengono poi modificate durante il ciclo". Non sono un esperto di Python, ma sono abbastanza certo che questo problema potrebbe essere banalmente risolto da una qualche forma di passaggio per riferimento.


13
+1 per rinnegare sempre la parte della domanda e concentrarsi sulla carne: se i metodi lunghi non sono buoni. Penso che l'OP stia cercando una giustificazione come se il suo scenario fosse un caso limite, anche se di solito quando sento le persone spiegare le loro cattive pratiche come necessarie per lo scenario non comune, è solo perché non si sono sforzati molto di usare le buone pratiche. Gli scenari non comuni sono davvero molto rari, ma i metodi lunghi sono purtroppo abbastanza comuni.
Jimmy Hoffa,

2
OK guardando l'elenco sopra: la leggibilità direi per esperienza passata è aumentata avendo il metodo più lungo, contenente molti commenti e ben formattato, piuttosto che dover saltare il codice da metodo a metodi Sebbene questo sia probabilmente abbastanza soggettivo. Non mi aspetto che le parti del codice vengano riutilizzate. La maggior parte del riutilizzo del codice è ottenuto dall'eredità al momento.
wobbily_col,

1
@wobbily_col A proposito, se stai cercando un testo ben scritto che attraversa la logica di avere metodi più brevi, leggi i primi capitoli di Clean Code , che fa un buon lavoro della spiegazione.
Daniel B,

5
@wobbily_col Dici che dover saltare troppo per capire il codice con molti metodi è confuso, penso che il punto mancante qui sia sull'importanza della denominazione. Se un metodo è ben chiamato, non è necessario guardarlo per scoprire cosa sta facendo, il metodo di chiamata dovrebbe essere completamente comprensibile senza alcuna conoscenza di base di ciò che i metodi che chiama stanno facendo, ad esempio hai mai usato someVar.toString()e sentito hai bisogno di vedere il codice di toString per sapere cosa sta facendo? Hai appena letto oltre a causa del buon metodo di denominazione.
Jimmy Hoffa,

4
Una nota a margine, avere un metodo che richiede n parametri è anche un odore di codice e indica che il metodo può fare più di una cosa. Lo stesso vale per avere un metodo che è difficile nominare. E se ha davvero bisogno di tutti quei parametri, di solito fanno parte di un concetto più ampio, che può e deve essere racchiuso in una classe a sé stante. Certo, potremmo trovare un esempio che è meglio non usare questa regola - il mio punto è che se vedi un tale metodo, investigalo a fondo, probabilmente è cattivo in qualche modo.
KL

28

I metodi lunghi sono sempre sbagliati, ma a volte sono migliori delle alternative.


5
senza una spiegazione, questa risposta potrebbe diventare inutile nel caso in cui qualcun altro pubblichi un'opinione opposta. Ad esempio, se qualcuno pubblica un reclamo come "I metodi lunghi non sono mai male, ma a volte sono peggio delle alternative". , in che modo questa risposta aiuterebbe il lettore a scegliere due opinioni opposte? Valuta di modificarlo in una forma migliore
moscerino il

9

I metodi lunghi sono un odore di codice . Di solito indicano che qualcosa non va, ma non è una regola rigida. Di solito, i casi in cui sono giustificati implicano un sacco di regole aziendali statali e abbastanza complesse (come hai trovato).

Per quanto riguarda l'altra domanda, è spesso utile separare blocchi di logica in metodi separati, anche se vengono chiamati solo una volta. Rende più facile vedere la logica di alto livello e può rendere la gestione delle eccezioni un po 'più pulita. Basta che non sia necessario passare venti parametri per rappresentare lo stato di elaborazione!


7

I metodi lunghi non sono sempre male. Di solito sono un segno che potrebbe esserci un problema.

Sul sistema su cui sto lavorando abbiamo una mezza dozzina di metodi lunghi più di 10.000 righe. Uno è attualmente 54.830 linee. E va bene.

Queste funzioni ridicolmente lunghe sono molto semplici e sono autogenerate. Quel grande mostro lungo 54.830 linee contiene i dati di movimento polare giornalieri dal 1 ° gennaio 1962 al 10 gennaio 2012 (la nostra ultima versione). Rilasciamo anche una procedura mediante la quale i nostri utenti possono aggiornare quel file generato automaticamente. Quel file sorgente contiene i dati di movimento polare da http://data.iers.org/products/214/14443/orig/eopc04_08_IAU2000.62- ora , tradotti automaticamente in C ++.

La lettura di quel sito Web al volo non è possibile in un'installazione sicura. Non c'è alcun legame con il mondo esterno. Anche il download del sito Web come copia locale e l'analisi in C ++ non è un'opzione; l'analisi è lenta e deve essere veloce. Download, traduzione automatica in C ++ e compilazione: ora hai qualcosa che è veloce. (Basta non compilarlo ottimizzato. È incredibile quanto tempo impiega un compilatore di ottimizzazione per compilare 50.000 righe di codice di linea retta estremamente semplice. Ci vuole più di mezz'ora sul mio computer per compilare quel file ottimizzato. E l'ottimizzazione non realizza assolutamente nulla Non c'è nulla da ottimizzare. È un semplice codice a linea retta, un'istruzione di assegnazione dopo l'altra.)


6
"una dichiarazione di assegnazione dopo l'altra" ... lo definirei un "file di dati". Perché è codice?
Joachim Sauer,

3
@JoachimSauer - Perché l'analisi di un file di dati di grandi dimensioni in fase di esecuzione in un'installazione di Monte Carlo è una cattiva idea. Una pessima idea.
David Hammen,

4
@DavidHammen: quindi fallo al momento dell'inizializzazione, proprio come stai forzando il tuo linker / caricatore a fare. Oppure scrivi il file di dati come struttura C in un file di intestazione, anziché come codice C. Almeno quindi il caricatore si carica come un blocco dati.
Javier,

3
@Javier: anche al momento dell'inizializzazione può essere una pessima idea, almeno in una configurazione di Monte Carlo. Una simulazione che richiede pochi minuti per l'inizializzazione, ma solo pochi secondi per eseguire va contro il grano di ottenere decine di migliaia di corse durante la notte. La modifica delle attività temporali di inizializzazione chiave per compilare le attività temporali risolve il problema. Abbiamo provato una serie di tecniche, incluso l'approccio della struttura dei dati compilato. Semplicemente non funziona o sarebbe molto difficile farlo funzionare in alcuni casi (ad esempio, un enorme modello di gravità). L'approccio del codice in linea retta è facile da generare automaticamente, facile da verificare. È solo un brutto codice.
David Hammen,

7
+1 storia interessante. il codice generato non è in realtà il codice sorgente, quindi si potrebbe sostenere che ciò non "infrange" la regola. si presume che il generatore di codice stesso avesse dei metodi brevi e piacevoli
jk.

7

Diciamo solo che ci sono modi buoni e cattivi per spezzare un metodo lungo. Dover [[mantenere] il metodo più esterno nella tua testa "è un segno che non lo stai rompendo nel modo più ottimale, o che i tuoi sottometodi sono mal nominati. In teoria, ci sono casi in cui è meglio un metodo lungo. In pratica, è estremamente raro. Se non riesci a capire come rendere leggibile un metodo più breve, chiedi a qualcuno di rivedere il tuo codice e chiedi loro idee specifiche sull'accorciamento dei metodi.

Per quanto riguarda i loop multipli che causano un presunto hit delle prestazioni, non c'è modo di saperlo senza misurare. Più loop più piccoli possono essere significativamente più veloci se ciò significa che tutto ciò di cui ha bisogno può rimanere nella cache. Anche se c'è un colpo di prestazione, di solito è trascurabile a favore della leggibilità.

Dirò che spesso i metodi lunghi sono più facili da scrivere , anche se sono più difficili da leggere . Ecco perché proliferano anche se non piacciono a nessuno. Non c'è niente di sbagliato nella pianificazione dall'inizio del refactoring prima del check-in.


1
"Non c'è niente di sbagliato nella pianificazione dall'inizio del refactoring prima del check-in." +1 per quello. Oggi la maggior parte degli IDE dispone di strumenti di refactoring che lo rendono estremamente semplice. Ma esiste un metodo inverso in cui deleghi le cose a funzioni inesistenti e successivamente vai a compilare i metodi, ma non sono mai stato in grado di programmare in quel modo, per quanto ho provato.
Tjaart,

+1 per "Dover" [mantenere] il metodo più esterno nella tua testa "è un segno che non lo stai rompendo nel modo più ottimale",
Michael Shaw,

4

I metodi lunghi possono essere più computazionali ed efficienti nello spazio, può essere più facile vedere la logica e più facile eseguirne il debug. Tuttavia, queste regole si applicano solo quando un solo programmatore tocca quel codice. Il codice sarà un problema da estendere se non è atomico, in sostanza la persona successiva dovrà ricominciare da capo e quindi il debug e il test ci vorranno per sempre in quanto non utilizza alcun buon codice noto.


34
Ci sono sempre almeno due programmatori coinvolti: "tu" e "tu, tra tre settimane".
Joachim Sauer,

3

C'è qualcosa che chiamiamo decomposizione funzionale che implica la suddivisione dei metodi più lunghi in metodi più piccoli, ove possibile. Come hai detto che il tuo metodo prevede l'ordinamento / filtro, allora è meglio avere metodi o funzioni separati per queste attività.

Precisamente, il tuo metodo dovrebbe essere focalizzato solo sulla perforimng 1 attività.

E se ha bisogno di chiamare un altro metodo per qualche motivo, allora fallo altrimenti con quello che stai già scrivendo. Anche per le pruposi di leggibilità, è possibile aggiungere commenti. Convenzionalmente, i programmatori usano i commenti su più righe (/ ** / in C, C ++, C # e Java) per le descrizioni dei metodi e usano i commenti su una riga (// in C, C ++, C # e Java). Sono disponibili anche buoni strumenti di documentazione per una maggiore leggibilità del codice (ad es. JavaDoc ). Puoi anche esaminare i commenti basati su XML se sei uno sviluppatore .Net.

I loop influiscono sulle prestazioni del programma e possono causare sovraccarico dell'applicazione se non utilizzati correttamente. L'idea è di progettare il tuo algoritmo in modo tale da utilizzare i loop nidificati il ​​meno possibile.


Conosciuto anche come "Una funzione dovrebbe fare UNA COSA".
lorddev,

3

Va benissimo scrivere lunghe funzioni. Ma varia in base al contesto se ne hai davvero bisogno o no. Ad esempio, alcuni dei migliori algoritmi sono espressi al meglio quando è una cosa. D'altra parte, una grande percentuale di routine nei programmi orientati agli oggetti sarà routine di accesso, che sarà molto breve. Alcune delle lunghe procedure di elaborazione che presentano lunghi casi di commutazione, se le condizioni possono essere ottimizzate tramite metodi basati su tabella.

C'è una eccellente breve discussione in Code Complete 2 sulla lunghezza delle routine.

La migliore lunghezza massima teorica di 497 è spesso descritta come una o due pagine dell'elenco dei programmi, da 66 a 132 righe. I programmi moderni tendono ad avere volumi di routine estremamente brevi mescolati con routine più lunghe.

Decenni di prove affermano che routine di tale lunghezza non sono più soggette ad errori rispetto a routine più brevi. Lascia che questioni come la profondità della nidificazione, il numero di variabili e altre considerazioni relative alla complessità determinino la lunghezza della routine 535 anziché imporre una lunghezza

Se si desidera scrivere routine più lunghe di circa 200 righe, fare attenzione. Nessuno degli studi che hanno riportato una riduzione dei costi, una riduzione dei tassi di errore o entrambi con routine più grandi si sono distinti tra dimensioni superiori a 200 righe e si è tenuti a incontrare un limite superiore di comprensibilità quando si passano 200 righe di codice. 536 restrizione in sé.


2

Un altro voto è quasi sempre sbagliato. Trovo due casi di base in cui è la risposta corretta, però:

1) Un metodo che in pratica chiama solo un mucchio di altri metodi e non funziona davvero da solo. Hai un processo che richiede 50 passaggi per ottenere, ottieni un metodo con 50 chiamate al suo interno. Di solito non c'è niente da guadagnare cercando di romperlo.

2) Dispatcher. La progettazione OOP si è sbarazzata della maggior parte di tali metodi, ma le fonti di dati in entrata sono per loro stessa natura solo dati e quindi non possono seguire i principi OOP. Non è esattamente insolito avere una sorta di routine di dispatcher nel codice che gestisce i dati.

Direi anche che non si dovrebbe nemmeno considerare la domanda quando si tratta di cose autogenerate. Nessuno sta cercando di capire cosa fa il codice autogenerato, non importa se è facile da capire per un essere umano.


1
Il processo in 50 fasi può probabilmente essere riassunto in diversi secchi. I passaggi 1 - 9 sono i controlli dei parametri, quindi crea un nuovo metodo chiamato controllo dei parametri. (Sono sicuro che ci sono alcuni esempi in cui ciò non è possibile. Sarei interessato a vederne uno).
sixtyfootersdude,

@sixtyfootersdude: Certo, potresti romperlo. Non ho detto che era impossibile, ho detto che non c'era nulla da guadagnare rompendolo. Anche se non sono stati 50 i passaggi che ho colpito qualcosa del genere: la creazione di un mondo di gioco. Il n. 1 ha creato il mondo vuoto, il n. 2 ha creato il terreno e poi un sacco di passaggi dopo averlo massaggiato in un modo o nell'altro.
Loren Pechtel,

& sixtyfootersdude: è incredibile come conosci il codice che non hai mai visto e come migliorarlo.
gnasher729,

2

Volevo affrontare l'esempio che hai dato:

Ad esempio, ho alcune viste Django che eseguono un po 'di elaborazione degli oggetti prima di inviarli alla vista, un metodo lungo è 350 righe di codice. Ho scritto il mio codice in modo che si occupi dei parametri: ordinare / filtrare il queryset, quindi a poco a poco esegue alcune elaborazioni sugli oggetti restituiti dalla mia query.

Nella mia azienda il nostro più grande progetto è basato su Django e abbiamo anche funzioni di visualizzazione lunga (molte sono più di 350 linee). Direi che la nostra non deve essere così lunga, e ci stanno facendo del male.

Queste funzioni di visualizzazione stanno svolgendo un sacco di lavoro vagamente correlato che dovrebbe essere estratto nel modello, nelle classi di supporto o nelle funzioni di supporto. Inoltre, finiamo per riutilizzare le viste per fare cose diverse, che dovrebbero invece essere divise in viste più coerenti.

Sospetto che le tue opinioni abbiano caratteristiche simili. Nel mio caso, so che provoca problemi e sto lavorando per apportare modifiche. Se non sei d'accordo sul fatto che sta causando problemi, non è necessario risolverlo.


2

Non so se qualcuno lo abbia già menzionato, ma uno dei motivi per cui i metodi lunghi sono sbagliati è perché di solito coinvolgono diversi livelli di astrazione. Hai variabili loop e tutto ciò che accade. Considera la funzione fittizia:

function nextSlide() {
  var content = getNextSlideContent();
  hideCurrentSlide();
  var newSlide = createSlide(content);
  setNextSlide(newSlide);
  showNextSlide();
}

Se avessi fatto tutte le animazioni, i calcoli, l'accesso ai dati ecc. In quella funzione sarebbe stato un casino. La funzione nextSlide () mantiene un livello di astrazione coerente (il sistema dello stato delle diapositive) e ignora gli altri. Questo rende il codice leggibile.

Se devi vedere costantemente metodi più piccoli per vedere cosa fanno, l'esercizio di divisione della funzione è fallito. Solo perché il codice che stai leggendo non sta facendo cose ovvie nei metodi figlio non significa che i metodi figlio siano una cattiva idea, solo che è stato fatto in modo errato.

Quando creo metodi di solito finisco per dividerli in metodi più piccoli come una sorta di strategia di divisione e conquista. Un metodo simile

   if (hasMoreRecords()) { ... }

è sicuramente più leggibile di

if (file.isOpen() && i < recordLimit && currentRecord != null) { ... } 

Giusto?

Concordo sul fatto che le affermazioni assolute siano negative e che anche un metodo lungo sia negativo.


1

Storia vera. Una volta ho incontrato un metodo lungo più di duemila righe. Il metodo aveva regioni che descrivevano cosa stava facendo in quelle regioni. Dopo aver letto una regione, ho deciso di eseguire un metodo di estrazione automatizzato, denominandolo in base al nome della regione. quando ho finito, il metodo non era altro che 40 chiamate di metodo di circa cinquanta righe ciascuna e tutto ha funzionato allo stesso modo.

Ciò che è troppo grande è soggettivo. A volte, un metodo non può essere suddiviso oltre ciò che è attualmente. È come scrivere un libro. La maggior parte delle persone concorda sul fatto che i paragrafi lunghi dovrebbero essere generalmente divisi. Ma a volte, c'è solo un'idea e dividerla provoca più confusione di quanto sarebbe causato dalla lunghezza di quel paragrafo.


0

Il punto di un metodo è di aiutare a ridurre il rigurgito del codice. Un metodo dovrebbe avere una funzione specifica di cui è responsabile. Se si finisce per ripassare il codice in numerosi luoghi si corre il rischio che il codice abbia risultati imprevisti se si modificano le specifiche che il software è progettato per indirizzare.

Affinché un metodo abbia 350 righe suggerirebbe che molte delle attività che sta eseguendo vengono replicate altrove, poiché è insolito richiedere una quantità così grande di codice per eseguire un'attività specializzata.


Aiuta a ridurre il codice cosa ?
Avner Shahar-Kashtan,

@ AvnerShahar-Kashtan, probabilmente significa "duplicazione" :-)
Péter Török,

0

In realtà non sono i metodi lunghi che sono cattive pratiche, è piuttosto lasciarli in quel modo che sono cattivi.

Intendo che l'atto effettivo di refactoring del campione da:

varaible_1 = 0
variable_2 = 0
for object in queryset :
     if object.condition_condition_a and variable_2 > 0 :
     variable 1+= 1
     .....
     ...    
     . 
      more conditions to alter the variables

return queryset, and context 

per

Status status = new Status();
status.variable1 = 0;
status.variable2 = 0;
for object in queryset :
     if object.condition_condition_a and status.variable2 > 0 :
     status.variable1 += 1
     .....
     ...    
     . 
      more conditions to alter the variables (status)

return queryset, and context 

e poi a

class Status {
    variable1 = 0;
    variable2 = 0;

    void update(object) {
        if object.condition_condition_a and variable2 > 0 {
            variable1 += 1
        }
    }
};

Status status = new Status();
for object in queryset :
     status.update(object);
     .....
     ...    
     . 
      more conditions to alter the variables (status)

return queryset, and context 

ora sei sulla buona strada non solo per un metodo molto più breve, ma molto più utilizzabile e comprensibile.


0

Penso che il fatto che il metodo sia molto lungo sia qualcosa da controllare, ma sicuramente non è un anti-pattern istantaneo. La cosa grande da cercare in metodi enormi è un sacco di nidificazione. Se hai

foreach(var x in y)
{
    //do ALL the things
    //....
}

e il corpo del loop non è estremamente localizzato (ad esempio, potresti inviarlo con meno di 4 parametri), quindi è probabilmente meglio convertirlo in:

foreach(var x in y)
{
    DoAllTheThings(x);
}
...
void DoAllTheThings(object x)
{
    //do ALL the things
    //....
}

A sua volta, ciò può ridurre notevolmente la lunghezza di una funzione. Inoltre, assicurati di cercare un codice duplicato nella funzione e di spostarlo in una funzione separata

Infine, alcuni metodi sono solo lunghi e complicati e non c'è nulla che tu possa fare. Alcuni problemi richiedono soluzioni che non si prestano facilmente al codice. Ad esempio, l'analisi di una grammatica di molta complessità può rendere metodi molto lunghi di cui non si può fare molto senza peggiorare la situazione.


0

La verità è che dipende. Come accennato, se il codice non separa le preoccupazioni e cerca di fare tutto in un metodo, allora è un problema. La separazione del codice in più moduli semplifica la lettura del codice e la scrittura del codice (da parte di più programmatori). L'adesione a un modulo (classe) per file sorgente è una buona idea per cominciare.

In secondo luogo, quando si tratta di funzioni / procedure:

void setDataValueAndCheckForRange(Data *data) {/*code*/} 

è un buon metodo se controlla l'intervallo di soli "Dati". È un metodo BAD quando lo stesso intervallo si applica a più funzioni (esempio di codice errato):

void setDataValueAndCheckForRange(Data *data){ /*code */}
void addDataValuesAndCheckForRange(Data *result, Data *d1, Data *d2){ /*code*/}
void subDataValuesAndCheckForRange(Data *result, Data *d1, Data *d2){ /*code*/}
void mulDataValuesAndCheckForRange(Data *result, Data *d1, Data *d2){ /*code*/}

Questo deve essere riformattato per:

bool isWithinRange(Data *d){ /*code*/ }
void setDataValue(Data *d) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 
void addDataValue(Data *d, Data *d1, Data *d2) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 
void subDataValue(Data *d, Data *d1, Data *d2) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 
void mulDataValue(Data *d, Data *d1, Data *d2) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 

Riutilizzare il codice il più possibile. E questo è possibile quando ogni funzione del tuo programma è abbastanza SEMPLICE (non necessariamente facile).

PREVENTIVO: LA MONTAGNA è composta da piccoli granelli di terra. L'oceano è composto da minuscole gocce d'acqua .. (- Sivananda)


0

I metodi lunghi tendono al "cattivo" nei linguaggi imperativi che favoriscono le affermazioni, gli effetti collaterali e la mutabilità, proprio perché quelle caratteristiche aumentano la complessità e quindi i bug.

Nei linguaggi di programmazione funzionale, che favoriscono espressioni, purezza e immutabilità, ci sono meno motivi di preoccupazione.

Sia nei linguaggi funzionali che in quelli imperativi, è sempre meglio fattorizzare blocchi di codice riutilizzabili in routine di livello superiore comuni, ma in linguaggi funzionali che supportano l'ambito lessicale con funzioni nidificate ecc., In realtà è meglio l'incapsulamento per nascondere le routine secondarie nella parte superiore -level (metodo) piuttosto che suddividerli in altre funzioni di livello superiore.


Nei linguaggi funzionali, tuttavia, i metodi lunghi sono molto meno comuni.
itsbruce,
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.