Come evitare la duplicazione del codice o le modifiche in cascata e il principale refactoring nel livello della business logic?

2

Diciamo che ho creato un servizio di livello di logica aziendale (o un gestore nel modello Comando / Query) con un metodo DoSomething che elabora un gruppo di entità e le memorizza nel database.

Più tardi, un altro sviluppatore vede: "oh, questo metodo DoSomething fa quasi tutto ciò di cui ho bisogno, posso chiamarlo dal mio metodo DoThisSomethingAndMore ." Sembra la cosa giusta da fare per evitare di copiare il codice da DoSomething a DoThisSomethingAndMore . I test unitari passano, tutto è OK.

Quindi arriva un nuovo requisito aziendale per modificare l'operazione DoSomething . Quindi, cambio il codice di DoSomething , e quindi DoThisSomethingAndMore si rompe.

Se abbiamo buoni test, possiamo rilevarlo presto. Ma come risolvere il problema? Crea DoThisSomethingAndMore per non chiamare DoSomething e copia-incolla il codice, invece? Refactor DoSomething in pezzi che possono essere riutilizzati sia da DoSomething sia da DoThisSomethingAndMore ? Potrebbe trattarsi di una notevole quantità di lavoro, coinvolgendo tutti gli sviluppatori che chiamano DoSomething dal loro codice e si collegano a un numero ancora maggiore di codice che chiama altri metodi. Inoltre, questo potrebbe portare a una serie di metodi pubblici ( DoPart1OfSomething , DoPart2OfSomething ...) sulla classe di servizio del livello aziendale, quando questi metodi dovrebbero essere interni perché non eseguono effettivamente una singola operazione di business atomico ma solo una parte di esso.

Si tratta di un problema di programmazione comune e dovrebbe sempre essere risolto tramite refactoring o significa che dovremmo optare per il completo servizio aziendale e il disaccoppiamento delle operazioni, accettando che ciò comporterà una duplicazione del codice?

La voce interiore dice: rendere ogni sviluppatore responsabile solo del proprio codice nei metodi commerciali che ha creato e non chiamare i metodi degli altri quando si sa che, molto probabilmente, cambieranno la loro implementazione interna. Ciò sembra ragionevole considerando che il progetto è stato sviluppato da una società di startup con alcuni sviluppatori non esperti che trarrebbero vantaggio da una chiara "regola empirica" fin dall'inizio, invece di investigare ogni chiamata di metodo separatamente, e anche considerando che i requisiti aziendali stanno cambiando spesso durante le prime fasi di sviluppo.

E poi c'è un'altra voce interiore "hey, non duplicare il codice, riutilizzare il codice è una delle migliori pratiche".

Quindi, mentre mi piacerebbe andare con la singola responsabilità con l'approccio alla duplicazione del codice, non riesco a trovare una scusa ragionevole o solide basi per questo. C'è qualche? Sarebbe bello avere un riferimento ad alcune fonti attendibili (ad es. "La banda dei quattro") dicendo in quali casi la duplicazione del codice è generalmente accettabile.

    
posta JustAMartin 06.07.2016 - 13:04
fonte

2 risposte

2

Se qualcuno sta per cambiare un metodo che è riutilizzato da qualche parte nella base di codice, dovrebbe essere responsabile di fare un'analisi di impatto prima. Quindi un dev che inizia a implementare una modifica in DoSomething dovrebbe verificare in anticipo da dove viene chiamato questo metodo. Pertanto, supponiamo che tu abbia già scoperto che DoThisSomethingAndMore non funzionerà più correttamente quando eseguirai la modifica in modo ingannevole.

Per risolvere il problema, ci sono diverse possibilità. Il modo sbagliato è duplicare il codice di implementazione di DoSomething . Refactoring DoSomething in pezzi che possono essere riutilizzati da entrambi i metodi è un'opzione praticabile. Se questo è "una quantità notevole di lavoro", questo è probabilmente un segno che il metodo è già troppo grande e troppo complicato, e quanto prima inizi a rifattorizzare in blocchi più piccoli, tanto meglio.

Se ci sono molti posti in cui DoSomething è stato utilizzato per tutto il codice, e il vecchio comportamento dovrebbe essere mantenuto nella maggior parte dei luoghi in cui si è verificato il riutilizzo, l'altra opzione è assicurarsi che DoSomething non sia cambia il suo comportamento e implementa il nuovo requisito in un nuovo metodo DoSomethingNew . Refactoring DoSomething in pezzi che possono essere riutilizzati da DoSomething e DoSomethingNew dovrebbe essere la strada da percorrere, ma ora è un vero refactoring, perché non cambia il comportamento di DoSomething , e nessuno dei metodi usare questo metodo deve essere cambiato.

    
risposta data 06.07.2016 - 16:31
fonte
0

IMO Vorrei duplicare il codice, apportare le modifiche necessarie e quindi refactator, purché la duplicazione resti. A volte, devi fare un casino prima di poter iniziare a ripulire.

Ma sono d'accordo con il commento di Kilian Foth . C'è qualcosa di molto più profondo qui. Il problema è che se questo caso accade, allora DoSomething non era un buon metodo int al primo posto. Non rappresentava la singola responsabilità reale che avrebbe dovuto fare. Ad esempio, se avesse 2 responsabilità, passare a una di quelle responsabilità potrebbe rompere il codice che usa anche l'altra responsabilità ma non vuole cambiare il primo. Quindi dovrebbe essere in realtà due metodi diversi. E il mio suggerimento di cui sopra si tradurrebbe in questo diventando ovvio.

    
risposta data 07.07.2016 - 08:26
fonte

Leggi altre domande sui tag