2009-06-15 10 views
7

Qual è la procedura migliore per riutilizzare il codice rispetto a copia/incolla?Riutilizzo e refactoring del codice

Il problema con il riutilizzo può essere dovuto al fatto che la modifica del codice riutilizzato influirà su molti altri aspetti della funzionalità.

Questo è buono & cattivo: buono se la modifica è una correzione di errore o un miglioramento utile. Cattivo se un altro codice di riutilizzo si rompe inaspettatamente perché si è basato sulla vecchia versione (o la nuova versione ha un bug).

In alcuni casi sembra che la copia/incolla sia migliore - ogni utente del codice incollato ha una copia privata che può personalizzare senza conseguenze.

Esiste una best practice per questo problema; il riutilizzo richiede test delle unità stagne?

risposta

2

Quindi il codice utente (riutilizzatore) dipende dal codice riutilizzato, giusto.

È necessario gestire questa dipendenza.

E 'vero per il riutilizzo binario (ad es. Una dll) e il riutilizzo del codice (ad es. Una libreria di script) pure.

  • consumatore dovrebbe dipendere da un certo (noto) versione del codice/binario riutilizzato .

  • dei consumatori dovrebbe mantenere una copia del codice/binario riutilizzato, ma mai direttamente modificarlo, solo aggiornamento ad una nuova versione quando è sicuro.

  • Pensare attentamente quando si modifica la base di codici in attesa. Ramo per la rottura delle modifiche.

  • se un consumatore vuole aggiornare il codice/binario riutilizzato allora deve prima prova per vedere se è sicuro. Se i test falliscono, il consumatore può sempre ricorrere all'ultima versione nota (e mantenuta) valida.

In questo modo è possibile trarre vantaggio dal riutilizzo (ad esempio, è necessario correggere un bug in un unico punto) e si è ancora in grado di controllare le modifiche. Ma nulla ti salva dal test ogni volta che aggiorni il codice/binario riutilizzato.

11

Ogni riga di codice ha un costo.

Studies mostra che il costo non è lineare con il numero di righe di codice, è esponenziale.

La copia/incolla di programmazione è il modo più costoso per riutilizzare il software.

"il riutilizzo richiede test delle unità stagne?"

No.

Tutto il codice richiede test di unità adeguati. Tutto il codice è un candidato per il riutilizzo.

+0

+1 per la leggibilità e l'annotazione sul costo del codice. – cgp

+0

-1 per abuso grave di "esponenziale". In realtà non è nemmeno quadratico. –

+2

COCOMO mi sembra esponenziale: effort = 2.5 Ksloc ** 1.05. Non è esponenziale? –

1

Dovresti scrivere test di unità, e mentre sì, avere codice clonato può in un certo senso dare la sensazione che il tuo cambiamento non stia effettuando un gran numero di altre routine, probabilmente è un falso senso di sicurezza . Fondamentalmente, il tuo senso di sicurezza deriva dall'ignoranza di sapere come viene usato il codice. (l'ignoranza qui non è peggiorativa, viene solo dal fatto di non essere in grado di sapere tutto sulla base di codice) abituarsi a usare l'IDE per sapere dove viene utilizzato il codice e abituarsi a leggere il codice per sapere come è in uso.

2

Copia e incolla non è mai una buona pratica. A volte potrebbe sembrare meglio come una soluzione a breve termine, in un piuttosto scarsa base di codice, ma in una base di codice ben progettato si avrà il seguente offrendo un facile riutilizzo:

  • incapsulamento
  • interfacce ben definite
  • accoppiamento libero tra oggetti (poche dipendenze)

Se il codice di base mostra queste proprietà, la copia e incollatura non sarà mai l'opzione migliore. E come dice S Lott, c'è un enorme costo per aumentare inutilmente la dimensione del codice base.

3

Mi sembra che un pezzo di codice che viene utilizzato in più punti che ha il potenziale di cambiare per un posto e non per un altro luogo non segue le corrette regole di scopo. Se lo "stesso" metodo/classe è necessario da due cose diverse per fare due diverse funzioni, allora quel metodo/classe dovrebbe essere diviso.

Non copiare/incollare. Se risulta che è necessario modificare il codice per un posto, è possibile estenderlo, possibilmente attraverso l'ereditarietà, l'overloading o se è necessario, copiare e incollare. Ma non iniziare con il copia-incolla di segmenti simili.

3

L'utilizzo di copia e incolla è quasi sempre una cattiva idea. Come hai detto, puoi fare dei test per verificare se rompi qualcosa.

Il punto è che quando si chiama un metodo, non ci si deve preoccupare di come funziona, ma di cosa fa. Se modifichi il metodo, cambiando ciò che fa, allora dovrebbe essere un nuovo metodo, o dovresti controllare ovunque venga chiamato questo metodo.

Dall'altro lato, se la modifica non modifica COSA il metodo (solo come), quindi non si dovrebbe avere un problema altrove. Se lo fai, hai fatto qualcosa di sbagliato ...

2

Esiste una best practice per questo problema ; riutilizzo richiede prove di tenuta stagne ?

Sì e una sorta di sì. Riscrivere il codice che hai già fatto bene una volta non è mai una buona idea. Se non riutilizzi mai il codice e lo riscrivi semplicemente, stai raddoppiando la tua superficie. Come per molte domande sul tipo di pratica migliore, lo Code Complete ha cambiato il mio modo di lavorare. Sì test delle unità al meglio delle tue possibilità, sì riusare il codice e ottenere una copia di Code Complete e sarai tutto pronto.

1

Dove si scrive:

Il problema con il riutilizzo può essere che cambiare il codice riutilizzato influenzerà molti altri pezzi di funzionalità. ... In alcuni casi sembrerebbe che copia/incolla sia migliore - ogni utente di il codice incollato ha una copia privata che può personalizzare senza conseguenze .

Penso che tu abbia invertito le preoccupazioni relative al copia-incolla. Se copi il codice in 10 posizioni e poi devi apportare una leggera modifica al comportamento, ti ricorderai di cambiarlo in tutti e 10 i posti?

Ho lavorato su un numero purtroppo elevato di codebase grandi e sciatte e in genere quello che vedrete sono i risultati di questo - 20 versioni delle stesse 4 righe di codice. Alcuni (in genere piccoli) sottoinsiemi hanno 1 piccolo cambiamento, altri piccoli (e solo parzialmente intersecanti sottoinsieme) hanno qualche altro piccolo cambiamento, non perché le variazioni siano corrette ma perché il codice è stato copiato e incollato 20 volte e le modifiche sono state applicate quasi , ma non abbastanza coerentemente.

Quando arriva a quel punto è quasi impossibile dire quali di queste variazioni ci sono per un motivo e che ci sono a causa di un errore (e poiché è più spesso un errore di omissione - dimenticando di applicare una patch piuttosto che alterare qualcosa - non è probabile che vi siano prove o commenti).

Se è necessaria una funzionalità diversa, chiamare una funzione diversa. Se hai bisogno della stessa funzionalità, ti preghiamo di evitare copia incolla per la sanità mentale di chi ti seguirà.

1

Ci sono metriche che possono essere utilizzate per misurare il codice, e spetta a voi (o al vostro team di sviluppo) decidere su una soglia adeguata. Ruby on Rails ha la gemma "Metric-Fu", che incorpora molti strumenti che possono aiutarti a rifattare il tuo codice e mantenerlo in ottima forma.

Non sono sicuro quali strumenti siano disponibili per altri tipi di laguna, ma credo che ce ne sia uno per .NET.

2

Copia/Incolla porta a funzionalità divergenti. Il codice può iniziare nello stesso modo ma nel tempo, le modifiche in una copia non si riflettono su tutte le altre copie dove dovrebbe.

Inoltre, copia/incolla può sembrare "OK" in casi molto semplici, ma inizia anche mettere i programmatori in una mentalità in cui copia/incolla va bene. Questo è il "pendio scivoloso". I programmatori iniziano a utilizzare copia/incolla quando il refactoring dovrebbe essere l'approccio giusto. Devi sempre stare attento a stabilire un precedente e quali segnali inviare ai futuri sviluppatori.

C'è anche una citazione su questo da qualcuno con più esperienza di me,

"Se si usa il copia e incolla, mentre si sta codifica, probabilmente stai commettendo un errore di progettazione."
-- David Parnas

2

Un uso molto appropriato di copia e incolla è Triangulation. Scrivi il codice per un caso, vedi una seconda applicazione che ha qualche variazione, copia & incolla nel nuovo contesto - ma non hai finito. È il caso in cui tu, , fermi il a quel punto in cui ti trovi nei guai. Avere questo codice duplicato, magari con una variazione minore, espone alcune funzionalità comuni richieste dal codice. Una volta che è in entrambi i posti, testato e funzionante in entrambi i luoghi, dovresti estrarre quella comunanza in un unico posto, chiamarla dai due posti originali e (ovviamente) ripetere il test.

Se hai dubbi che il codice che viene chiamato da più punti sta introducendo il rischio di fragilità, le funzioni non sono probabilmente sufficienti a grana fine. Funzioni troppo grossolane, funzioni che fanno troppo, sono difficili da riutilizzare, difficili da nominare, difficili da debugare. Trova i bit atomici di funzionalità, assegna loro un nome e riutilizzali.

+0

Non penso che questo valga davvero come copia e incolla, dal momento che l'intero punto dell'esercizio è di non avere il codice duplicato. Tuttavia, ho usato questa tecnica in passato e talvolta può essere utile quando si cerca di capire un algoritmo difficile. – Dolphin

0

In generale, copia e incolla è una cattiva idea. Tuttavia, come qualsiasi regola, questo ha delle eccezioni. Dal momento che le eccezioni sono meno ben noti che la regola sarò in evidenza ciò che secondo me sono alcuni tra quelli importanti:

  1. Si dispone di un design molto semplice per qualcosa che non si vuole fare più complicato con modelli di progettazione e Roba OO. Hai due o tre casi che variano in circa un miliardo di modi sottili, cioè una linea qui, una linea lì. Sapete dalla natura del problema che probabilmente non avrete mai più di 2 o 3 casi. A volte può essere il minore dei due mali da tagliare e incollare piuttosto che ingannare la cosa per risolvere un problema relativamente semplice come questo. Il volume del codice ha i suoi costi, ma lo stesso vale per la complessità concettuale.

  2. avete un po 'di codice che è molto simile per ora, ma il progetto è in rapida evoluzione e si prevede che le due istanze saranno divergere in modo significativo nel corso del tempo, fino al punto in cui si cerca di individuare anche ragionevolmente grandi, pezzi factorable di funzionalità che rimarranno comuni, e tanto meno il loro refactoring in componenti riutilizzabili, sarebbero più problemi di quanti ne valga la pena. Questo si applica quando ritieni che la probabilità di un cambiamento divergente in un'istanza sia molto maggiore di quella di un cambiamento di funzionalità comune.

+0

per 1 è sempre possibile utilizzare macro. Il preprocessore potrebbe fare l'equivalente del lavoro C & P, ma nell'origine c'è ancora solo una versione. Per quanto riguarda il # 2, dovrei certamente mettere in discussione il design. Se il tuo progetto si sta "evolvendo" così velocemente, probabilmente dovrai fare qualche altro ragionamento su cosa esattamente stai cercando di fare. – Dolphin

+0

Per il # 1, se ti riferisci al preprocessore C, questa è una soluzione estremamente complicata. Se ti riferisci a uno di terze parti, è un altro strumento nella toolchain e potrebbe aggiungere più complessità rispetto a C & P. Per il n. 2 scrivo codice di ricerca e per me questo accade sempre perché determiniamo cosa vogliamo fare ad ogni iterazione in base ai risultati delle precedenti iterazioni. Non vale la pena di dedicare troppo impegno al buon design quando le cose stanno cambiando troppo velocemente e in un modo troppo imprevedibile. – dsimcha