Violazione del principio DRY


10

Sono sicuro che ci sia un nome per questo anti-pattern da qualche parte; tuttavia non ho abbastanza familiarità con la letteratura anti-pattern per saperlo.

Considera il seguente scenario:

or0è una funzione membro in una classe. Nel bene e nel male, dipende fortemente dalle variabili dei membri della classe. Il programmatore A arriva e necessita di funzionalità come or0ma piuttosto che chiamare or0, il programmatore A copia e rinomina l'intera classe. Immagino che non chiami or0perché, come ho detto, dipende fortemente dalle variabili membro per la sua funzionalità. O forse è una programmatrice junior e non sa come chiamarla da un altro codice. Quindi ora abbiamo or0e c0(c per copia). Non posso criticare completamente il programmatore A per questo approccio: siamo tutti sotto scadenze strette e hackeriamo il codice per completare il lavoro.

Diversi programmatori mantengono or0quindi è ora la versione orN. c0è ora la versione cN. Sfortunatamente la maggior parte dei programmatori che hanno mantenuto la classe contenente or0sembravano completamente inconsapevoli di c0- qual è uno degli argomenti più forti a cui posso pensare per la saggezza del principio DRY. E potrebbe anche esserci stata una manutenzione indipendente del codice in c. Ad ogni modo sembra che or0e c0sono stati mantenuti indipendenti l'uno dall'altro. E, gioia e felicità, si sta verificando un errore in cNcui non si verifica orN.

Quindi ho alcune domande:

1.) C'è un nome per questo anti-pattern? L'ho visto accadere così spesso che troverei difficile credere che questo non sia un anti-modello chiamato.

2.) Vedo alcune alternative:

a.) Risolto orNil problema per prendere un parametro che specifica i valori di tutte le variabili membro di cui ha bisogno. Quindi modificare cNper chiamare orNcon tutti i parametri necessari passati.

b.) Prova a trasferire manualmente le correzioni da orNa cN. (Intendiamoci, non voglio farlo, ma è una possibilità realistica.)

c.) Ricopia orNper: cNnuovamente, schifo ma lo elencherò per completezza.

d.) Prova a capire dove cNè rotto e poi riparalo indipendentemente da orN.

L'alternativa a sembra la migliore soluzione a lungo termine ma dubito che il cliente mi lascerà implementare. Mai tempo o denaro per sistemare le cose nel modo giusto, ma sempre tempo e denaro per riparare lo stesso problema 40 o 50 volte, giusto?

Qualcuno può suggerire altri approcci che potrei non aver preso in considerazione?


"C'è un nome per questo anti-pattern?" L'anti-pattern "violento-secco"? :) IMHO, hai praticamente risposto tu stesso.
Steven Jeuris,

Forse chiamarlo "The Dry Violator"?
FrustratedWithFormsDesigner,

2
Lo chiamo: urtare a secco.
AJC,

5
Copia e incolla la codifica?
Tylermac,

Si chiama il modello "troppi cuochi rovinano il brodo".
Doc Brown,

Risposte:


18
  1. si chiama semplicemente codice duplicato - non conosco altri nomi fantasiosi per questo. Le conseguenze a lungo termine sono come hai descritto e peggio.

  2. Naturalmente, eliminare la duplicazione è l'opzione ideale se possibile. Potrebbe volerci molto tempo (in un recente caso nel nostro progetto legacy, ho avuto diversi metodi duplicati in più di 20 sottoclassi in una gerarchia di classi, molti dei quali hanno evoluto progressivamente le loro lievi differenze / estensioni nel corso degli anni. me circa 1,5 anni attraverso successive prove unitarie di scrittura e refactoring per sbarazzarsi di tutte le duplicazioni. Ma la perseveranza ne è valsa la pena).

    In tal caso, potresti aver ancora bisogno di una o più delle altre opzioni come correzioni temporanee, anche se decidi di iniziare a eliminare la duplicazione. Tuttavia, quale di questi è meglio dipende da molti fattori e senza più contesto stiamo solo indovinando.

    Molti piccoli miglioramenti possono fare la differenza nel lungo periodo. Non è necessariamente necessaria l'approvazione esplicita da parte del cliente per questi: un piccolo refactoring ogni volta che tocchi detta classe per correggere un bug o implementare una funzionalità può andare molto nel tempo. Includere solo un po 'di tempo extra per il refactoring nelle stime delle attività. È proprio come la manutenzione standard mantenere il software in salute a lungo termine.


3
+1, se non solo per la menzione di un codice duplicato, ma anche per il semplice sforzo di raccontare il refactoring del codice. : D
Andreas Johansson,

9

C'è un riferimento al modello WET (We Enjoy Typing) ma non so se sia un nome standard.

... Le licenze software sono una notevole eccezione alla pratica DRY (Don't Repeat Yourself) - il codice delle licenze software dovrebbe essere il più possibile WET (We Enjoy Typing - il contrario di DRY).

Se si isola la logica della licenza in un posto, separato da altri problemi, si rende molto più semplice modificare il software per disabilitare del tutto la licenza. È molto meglio ripetere la logica delle licenze più volte in tutta l'applicazione, preferibilmente in modo che venga eseguita più volte durante una singola esecuzione del software.

Ad esempio, ti consigliamo di eseguire un controllo delle licenze durante l'installazione, durante l'avvio dell'applicazione e ogni volta che si accede a funzionalità importanti. Non controllare la licenza una volta durante l'avvio e passare quel valore in giro; invece, replicare effettivamente il controllo delle licenze in ogni area. È scomodo, ma molto meglio di rilasciare un prodotto che è facile da decifrare ...


3
WET può significare: Scrivi tutto due volte
StuperUser il

1
@StuperUser L'ho scoperto ieri sul dailywtf ...
jeremy-george

3

Se ti capisco bene, c'è troppo da fare in classe. Ciò crea metodi che non seguono il principio della responsabilità singola . Portando al codice che deve essere spostato, pezzi presi mentre altri lasciati fuori. Ciò potrebbe anche creare molti membri.

È inoltre necessario rivedere i modificatori dell'accessibilità. Garantire che le cose che sono pubbliche, dovrebbero in effetti essere pubbliche. Il consumatore non ha bisogno di sapere di ogni piccolo membro ... usa l'incapsulamento.

Ciò richiede un refattore. Sembra anche che il codice sia stato scritto senza un design iniziale. Guarda lo sviluppo Test Driven. Scrivi il codice come dovrebbe essere chiamato invece di chiamare il codice comunque sia implementato. Esamina il TDD per alcuni suggerimenti su come eseguire l'attività.


3

Se stai copiando il codice, presenterai un debito tecnico di doppia manutenzione o più specificamente: duplicazione del codice .

Di solito questo viene risolto tramite refactoring. Più specificamente reindirizzi tutte le chiamate a una nuova funzione (o a un nuovo metodo in una nuova classe) che ha il codice comune. Il modo più semplice per iniziare è rimuovere tutto il codice copiato e vedere cosa si rompe, in cui risolvi reindirizzando le chiamate al codice comune.

Far concordare al cliente il codice del refactor può essere difficile poiché è difficile convincere una persona non tecnica a riparare un debito tecnico. Quindi la prossima volta che fornisci delle stime del tempo, includi solo il tempo necessario per rifattorizzare le tue stime . Il più delle volte i clienti presumono che tu stia ripulendo il codice durante il tempo in cui esegui la correzione.


1

Mi sembra un codice spaghetti . La soluzione migliore è un refactor / rewrite.

un termine peggiorativo per codice sorgente che ha una struttura di controllo complessa e intricata, in particolare uno che utilizza molti GOTO, eccezioni, thread o altri costrutti di ramificazione "non strutturati". È chiamato così perché il flusso del programma è concettualmente simile a una scodella di spaghetti, cioè attorcigliato e aggrovigliato ...

http://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Spaghetti.jpg/175px-Spaghetti.jpg


-1 Refactor e riscrittura sono due opzioni molto diverse. Le riscritture totali, gettando via il software, non sono mai una buona idea. joelonsoftware.com/articles/fog0000000069.html
P.Brian.Mackey

1
Il codice spaghetti è l'IMO un termine molto più generale - e più allentato. Sebbene tale codice contenga spesso duplicazioni, è possibile avere il codice spaghetti senza alcuna duplicazione e anche altamente duplicato ma non il codice spaghetti.
Péter Török,

@ P.Brian.Mackey Non ho mai detto che Refactor e riscrittura fossero la stessa cosa. OP dovrebbe decidere quale utilizzare.
Tom Squires,

2
Non sono mai stato un fan di quell'articolo. Concordo sul fatto che la riscrittura sia stata una cattiva idea nell'esempio citato, ma solo perché è stata una cattiva idea in quel caso non significa che sia sempre una cattiva idea. Per cominciare, fare la riscrittura bloccherà altri progressi? Se è così, non va bene; in caso contrario, beh, non è poi così male.
jhocking,

@jhocking - Credo che il punto della politica di non riscrittura non sia quello di bloccare i progressi in altri programmi, piuttosto la perdita di correzioni reali nel tempo. Quel magico "if (goldenNugget> 22)", sebbene scarsamente chiamato, risolve ancora un problema specifico che potrebbe essere impossibile da identificare senza ore o giorni di ricerca. Ora, prendere gli stessi dati e migliorarli è quello che dovrebbe essere fatto invece. Questo è un refattore. Eliminarlo e dire "lo faremo la prossima volta" è una perdita di tempo. Lo stesso motivo per risolvere problemi già risolti è una perdita di tempo. L'aggiunta di un buon codice oltre al cattivo aumenta il debito
P.Brian.Mackey,

0

Dici che non puoi incolpare completamente A - ma copiare una classe in questo modo è davvero imperdonabile. È un grave errore nel processo di revisione del codice. È probabilmente l'errore più grave, senza alcuna revisione del codice.

Se hai mai pensato di dover produrre un codice terribile per rispettare una scadenza, la richiesta di massima priorità assoluta per il rilascio dopo dovrebbe essere quella di correggere il codice terribile ADESSO. Quindi il tuo problema è sparito.

Il principio DRY è per situazioni che non sono del tutto perfette e che possono essere migliorate. La duplicazione di una classe è un calibro completamente nuovo. Lo chiamerei prima "codice duplicato", e col tempo cambierà nel peggiore dei perditempo, "codice duplicato divergente": più copie dello stesso codice che sono quasi, ma non del tutto identiche, e nessuno sa se le differenze sono intese, coincidenze o bug.


-3

Quasi un decennio in ritardo a questa festa, ma il nome di questo anti-modello è Cambiamento divergente , in cui più classi includono copie dello stesso comportamento ma quando il tempo e il progresso della manutenzione e alcune classi vengono dimenticati, questi comportamenti divergono.

A seconda di ciò che è il comportamento condiviso e di come è condiviso, potrebbe invece essere chiamato Chirurgia Shotgun , con la differenza che qui una singola funzione logica è fornita da molte classi anziché da una singola.


1
Questa non sembra la stessa cosa. Il cambiamento divergente si verifica quando vengono apportati molti cambiamenti alla stessa classe. L'OP descrive la duplicazione del codice. Anche la chirurgia del fucile non è la stessa cosa. La chirurgia del fucile a pompa descrive la stessa modifica apportata a diverse classi diverse.
Robert Harvey,
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.