Una difesa per boilerplate?


14

Per me, il codice boilerplate è ovviamente negativo. Tuttavia, ho incontrato uno sviluppatore che mostra resistenza in qualsiasi tentativo di ridurre la piastra di cottura. Mi sono reso conto che non avevo avuto una discussione prontamente formata e ben ponderata oltre l'aborrenza che ho sviluppato per questo nel tempo.

Affinché io possa formare un argomento convincente per favorire un minor numero di piatti, quali sono alcuni controargomenti? In altre parole, quali sono gli argomenti (se presenti) a favore di boilerplate?

(Intendo quello che penso sia generalmente inteso da boilerplate, ma un buon esempio sono getter e setter in Java.)


7
Argomenti contro il codice duplicato (supponendo che la piastra della caldaia sia copiata / incollata): stackoverflow.com/a/2490897/1583
Oded

1
@Oded: esatto. Ma hai letto male la domanda. :) Sta tentando di cercare se c'è qualcosa da dire per il codice del boilerplate. Suppongo che sia molto ben informato degli svantaggi.
Steven Jeuris,

3
@StevenJeuris - Ho letto perfettamente la domanda. Ecco perché non ho pubblicato una risposta. Sto solo aggiungendo all'altro lato dell'argomento. Proprio così l'OP ha "una discussione prontamente formata, ben ponderata oltre l'aborrenza che ho sviluppato per esso nel tempo" per la prossima volta;)
Oded

2
La piastra della caldaia può essere esteticamente piacevole: en.wikipedia.org/wiki/This_Is_the_House_That_Jack_Built
SK-logic

Diverse buone risposte e commenti che si completano a vicenda ... difficile scegliere quale accettare.
sottratto

Risposte:


15

Una cosa importante da ricordare è che il codice viene generalmente ridotto rimuovendo il contesto non necessario. Se il compilatore riesce a capire qualcosa, l'argomento va, non è necessario scriverlo esplicitamente.

E sarebbe fantastico se solo il compilatore fosse mai stato intenzionato a leggerlo. Ma ricorda che "i programmi dovrebbero essere scritti per essere letti dalle persone e solo per inciso da eseguire sulle macchine". (Ironia della sorte, questa citazione proviene da un libro di testo dedicato a una delle lingue più difficili da leggere per gli esseri umani ordinari, in gran parte dovuto alla sua eccessiva terseness.)

Ciò che può sembrare noioso, ripetitivo per te mentre scrivi, può essere un contesto prezioso per qualcun altro che arriva un anno (o cinque) dopo e deve mantenere il tuo codice.

WRT, in particolare, l'esempio Java, concordo sul fatto che si tratta di un buon esempio di cattiva targhetta, poiché può essere sostituita da qualcosa che è più breve e più facile da leggere, e anche più flessibile: Proprietà. Ma ciò non significa che tutti gli elementi sintattici di tutte le lingue siano dispendiosi come i getter e i setter di Java e C ++.


7
Naturalmente, questo argomento funziona in entrambi i modi. Una notevole quantità di codice boilerplate è lì solo per placare il compilatore e non aiuta gli umani a comprendere - per stare con getter / setter, quelle dozzine di righe devono essere lette interamente per essere sicuri "quelli sono semplicemente getter e setter che non fanno nulla" , anziché leggere una singola linea breve per proprietà che indica semplicemente che è una proprietà e che tipo ha.

6
Penso che il boilerplate sia dannoso anche per il lettore umano. Essendo costretti a scrivere testi ripetitivi e insignificanti, stiamo oscurando le parti pertinenti del codice da altre persone. Se qualcosa è utile, allora per definizione non è boilerplate.
Andres F.,

1
@Giorgio: al contrario, è molto più di una mia opinione; è l'opinione della stragrande maggioranza delle persone che hanno mai provato a studiarlo. E quando "difficile da leggere" è intrinsecamente una questione di opinione in primo luogo, il fatto che tale opinione sia così ampiamente condivisa lo rende praticamente un dato di fatto.
Mason Wheeler

1
@Mason Wheeler: il modo in cui le persone percepiscono i linguaggi di programmazione è spesso influenzato dalla loro esperienza passata. Le persone che hanno imparato a programmare in Scheme trovano C o Pascal goffe e difficili da leggere. D'altra parte, la stragrande maggioranza delle persone ha imparato a programmare in un linguaggio tradizionale.
Giorgio,

2
Sono dell'opinione che quando più contesto viene nascosto al programmatore rimuovendo la piastra di caldaia, ciò significa solo che l'Umano deve mantenere una mappa mentale più grande di tutto ciò che accade invisibile dietro le quinte E questo è un grande danno quando si tratta di debug piuttosto che risparmiare un po 'di spazio visivo durante la creazione.
Patrick Hughes,

7

Un argomento a favore del codice boilerplate è che se lo si modifica in un punto, influisce solo su un flusso del codice. Questo deve essere bilanciato dal fatto che il più delle volte, in realtà, si desidera che una modifica influisca su ogni parte di codice che lo utilizza. Ma ho visto esempi rari che supportano l'argomento.

Diciamo che hai un pezzo di codice che dice

public ForTheBar(Foo foo)
{
    Bar bar = foo.bar();
    return bar.BeFooed();
}

Questo è usato in circa 2 posti nel tuo codice.

Un giorno qualcuno arriva e dice "ok, solo in questo percorso, vogliamo che tu Grommit il bar prima di lanciarlo."

E pensi "bene, questo è semplice".

public ForTheBar(Foo foo, bool shouldIGrommit)
{
    Bar bar = foo.bar();

    if (shouldIGrommit)
    {
        bar.BeGrommitted();
    }

    return bar.BeFooed();
}

Quindi il tuo utente aggiunge alcune nuove funzionalità e pensi che si adatti bene a FooTheBar. E gli chiedi diligentemente se dovresti Grommit quel bar prima di Foo e loro dicono "no, non questa volta".

Quindi basta chiamare il metodo sopra.

Ma poi il tuo utente dice "ok, aspetta, nel terzo caso, vogliamo che scarabocchi la barra prima di chiamare BeFooed."

Nessun problema, pensi, posso farcela.

public ForTheBar(Foo foo, bool shouldIGrommit, bool shouldIDoodle)
{
    Bar bar = foo.bar();

    if (shouldIGrommit)
    {
        bar.BeGrommitted();
    }

    if (shouldIDoodle)
    {
        bar.BeDoodled();
    }

    return bar.BeFooed();
}

Improvvisamente il tuo codice sta diventando meno targhetta. Forse avresti dovuto accettare le due righe di codice ripetute. A questo punto avresti avuto tre pezzi di codice, ciascuno lungo 2-3 righe e non molto più ripetuto.

Detto questo, vorrei contrastare che con "questo non è un caso comune, e quando succede, puoi refactoring".

Un altro argomento che ho sentito recentemente è che il codice boilerplate a volte può aiutarti a navigare nel codice. L'esempio di cui stavamo discutendo era il punto in cui avevamo rimosso tonnellate di codice di mappatura del boilerplate e sostituito con AutoMapper. Ora, si è sostenuto, poiché tutto è basato su una convenzione, non si può dire "Dov'è questa proprietà impostata" all'IDE e aspettarsi che lo sappia.

Ho visto persone discutere cose simili sui container IoC.

Per non dire che sono d'accordo con loro, ma è comunque un argomento equo.


2
Ho preferito la seconda parte della tua risposta. ; p +1
Steven Jeuris,

renditi conto che il mio esempio è abbastanza simile al tuo ... indovina anche se non è un buon senso, sembra accadere un po ':)
kritzikratzi,

6

L'evoluzione dell'efficienza

Inizi con questo:

<p>
    <label for="field">My field</label>
    <input type="text" id="field">
</p>

poi ti sbarazzi di tutto quel fastidioso scaldabagno e lo metti in funzione:

  1. createFieldHtml( id, label )

    va bene, mi sto salvando così tante righe!

  2. createFieldHtml( id, label, defaultValue )

    sì, ho bisogno anche di un valore predefinito, che è stato facile aggiungere.

  3. createFieldHtml( id, label, defaultValue, type )

    bene, ora posso usarlo anche per le caselle di controllo

  4. createFieldHtml( id, label, defaultValue, type, labelFirst )

    Il progettista di UX ha detto che l'etichetta deve essere dopo la casella di controllo.

  5. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate )

    ora esegue il rendering di un selettore di date quando necessario. Hm ... i params stanno diventando un po 'fuori controllo

  6. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate, containerCssClasses )

    c'è stato un caso in cui ho bisogno di aggiungere classi CSS

  7. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate, containerCssClasses, fieldCssClasses, disabled, clearAfter, helpText, uploadPath )

    aaaaaaaaaaaaaaaaaaaaa

In difesa del boilerplate

Ho difficoltà a dirlo in parole perché è qualcosa che ho notato di recente, quindi farò un elenco:

  1. Mi sembra che ci sia una certa paura di avere linee duplicate che si allungano un po '. Se sono solo poche righe potrebbe non essere affatto un problema. alcune cose sono intrinsecamente "quasi ripetitive" (come nell'esempio sopra). Vedo poche possibilità di ottimizzazione a lungo termine.
  2. La gente ama incapsulare la funzionalità da qualche parte; se guardi obiettivamente e sembra che sia solo "nascondere il casino" - sii sospettoso! potrebbe essere il momento per qualche buon vecchio boilerplate
  3. Quando hai una funzione che diventa sempre più potente; che prende molti percorsi di esecuzione diversi a seconda dell'input e alla fine fa pochissimo - potrebbe essere il tempo della caldaia!
  4. Quando aggiungi uno strato di astrazione sopra un altro strato di astrazione, ma solo per abbreviare il tuo codice (lo strato sottostante non è pensato per essere cambiato) - tempo della piastra di cottura!
  5. Quando hai una funzione che accetta così tanti parametri che hai davvero bisogno di avere parametri nominati - forse è il tempo del piatto.

Una cosa che mi chiedo sempre di recente è questa:
posso copiare e incollare in un altro progetto senza cambiare nulla? in caso affermativo, va bene incapsulare o inserire in una libreria, in caso contrario: è il tempo del bollettino.

Ciò si oppone molto alla percezione generale che il bollettino sia il codice copia e incolla. Per me il plateplate riguarda il copia e incolla, ma devo sempre modificarlo un po '.


Aggiornamento : mi sono appena imbattuto in un articolo che riporta il mio esempio sopra un nome reale: "troppo DRY anti-pattern".

La funzione ottiene più parametri e ha una logica interna sempre più complessa per controllarne il comportamento in diversi casi. Le funzioni troppo DRY sono facili da individuare. Hanno molte intricate logiche if-then che cercano di affrontare un'ampia varietà di usi. [...] Inoltre, ripetere il codice non è sempre una cosa negativa se il codice è piccolo ed esegue una funzione discreta.

È una lettura breve e interessante, puoi trovare l'articolo qui: Too Dry Anti-Pattern


1
"Quando aggiungi uno strato di astrazione sopra un altro strato di astrazione, ma solo per abbreviare il tuo codice" Vero, dovresti aggiungere strati di astrazione solo quando esiste la possibilità di riutilizzarli.
Steven Jeuris,

4
+1. Non ripetere te stesso, ma non fare di tutto per evitare quasi di ripetere te stesso.
Julia Hayward,

4

Io disprezzo codice standard, ma essere in grado di rimuovere il codice boilerplate non sempre significa che è il modo migliore per andare.

Il framework WPF ha proprietà di dipendenza , che implicano una quantità folle di codice del boilerplate. Durante il mio tempo libero ho studiato una soluzione che riduce notevolmente la quantità di codice che deve essere scritto. Oltre un anno dopo sto ancora migliorando questa soluzione e devo ancora estenderne le funzionalità o correggere i bug.

Qual è il problema? Questo è ottimo per imparare nuove cose ed esplorare soluzioni alternative, ma probabilmente non è la migliore decisione commerciale .

Il framework WPF è ben documentato. E ' corretto documenta come scrivere il codice standard. Cercare di rimuovere questo codice boilerplate è un esercizio piacevole e qualcosa che vale sicuramente la pena esplorare, ma raggiungere lo stesso livello di "polacco" offerto da msdn richiede molto tempo, cosa che non sempre abbiamo.


Tuttavia, sono ancora abbastanza contento del risultato che ho in questo momento e lo uso volentieri nei miei progetti per il tempo libero. :)
Steven Jeuris,

3
ogni volta che tocco WPF e quelle proprietà di dipendenza, finisco sempre per desiderare che C # abbia qualcosa di semplice come le macro di C ++. Sicuramente le macro vengono abusate in mani sbagliate, ma potrebbero eliminare così tanta ripetizione qui. Dovrò dare un'occhiata al tuo framework AOP la prossima volta che comincerò a desiderare quelle macro :)
DXM

@DXM Se lo fai, e si blocca miseramente, non dimenticare di incolpare me e pubblicare gli errori. ; p
Steven Jeuris,

Lo snippet di codice ha funzionato abbastanza bene per me per le proprietà di dipendenza.
Codismo,

@Codismo: beh, sono una soluzione, ma disprezzo anche quelli . :)
Steven Jeuris,

1

Il problema con il boilerplate è che viola il DRY. In sostanza, quando si scrive boilerplate, si ripete lo stesso codice (o codice molto simile) in un numero di classi. Quando è necessario modificare tale codice, non è affatto certo che lo sviluppatore ricorderà tutti i punti in cui il codice è stato ripetuto. Questo porta a bug in cui vengono utilizzate vecchie API o vecchi metodi.

Se esegui il refactoring della caldaia in una libreria comune o in una classe genitore, devi modificare il codice in un solo posto quando l'API cambia. Ancora più importante, quando si verificano cambiamenti imprevisti, il codice si interrompe in un unico posto e ti consente di sapere esattamente cosa devi correggere per far funzionare di nuovo tutto. Questo è di gran lunga preferibile a uno scenario in cui un cambiamento provoca errori in dozzine o addirittura centinaia di classi.


2
In che modo questo è un argomento a favore di boilerplate ?
Chris Wesseling,

0

Prenderò un tatto diverso. La coerenza nello sviluppo è una delle caratteristiche più importanti della progettazione del software, è uno strumento fondamentale per rendere le applicazioni estensibili e gestibili, ma può essere difficile da raggiungere quando si gestisce un team su più siti, lingue e fusi orari.

Se raggiunta, la coerenza rende il codice molto più accessibile "una volta che ne hai visto uno, li hai visti tutti", molto più economico da mantenere e refactoring, ma soprattutto molto più facile da estendere. Quando scrivi una libreria che richiede un po 'di boilerplate, insieme alla potenza della tua libreria, hai anche dato allo sviluppatore:

  • Un punto di partenza comprende il preambolo (boilerplate) nella tua funzionalità, la maggior parte delle classi chiave e dei punti di accesso di solito appariranno come parte del boilerplate. Ciò fornisce agli sviluppatori un punto di partenza nella documentazione
  • Le aspettative sul posizionamento degli sviluppatori diventeranno evidenti, ad esempio se si configura un oggetto di tracciamento come parte del preambolo, gli sviluppatori sapranno dove registrare eccezioni e informazioni
  • Comprensione implicita mentre costringi lo sviluppatore a seguire il tuo processo di istanza delle classi, possono dedurre le tecniche di cui avranno bisogno per accedere al resto della tua biblioteca e avere l'opportunità di presentarle a tutte le convenzioni che hai usato in tutta la tua biblioteca
  • Facile convalida quando è necessario il codice della tua caldaia, di solito può validarsi molto facilmente con eccezioni e clausole di protezione, evitando che i consumatori rimangano bloccati molto più in là quando sei già impegnato in un processo difettoso
  • La configurazione di una libreria che richiede codice boilerplate è semplice in quanto esiste già un ovvio punto di implementazione per personalizzare la funzionalità per un singolo percorso di esecuzione. Ciò è particolarmente utile se il codice della caldaia richiesto è migliorato con il modello Factory o Command

Quando i consumatori della tua libreria hanno un controllo sull'istanza, possono facilmente creare metodi privati ​​/ di estensione, classi parent o persino modelli per implementare il codice boilerplate.


-3

L'unico vero problema con il codice boilerplate è che quando trovi un bug in esso devi risolvere ovunque che lo hai usato piuttosto che l'unico posto che hai riutilizzato .

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.