Eine Verteidigung für Boilerplate?

14

Boilerplate-Code ist für mich offensichtlich schlecht. Ich habe jedoch einen Entwickler getroffen, der Widerstand zeigt, wenn er versucht, die Heizplatte zu verkleinern. Mir wurde klar, dass ich kein leicht zu formulierendes, gut durchdachtes Argument hatte, das über die Abscheulichkeit hinausging, die ich im Laufe der Zeit dafür entwickelt hatte.

Was sind einige Gegenargumente, damit ich ein überzeugendes Argument für weniger Boilerplate bilden kann? Mit anderen Worten, was sind die Argumente (falls vorhanden) für Boilerplate?

(Ich meine, was ich denke, ist im Allgemeinen mit Boilerplate gemeint, aber ein gutes Beispiel sind Getter und Setter in Java.)

abstrahiert
quelle
7
Argumente gegen doppelten Code (unter der Annahme, dass das Boilerplate kopiert / eingefügt wurde): stackoverflow.com/a/2490897/1583
Oded
1
@Oded: Das stimmt. Aber Sie haben die Frage falsch verstanden. :) Er versucht zu sehen , ob es etwas zu sagen , ist für Standardcode. Ich vermute, er ist sehr gut über die Nachteile informiert.
Steven Jeuris
3
@StevenJeuris - Ich habe die Frage perfekt gelesen. Deshalb habe ich keine Antwort gepostet. Ich füge nur die andere Seite des Arguments hinzu. Nur damit das OP für das nächste Mal "ein gut durchdachtes Argument hinter der Abscheulichkeit hat, die ich im Laufe der Zeit dafür entwickelt habe";)
Oded
2
Boilerplate kann ästhetisch ansprechend sein: en.wikipedia.org/wiki/This_Is_the_House_That_Jack_Built
SK-logic
Mehrere gute Antworten und Kommentare, die sich gegenseitig ergänzen ... es ist schwierig, die zu akzeptieren.
abstrahiert

Antworten:

15

Eine wichtige Sache, an die man sich erinnern sollte, ist, dass Code im Allgemeinen kleiner gemacht wird, indem unnötiger Kontext entfernt wird. Wenn die Compiler etwas herausfinden können, so das Argument, es gibt keine Notwendigkeit , es zu schreiben ausdrücklich darauf hin.

Und das wäre großartig, wenn nur der Compiler es jemals lesen würde. Aber denken Sie daran, dass "Programme geschrieben werden sollten, damit die Leute sie lesen können, und nur im Übrigen, damit Maschinen sie ausführen können." (Ironischerweise stammt dieses Zitat aus einem Lehrbuch, das einer der am schwersten zu lesenden Sprachen für gewöhnliche Menschen gewidmet ist, was zum großen Teil auf seine übermäßige Knappheit zurückzuführen ist.)

Was für Sie nach langweiligem, sich wiederholendem Boilerplate aussieht, während Sie es schreiben, kann für jemanden, der ein Jahr (oder fünf) später vorbeikommt und Ihren Code warten muss, ein wertvoller Kontext sein.

Wenn ich das Java-Beispiel genauer betrachte, stimme ich zu, dass dies ein gutes Beispiel für ein schlechtes Boilerplate ist, da es durch etwas ersetzt werden kann, das sowohl kürzer als auch leichter zu lesen und auch flexibler ist: Eigenschaften. Dies bedeutet jedoch nicht, dass alle syntaktischen Elemente von Boilerplate aus allen Sprachen so verschwenderisch sind wie die Getter und Setter von Java und C ++.

Mason Wheeler
quelle
7
Natürlich funktioniert dieses Argument in beide Richtungen. Eine beträchtliche Menge an Code auf dem Kesselschild ist nur dazu da, den Compiler zu beruhigen, und hilft den Menschen nicht, dies zu verstehen. Um bei Gettern / Setzern zu bleiben, müssen diese Dutzenden Zeilen vollständig gelesen werden, um sicher zu sein, dass es sich bei ihnen nur um Do-nothing-Gettern und Setzern handelt. anstatt eine einzige kurze Zeile pro Eigenschaft zu lesen, die lediglich angibt, dass es sich um eine Eigenschaft handelt und welchen Typ sie hat.
6
Ich denke, dass Boilerplate auch für den menschlichen Leser schädlich ist . Indem wir gezwungen werden, sich wiederholenden, bedeutungslosen Text zu schreiben, verdunkeln wir die relevanten Teile des Codes vor anderen Menschen. Wenn etwas hilfreich ist, dann ist es per Definition kein Boilerplate.
Andres F.
1
@ Giorgio: Im Gegenteil, es ist viel mehr als nur meine Meinung. Es ist die Meinung der allermeisten Menschen, die jemals versucht haben, es zu studieren. Und wenn "schwer zu lesen" von Natur aus eine Ansichtssache ist, macht es die Tatsache, dass diese Meinung so weit verbreitet ist, zu einer Tatsache.
Mason Wheeler
1
@Mason Wheeler: Wie Menschen Programmiersprachen wahrnehmen, hängt oft von ihren Erfahrungen in der Vergangenheit ab. Leute, die gelernt haben, im Schema zu programmieren, finden C oder Pascal ungeschickt und schwer lesbar. Auf der anderen Seite lernte die überwiegende Mehrheit der Menschen, in einer Standardsprache zu programmieren.
Giorgio
2
Ich bin der Meinung, dass, wenn dem Programmierer durch das Entfernen der Kesselplatine mehr Kontext verborgen wird, der Mensch nur eine größere mentale Karte von all den Dingen führen muss, die ungesehen hinter den Kulissen passieren. Und das ist ein größerer Nachteil, wenn es darum geht Debuggen, als beim Authoring ein wenig visuellen Platz zu sparen.
Patrick Hughes
7

Ein Argument für Boilerplate-Code ist, dass eine Änderung an einer Stelle nur einen Codefluss betrifft. Dies muss gegen die Tatsache abgewogen werden, dass Sie in den meisten Fällen tatsächlich eine Änderung wünschen, die sich auf jeden Code auswirkt, der sie verwendet. Aber ich habe seltene Beispiele gesehen, die das Argument stützen.

Nehmen wir an, Sie haben einen Code, der besagt

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

Dies wird an ungefähr 2 Stellen in Ihrem Code verwendet.

Eines Tages kommt jemand vorbei und sagt: "Okay, nur auf diesem Weg möchten wir, dass Sie die Bar freigeben, bevor Sie sie feuern."

Und du denkst "gut das ist einfach."

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

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

    return bar.BeFooed();
}

Dann fügt Ihr Benutzer einige neue Funktionen hinzu, die Ihrer Meinung nach gut zu FooTheBar passen. Und du fragst sie pflichtbewusst, ob du diese Bar einkapseln solltest, bevor du es machst, und sie sagen "nein, diesmal nicht".

Also rufst du einfach die obige Methode auf.

Aber dann sagt Ihr Benutzer: "Okay, warten Sie, im dritten Fall möchten wir, dass Sie die Leiste kritzeln, bevor Sie BeFooed anrufen."

Kein Problem, denkst du, das kann ich.

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

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

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

    return bar.BeFooed();
}

Plötzlich wird Ihr Code weniger auffällig. Vielleicht hätten Sie die wiederholten zwei Codezeilen akzeptieren sollen. Inzwischen haben Sie drei Code-Teile, die jeweils 2-3 Zeilen lang sind und nicht mehr sehr wiederholt aussehen.

All dies sagte, ich würde dem mit "Dies ist kein gewöhnlicher Fall, und wenn es passiert, können Sie refactor."

Ein weiteres Argument, das ich kürzlich gehört habe, ist, dass Boilerplate-Code manchmal beim Navigieren im Code helfen kann. Das besprochene Beispiel war, wo wir Tonnen von Boilerplate-Mapping-Code entfernt und durch AutoMapper ersetzt hatten. Nun, es wurde argumentiert, da alles auf Konventionen basiert, können Sie der IDE nicht sagen, wo diese Eigenschaft festgelegt ist, und erwarten, dass sie es weiß.

Ich habe Leute gesehen, die ähnliche Dinge über IoC-Container diskutierten.

Um nicht zu sagen, dass ich ihnen zustimme, aber es ist trotzdem ein faires Argument.

pdr
quelle
2
Ich habe den zweiten Teil Ihrer Antwort vorgezogen. ; p +1
Steven Jeuris
stell
6

Die Evolution der Effizienz

Sie beginnen damit:

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

dann werden Sie das nervige Kochfeld los und ordnen es einer Funktion zu:

  1. createFieldHtml( id, label )

    das ist gut, ich spare mir so viele Zeilen!

  2. createFieldHtml( id, label, defaultValue )

    Ja, ich brauche auch einen Standardwert, der einfach hinzuzufügen war.

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

    cool, ich kann es jetzt auch für checkboxes verwenden

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

    Der UX-Designer hat angegeben, dass die Beschriftung hinter dem Kontrollkästchen stehen muss.

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

    Bei Bedarf wird jetzt eine Datumsauswahl angezeigt. Hm .. Params geraten etwas außer Kontrolle

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

    In diesem einen Fall musste ich CSS-Klassen hinzufügen

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

    aaaaaaaaaaaaaaaaaaa

Zur Verteidigung der Kesselplatte

Es fällt mir schwer, dies in Worte zu fassen, weil ich es erst kürzlich bemerkt habe. Deshalb werde ich eine Liste erstellen:

  1. Es scheint mir, dass es eine gewisse Angst gibt, doppelte Linien zu haben, die sich etwas ausdehnen. Wenn es sich nur um ein paar Zeilen handelt, ist dies möglicherweise überhaupt kein Problem. Einige Dinge sind von Natur aus "fast repetitiv" (wie im obigen Beispiel). Langfristig sehe ich wenig Chancen, dort zu optimieren.
  2. Die Leute lieben es, Funktionalität irgendwo zu verkapseln. wenn du objektiv schaust und es so aussieht, als ob es nur "das Durcheinander verstecken" - sei misstrauisch! Es könnte die Zeit für ein gutes altes Kochfeld sein
  3. Wenn Sie eine Funktion haben, die immer leistungsfähiger wird; das braucht je nach eingabe viele verschiedene ausführungspfade und macht letztendlich nur sehr wenig - es kann sich um die boilerplate-zeit handeln!
  4. Wenn Sie eine Abstraktionsebene über eine andere Abstraktionsebene legen, aber nur, um den Code zu verkürzen (die zugrunde liegende Ebene darf nicht geändert werden) - Boilerplate-Zeit!
  5. Wenn Sie eine Funktion haben, die so viele Parameter akzeptiert, dass Sie wirklich benannte Parameter benötigen - vielleicht ist es die Boilerplate-Zeit.

Eine Sache, die ich mir in letzter Zeit immer wieder frage, ist folgende:
Kann ich kopieren und in ein anderes Projekt einfügen, ohne etwas zu ändern? Wenn ja, ist es in Ordnung, zu kapseln oder in eine Bibliothek zu stellen. Wenn nein, ist es Zeit für das Boilerplate.

Dies widerspricht der allgemeinen Auffassung, dass es sich bei Boilerplate um Copy & Paste-Code handelt. Für mich geht es beim Boilerplate um das Kopieren und Einfügen, aber es muss immer ein bisschen optimiert werden.


Update : Ich bin gerade auf einen Artikel gestoßen, in dem mein Beispiel über einem tatsächlichen Namen steht: "too DRY anti-pattern".

Die Funktion erhält mehr Parameter und verfügt über eine zunehmend komplexe interne Logik, um ihr Verhalten in verschiedenen Fällen zu steuern. Zu TROCKENE Funktionen sind leicht zu erkennen. Sie haben viele komplizierte Wenn-Dann-Logik, die versucht, eine breite Vielfalt der Verwendung zu adressieren. [...] Auch das Wiederholen von Code ist nicht immer eine schlechte Sache, wenn der Code klein ist und eine diskrete Funktion ausführt.

Es ist eine kurze und interessante Lektüre, den Artikel finden Sie hier: Too Dry Anti-Pattern

kritzikratzi
quelle
1
"Wenn Sie eine Abstraktionsebene über eine andere Abstraktionsebene legen, aber nur, um den Code zu verkürzen" Richtig, sollten Sie Abstraktionsebenen nur dann hinzufügen, wenn die Möglichkeit der Wiederverwendung besteht.
Steven Jeuris
4
+1. Wiederholen Sie nicht selbst, aber gehen Sie nicht zu umständlich Längen zu vermeiden , fast sich selbst zu wiederholen.
Julia Hayward
4

Ich verachte Boilerplate-Code, aber in der Lage zu sein, Boilerplate-Code zu entfernen, bedeutet nicht immer, dass dies der beste Weg ist.

Das WPF-Framework verfügt über Abhängigkeitseigenschaften , die eine irrsinnige Menge an Boilerplate-Code beinhalten. In meiner Freizeit habe ich nach einer Lösung gesucht, die die Menge an Code, die geschrieben werden muss, erheblich reduziert. Über ein Jahr später verbessere ich diese Lösung immer noch und muss ihre Funktionalität noch erweitern oder Fehler beheben.

Worin besteht das Problem? Dies ist großartig, um neue Dinge zu lernen und alternative Lösungen zu erkunden, aber es ist wahrscheinlich nicht die beste kommerzielle Entscheidung.

Das WPF-Framework ist gut dokumentiert. Es dokumentiert ordnungsgemäß , wie Sie Ihren Code für die Heizplatte schreiben. Der Versuch, diesen Boilerplate-Code zu entfernen, ist eine nette Übung, die es definitiv wert ist, erkundet zu werden. Es dauert jedoch lange, bis derselbe Grad an "Polnisch" erreicht ist, den msdn anbietet, was wir nicht immer haben.

Steven Jeuris
quelle
Dennoch bin ich mit dem Ergebnis, das ich im Moment habe, recht zufrieden und nutze es gerne in meinen Freizeitprojekten. :)
Steven Jeuris
3
Jedes Mal, wenn ich WPF und diese Abhängigkeitseigenschaften berühre, wünsche ich mir immer, C # hätte etwas so Einfaches wie die Makros von C ++. Sicher, Makros werden in falschen Händen missbraucht, aber sie könnten so viele Wiederholungen hier eliminieren. Ich muss mir das nächste Mal Ihr AOP-Framework ansehen, wenn ich mir diese Makros
wünsche
@DXM Wenn Sie dies tun und es kläglich abstürzt, vergessen Sie nicht, mir die Schuld zu geben und die Fehler zu posten. ; p
Steven Jeuris
Code-Snippet funktionierte für Abhängigkeitseigenschaften ziemlich gut.
Codism
@Codism: Nun, sie sind eine Lösung, aber ich verachte diese auch . :)
Steven Jeuris
1

Das Problem mit Boilerplate ist, dass es DRY verletzt. Wenn Sie Boilerplate schreiben, wiederholen Sie im Wesentlichen den gleichen Code (oder einen sehr ähnlichen Code) in einer Reihe von Klassen. Wenn dieser Code geändert werden muss, ist es keineswegs sicher, dass sich der Entwickler an alle Stellen erinnert, an denen der Code wiederholt wurde. Dies führt zu Fehlern, bei denen alte APIs oder alte Methoden verwendet werden.

Wenn Sie das Boilerplate in eine gemeinsame Bibliothek oder übergeordnete Klasse umgestalten, müssen Sie den Code nur an einer Stelle ändern, wenn sich Ihre API ändert. Noch wichtiger ist, dass bei unerwarteten Änderungen der Code an einer Stelle unterbrochen wird und Sie genau wissen, was Sie korrigieren müssen, damit alles wieder funktioniert. Dies ist einem Szenario weit vorzuziehen, in dem eine Änderung zu Fehlern in Dutzenden oder sogar Hunderten von Klassen führt.

Quantikel
quelle
2
Wie ist dies ein Argument zugunsten von vorformulierten ?
Chris Wesseling
0

Ich werde einen anderen Takt wählen. Konsistenz in der Entwicklung ist eines der wichtigsten Merkmale des Softwaredesigns. Es ist ein wichtiges Werkzeug, um Anwendungen erweiterbar und wartbar zu machen, kann jedoch schwierig sein, wenn ein Team über mehrere Standorte, Sprachen und Zeitzonen hinweg verwaltet wird.

Wenn dies erreicht ist, wird der Zugriff auf Code durch Konsistenz erheblich erleichtert, da die Wartung und Umgestaltung von Code wesentlich kostengünstiger und vor allem die Erweiterung erheblich einfacher ist. Wenn Sie eine Bibliothek schreiben, für die ein Boilerplate erforderlich ist, haben Sie neben der Leistung Ihrer Bibliothek auch dem Entwickler Folgendes mitgeteilt:

  • Ein Ausgangspunkt , der die Präambel (Boilerplate) in Ihre Funktionalität einbezieht. Die meisten Schlüsselklassen und Zugriffspunkte sind normalerweise Teil der Boilerplate. Dies gibt Entwicklern einen Einstieg in die Dokumentation
  • Die Erwartungen, die Sie an Entwickler stellen, werden offensichtlich. Wenn Sie beispielsweise ein Ablaufverfolgungsobjekt als Teil der Präambel einrichten, wissen Entwickler, wo Ausnahmen und Informationen protokolliert werden müssen
  • Implizites Verständnis, wenn Sie den Entwickler zwingen, den Prozess des Instanziierens von Klassen zu durchlaufen, kann er auf die Techniken schließen, die er für den Zugriff auf den Rest Ihrer Bibliothek benötigt, und er kann sie in Konventionen einführen, die Sie in Ihrer gesamten Bibliothek verwendet haben
  • Einfache Validierung, wenn Ihr Kesselschild-Code benötigt wird. Normalerweise kann er sich selbst mit Ausnahmen und Schutzklauseln sehr einfach validieren, um zu verhindern, dass Verbraucher viel später hängen bleiben, wenn Sie bereits an einem fehlerhaften Prozess beteiligt sind
  • Die Konfiguration einer Bibliothek, die Boilerplate-Code erfordert, ist einfach, da es bereits einen offensichtlichen Implementierungspunkt gibt, um die Funktionalität für einen einzelnen Ausführungspfad anzupassen. Dies ist besonders nützlich, wenn Ihr erforderlicher Kesselschildcode um das Factory- oder Command-Muster erweitert wurde

Wenn die Konsumenten Ihrer Bibliothek die Instanziierung im Griff haben, können sie auf einfache Weise private / Erweiterungsmethoden, übergeordnete Klassen oder sogar Vorlagen erstellen, um den Boilerplate-Code zu implementieren.

Dead.Rabit
quelle
-3

Das einzige wirkliche Problem mit Boilerplate-Code besteht darin, dass Sie, wenn Sie einen Fehler darin finden, überall beheben müssen, dass Sie ihn verwendet haben, und nicht an der Stelle, an der Sie ihn wiederverwendet haben .

Edward Strange
quelle