Ci sono casi eccezionali in cui possiamo accettare codice duplicato?


57

Sto lavorando a un progetto software in cui dobbiamo costruire tre API. Uno per il canale di home banking, uno per il canale dell'agenzia e un terzo per il canale mobile .

L'API dell'agenzia è la più completa in quanto ha tutte le funzionalità .. quindi un'API Home un po 'più piccola e quindi un'API mobile.

Gli architetti qui hanno creato un livello comune (servizi EJB cross channel condivisi da tutte le API). Ma poi le API sono diverse.

Per ora non ci sono grandi differenze tra le API. Il grande team ha iniziato con il canale dell'agenzia e ora lo stiamo adattando per il canale principale. Stiamo solo arricchendo oggetti appositamente per la nostra app domestica. In caso contrario, il codice è simile al 95% tra le API. Le API si basano su Spring MVC e dispongono di (controller, modelli e alcune utility).

Fondamentalmente i controller stanno eseguendo la mappatura di BO su ChannelObject (non mi sembra il posto giusto per farlo) e alcune utility e serializzatori extra. Tutto è duplicato per ora. Stanno dicendo che il motivo della duplicazione è che vogliono che le API siano indipendenti. "Se domani vogliamo un comportamento diverso per la casa rispetto all'agenzia o al cellulare non faremo fatica !!"

C'è un caso in cui dovremmo accettare un codice duplicato?


22
E se tre passaggi lungo la strada decidono di desiderare un accesso e una rappresentazione dei dati coerenti tra tutte le API ... beh ... "Lotta!"
Becuzz,

26
Il codice duplicato non è necessariamente una cosa negativa. Il detto "DRY è il nemico del disaccoppiamento" non può essere enfatizzato abbastanza. Avendo detto che, progettare per il futuro, piuttosto che per ora, è davvero una brutta cosa. Quel futuro non passa quasi mai. Invece, progetta una soluzione altamente disaccoppiata, coperta da buoni test automatizzati per ciò che è necessario ora. Quindi, in futuro, se è necessario qualcosa di diverso, sarà più facile cambiare.
David Arno,

2
Penso che i due casi in cui non mi sono mai pentito di duplicare il codice siano (a) in cui il codice duplicato è una parte molto piccola e non molto importante del totale, e (b) in cui sto copiando il codice da un sistema che sta già morendo in un nuovo sistema progettato per la longevità. Ci sono molti altri casi in cui ho pianto lacrime amare dopo aver biforcuto il codice.
Michael Kay,

14
Dove ho lavorato, è stato spesso notato che si dovrebbe (spesso) duplicare una volta e astrarre la comunanza la terza volta. Questo rimuove lo zeitgeist per l'astrazione precoce, forse inappropriata, che aumenta l'accoppiamento invece della coesione. Quando i requisiti futuri sono effettivamente ben compresi, si possono ovviamente fare eccezioni.
Pieter Geerkens,

3
Un caso banale in cui il codice duplicato può essere accettabile è se viene generato automaticamente
samgak

Risposte:


70

La duplicazione può essere la cosa giusta da fare, ma non per questo motivo.

Dire "potremmo desiderare che questi tre posti nella base di codice si comportino diversamente anche se in questo momento, sono identici" non è una buona ragione per la duplicazione su larga scala. Questa nozione potrebbe applicarsi a tutti i sistemi e potrebbe essere usata per giustificare qualsiasi duplicazione, il che ovviamente non è ragionevole.

La duplicazione dovrebbe essere tollerata solo quando rimuoverla sarebbe complessivamente più costosa ora per qualche altro motivo (non riesco a pensare a una buona in questo momento, ma assicurati che ce ne può essere una - praticamente tutto nella programmazione è un compromesso piuttosto che un legge).

Per quello che stai facendo, la soluzione giusta potrebbe essere ad esempio estrarre il comportamento che è duplicato proprio ora in una strategia o in qualche altro modello che modella il comportamento come classi e quindi utilizzare tre istanze della stessa classe. In questo modo, quando si fa desidera modificare il comportamento in uno dei tre posti, è sufficiente creare una nuova strategia e creare un'istanza che in un unico luogo. In questo modo devi solo aggiungere alcune classi e lasciare il resto della base di codice quasi completamente intatto.


1
Se due cose si comportano allo stesso modo, questa è duplicazione. Sebbene a meno che non si comportino allo stesso modo per un motivo, non dovrebbero essere uniti. Si può estrarre una parte comune delle implementazioni? A volte ci sono blocchi non ancora astratti, chissà.
Deduplicatore

32
Ad esempio, avevamo un pezzo di codice usato da tre parti della nostra applicazione, ed era abbastanza terribilmente scritto con molti piccoli rami condizionali ovunque per coprire le eccezioni per ognuno di quei tre. Ma , e questa era la parte importante, era stata ampiamente utilizzata per due anni senza segnalazioni di bug significative di alcun tipo. Quindi, quando una quarta parte dell'applicazione aveva bisogno di farci qualcosa, ma di nuovo leggermente diversa, è stata presa la decisione di non toccare semplicemente il codice difettoso che correva in modo impeccabile e di copiarlo e creare una base flessibile e meglio scritta per il futuro.
KRyan,

2
La duplicazione è la cosa giusta da fare quando i costi di leggibilità aumentano troppo rispetto ai costi di manutenzione che finiscono per essere legati insieme. Non penso che ciò si applichi affatto in questo scenario, ed è spesso visto su scala ridotta in un progetto, non qualcosa del genere. Anche allora è molto raro che ti trovi in ​​una situazione in cui questo è sempre il caso, accadrà se hai qualche duplicazione nidificata di nicchia che ti costringerebbe ad usare il modello del metodo del modello o simili ma in piccoli luoghi. Questo in genere finirà per offuscare il codice.
opa,

Un esempio in cui la duplicazione è utile (e "rimuoverla potrebbe essere complessivamente più costosa ora ") è l'input valdation nelle applicazioni web: Utilizziamo una prima convalida (possibilmente semplificata) sul client in modo che l'utente riceva un feedback immediato sui problemi; e quindi eseguiamo la stessa (o più approfondita) convalida sul server perché i client non possono essere considerati affidabili.
Hagen von Eitzen,

3
@HagenvonEitzen Ma questa non deve nemmeno essere una duplicazione, a seconda dello stack tecnologico. Ad esempio, potresti avere l'immissione del controllo JavaScript nel browser e quindi il controllo Java sul server, quindi hai una funzionalità duplicata. Ma se dovessi eseguire Node.js sul server, potresti utilizzare la stessa convalida JavaScript nel browser e sul server, eliminando la duplicazione. Si desidera comunque che il codice venga eseguito in più posizioni (un ambiente attendibile e non attendibile), ma non è necessario duplicare il codice .
Joshua Taylor,

87

Sandi Metz, un rinomato ingegnere informatico e autore nell'ecosistema Ruby, ha un ottimo post sul blog e un discorso in cui parla anche del rapporto tra duplicazione e astrazione. Arriva alla seguente conclusione

la duplicazione è molto più economica dell'astrazione sbagliata

E sono completamente d'accordo con lei. Lascia che ti dia più contesto a questa citazione. A volte trovare l'astrazione giusta è molto difficile. In questi casi, si è tentati di cercare qualsiasi astrazione per ridurre la duplicazione. Ma più tardi potresti scoprire che la tua astrazione non vale per tutti i casi. Tuttavia, è costoso cambiare di nuovo tutto e seguire una strada diversa (per una spiegazione molto migliore guardala parlare!).

Quindi sì, per me ci sono casi eccezionali, in cui accettare la duplicazione è la decisione giusta, soprattutto quando non si è sicuri di ciò che verrà e i requisiti potrebbero cambiare. Dal tuo post prendo che ci sono molte duplicazioni ora, ma i tuoi colleghi suggeriscono che questo potrebbe cambiare e non accoppiare entrambe le domande. Secondo me questo è un argomento valido e non può essere ignorato in generale.


23
Ah sì, se non riesci a dedurre le regole generalizzate, provare ad astrarle non può che fallire. E se la corrispondenza è una coincidenza, potrebbe essere di breve durata.
Deduplicatore

5
Può essere costoso cambiare un'astrazione una volta che è in atto, ma liberarsi della duplicazione una volta che è in atto può essere ancora più problematico. Ovviamente questo dipende molto dalla lingua, ecc. - I moderni sistemi di tipo statico possono fare un buon lavoro nell'aiutarti ad apportare modifiche anche su larga scala a qualche astrazione giusta. Mantenere le funzionalità duplicate sincronizzate, tuttavia, non è qualcosa in cui un sistema di tipi può aiutarti molto (perché i duplicati sono, per il sistema di tipi , solo diversi). Ma suppongo che in linguaggi dinamici e tipicamente anatra sia piuttosto il contrario; quindi potrebbe avere senso per Ruby.
lasciato circa il

34

Se le persone iniziano a ragionare sul design con le parole "se domani" , questo è spesso un grande segnale di avvertimento per me, soprattutto quando l'argomento viene utilizzato per giustificare una decisione che include un lavoro e uno sforzo extra, per i quali nessuno sa davvero se questo mai pagare, e che è più difficile cambiare o ripristinare rispetto alla decisione opposta.

La duplicazione del codice riduce lo sforzo solo per un breve periodo, ma aumenterà gli sforzi di manutenzione quasi immediatamente, proporzionalmente al numero di righe duplicate di codice. Si noti inoltre che una volta duplicato il codice, sarà difficile rimuovere la duplicazione quando si scopre che questa è stata la decisione sbagliata, mentre se non si duplica il codice ora, è comunque facile introdurre la duplicazione in seguito se risulta attaccare a SECCO è stata una decisione sbagliata.

Ha affermato che, nelle organizzazioni più grandi, a volte è utile favorire l'indipendenza di team diversi rispetto al principio DRY. Se rimuovendo la duplicazione estraendo due parti comuni del 95% delle API, un nuovo componente porta a un accoppiamento di due team altrimenti indipendenti, questa potrebbe non essere la decisione più saggia. D'altra parte, se hai risorse limitate e ci sarà un solo team a mantenere entrambe le API, sono sicuro che sarà nel loro interesse non creare alcun doppio sforzo ed evitare inutili duplicazioni del codice.

Nota inoltre che fa la differenza se le API "Home" e "Agency" sono utilizzate esclusivamente da applicazioni completamente diverse o se si potrebbe provare a scrivere un componente costruito sopra quelle API che possono essere utilizzate anche in un contesto "Home" come in un contesto di "agenzia". Per questa situazione, avendo le parti comuni delle API esattamente identiche (cosa che si può garantire solo se le parti comuni non sono duplicate), probabilmente lo sviluppo di tale componente sarà probabilmente molto più semplice.

Quindi, se si scopre che ci saranno sottogruppi davvero diversi, ognuno responsabile di ciascuna delle API, ognuno con una pianificazione e risorse diverse, allora è tempo di duplicare il codice, ma non "per ogni evenienza".


3
Anche un segnale di avvertimento più grande di "se domani" per me è "Non cambierebbe mai".
abuzittin gillifirca,

@abuzittingillifirca: e cosa c'entra questo con la domanda o la mia risposta?
Doc Brown,

1
Sto sfidando il tuo primo paragrafo.
abuzittin gillifirca,

2
@abuzittingillifirca: beh, leggi di nuovo la domanda: si tratta di ragionare con un argomento "se domani" per giustificare una decisione di duplicazione che è difficile da annullare , rendendo così il software effettivamente più difficile da cambiare in alcuni casi. Potrebbe essere un po 'controintuitivo, ma il modo migliore per mantenere il software modificabile per il futuro non è fare ipotesi (probabilmente sbagliate) sul futuro, ma mantenere il software il più piccolo e SOLIDO possibile.
Doc Brown,

13

Duplicazione per impedire l'accoppiamento . Diciamo che hai due grandi sistemi e li costringi ad usare la stessa libreria. È possibile che si stia associando il ciclo di rilascio di entrambi i sistemi. Questo potrebbe non essere così male, ma diciamo che un sistema deve introdurre un cambiamento. L'altro deve analizzare il cambiamento e potrebbe essere interessato. A volte può rompere le cose. Anche se entrambe le parti sono in grado di coordinare i cambiamenti, potrebbero esserci molte riunioni, passando per manager, test, dipendenze e la fine del piccolo team autonomo.

Quindi stai pagando il prezzo di un codice duplicato per ottenere autonomia e indipendenza.


Quindi questa è una duplicazione tra i componenti per evitare l'accoppiamento. Ma vorresti comunque evitare la duplicazione intra-componente, giusto?
TemplateRex

Bene, sì, vuoi minimizzare il codice duplicato in quanto renderà il tuo codice più facile da capire e modificare. Ma ricorda che ci sono buone risposte con eccezioni praticabili. L'astrazione giusta per evitare la duplicazione può essere difficile da trovare.
Borjab,
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.