Linee guida per la codifica: i metodi non devono contenere più di 7 istruzioni?


78

Stavo esaminando le Linee guida per la codifica AvSol per C # e sono d'accordo con quasi tutto, ma sono davvero curioso di vedere cosa pensano gli altri di una regola specifica.

AV1500

I metodi non devono superare 7 affermazioni Un metodo che richiede più di 7 affermazioni sta facendo troppo o ha troppe responsabilità. Richiede anche che la mente umana analizzi le affermazioni esatte per capire cosa sta facendo il codice. Suddividilo in più metodi piccoli e mirati con nomi che si spiegano da soli.

Molti di voi seguono questa regola? Anche se c'è poco da salvare dalla creazione di un nuovo metodo (il tuo codice è ancora ASCIUTTO ) a parte la leggibilità che aumenta notevolmente? E il tuo numero è ancora basso come 7? Tenderei di più verso il 10.

Non sto dicendo di violare questa regola ovunque - al contrario, i miei metodi sono piccoli al 95% e focalizzati, ma dire che non dovresti mai violare questa regola mi ha davvero lasciato senza fiato.

Voglio solo sapere cosa pensano tutti di MAI violare questa regola (è un '1' sullo standard di codifica - il che significa MAI farlo). Ma penso che avresti problemi a trovare una base di codice che non lo fa.


48
Contano anche le casedichiarazioni in un singolo switch? Ad ogni modo, non è altro che un requisito idiota e inutile. Chi l'ha scritto non sa nulla di programmazione.
Logica SK

86
L'unica regola che dovrebbe essere un '1' sullo standard di codifica dovrebbe essere la regola "dovrai prendere tutte le linee guida di codifica con un granello di sale".
Mike Nakis,

6
@ SK-logic 1027 non è neanche male - deve essere divertente scrivere il codice che deve gestire i dati mancanti, se devi trattare una stringa vuota come uguale a una stringa nulla.
quant_dev,

25
Leggendo questa linea guida mi aspetto di vedere una base di codice piena di: void DoSomething () {DoSomethingFirstSevenLines (); DoSomethingSecondSevenLines (); DoSomethingThirdSevenLines (); eccetera; }
tira il

12
Prova a riflettere la maggior parte di .NET Framework e vedi quanti metodi hanno meno di 7 istruzioni ...
David Boike,

Risposte:


195

Questo è un "odore standard" per me. Ogni volta che vedo standard di codifica con limiti specifici, mi preoccupo. Ti imbatti quasi sempre in un caso in cui un metodo deve essere più grande di quello consentito dalla norma (che si tratti di lunghezza / conteggio della linea, numero di variabili, numero di punti di uscita, ecc.). Gli standard dovrebbero essere più simili alle linee guida e consentire un margine di manovra sufficiente per esercitare il buon senso. Non fraintendetemi, è bene avere degli standard, ma non dovrebbero diventare "microgestione per procura".


25
+1 per "microgestione per procura". Sospetto che qualcuno abbia letto della regola "7 più o meno 2" ( en.wikipedia.org/wiki/… ) e abbia confuso la conservazione dei fatti a breve termine con l'archiviazione a lungo termine come, sai, un editor di codice.
soffice

25
Qualche standard sensatamente studiato proibisce i numeri magici nel codice, giusto? Penseresti che anche lo standard di codifica verrebbe mantenuto a quello standard. Il numero 7 ha sicuramente una qualità sicuramente "magica".
Adam Crossland,

2
La tua risposta avrebbe più senso se il titolo del documento non fosse "Coding Guidlinesper C # 3.0 e 4.0.
Andy,

+1 Nella mia mente, l'unica ragione per cui dovresti seguire gli standard di codifica non è mai seguire dogmaticamente un numero arbitrario, ma assicurarti di non causare inutili problemi di fusione nel controllo della versione (cioè problemi associati quando lavori in una squadra). Di solito file più corti e più componenti significano meno possibilità di avere problemi quando si uniscono le modifiche al codice.
Spoike,

3
Ho scaricato questo documento e ho iniziato a cercarlo. In 1.6, afferma: "Il documento non afferma che i progetti devono rispettare queste linee guida, né afferma quali linee guida siano più importanti di altre. Tuttavia, incoraggiamo i progetti a decidere autonomamente quali linee guida sono importanti, quali deviazioni un progetto utilizzare, chi è il consulente in caso di dubbi e quale tipo di layout deve essere utilizzato per il codice sorgente. " Anche se un 1 significa "Linee guida che non dovresti mai saltare e che dovrebbero essere applicabili a tutte le soluzioni", puoi scegliere di modificarlo.
chrish,

83

Di solito è una buona idea dividere le cose in piccoli metodi. Ma l'importante è dividere le cose dove ha senso.

Se non ha senso dividere, allora non dividere. Questo è spesso il caso di alcune procedure o codice GUI.

Steve McConnell ha dichiarato nel Codice completo che non si è sempre più produttivi quando si utilizzano metodi brevi. Se dividi quando non ha senso, aggiungi complessità al codice senza alcun vantaggio.

Come sempre con le linee guida, è bene ricordare perché esistono i vincoli, in modo da poter imparare quando non si applica. Nella maggior parte del codice i metodi saranno brevi, o probabilmente hai un problema con DRY o la separazione dei problemi . Ma se non è il caso, allora va bene.


1
Bella risposta. Le ultime due righe guidano in particolare il punto.
Xonatron,

6
Penso che l'importante regola empirica sia verificare se i sottometodi sono ortogonali. Se sono indipendenti, possono essere chiamati in qualsiasi ordine e rispettare l'invariante di classe, quindi è meglio tenerli separati. Se i metodi sono strettamente accoppiati, infrangono gli invarianti di classe e / o devono essere chiamati in un certo ordine, forse è meglio tenerli insieme.
hugomg,

4
Il codice completo è pieno di cose buone. Ogni programmatore dovrebbe mangiarne un pezzo a pranzo ogni giorno.
deadalnix,

29

Dovrebbe essere considerato una regola empirica.

Cose come "Non più di 80 (100.120) colonne di testo", "un punto di uscita per metodo", "non più di 2 livelli di annidamento", sono ciò che definirei soglie per gli indicatori di odore di codice. Se li violate occasionalmente, ciò non significa necessariamente che il codice sia errato. Se ti accorgi che li stai violando in modo coerente, qualcosa ha un odore nel codice e potresti voler fare una pausa e ripensare il tuo approccio.

Per me, i criteri più importanti sono: "Questo codice è comprensibile?", "È ripetitivo?", "È suddiviso in luoghi logici?", "È liberamente accoppiato?" Ce ne sono alcuni altri, ma penso che l'idea di base possa essere riassunta ricordando il consiglio di Donald Knuth: "I programmi sono pensati per essere letti dagli umani e solo per inciso da eseguire sui computer".


7
Il limite delle colonne "80/100/120" è che possiamo leggere il codice. La maggior parte dei terminali si aprono a 80 colonne ed è meno sforzo per fare in modo che l'autore passi a 80 colonne piuttosto che fare in modo che ogni lettore ridimensioni il proprio terminale ogni volta che vogliono leggere il codice. A differenza degli altri limiti, il limite della colonna N non influisce sulla semantica del codice, è una regola puramente stilistica; nella stessa categoria di "usa le schede a 4 spazi" o "metti le parentesi graffe di apertura per le funzioni sulla propria linea".
Dietrich Epp,

4
Certo, è un aspetto estetico più che un aspetto semantico. Tuttavia, è qui che si applica la mia ultima frase. Non è raro trovare istruzioni Java che superano la regola delle 80 colonne senza un "bel" posto per dividere la linea. Ciò influisce sulla leggibilità e sulla comprensione del codice. Potrebbe anche indicare violazioni della Legge di Demetra
seggy,

7
Nel 21 ° secolo, il mio IDE ha questa funzione chiamata "a capo dinamico".
György Andrasek,

9
@ GyörgyAndrasek: Ma non tutti usano sempre il tuo IDE: guardiamo il codice in GitHub, nei terminali con less, in vime emacs; e il confezionamento automatico sembra nella migliore delle ipotesi casuale. Gli standard di codifica non sono a tuo vantaggio, sono a vantaggio delle persone che lavorano in team.
Dietrich Epp,

2
@DietrichEpp Personalmente ho difficoltà a leggere il codice che è sempre racchiuso nella colonna 80. Di recente ho dovuto lavorare su un progetto Java in cui è stato utilizzato il formatter standard Eclipse. E all'interno di un metodo è stato molto difficile tenere traccia delle linee che si sono svolte su due o anche tre linee (ma do la colpa anche alle altre impostazioni del formatter). In conclusione, penso che l'80 sia un po 'datato. Personalmente uso un limite di 120, ho i miei editor impostati per imporlo, ho una console larga 120 colonne e Github mostra effettivamente 125 colonne. E penso che sia molto più leggibile in quel modo.
colpì il

18

Non ho mai avuto il tempo di contare effettivamente il numero di istruzioni nei miei metodi, ma mi sforzo di scrivere metodi che eseguano in modo pulito un unico scopo chiaro. Finché il codice è pulito, leggibile e segue i principi DRY e Single Responsibility , probabilmente hai fatto il tuo lavoro. Penso che dividere arbitrariamente un metodo solo per imporre il limite di sette istruzioni potrebbe rendere il tuo codice meno leggibile / gestibile.


1
+1 per leggibilità. Non dovrebbe nemmeno importare se un metodo è lungo 20, 30 o anche 50 righe. Se DRY e SRP sono i tuoi obiettivi, non importa se i metodi sembrano essere un po 'longevi ... anche se molto spesso scoprirai che più leggerai che provi a creare il tuo codice, più brevi saranno i tuoi metodi diventerà naturalmente.
S.Robins,

11

È approssimativo

Questo tipo di regole non dovrebbe essere preso alla lettera. Avrebbero potuto dire "i metodi dovrebbero essere brevi ". Tuttavia, alcune persone lo avrebbero interpretato come "meno di 1 pagina" e altri come "2 righe al massimo".

Suppongo che abbiano detto "7 dichiarazioni" per darti un'idea approssimativa (anche se penso che avrebbero dovuto dire "circa 7"). Se hai bisogno di 9 di tanto in tanto, non sudare. Ma se stai colpendo 20, saprai che non sei nel campo giusto per questa regola.


Ciò rende quindi un'approssimazione piuttosto esplicita. È contrassegnato sotto "Linee guida che non dovresti mai saltare e dovrebbero essere applicabili a tutte le situazioni".
Brian

1
@brian - forse gli autori delle linee guida hanno omesso accidentalmente la parola "in modo approssimativo", o forse erano pazzi tipi di dittatori. Il mio punto è che l'OP dovrebbe prendere questo come un numero di palla da baseball. Qualsiasi regola che il compilatore o l'interprete non applica è solo un suggerimento.
Nathan Long,

"Qualsiasi regola che il compilatore o l'interprete non applica è solo un suggerimento" Non necessariamente vero. Non ho esaminato le sue regole personalizzate di resharper o fxcop e se effettivamente applicano questa regola particolare, ma ci sono aziende che ti costringono a convalidare contro tutte le linee guida di stile. Ho incontrato persone la cui azienda li costringe a scrivere codice in grado di superare le rigide linee guida sulla codifica Microsoft.
Brian

Sono d'accordo che sia approssimativo e dovrebbe essere preso da un granello di sale, avere un paragrafo di codice standard che fa apparire un numero arbitrario causerà inevitabilmente confusione. La maggior parte delle volte gli standard saranno esclusi dal contesto e le "persone" seguiranno quella approssimazione arbitraria come dogma.
Spoike,

10

7 è un numero completamente arbitrario senza alcun significato.

La complessità ciclomatica è un problema maggiore rispetto al numero di affermazioni. Ho visto codice che conteneva centinaia di affermazioni in un singolo metodo (che pensavo fosse terribile), ma aveva una complessità ciclomatica di 1 e in realtà faceva solo 1 cosa. C'erano solo molti passaggi. Abbiamo discusso della suddivisione in metodi più piccoli, ma quei metodi sarebbero stati chiamati solo da questo metodo.

Anche se questo è un caso abbastanza estremo, il punto è che devi mantenere il codice DRY e una bassa complessità ciclomatica. Questo è più importante del numero di righe in un metodo.

Prendi ad esempio un'istruzione switch / case. Se hai più di 7 possibili valori, devi suddividere la valutazione in più metodi? Certo che no, sarebbe sciocco.

La suddivisione artificiale del codice in più metodi solo per mantenere il numero di istruzioni inferiore a 7 non fa che peggiorare il codice.

La linea guida dovrebbe essere Ogni metodo dovrebbe fare 1 cosa e mantenere il codice DRY.


1
+1: i limiti arbitrari sono solo arbitrariamente utili. Un metodo dovrebbe contenere un'unica operazione coerente a un singolo livello di astrazione. La rottura di una tale unità atomica rende il codice più complesso, rendendo più difficile la comprensione del codice.
Allon Guralnek,

DRY è sopravvalutato. Abbastanza spesso significa accoppiare strettamente due aspetti di qualcosa che non dovrebbe essere così strettamente accoppiato.
Brad Thomas

4

Bene, dipende un po '. Scrivo molto codice che accede ai database. Il codice della piastra della caldaia per la gestione delle eccezioni è lungo più di sette istruzioni in molti casi. Direi che la migliore linea guida è assicurarsi che la tua funzione abbia uno scopo


8
Non puoi astrarre il codice del boilerplate nel suo metodo?
Erjiang,

Ho notato dopo aver pubblicato che questo non è C # Java ma sto pensando a questo tipo di cose. stackoverflow.com/questions/321418/…
Jaydee,

@erjang: puoi. È molto brutto in Java, dal momento che devi racchiudere ogni query in una classe anonima, ma vale comunque la pena farlo. Non così brutto in C #, e sicuramente vale la pena farlo.
Kevin Cline,

Personalmente, trovo che alcune righe extra di codice di riga verticale siano più leggibili. Ma forse sono solo io.
Jaydee,

@Jaydee La domanda collegata mostra una pratica comune ma strana: avvolgere un'eccezione e registrare. Al livello successivo puoi fare lo stesso ... in questo modo una singola eccezione appare più volte nel registro. Sarebbe meglio dichiarare il metodo lanciando e hai salvato 3 righe. Scrivere un metodo di supporto chiusura sia pse rse salvare un altro. Oppure scrivere un metodo List<Row> readDb(String sql, Object... args)che esegua l'intero lavoro (funziona solo per l'inserimento di risultati nella memoria, ma il recupero di troppi dati di solito implica che il lavoro debba comunque essere eseguito nel DB).
maaartinus,

4

Tutto è un compromesso. Il problema con l'approccio proposto - il refactoring in diversi metodi e classi in modo che ogni metodo sia breve - è che, sebbene per ragioni diverse, porta a un codice illeggibile se portato all'estremo.

Immagina un metodo foo()che fa 7 cose. Potresti sostenere che 7 cose sono troppo. Forse in molti casi hai ragione. D'altra parte, queste 7 cose potrebbero essere strettamente correlate; la logica può scorrere senza intoppi e leggere come in prosa; potresti non avere problemi a capirlo quando ne hai effettivamente bisogno. Ciò che potrebbe finire molto peggio è avere quelle 7 cose distribuite su un grande albero sorgente, in modo che se guardi foo()non hai idea di cosa faccia senza guardare in 7 luoghi diversi.

Molte persone hanno in testa regole come questa, e il risultato è quello che penso come spaghetti OO. Tutto è pulito, inscatolato nel suo piccolo metodo o classe, con piccole micro-transazioni atomiche che si verificano in ogni luogo. Ma è impossibile arrivare a una tale base di codice e sapere cosa sta facendo. Ti perdi.


4

non è una cattiva linea guida. Non mi sono mai pentito di aver suddiviso metodi e classi (non ho mai scoperto di averne troppi) purché siano raggruppati e collegati abbastanza bene.

Il trucco è di NON dividerlo verticalmente (basta pizzicare un metodo in un punto e avviarne uno nuovo). Il trucco, come per i test unitari, è tenere presente una regola del genere fin dall'inizio in modo da progettare meglio, passando 3 o 4 istruzioni a metà metodo a un altro metodo perché avere una chiamata al metodo descrive cosa stai facendo meglio di quelle 3 o 4 istruzioni nel mezzo del codice.

Questo tipo di suddivisione, anche se arbitraria e utilizzata una sola volta, può portare a migliori refactoring in seguito a causa di una nuova chiarezza del codice, questo vale anche per le classi più piccole.

Pensa come faresti per test unitari. Se si tenta di aggiungere test unitari dopo il fatto è difficile e talvolta sembra impossibile, ma se lo si progetta dall'inizio, in realtà migliora tutto il codice.

Sommario? Se confrontando l'odore di design di "Usa meno di 7 istruzioni" con l'odore di codice di "Ho usato più di 7 istruzioni", preferirei eliminare l'odore di codice.


4

Wow! Non mi sarei mai aspettato di trovare una discussione così intensa su una semplice linea guida che dice approssimativamente che i tuoi metodi dovrebbero essere molto piccoli. Dato che sono sempre sviluppatori che vogliono che le loro linee guida siano esplicite, ho scelto 7 perché sembrava una bella soglia.

Alcuni di voi hanno già citato il disclaimer all'inizio del documento. Ma per essere chiari, questo documento rappresenta una raccolta di linee guida che cercano di aiutarti a scrivere codice migliore e progettare sistemi migliori. Non ho mai affermato che qualcosa dovrebbe essere una regola, anche se una linea guida è contrassegnata come un livello 1. Quei livelli sono semplicemente l'opinione collettiva delle molte persone che hanno usato questo documento per un po '.

Inoltre, non ho mai affermato di essere un esperto. Ma sono stato in questa professione per 15 anni, con circa 4 anni di esperienza in C ++ e 11 anni di esperienza in C #. Originariamente era basato su Industrial Strength C ++, ma da allora lo sto perfezionando con il contributo della community.

Indipendentemente da ciò, il punto che stavo cercando di sollevare è che dovresti continuare a pensare da solo. Se ritieni che la linea guida delle 7 affermazioni non sia utile, non limitarti a prolungarla. Cavolo, ho persino violato quella linea guida di tanto in tanto. Lo violo solo coscientemente e accetto le conseguenze.


3
È buono da parte tua intervenire e penso che tu abbia argomentato in modo ragionevole. Detto questo, non sono d'accordo con la tua logica "sono sempre sviluppatori che vogliono che le loro linee guida siano esplicite": non puoi sempre soddisfare gli idioti e non dovresti provare. Rendere esplicite le linee guida è buono fintanto che ciò non le rende errate: ora non è più una linea guida, è una regola arbitraria. L'introduzione di numeri arbitrari, come hai visto, è un modo certo morto per essere abbattuto e giustificato.
Konrad Rudolph,

3

Innanzitutto: è una linea guida, non una regola. Si chiama linea guida, quindi per favore trattalo come tale. Ciò implica che è richiesto anche il tuo giudizio (come sempre)

A parte questo, posso pensare a molti esempi di buon codice che non aderisce a questo vincolo. Anche se è solo una linea guida, è povera.


2

Sono d'accordo con l'affermazione sopra di me. Questa è solo una linea guida e in un mondo perfetto tutto sarebbe oggetti, riutilizzati in ogni programma, e il mondo sarebbe un posto bellissimo. Non è sempre vero e talvolta ciò comporterebbe molte risorse generali o sprecate. È necessario ricordare anche questo.


6
"Sono d'accordo con l'affermazione sopra di me" Evita questo tipo di frasi nei siti di stackexchange. Ricorda che l'ordine in cui vengono pubblicate le risposte non è necessariamente l'ordine in cui vengono visualizzate.
luiscubal

Lo so, non ci ho pensato finché non era troppo tardi. Ma ti farò ancora +1 per aver indicato la mia scoreggia cerebrale.
Falcon165o

2

Abbastanza sciocco quando aggiungi la gestione delle eccezioni nella miscela.

Dopo "prova, cattura, finalmente" ti rimangono quattro istruzioni per metodo!

Considera anche un metodo "validateForm" per un modulo di 20 campi, anche se gestisci tutte le singole convalide in metodi separati, hai ancora 20 metodi di convalida di campo da invocare. Secondo queste linee guida si otterrebbe una divisione inutile come "validateTopOfScreen", "validateMiddleOfScreen" e "validateBottomOfScreen".


Penso che sia abbastanza sicuro dire che try/ catch/ finallynon sono dichiarazioni in C #. Vedi Ecma-334 § 12.3.3.15 e sezioni circostanti. (abbreviato) " un'istruzione try-catch-finally del modulo : provare a provare-block catch (...) catch-block-n finally finally-block "
un CVn del

Bene, come ho detto prima, è una decisione che devi prendere più e più volte. Tuttavia, il tuo esempio particolare potrebbe essere un esempio di non eseguire correttamente la progettazione orientata agli oggetti. Potresti voler dividere lo schermo in più controlli che eseguono la convalida da soli.
Dennis Doomen,

@Dennis - vero, ho fatto moduli HTML per troppo tempo!
James Anderson

@James Ed è a questo che serve questa linea guida. Cercando di farti pensare a soluzioni alternative, potenzialmente migliori.
Dennis Doomen,

2

La domanda sta fondendo "regole" con "linee guida". Le regole devono essere rispettate - le linee guida sono consigli che hanno lo scopo di farti considerare ciò che stai facendo e se davvero potrebbe essere fatto in un modo migliore.

Direi che, in media, la maggior parte della programmazione è probabilmente migliorata seguendo le linee guida, ma ci saranno sempre casi in cui seguire le linee guida dogmaticamente causerà più problemi di quelli che avrebbero dovuto risolvere. Ecco perché non sono presentati come regole, ma linee guida.

Un precedente risponditore ha dimostrato che gli autori delle linee guida non hanno mai voluto che fossero applicati dogmaticamente e includevano dichiarazioni in tal senso nel loro documento.


0

Sono d'accordo con soe dei commenti sopra. 7 per me è arbitrario e può essere utile in alcune lingue in cui ruby, ma per linguaggi come C #, Java, C ++ dubito di questa convenzione "7 righe". Lasciate che vi faccia un esempio. La mia applicazione attuale ha 22 campi di testo e faccio la convalida lato server. Il metodo si chiama validateInput () e la mia preferenza è convalidare tutti i campi in un solo metodo a meno che non abbia convalidato qualcosa di complesso come checkEmailFormat (). Quindi sostanzialmente il mio codice del metodo validateInput è di 108 righe con chiamate occasionali a validazione complessa.

Ora immagina se ho chiamato 25 metodi per validare ogni campo. Se entra un nuovo sviluppatore dovrà entrare e uscire dal metodo principale per saltare attraverso 25 metodi che a sua volta potrebbero chiamarne alcuni. È destinato a perdersi in grandi progetti.

Quello che faccio davvero per chiarire il mio codice è fornire commenti chiari che sostanzialmente dicono cosa stanno facendo queste 4 righe ex -

validateInput (utente UserObj) {

// Convalida nome ....... ......

// convalida il cognome ...... ......

// convalida la posta elettronica ..... // troppo complessa per controllare il formato della posta elettronica checkExmail checkEmailFormat (); .... .....

e così via.. }


1
Vedi anche la mia risposta alla domanda di James Andersons. Nel tuo caso particolare, mi chiedo se quel metodo di validazione non stia violando diversi principi e linee guida contemporaneamente.
Dennis Doomen,

0

Cattiva regola. Con il codice per la gestione delle eccezioni, l'impostazione dei campi del database, la convalida, come possono la maggior parte dei metodi essere inclusi in sette istruzioni? Non dovremmo mai svolgere le funzioni lambda in linea?

Le righe di codice rappresentano un conteggio arbitrario della complessità. Con i metodi di estensione posso creare un codice simile

                Parallel.ForEach(regions, region => {   Console.Write(region.Resorts.Where(x => x.name == "Four Seasons").OrderBy(x => x.RegionId).ThenBy(x => x.ResortId).ThenBy(x => x.name).ToList());   });

Ancora una volta un ottimo esempio di fare troppo in un singolo metodo. In quasi tutti gli argomenti contrari, le persone violano il principio della responsabilità singola (nel contesto di un metodo).
Dennis Doomen,

-1

Tutti i programmatori junior dovrebbero essere obbligati ad aderire a questo principio. Ciò li costringerebbe a pensare alla struttura di ciò con cui sono impegnati, invece di aggiungere sempre più righe di codice.

Sto attualmente esaminando un metodo di 550 righe di codice con molte istruzioni if ​​else e continua e restituisce intessute. E 'spazzatura. Se il programmatore fosse stato costretto a pensare solo a quello che stava facendo ...

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.