Qual è il giusto equilibrio tra coerenza del codice e miglioramento del codice?

52

Recentemente ho avuto una discussione con un collega sullo stile del codice. Stava sostenendo che l'utilizzo delle API e gli schemi generali che si stanno utilizzando dovrebbero essere il più possibile simili con il codice circostante, se non con la base di codici nel suo insieme, proprio come si farebbe con l'aspetto del codice (posizionamento delle parentesi, lettere maiuscole, ecc.) . Ad esempio, se aggiungessi un metodo a una classe DAO in C #, proverei a utilizzare LINQ dove appropriato per rendere il mio codice pulito e facile da mantenere, anche se nessuno degli altri metodi in quella classe lo stava usando. Tuttavia, il mio collega sosterrebbe che non dovrei usarlo in quell'istanza perché sarebbe contro lo stile esistente di quella classe e quindi più difficile da capire.

All'inizio ho trovato la sua posizione piuttosto estrema, ma dopo averci pensato per un po 'comincio a vedere il suo punto. Con l'ipotetico esempio LINQ, forse questa classe non la contiene perché i miei colleghi non hanno familiarità con LINQ? In tal caso, il mio codice non sarebbe più mantenibile per i miei colleghi sviluppatori se non lo usassi? D'altra parte, se credo davvero che l'uso di una tale tecnica porterebbe a un codice più pulito, allora non dovrei usarlo anche se differisce drasticamente dal codice circostante?

Penso che il punto cruciale dell'argomento del mio collega sia che se tutti andiamo a implementare funzionalità simili in un codebase in modi diversi, e ognuno di noi pensa che il nostro modo sia "il migliore", quindi alla fine il codice nel suo complesso diventa solo più difficile da capire. Tuttavia al momento penso ancora che se seguiremo ciecamente il codice esistente troppo, la qualità si modificherà lentamente nel tempo.

Quindi, in che misura i pattern fanno parte dello stile del codice, e dove dovremmo tracciare la linea tra coerenza e miglioramento?

    
posta Robert Johnson 15.03.2013 - 08:55
fonte

9 risposte

53

Per dare una risposta più generale:

In un caso come questo, ci sono due "best practice" di programmazione che sono opposte l'una all'altra: la coerenza del codice è importante, ma lo è anche la scelta del metodo migliore per eseguire il tuo compito. Non esiste una risposta corretta a questo dilemma; dipende da un paio di fattori:

  • Quanto è utile la "corretta"?

    • A volte le best practice nuove e migliorate aumentano drasticamente le prestazioni, eliminano bug, sono molto più facili da programmare, ecc. In tal caso, mi preme molto per utilizzare il nuovo metodo. D'altra parte , il "modo corretto" potrebbe essere poco più dello zucchero sintattico o un metodo idiomatico concordato per fare qualcosa che non sia in realtà superiore. In tal caso, la coerenza del codice è probabilmente più importante.
  • Quanto grande sarebbe il problema di un'incoerenza?

    • Quanto è interconnesso il nuovo codice con codice legacy? Il tuo nuovo codice fa parte di una libreria? Crea un oggetto che viene passato a molte parti del programma? In casi come questi, la coerenza è molto importante. L'utilizzo di una nuova API o di un nuovo modo di fare le cose in generale, potrebbe creare risultati sottilmente diversi che rompono le ipotesi altrove nel programma. D'altra parte , se stai scrivendo una parte di codice abbastanza isolata, l'incoerenza è meno probabile che sia un problema.
    • Quanto è grande e quanto è maturo il tuo codice base? Quanti sviluppatori hanno bisogno di capirlo e lavorarci? Gli standard coerenti e concordati sono molto più importanti per i progetti più grandi.
    • Il codice deve essere eseguito in ambienti meno recenti che potrebbero non supportare le funzionalità più recenti?

Sulla base del bilanciamento di questi problemi, devi fare la scelta giusta su quale strada prendere. Personalmente ritengo poco utile la coerenza per motivi di coerenza e preferirei usare i metodi migliori e più recenti, a meno che non ci sia un costo significativo per farlo.

Naturalmente, c'è una terza opzione: riscrivere il codice esistente in modo che usi i metodi migliori e sia coerente. Ci sono momenti in cui questo è necessario, ma ha un costo elevato.

    
risposta data 15.03.2013 - 10:17
fonte
26

Restare coerenti ha poco valore nella mia prospettiva; fare continuamente miglioramenti è un must.

La posizione del tuo collega ostacola davvero l'innovazione. L'argomento della coerenza ti porta in una situazione in cui puoi utilizzare, per esempio, LINQ solo se si esegue la migrazione del codice tutto per utilizzare LINQ. E bene, non abbiamo tempo per questo, vero?

Preferirei avere incoerenza laddove alcuni codici stanno ancora facendo foreach su ArrayLists e altre parti usano LINQ su IEnumerable<T> , invece di attenersi al modo più vecchio di fare le cose fino alla fine dei tempi.

È responsabilità dei tuoi colleghi rimanere pertinenti e apprendere nuovi modi di fare le cose.

    
risposta data 15.03.2013 - 09:59
fonte
8

La coerenza delle API è molto importante, sia per le API pubbliche che per quelle interne.

La coerenza della formattazione del codice è importante e dovrebbe idealmente essere applicata dallo strumento di formattazione automatico con le stesse regole di formattazione per tutti. Rende più semplice la vita con codebase con controllo della versione condiviso.

Le convenzioni sui nomi dovrebbero essere coerenti, anche per cose come variabili locali ecc.

Gli strumenti di analisi statica dovrebbero essere usati per far rispettare certe altre convenzioni e buone pratiche (ma non seguire ciecamente le impostazioni predefinite di uno di questi strumenti, le impostazioni predefinite possono talvolta rasentare il folle), anche se qualcosa lo richiede, non aver paura per disabilitare qualche controllo (di solito con una direttiva all'interno di un commento) temporaneamente, se puoi giustificarlo.

Cosa succede all'interno di funzioni / metodi , a parte ciò che è elencato sopra, non ha bisogno di essere coerente in alcun modo, purché sia di per sé un buon codice . Buono, comprensibile, bene codice commentato è molto importante, ma dopo, se il compilatore e gli strumenti di analisi statica pensano che sia un codice coerente, è abbastanza coerente.

Informazioni sulle nuove funzionalità della lingua come LINQ (beh, non è esattamente nuovo), l'unica cosa che deve essere considerata è, una nuova versione della lingua / delle librerie sarà in uso ovunque dove il codice sarà usato? In caso di dubbio, attenersi a caratteristiche che sono noti per essere compatibili. Questo naturalmente non ti impedisce di spingere l'aggiornamento della versione in tutto il sistema, quindi puoi iniziare a utilizzare le nuove cose carine.

E ogni sviluppatore che lavora con il codice dovrebbe tenersi aggiornato, quindi qualsiasi sviluppatore .NET dovrebbe conoscere LINQ, e se non lo fanno dovrebbero essere costretti ad imparare, per il loro bene (non si sa mai quando si guarderanno per un nuovo lavoro in questo settore, per un motivo o per un altro).

    
risposta data 15.03.2013 - 09:20
fonte
5

La risposta a questo è semplice.

La coerenza è di fondamentale importanza.

ma viene fornito con un avvertimento ...

Tu e il tuo collaboratore siete probabilmente ossessionati dal tipo sbagliato di consistenza

Le implementazioni sono usa e getta. Possono essere completamente revisionati con diversi gradi di facilità a seconda della qualità e della completezza della suite di test. Preoccuparsi di cose come "Dovrebbe essere una proprietà?", "Il codice di Thins non dovrebbe usare LINQ invece di un costrutto di livello inferiore?" ha un valore dubbio. È molto difficile legare qualsiasi misura al valore di coerenza a livello di implementazione. Una domanda molto migliore da porre a questo livello è "Questo codice funziona come pubblicizzato?". TL: la coerenza dell'implementazione DR è quella in cui le "piccole menti" prendono il loro hobgoblin.

Perché la coerenza non è importante qui? Le implementazioni di solito hanno un piccolo numero di contributori. La maggior parte dei metodi sono scritti e mai più toccati. Del codice rimanente il numero di metodi che hanno due contributori è quasi certamente una maggioranza. Questo modello continua ad infinitum . In questo contesto, la coerenza non è così importante. Se il periodo di validità del codice è piuttosto piccolo ( alcuni anni ) i guadagni dalla consistenza aggressiva sono probabilmente un non fattore.

Questo non vuol dire che dovresti impazzire nelle tue implementazioni. Piuttosto, dire che un design bello, pulito e semplice sarà un ordine di grandezza più prezioso per il tuo ipotetico futuro manutentore rispetto al metodo di consistenza della piastra di caldaia sciocco. Questo ci porta al punto reale ...

Le API non sono usa e getta.

Questo è tutto livello di codice API, servizi Web, SDK ecc. Questi devono, devono, DEVE essere coerenti. I guadagni di produttività di questa varietà di consistenza sono enormi per una serie di motivi:

Test di integrazione:

Se mantieni la coerenza delle tue API puoi creare suite di test di integrazione. Ciò consente agli sviluppatori di scambiare liberamente i dettagli di implementazione e ottenere una convalida immediata. Vuoi scambiare i tuoi copioni con quelli di LINQ? I test di integrazione sono eseguiti? Fornisce anche la convalida quando si prepara per andare in produzione. Poiché i computer sono veloci, un singolo laptop può preformare il lavoro di migliaia di tester che eseguono compiti banali. È equivalente ad aumentare considerevolmente l'organico della tua organizzazione.

Produttività

Quando le API sono coerenti, puoi fare ipotesi su come utilizzare un'API seguendo semplicemente ciò che hai imparato sull'utilizzo di altre parti dell'API. Questo perché l'API offre un "look and feel" naturale e coerente. Significa che i tuoi clienti passano meno tempo a setacciare la documentazione. L'onboarding è più facile ed economico. Vengono poste meno domande alle persone che hanno sviluppato l'API. La coerenza rende tutti un vincitore

Perché la coerenza è importante in questo scenario? Perché le API hanno esattamente l'opposto problema delle implementazioni. Il numero di persone che li usano è in genere molto maggiore del numero di persone che contribuiscono alle loro implementazioni. Piccoli guadagni da una piccola consistenza vengono moltiplicati e i costi di mantenimento di tale consistenza vengono ammortizzati.

Conclusione

La coerenza è costosa. Di fronte riduce la produttività. Limita gli sviluppatori e rende le loro vite più difficili. Pone limitazioni sul modo in cui possono risolvere un problema, a volte costringendoli a risolverlo in modo non ottimale. Questo è spesso per motivi che non capiscono, sono mal concepiti o non sono a conoscenza (contratti, politiche organizzative o interorganizzative più grandi).

Raymond Hettinger ha fatto alcuni punti eccellenti nel suo discorso Pycon 2015 sull'uso della guida in stile PEP8 per i team di programmatori Python. Ha dimostrato che l'ossessione per la coerenza stilistica su un pezzo di codice ha fatto sì che i revisori del codice perdessero i difetti logici e di progettazione. La sua ipotesi può essere riassunta come trovare incongruenze stilistiche è facile; determinare la vera qualità di un pezzo di codice è difficile

Il punto qui è critico. Individuare dove è importante la coerenza e proteggerlo in modo aggressivo. Dove non è importante non perdere tempo. Se non è possibile fornire un metodo oggettivo per misurare il valore della consistenza (nei casi sopra "effettivi", costo in funzione della produttività) e non è possibile dimostrare che i rendimenti sono sostanziali, è probabile che si stia facendo un cattivo servizio a la tua organizzazione.

    
risposta data 02.05.2015 - 16:03
fonte
4

Unfamiliar with LINQ? If so, wouldn't my code be more maintainable for my fellow developers if I didn't use it?

Il linguaggio C # è ancora in evoluzione. Se le persone non imparassero i cambiamenti da C # 1, si perderebbero:

  • Generics
  • I partial
  • Metodi anonimi
  • Iteratori
  • Tipi Nullable
  • Auto-properties
  • Tipi anonimi
  • Metodi di estensione
  • Ling
  • lambda
  • Metodi asincroni

Questa è solo una piccola selezione di caratteristiche comuni trovate nell'articolo di Wikipedia. Il punto che sto facendo è che se gli sviluppatori non imparano, il codebase rimarrà nel vuoto. Si spera che i tuoi sviluppatori migliorino continuamente e la base di codice si evolva, supportata da una suite di test completa. Ti ricordi quanto è stato pessimo con .NET 1 implementare manualmente le proprietà.

Linq semplifica la vita. Usalo dove puoi. Potresti motivare i membri del tuo team.

So, to what extent are patterns part of code style, and where should we draw the line between staying consistent and making improvements?

I miglioramenti sono graduali. Per me, non ha senso mantenere il codice vecchio stile che è meno leggibile e potenzialmente meno conservabile. I membri del tuo team dovrebbero almeno essere in grado di capire cosa sta succedendo, anche se non possono scriverlo.

    
risposta data 15.03.2013 - 09:18
fonte
3

Dovresti essere coerente, ma non necessariamente con il vecchio codice. Cioè, la tua squadra dovrebbe essere d'accordo sul modo giusto di fare qualcosa e usarla in questo modo ogni volta che viene scritto un nuovo codice o vengono apportate modifiche sostanziali.

In questo modo, raccogli la maggior parte dei vantaggi della coerenza (in particolare, non importa chi scrive il codice), ma puoi ancora migliorare se il team vede un chiaro vantaggio facendo le cose in un altro modo.

In un mondo ideale, dovremmo riscrivere tutto il vecchio codice per conformarci al nuovo modo giusto. Anche se questo non è economicamente sostenibile, dovrebbe avere un senso tecnico (oppure, il nuovo modo non è un modo migliore), e il tuo piano a lungo termine dovrebbe essere quello di aggiornarlo. Se non ne vale la pena, non preoccuparti del nuovo modo. In altre parole, deve esserci un chiaro vantaggio per il nuovo modo di considerare di dichiararlo giusto.

    
risposta data 15.03.2013 - 14:10
fonte
1

Penso che sia importante seguire un codice stile in un progetto es. convenzioni di denominazione, indentazioni ecc.

Non sono d'accordo sul fatto che tu debba essere limitato dall'uso di costrutti di nuova lingua o schemi di progettazione semplicemente perché i tuoi colleghi non li capiscono, o non sono mai stati utilizzati nel progetto in precedenza.

Ovviamente queste cose dovrebbero avere buone ragioni per usarle ad es. prestazioni o brevità, se appropriato.

    
risposta data 15.03.2013 - 11:20
fonte
0

Sarei estremamente attento a seguire ciecamente gli schemi di progettazione attuali. Ovviamente, quando non ci sono svantaggi apprezzabili, si dovrebbe sempre tentare di seguire modelli simili attraverso la base del codice.

Tuttavia, è fin troppo facile entrare in circostanze in cui la maggior parte degli sviluppatori si sente come se fosse la "migliore pratica" seguire i modelli errati esistenti che portano a situazioni in cui i buoni sviluppatori scrivono codice cattivo e non gestibile.

D'altra parte, la coerenza è importante. Quando si affrontano enormi basi di codice, è estremamente utile provare a seguire schemi simili in modo che anche se gli sviluppatori non hanno letto ogni centimetro del codice base, sanno cosa aspettarsi.

Pertanto, ritengo sia meglio stabilire e aggiornare le linee guida su quali pattern dovrebbero seguire gli sviluppatori, se possibile. In questo modo, qualsiasi nuovo codice è coerente con un altro nuovo codice.

    
risposta data 15.03.2013 - 19:16
fonte
-1

Organizziamo riunioni tecniche regolari, piuttosto informali, che ognuno di noi può eseguire. Se troviamo una nuova tecnica, la presentiamo all'incontro. In genere hai una buona sensazione di quanto l'idea sia accettata e compresa dai tuoi colleghi. Questo ti aiuta a decidere se è saggio includerlo nel tuo codice, aiuta gli altri a decifrarlo se lo fai e stabilisce anche la persona "vai a" se altri hanno bisogno di aiuto con quello stile. Se nessuno ha reinventato la ruota, continueremmo a trascinare la roba nei registri.

    
risposta data 15.03.2013 - 17:26
fonte

Leggi altre domande sui tag