Perché è DRY importante?


81

Abbastanza semplice, perché dovrei voler scrivere un codice che funzioni per tutti i casi e dati scalabili quando tutto ciò che devo fare è ripetere lo stesso processo alcune volte con alcune piccole modifiche?

Difficilmente dovrò modificarlo di nuovo in qualunque momento presto.

Sembra molto meno lavoro per andare solo ...

function doStuff1(){/*.a.*/}
function doStuff2(){/*.b.*/}
function doStuff3(){/*.c.*/}

E se mai dovessi aggiungere qualcosa ...

function doStuff4(){/*.d.*/}

E se devo rimuoverlo, lo rimuovo.

È più difficile capire come trasformarli tutti in un modello semplice in cui posso semplicemente inserire i dati e gestire tutti i casi, e apportare un sacco di modifiche che non mi sembra che avrò mai fare.

Perché essere ASCIUTTO quando sembra che un taglio rapido + incolla sarà molto meno lavoro?


11
perché dry è ancora più veloce quando lo fai bene, e anche se hai fatto un errore in a. che ha effetto su tutti gli altri
Daniel Little,

97
"Difficilmente dovrò modificarlo di nuovo in qualunque momento presto" - potresti sperare, ma molto probabilmente stai commettendo un errore qui. E se lavorerai di nuovo su quel codice, ma non così presto, peggiorerà le cose; dimenticherai dove si trovano i duplicati e i duplicati diventeranno discrepanze sottili ma insidiose. "Scrivi come se la persona che manterrà il tuo codice è un maniaco pericoloso che sa dove vivi", per citare i classici.
9000,

14
Penso che puoi praticamente riassumere: un singolo punto di cambiamento è più facile da mantenere.
Falcon,

17
Se non riesci a rispondere da solo, devi ottenere qualche esperienza nel mondo reale di sviluppo e manutenzione.
David Heffernan,

15
@Wayne ho sentito un grande disturbo alla fonte, come se milioni di programmatori improvvisamente gridassero terrorizzati.
Incognito,

Risposte:


121

Se ti ripeti, puoi creare problemi di manutenibilità. Se doStuff1-3 ha tutti un codice strutturato in modo simile e risolvi un problema in uno, potresti facilmente dimenticare di risolvere il problema in altri luoghi. Inoltre, se devi aggiungere un nuovo caso da gestire, puoi semplicemente passare parametri diversi in una funzione piuttosto che incollare dappertutto.

Tuttavia, DRY è spesso portato all'estremo da programmatori intelligenti. A volte per non ripetere te stesso devi creare astrazioni così ottuse che i tuoi compagni di squadra non possono seguirle. A volte la struttura di due cose è solo vagamente simile ma abbastanza diversa. Se doStuff1-4 è abbastanza diverso da non essere più ripetuto, il refactoring per non ripeterti comporta la necessità di scrivere un codice innaturale o di subire dei capovolgimenti di codifica che potrebbero farti abbagliare dalla tua squadra, quindi potrebbe essere giusto ripeterti. Mi sono chinato all'indietro per non ripetermi un paio di volte in modi innaturali e mi sono pentito del prodotto finale.

Faccio sempre errori da parte di DRY, nel raro caso in cui mi ripeto quando penso che i vantaggi della leggibilità valgano i rischi di qualcuno che si dimentica di correggere un bug in più punti.

Tenendo conto di quel consiglio, sembra come nel tuo caso

ripetere lo stesso processo alcune volte con alcune piccole modifiche

Lavorerei sodo per non ripetermi nel tuo caso. Supponendo "modifiche" minime, possono essere gestite con parametri diversi che influiscono sul comportamento o possono essere iniettate dipendenza per eseguire diverse attività secondarie.

Perché essere ASCIUTTO quando sembra che un taglio rapido + incolla sarà molto meno lavoro?

Le ultime parole famose. Ti pentirai di pensare che quando un ingegnere junior modifica / corregge / refatta uno fa Stuff e non si rende nemmeno conto che esiste l'altro. Ne deriva l'ilarità. Non segue per lo più bruciore di stomaco. Ogni riga di codice costa di più. Quanti percorsi di codice devi testare con così tante funzioni ripetute? Se una funzione, devi solo testare un percorso principale con alcune modifiche comportamentali. Se incollato, devi testare ogni doStuff separatamente. Probabilmente ne perderai uno e un cliente potrebbe avere un bug indesiderato e potresti avere alcune email indesiderate nella tua casella di posta.


2
Ehm, solo per essere chiari, non sto proponendo che il secco sia negativo, questa domanda è più di un sostenitore dei diavoli. Sto davvero cercando una risposta logica che posso collegare a persone che pensano che il codice cut + paste + tweak vada bene.
Incognito,

2
Detto questo, mi piace di più la tua risposta in quanto copre entrambi i guasti di DRY: non preoccuparti, esagerando, oltre a spiegare gli impatti. - Per quanto riguarda il sacrificio della leggibilità per i bug, direi che il codice ripetitivo è meno leggibile per lo stesso motivo che fai notare, dove è facile perdere traccia delle cose.
Incognito,

16
Sottolineerei un semplice trabocchetto di DRY: codice simile unito. Se hai due casi d'uso che non sono funzionalmente correlati ma hanno un codice molto simile, è facile unire i due perché DRY è buono . Sfortunatamente, quando uno ha bisogno di evolversi, spesso ti ritrovi con il compito spiacevole di dover dividere di nuovo la funzione, quindi passare attraverso tutti i siti di chiamata e considerare attentamente quale dovrebbe essere chiamato qui ... Esempio: Digitazione strutturale LLVM (tutti i tipi simili sono uniti in uno) rende quasi impossibile mappare l'IR al codice originale.
Matthieu M.,

1
Bingo. Se due o più parti di codice verranno modificate e le modifiche saranno sempre le stesse per tutte le parti, è necessario unirle. Qualsiasi pezzo che dovrà cambiare in modo diverso dagli altri non dovrebbe essere unito. Se il codice non cambierà mai, non importa molto se viene unito o meno. La questione se le modifiche debbano essere bloccate o staccate è molto più importante della dimensione del codice in questione.
supercat,

1
@MatthieuM è un esempio un po 'ingiusto. LLVM applica la tipizzazione strutturale come ottimizzazione ; cioè, la gente di LLVM ha deciso di pagare il prezzo di IR difficile da capire per i benefici di prestazione. DRY è di solito un problema di manutenibilità, ma in questo caso è stata chiaramente una decisione deliberata per ridurre la manutenibilità.
Benjamin Hodgson,

47

Perché DRY sarà meno lavoro in seguito.


SECCO: (non ripetere te stesso)

Una funzione accetta un argomento.

def log(arg):
    print(arg)

C&P: (Copia e incolla)

26 funzioni di gazillion fanno sostanzialmente la stessa cosa, ma con una differenza di 2 caratteri.

def logA():
    print('a')

def logB():
    print('b')

...ad infinitum...

Che ne dite di aggiornare la nostra stampa per specificare cosa sta esattamente stampando?

ASCIUTTO:

def log(arg):
    print(arg + "Printed from process foo")

Fatto.

C & P:

Devi tornare indietro e cambiare ogni singola funzione .


Quale pensi che sarebbe più facile eseguire il debug?


10
Inoltre, è necessario scrivere tutte le suite di test simili quante sono le funzioni duplicate.
9000,

Hai illustrato adeguatamente il concetto, ma in pratica nessuno farebbe ciò che hai descritto con le funzioni gazillion, non in quel modo comunque.
Robert Harvey,

@Robert Spero di no! Ho scelto un compito molto semplice per cercare di illustrare meglio il concetto e perché può essere una buona cosa.
Giovanni,

11
@Robert - hai letto qualcuno degli articoli su thedailywtf.com ;) - ci sono alcuni là fuori che lo farebbero
HorusKol

1
@ 9000 Non se non hai nessuna suite di test: p (che in realtà spesso potrebbe essere il caso in alcuni progetti ... purtroppo ...)
Svish

16

Perché , applicato al tuo esempio:

  • + leggibilità

    Meno codice si traduce spesso in meno rumore . (non sempre...)

  • + flessibilità

    Se hai mai dovuto cambiare il comportamento di doStuffX, ti consigliamo di uccidere te stesso o chiunque lo abbia scritto,

  • + estensibilità

    Se aveste estratto le parti distinte in una struttura di dati di vostra scelta e doStuffvi aveste semplicemente ripetuto chiamando un generico , potreste anche aggiungere una riga nella struttura di dati in cui desiderate una nuova voce o rimuoverne una e cambiare il comportamento significherà solo modificare doStuff. Più facile da mantenere .

  • + efficienza dei costi

    meno codice qui significa:

    • => meno sviluppo => costo ridotto
    • => meno probabilità di bug => meno tempo di supporto => costo ridotto
  • + (possibile) ottimizzazione gestita

    A seconda della lingua, il compilatore / interprete potrebbe avere maggiori probabilità di determinare che il generico doStufffa sempre le cose quasi identiche spesso una chiamata dopo l'altra, e potrebbe incorporarlo o tentare di ottimizzarlo . Probabilmente no per X variazioni di doStuffX.

  • + test e qualità

    Il test è più semplice: doStuffdeve essere testato e basta. Bene, non esattamente, ma questo copre già di più . Solo le sue aspettative di IO variano e devono essere testate in condizioni diverse, ma è ancora molto più facile da testare e più gestibile di tutte le varianti di doStuffX.

Complessivamente ciò rappresenta un codice più gestibile e una migliore efficienza di sviluppo per il tuo team, ed è una delle molte buone pratiche per aiutarti a produrre software più robusto e affidabile.


13

Poiché tutti gli altri hanno fatto un ottimo lavoro nel spiegare i problemi di manutenibilità con codice duplicato, dirò solo questo:

Gran parte della programmazione richiede di pensare al futuro, non solo al presente immediato. Hai ragione sul fatto che copia e incolla ora è più facile, ma è improbabile che presto dovrò modificarlo di nuovo in qualsiasi momento " indica che non stai pensando correttamente. Sì, potresti guadagnare un po 'di tempo con un copia / incolla veloce e sporco, ma nel farlo stai dimostrando che non puoi guardare oltre il tuo problema immediato e pensare a domani. Sei sicuro che non dovrai mai rivedere questo codice? Sai per certo che ci sono nessun bug in esso? Puoi garantire al 100% che non dovrai rivederlo quando il tuo prossimo set di funzionalità deve essere implementato? Questi sono problemi per domani e devono essere considerati quando stai progettando oggi.

Certo, ci sono momenti in cui sarà necessario copiare / incollare. Come sviluppatore dell'interfaccia utente, ho scoperto che ci sono momenti in cui devo violare il principio DRY. Fa schifo, rabbrividisco ogni volta che succede, e per fortuna, è raro. Ma non accade.

La differenza è che quando si viola DRY, si dovrebbe avere una ragione molto convincente per farlo, e l'affermazione, è più difficile capire come trasformare tutti questi in un modello diretto non è davvero uno di loro. A meno che tu non sia sottoposto a una massiccia crisi del tempo e che il tuo capo urli per ottenere qualcosa nelle prossime ore o perderai il lavoro, non credo che questa sia una logica valida.

Non prenderla nel modo sbagliato: non sto cercando di castigare o castigarti, ma piuttosto cercare di farti vedere dove la tua mentalità è sbagliata. I programmatori investono nella pigrizia futura; DRY è un modo per raggiungere questo obiettivo. Il lavoro che svolgi oggi per risolvere un difficile problema di progettazione sarà ripagato domani.


Non sono sicuro di essere d'accordo con un capo che ti dice "fallo o sei licenziato" è un ottimo motivo per violare il DRY. Il debito tecnico, quando hai tempo per farlo nel modo giusto, fa davvero risparmiare tempo, ecc.?
Incognito,

1
@Incognito, stavo cercando di essere un po 'ironico :)
bedwyr il

7

Difficilmente dovrò modificarlo di nuovo in qualunque momento presto.

Se questo è davvero il caso, allora potresti essere in grado di cavartela, ma il più delle volte lavorerai sul codice che deve essere mantenuto. Ciò significa estendere la funzionalità, correggere bug e altri miglioramenti. Se hai piccole variazioni dello stesso codice in 10 luoghi diversi e un giorno torni a quel codice e devi apportare una modifica, ora hai il compito soggetto ad errori di apportare la stessa modifica in 10 luoghi diversi (Siamo spiacenti, lì erano 11 posti, te ne sei dimenticato uno e ora hai un bug).

Se riesci a generalizzare quale problema stai cercando di risolvere, puoi semplificare l'estensione e la correzione del codice in caso di comparsa di bug.


Bella risposta, ma anche se potessi cavarmela, che dire della povera linfa che riesce a mantenerla dopo di me? ;).
Incognito,

Vedi: "il più delle volte lavorerai sul codice che deve essere mantenuto" :)
Alex

Anche allora è solo il caso se ciò che stai copiando e incollando è una perfezione senza errori al 100%. E non lo è, e smetti di pensare che potrebbe essere.
Dan Ray,

Devo ammettere di aver copiato e incollato cose in passato, ma mai per nulla che avrei tenuto in giro per più di un giorno. A volte hai solo bisogno di uno script da buttare via veloce e sporco.
Alex

6

Come ho affermato nella risposta a un'altra domanda, il mio approccio è il seguente:

  1. La prima volta che risolvo un certo problema, l'ho appena fatto.
  2. La seconda volta (cioè quando risolvo un problema simile) penso: hm, forse mi sto ripetendo, ma per ora cercherò un copia-e-incolla veloce.
  3. La terza volta penso: hm, mi sto ripetendo -> rendilo generale!

Vale a dire fino a 2, un altro principio (YAGNI) vince su DRY. Ma a partire da 3 (o 4 se sono davvero pigro!) Sembra che ne avrò bisogno e quindi seguo DRY.

Aggiornare

Alcune ulteriori idee della mia recente esperienza. Ho dovuto adattare / integrare due componenti A e B sviluppati da un altro team nel nostro prodotto. Primo: i due componenti A eb B sono molto simili tra loro, quindi ero già disturbato dal fatto che avevano un'architettura un po 'diversa. Secondo: ho dovuto adattarli, quindi sarei stato felice di usare le sottoclassi e sovrascrivere solo ciò di cui avevo veramente bisogno.

Quindi ho iniziato a refactoring di questi due componenti (ognuno dei quali è costituito da circa 8 classi C ++): volevo avere un'architettura comune per A e B, e quindi aggiungere le funzionalità di cui abbiamo bisogno definendo le sottoclassi. In questo modo, i nostri due nuovi componenti A 'e B' sarebbero stati derivati ​​da quelli esistenti.

Dopo due settimane che cercavo di ottenere una struttura comune e ben definita dal codice esistente e di dover spiegare durante le nostre riunioni quotidiane che stavo facendo pochi progressi perché il codice originale era troppo disordinato, ho parlato con il mio capo. Abbiamo osservato che non avremmo avuto bisogno di qualcosa di più di questi due nuovi componenti A 'e B' (non ce ne sarebbero stati quattro o sei, solo quei due).

Ok, così sia: ho fatto una copia enorme e un nuovo nome delle classi da A e B e ho iniziato ad adattare la copia del codice. L'ho fatto funzionare tra altre due settimane (sto ancora facendo un po 'di correzione degli errori).

Vantaggi: ora abbiamo quasi finito la funzionalità e quando abbiamo risolto tutti i bug abbiamo finito. Abbiamo salvato tutti i refactoring e i test di A e B.

Svantaggi: Due settimane fa l'altra squadra ha cambiato un altro componente C, che è usato da A e B. Hanno adattato A e B ma anche A 'e B' sono stati rotti e abbiamo dovuto cambiarli da soli. Ciò ha introdotto un nuovo bug che abbiamo dovuto correggere. Questo lavoro extra probabilmente non sarebbe stato necessario se A 'e B' avessero condiviso la maggior parte del loro codice con A e B.

Quindi: la duplicazione del codice è sempre pericolosa. Penso che sia sempre una questione di trovare compromessi e spesso non è facile.


5

Giusto per chiarire, poiché non lo trovo in nessuna delle altre risposte:

DRY è un principio di sviluppo software volto a ridurre la ripetizione di informazioni di ogni tipo .

Ogni pezzo di conoscenza deve avere un'unica, inequivocabile, autorevole rappresentazione all'interno di un sistema.

Il principio DRY menzionato da Andy Hunt e Dave Thomas non si limita a prevenire la duplicazione del codice. Promuove inoltre la generazione di codice e qualsiasi processo di automazione. Ironia della sorte, i risultati della generazione del codice potrebbero anche essere un codice duplicato ...

Il motivo per cui è già stato ampiamente spiegato nelle altre risposte, ma il commento di Falcon lo riassume abbastanza bene IMHO:

Un singolo punto di cambiamento è più facile da mantenere.


Oh wow, pensavo che il tag contenesse alcuni dati. Metterò alcune informazioni lì dentro.
Incognito,

3

C'è qualcosa di troppo SECCO. Quando ciò accade, due concetti che a un certo punto sembrano abbastanza simili da giustificare il codice di factoring (1) possono in seguito rivelarsi sufficientemente diversi da meritare implementazioni separate.

In altre parole, DRY e accoppiamento lento a volte sono in conflitto. Se ti aspetti che doStuff1 e i tuoi amici divergano con ogni nuova versione del software, è OK duplicare il loro codice.

Nella mia esperienza, può essere difficile giudicare dove sta andando il tuo software in futuro, e per questo motivo, DRY è spesso una scelta sicura.

Il codice che è stato eccessivamente "essiccato" in genere ha un flusso di controllo complesso e troppi parametri. Quella che inizialmente era una semplice funzione è stata successivamente estesa per supportare una nuova funzionalità controllata da un parametro aggiuntivo. Dopo due o tre iterazioni, la funzione non è più mantenibile. Risolto un bug che si verifica in un'impostazione e si introducono nuovi bug in altre impostazioni.

È comprensibile che la qualità del codice spesso diminuisca man mano che il codice si evolve, ma ho visto casi in cui una funzione multiparametrica con spaghetti if-then-else nel corpo era il risultato di uno sforzo di refactoring ben intenzionato ma mal condotto.

(1) Sto usando la parola "codice", ma questo vale anche per il design.


Sarebbe utile dare un esempio di "troppo secco" in quanto è la fine meno vista dello spettro.
Incognito,

@Incognito: ho modificato la mia risposta. Nessun esempio concreto, ma spero che ciò che intendevo sia abbastanza chiaro.
Joh,

2

Devo menzionare i problemi con DRY nel mondo dei database relazionali. I database sono progettati per funzionare rapidamente e bene utilizzando la logica basata su set e tramite query di grandi dimensioni. I principi DRY spesso inducono lo sviluppatore a scrivere query non Sargable o utilizzare la logica Row-by-agonizing-Row per sfruttare il codice esistente in più situazioni. DRY e l'ottimizzazione delle prestazioni sono spesso in contrasto e nel mondo del database, le prestazioni sono generalmente molto più critiche della manutenibilità. Questo non significa che non dovresti assolutamente usare i principi DRY, ma solo che devi essere consapevole di come influenzerà l'usabilità complessiva del database. Gli sviluppatori di applicazioni si asciugano per primi e le prestazioni in secondo luogo, gli sviluppatori del database pensano prima l'integrità dei dati, le prestazioni in secondo luogo, la sicurezza dei dati in terzo luogo (le prestazioni e la sicurezza potrebbero scambiare posizioni in alcuni sistemi).

Ho notato in generale che più strati di astrazione vengono inseriti nelle query del database, più lentamente diventano. Non sto dicendo che non desideravo che le persone che progettavano i programmi di basi di dati stesse non avessero fatto un lavoro migliore nel consentire agli sviluppatori di usare DRY senza influire sulle prestazioni del database, ma non progetto software di database a quel livello , quindi forse il conflitto tra astrazione e prestazioni nel database è più difficile da risolvere di quanto suppongo. Tuttavia, dobbiamo lavorare con i sistemi così come sono attualmente costruiti. Possiamo chiedere una migliore implementazione dei principi DRY nelle versioni future che non uccideranno anche le prestazioni (e è migliorata negli anni ma è ancora problematica), ma nel frattempo dobbiamo considerare se DRY è la mossa giusta per questo database A quest'ora.

Ma spesso le stesse funzionalità che si desidera utilizzare per garantire il rispetto del principio DRY sono quelle che causano enormi problemi al database. Non sto dicendo di non usare mai DRY ma non esagerare.

Esempi di cosa sto parlando. È necessario eseguire un'importazione di dati di un milione di record una volta al mese. I record possono già essere aggiunti manualmente tramite l'interfaccia utente chiamando un proc memorizzato. Questo proc, poiché è stato progettato per l'importazione di singoli record, aggiunge un solo record alla volta. Utilizzando DRY per evitare di inserire il codice di inserimento in due punti, si scrive un cursore per chiamare ripetutamente il proc anziché scrivere le importazioni basate su set necessarie. Il tempo per l'importazione va dai 30 minuti che impiegherebbe usando la logica basata su set a 18 ore. Ora il modo giusto di aderire a DRY in questo caso sarebbe quello di riparare il proc per gestire le importazioni di record mulitple. Sfortunatamente, è spesso impossibile o molto difficile inviare un array a un proc (a seconda del back-end db) e cambiando il proc, si finisce per rompere l'applicazione.

Le funzioni scalari e le funzioni con valori di tabella vengono utilizzate anche per implementare i principi DRY e, di nuovo, possono influenzare seriamente le prestazioni, soprattutto se è necessario utilizzarle in modo da impedire che gli indici siano utili.

Le viste sono buone anche per l'implementazione di DRY. Tuttavia, se si implementa DRY attraverso l'uso di viste che richiamano viste che richiamano altre viste, si arriva rapidamente al punto in cui le query scadranno sotto carico. In effetti potresti finire con la necessità di generare set di dati di milioni di record quando ne hai bisogno solo tre alla fine. Pertanto, una vista a un livello di un insieme complesso di join per l'implementazione di DRY può essere eccellente (ne ho uno io stesso che utilizziamo per assicurarci che tutti i report finanziari utilizzino lo stesso set di tabelle e calcoli di base), più di due livelli e devi considerare se stai creando un pasticcio di prestazioni.


1

Non vedo i punti chiave della mia risposta sopra, quindi ecco qui. Non guardare a SECCO come una regola controfacendo qualcosa. Può essere espresso così, ma può davvero servire a uno scopo ben diverso e positivo. È un segnale per fermarsi, pensare e trovare una risposta migliore. Mi sfida a cercare opportunità per progettare una soluzione migliore. È il lato positivo di un cattivo odore nel mio codice che mi induce a ripensare il mio design e mi fa fare molto meglio. DRY non riguarda solo una brutta violazione della sintassi. Mi sfida a modularizzare. Mi sfida a strutturare. Segnala una ripetizione che mi ricorda di pensare a usare modelli e generazione di codice anziché forza bruta e ignoranza. Mi aiuta a capire che dovrei trovare del tempo per automatizzare la mia automazione. Ti porta a uno stile di vita parsimonioso! Ti aiuta a dedicare più tempo a fare nuove cose più interessanti invece di vecchi dettagli noiosi e nitidi. E ti dà buone maniere, buon respiro e uno stile di vita sano! Beh, forse mi sto un po 'smarrendo ...


DRY ha effetti molto diversi su di me, tuttavia, se questi sono i suoi effetti su di me, mi piace piuttosto la filosofia di qualcosa che è "un segnale per fermare, pensare e trovare una risposta migliore", e la sfida.
n611x007

1

Ho un vecchio progetto legacy, in cui alcuni ex sviluppatori non si preoccupavano affatto di DRY. Quindi l'intera base di codice è stata ingombra di metodi di supporto come GetSystemTimeAsString (), LogToFile () e molte altre cose. Alcuni metodi sono stati leggermente personalizzati per esigenze speciali, ma la maggior parte erano solo copia e incolla.

Sfortunatamente alcuni dei metodi avevano bug sottili come char array non abbastanza lunghi in alcuni casi, usando cose insicure come strcpy (), ecc.

Quindi è stato un vero PITA trovare tutti i frammenti di codice, armonizzarli e correggere i bug. E stiamo ancora armonizzando e sistemando le cose.

Non si sa mai, se hai fatto un errore nel tuo primo metodo e poi devi ripararlo più volte, perché l'hai appena copiato. E se vuoi usare alcuni dei metodi in seguito, come fai a sapere quale dei 5 metodi nella base di codice è quello per il tuo caso adesso? Quindi basta copiarne uno, personalizzarlo e qui ricomincia ...


1

Sì, non preoccuparti di DRY se stai scrivendo il codice Throwaway .

Ma DRY è importante, ovviamente, se prevedi di conservare il codice.


1

La frase "non ripetere te stesso" è un po 'troppo semplicistica. L'importante è "evitare di avere una parte di informazioni potenzialmente mutevoli incapsulate in due luoghi indipendenti ".

Se si suppone che un programma elabori i widget, ognuno con tre woozles e che siano molti loop del modulo

for (i=0; i<3; i++)
  thisWidget.processWoozle(i);

quindi l'aspettativa che i widget contengano tre woozle sarebbe incapsulata in ciascuno di quei loop e l'aggiornamento del codice per adattarsi a qualsiasi altro numero di woozle per widget potrebbe essere difficile. Al contrario, se si dovesse dire

#define WOOZLES_PER_WIDGET 3

e ogni ciclo sono stati riscritti

for (i=0; i<WOOZLES_PER_WIDGET; i++) ...

un tale design potrebbe rendere molto semplice modificare il numero di woozles per widget.

È importante notare, tuttavia, che mentre è desiderabile consolidare informazioni come il numero di woozles per widget in un singolo punto, non è sempre pratico. A volte può essere necessario codificare la logica che funzionerà solo se le cose hanno dimensioni particolari. Ad esempio, se ogni woozle ha un valore e si desidera trovare la mediana associata a un particolare widget, potrebbe essere possibile ordinare i valori e prendere quello di mezzo, e un tale approccio funzionerebbe con qualsiasi numero di woozle, ma la logica che è scritto a mano specificatamente per trovare la mediana di tre elementi potrebbe essere significativamente più veloce.

Mentre avere una costante WOOZLES_PER_WIDGET può rendere il codice più leggibile, è necessario commentarlo per chiarire che il suo valore non può essere modificato senza apportare altre modifiche alla logica del programma. In tal caso, la logica codificata per tre elementi e la costante WOOZLES_PER_WIDGET duplicheranno entrambi le informazioni "ogni widget ha tre woozle", ma i vantaggi di tale duplicazione (maggiore velocità di esecuzione) potrebbero superare il costo.


0

Mentre in realtà sono d'accordo con gli altri poster, i commenti sulla manutenibilità ecc. Sono tutti validi.

Vorrei aggiungere una piccola voce dissenziente al dibattito.

  • È importante solo per i programmatori. Le persone che pagano i tuoi stipendi non possono fregare di meno finché il software passa UAT.
  • In termini di importanza si colloca ben al di sotto di elementi come ottenere i requisiti corretti, ascoltare gli sponsor del progetto e consegnare in tempo.

dato che questo sito è per "programmatori", penso che sia sicuro dire che la domanda è diretta al "punto di vista dei programmatori". Le tue dichiarazioni su chi paga, UAT e il grado di importanza sono ovviamente valide, ma non rilevanti per questa domanda specifica.
ozz,

1
Non sono assolutamente d'accordo. Una buona gestione comprenderà i principi e il motivo per cui vengono eseguiti se spiegati in dettaglio. Questa dovrebbe essere una conversazione approfondita, non una caduta di 5 minuti.
Michael Durrant,

2
Il tuo secondo punto elenco è del tutto corretto.
Jim G.

1
@Ozz, l'orgoglio nel tuo mestiere è importante anche per un buon programmatore, ma forse il "punto di vista dei programmatori" dovrebbe includere un minimo di preoccupazione per la "soddisfazione del cliente".
James Anderson

0

<tl;dr>

Non sono riuscito a leggere tutte le risposte ripetute, quindi potrei aver perso qualcosa (e lo ripeterò da solo <= vedi cosa ho fatto qui?).

Ecco l'elenco di cose fantastiche sulla prevenzione della duplicazione del codice!

  1. Più facile da testare: devi solo testare una 'copia' del codice.
  2. Più facile da correggere: devi solo trovare il bug in una 'copia' del codice e risolverlo una volta.
  3. Più facile da aggiornare (come sopra): le modifiche necessarie, possono spesso essere gestite modificando il codice in pochissimi posti perché hai impiegato del tempo per riutilizzare correttamente il codice e non hai copiato le stesse righe in centinaia o migliaia di luoghi diversi nella fonte.
  4. Più facile da riutilizzare: quando (non è duplicato in alcuni punti) ed è conservato in metodi generici con nome appropriato, è facile trovarli e usarli invece di scriverne uno proprio.
  5. Più facile da leggere: il codice duplicato è difficile da leggere perché inutilmente dettagliato; contiene molte righe che non fanno parte della logica e delle funzionalità specifiche previste (ad esempio comandi generici utilizzati per impostare lo stage affinché si verifichi l'azione o attività ripetute semplici generiche necessarie in molti luoghi). Il codice pulito rende la logica e la funzionalità pop-out perché non c'è ripetizione che sporca lo spazio del codice.
  6. Più facile da eseguire il debug a causa di (1) e (5).
  7. Risparmia tempo e denaro e fai cose più divertenti in futuro; in particolare creare codice migliore e più affidabile. Questa è la linea di fondo ed è una somma di quasi tutto quanto sopra. Se molte persone usano la stessa funzione doFoo1(a, b), è più probabile che molti dei suoi fastidiosi guasti e casi limite vengano scoperti e risolti. Se tutti copiano il codice e creano doFoo2(specialA)... doFuu2^n(a, b, c)allora duplicano i problemi doFoo1e concretamente creano molto più lavoro.

</tl;dr>

Versione lunga:

Il problema con la duplicazione del codice è che "cresce esponenzialmente" (in altre parole, si espande rapidamente) perché quando si duplica il codice si concede inconsapevolmente ad altri il permesso di (per uno, non si è più in grado di giudicarli) e li incoraggi a fare lo stesso. Rendi anche più difficile non farlo perché è più difficile individuare e riutilizzare il codice utile quando c'è molta ripetizione ridondante e confusa nella fonte. Soprattutto se il codice non è già estratto in una funzione con nome appropriato. Quindi, se affronti un problema semplice da risolvere, probabilmente scriverai tu stesso un pezzo di codice che lo risolve ... E probabilmente non riuscirai a controllare alcuni casi limite, aggiungendo più codice non testato.

Un'altra cosa è che per un principiante questo può sembrare un problema che riguarderà solo le grandi aziende, ma ho scoperto che affligge piccole startup solo in modo grave (come in 10.000 righe di codice lato server duplicato). E 'uno stato mentale. Non dovresti solo dominare il DRY, ma cercare di incoraggiare gli altri a fare lo stesso; perché altrimenti ti condannerai principalmente a duplicare il codice. Quando i mezzi di DRY sono a portata di mano e applicati, è molto più facile applicarli. Quando è presente un sacco di codice duplicato, è molto più semplice applicare le soluzioni di copia e incolla.

Cose che trovo dannose nella duplicazione del codice:

  1. Questa funzione è utilizzabile? Diciamo che trovi una funzione che fa (o sembra fare ciò di cui hai bisogno), come fai a sapere se dovrebbe funzionare correttamente o se è solo un codice che è stato duplicato e abbandonato.
  2. Codice ridondante. A volte le persone duplicano il codice, lo usano e lo dimenticano (possono sempre duplicarlo di nuovo in futuro). A un certo punto qualcuno rimuove le chiamate alla funzione duplicata in alcuni punti nel tentativo di eseguire il refactoring, ma la funzione non utilizzata rimane anche se non viene utilizzata attivamente.
  3. Difficile trovare quello che stai cercando. Il codice duplicato occupa spazio e rende la ricerca di cose utili e necessarie (usando strumenti come grep) un compito più difficile di quanto non lo sia quando si ottengono dozzine o migliaia di risultati in cui avresti dovuto ottenere solo una manciata.
  4. (È stato menzionato in precedenza): difficile da mantenere ma anche difficile da utilizzare per scopi di manutenzione e regressione. Se il codice di test viene duplicato e non correttamente estratto in funzioni, altri lo duplicheranno. Qualcuno si preoccuperà di scrivere un'API facile da usare e da leggere per migliorare la qualità della vita? Nella mia esperienza, no, c'è spesso qualcosa che la gente considera la materia più pressante fino a quando non sfugge di mano.
  5. La duplicazione del codice è più difficile da leggere perché rende il codice dettagliato dove non deve essere, in luoghi in cui la verbosità non aggiunge informazioni sulla funzionalità prevista: ad esempio chiamate di metodi generici che vengono utilizzate [ripetutamente] per gettare le basi per molteplici tipi di funzionalità prevista, rende più difficile la comparsa di questa funzionalità effettiva.
  6. Questo è stato menzionato molto. Se il codice è sbagliato, qualche ragazza o ragazzo povero dovrà cercare e cambiare ogni uso di quel codice. Ad esempio, se qualcuno utilizzava una chiamata non sicura di SQL injection a mysql_query in pochissimi posti in una classe organizzata in cui è necessario, sarebbe facile ripararlo e utilizzare PHP PDO invece, ma se lo utilizzava in più di mille posti copiando la chiamata su e oltre, risolverlo sarà praticamente necessario esternalizzare o talvolta più pericolosamente, il codice dovrà essere riscritto da zero.
  7. La duplicazione del codice è una cattiva abitudine. Se pratichi qualcosa, questa diventa lentamente una seconda natura e colpisce le persone intorno a te. Gli sviluppatori junior ti vedono farlo e lo fanno anche. Dovresti mettere in pratica ciò che predichi e prendere l'abitudine di fare la cosa giusta. Impari di più. Scrivere codice non duplicato è più difficile e impegnativo. È un'abitudine gratificante.

Ultime note sulla prevenzione della duplicazione del codice troppo zelante e sulla sintesi delle cose:

Questo è già stato detto prima, ma a volte evitare la duplicazione ti fa "piegare all'indietro" e fare cose che sono troppo sofisticate (o non importanti) per essere capite dagli altri. Scrivere codice illeggibile (o come lo chiamiamo scherzosamente codice di "conservazione del lavoro") è un problema in sé anche quando non è coinvolta la prevenzione della duplicazione del codice. Tuttavia, trovo che se l'infrastruttura e le migliori pratiche giuste vengono instillate dall'inizio, è molto più facile prevenire la duplicazione del codice e le persone spesso possono evitare di fare cose non intuitive in modo da prevenire futuri cumuli di lavoro inutili e illeggibili svolti per la prevenzione della duplicazione del codice se fai le cose fin dall'inizio.

Cosa sta facendo le cose nel modo giusto? Bene, questa è una domanda difficile a cui rispondere, ma una cosa è definire quali metodi sono necessari per il progetto e vedere cosa è già stato implementato da altri (all'esterno e) all'interno dell'azienda e riutilizzarlo quando possibile; documentando tutto ciò che fai aggiungi alla base di codice e provando a renderlo di un livello più generico di quanto non sia, ma il gioco è fatto. Non esagerare con i modelli di progettazione solo per rendere flessibile il codice dove non è necessario.

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.