Programmazione copia e incolla - Copy-and-paste programming

La programmazione copia e incolla , a volte indicata come solo incolla , è la produzione di codice di programmazione per computer altamente ripetitivo , prodotto dalle operazioni di copia e incolla . È principalmente un termine peggiorativo; coloro che usano il termine spesso implicano una mancanza di competenza di programmazione. Può anche essere il risultato di limitazioni tecnologiche (ad esempio, un ambiente di sviluppo non sufficientemente espressivo) in quanto normalmente verrebbero utilizzate subroutine o librerie. Tuttavia, ci sono occasioni in cui la programmazione copia e incolla è considerata accettabile o necessaria, come per boilerplate , loop unrolling (quando non è supportata automaticamente dal compilatore) o alcuni idiomi di programmazione, ed è supportata da alcuni editor di codice sorgente in la forma degli snippet .

Origini

La programmazione copia e incolla viene spesso eseguita da programmatori inesperti o studenti, che trovano l'atto di scrivere codice da zero difficile o irritante e preferiscono cercare una soluzione pre-scritta o una soluzione parziale che possono utilizzare come base per il proprio problema risolvendo. (Vedi anche Cargo cult programming )

I programmatori inesperti che copiano il codice spesso non comprendono appieno il codice pre-scritto che stanno prendendo. In quanto tale, il problema nasce più dalla loro inesperienza e mancanza di coraggio nella programmazione che dall'atto di copiare e incollare, di per sé. Il codice spesso proviene da fonti disparate come il codice di amici o colleghi, forum Internet , codice fornito dai professori / assistenti tecnici dello studente o libri di testo di informatica . Il risultato rischia di essere uno scontro di stili sconnesso e può avere codice superfluo che affronta problemi per i quali non sono più necessarie nuove soluzioni.

Un ulteriore problema è che i bug possono essere facilmente introdotti da assunzioni e scelte di progettazione fatte nelle sorgenti separate che non si applicano più quando collocate in un nuovo ambiente.

Tale codice può anche, in effetti, essere offuscato involontariamente , poiché i nomi di variabili, classi, funzioni e simili sono tipicamente lasciati invariati, anche se il loro scopo può essere completamente diverso nel nuovo contesto.

La programmazione copia e incolla può anche essere il risultato di una scarsa comprensione delle caratteristiche comuni nei linguaggi dei computer, come le strutture di loop, le funzioni e le subroutine.

Duplicazione

Image
Codice ripetitivo sottoposto a refactoring utilizzando un meccanismo di astrazione come la funzione .

Applicazione del codice della libreria

Le operazioni di copia e incolla vengono eseguite anche da programmatori esperti, che spesso dispongono di proprie librerie di frammenti di codice ben collaudati e pronti per l'uso e di algoritmi generici che possono essere facilmente adattati a compiti specifici.

Essendo una forma di duplicazione del codice , la programmazione copia e incolla presenta alcuni problemi intrinseci; tali problemi sono esacerbati se il codice non conserva alcun collegamento semantico tra il testo sorgente e le copie. In questo caso, se sono necessarie modifiche, si perde tempo a cercare tutte le posizioni duplicate. (Questo può essere parzialmente mitigato se il codice originale e / o la copia sono commentati correttamente; tuttavia, anche in questo caso rimane il problema di fare le stesse modifiche più volte. Inoltre, poiché la manutenzione del codice spesso omette di aggiornare i commenti, commenti che descrivono dove trovarli pezzi di codice remoti sono noti per essere obsoleti.)

Gli aderenti alle metodologie orientate agli oggetti si oppongono ulteriormente all'uso della "libreria di codici" del copia e incolla. Invece di creare più copie mutate di un algoritmo generico, un approccio orientato agli oggetti astrarre l'algoritmo in una classe incapsulata riutilizzabile . La classe è scritta in modo flessibile, con pieno supporto dell'ereditarietà e del sovraccarico , in modo che tutto il codice chiamante possa essere interfacciato per utilizzare direttamente questo codice generico, invece di mutare l'originale. Poiché sono necessarie funzionalità aggiuntive, la libreria viene estesa (pur mantenendo la compatibilità con le versioni precedenti ). In questo modo, se l'algoritmo originale ha un bug da correggere o può essere migliorato, tutto il software che lo utilizza ne trarrà vantaggio.

Codice di ramificazione

Il codice ramificato è una parte normale dello sviluppo di software per team di grandi dimensioni, consentendo lo sviluppo parallelo su entrambi i rami e quindi cicli di sviluppo più brevi. La ramificazione classica ha le seguenti qualità:

  • È gestito da un sistema di controllo della versione che supporta la ramificazione
  • Le filiali vengono riunite una volta completato lo sviluppo parallelo.

Copia e incolla è un'alternativa meno formale alla ramificazione classica, spesso utilizzata quando si prevede che i rami divergeranno sempre di più nel tempo, come quando un nuovo prodotto viene scorporato da un prodotto esistente.

Come metodo per creare un nuovo prodotto, la programmazione copia e incolla presenta alcuni vantaggi. Perché la nuova iniziativa di sviluppo non tocca il codice del prodotto esistente:

  • Non è necessario testare la regressione del prodotto esistente, risparmiando tempo per il controllo qualità associato al lancio del nuovo prodotto e riducendo il time to market .
  • Non vi è alcun rischio di bug introdotti nel prodotto esistente, che potrebbero sconvolgere la base di utenti installati.

Gli svantaggi sono:

  • Se il nuovo prodotto non si discosta tanto quanto previsto dal prodotto esistente, potrebbe essere necessario supportare due basi di codice (al doppio del costo) dove una avrebbe fatto. Ciò può portare a costosi refactoring e fusione manuale su tutta la linea.
  • La base di codice duplicata raddoppia il tempo necessario per implementare le modifiche desiderate in entrambi i prodotti; questo aumenta il time-to-market per tali modifiche e, di fatto, può cancellare qualsiasi guadagno di tempo ottenuto ramificando il codice in primo luogo.

Analogamente a quanto sopra, l'alternativa a un approccio copia e incolla sarebbe un approccio modulare:

  • Inizia fattorizzando il codice da condividere da entrambi i prodotti nelle librerie.
  • Usa quelle librerie (piuttosto che una seconda copia del codice base) come base per lo sviluppo del nuovo prodotto.
  • Se è prevista una terza, quarta o quinta versione aggiuntiva del prodotto su tutta la linea, questo approccio è molto più forte, perché le librerie di codici già pronte riducono drasticamente il ciclo di vita di sviluppo per qualsiasi prodotto aggiuntivo dopo il secondo.

Attività ripetitive o variazioni di un'attività

Image
Difficoltà e rischio di mantenere il codice scritto dalla programmazione copia-incolla

Una delle forme più dannose di programmazione copia e incolla si verifica nel codice che esegue un'attività ripetitiva o variazioni della stessa attività di base a seconda di alcune variabili. Ogni istanza viene copiata dall'alto e incollata di nuovo, con piccole modifiche. Gli effetti nocivi includono:

  • L'approccio copia e incolla spesso porta a metodi di grandi dimensioni (un cattivo odore di codice ).
  • Ogni istanza crea un duplicato di codice, con tutti i problemi discussi nelle sezioni precedenti, ma con un ambito molto più ampio. Molteplici duplicazioni sono comuni; sono possibili centinaia. Le correzioni di bug, in particolare, diventano molto difficili e costose in questo codice.
  • Tale codice soffre anche di problemi di leggibilità significativi, a causa della difficoltà di discernere esattamente cosa differisce tra ogni ripetizione. Ciò ha un impatto diretto sui rischi e sui costi della revisione del codice.
  • Il modello di programmazione procedurale scoraggia fortemente l'approccio copia e incolla alle attività ripetitive. In un modello procedurale, un approccio preferito alle attività ripetitive è creare una funzione o una subroutine che esegue un singolo passaggio attraverso l'attività; questa subroutine viene quindi chiamata dalla routine genitore, ripetutamente o meglio ancora, con una qualche forma di struttura a ciclo. Tale codice è definito "ben scomposto" ed è consigliato perché è più facile da leggere e più facilmente estendibile.
  • La regola generale applicabile a questo caso è " non ripetere te stesso ".

Scelta deliberata di design

La programmazione copia e incolla è occasionalmente accettata come una tecnica di programmazione valida. Questo è più comunemente visto in boilerplate, come le dichiarazioni di classe o l'importazione di librerie standard, o nell'uso di un modello di codice esistente (con contenuti vuoti o funzioni stub) come framework da compilare.

L'uso di idiomi di programmazione e modelli di progettazione è simile alla programmazione copia e incolla, poiché utilizzano anche codice formulaico. In alcuni casi, questo può essere espresso come uno snippet , che può quindi essere incollato quando tale codice è necessario, sebbene spesso venga semplicemente richiamato dalla mente del programmatore. In altri casi gli idiomi non possono essere ridotti a un modello di codice. Nella maggior parte dei casi, tuttavia, anche se un idioma può essere ridotto a codice, sarà abbastanza lungo da essere astratto in una funzione o abbastanza breve da poter essere digitato direttamente.

Il linguaggio di programmazione Subtext è un progetto di ricerca finalizzato alla "depenalizzazione" di taglia e incolla. Utilizzando questo linguaggio, taglia e incolla è il modello di interazione principale e quindi non è considerato un anti-pattern.

Esempio

Un semplice esempio è un ciclo for, che potrebbe essere espresso come . for (int i=0; i!=n; ++i) {}

Il codice di esempio che utilizza un tale ciclo for potrebbe essere:

void foo(int n) {
    for (int i=0; i!=n; ++i) {
       /* body */
    }
}

Il codice di looping potrebbe quindi essere stato generato dal seguente frammento (specificando tipi e nomi di variabili):

    for ($type $loop_var = 0; $loop_var != $stop; ++$loop_var) {
        /* body */
    }

Guarda anche

Riferimenti

link esterno