Dies ist der erste Teil meiner Artikel-Reihe "Clean Code", welchem noch einige Weitere folgen werden und welche sich hauptsächlich damit befassen, wie man sauberen, wartbaren und stabilen Code schreibt. Ich versuche dabei möglichst von der Programmiersprache selbst zu abstrahieren und mich nur mit den prinzipiellen Mustern und Vorgehensweisen zu beschäftigen. Dennoch muss ich ab und an Code-Beispiele einbringen und da werde ich mir dann wohl mit PHP und Java helfen.
in diesem Artikel geht es also um das DRY-Prinzip, welches nicht nur die einfachste Regel darstellt, sondern zugleich auch die, die am meisten misachtet wird.
DRY steht für Don't Repeat Yourself und der Name ist Programm(code): Ein Code-Fragement sollte immer nur exakt einmal vorkommen und sollte man dieses Fragment nochmal benötigen, wird es in eine Funktion/Methode ausgelagert. Leider erfordert das klassiche Copy'n'Paste weitaus weniger Aufwand und Gehirn-Aktivität, weshalb dies meist die bevorzugte Vorgehensweise ist. Gerade wenn es schnell gehen muss, spart man sich den Aufwand eine neue Methode zu implementieren gerne.
Dieses leichtsinnige Verhalten bläht nicht nur den Code auf, wie man erst vermuten mag: Das eigentliche Problem sind die potentiellen Fehlerquellen, die man dadurch erschafft.
Stelen wir uns folgendes Szenario vor:
Wir haben ein Code-Fragment geschrieben, welches die Verbindung zu einem IMAP-Server aufbaut, eine Liste der ungelesenen E-Mails erstellt und die Verbindung wieder schließt. Diese Funktion benötigen wir an einer anderen Stelle in einer anderen Klasse nochmal, also wird das Code-Fragment einfach kopiert. Nach einiger Zeit fällt auf "Ups, hab die Zeile, mit dem close-Aufruf vergessen zu kopieren …". Diese wir dann noch schnell hinterhergeworfen und direkt haben wir den ersten Fehler: Beim Kopieren wurde das Code-Fragment verändert weil ein Teil nicht mitkopiert wurde.
Zwei Monate später, soll ein Kollege einen Bugfix an diesem Code-Fragment durchführen. Er weiß in welcher Datei und in welcher Zeile der Fehler aufgetreten ist, öffnet diese Datei, korrigiert die Zeile, schließt die Datei, führt ein commit durch und damit wars das. Und hier haben wir direkt das nächste Problem: Dieses Code-Fragment, welches gerade korrigiert wurde, kommt (mit genau dem gleichen Fehler) noch an mindestens einer weiteren Stelle im Code vor. Dieser redundante Code wurde nicht korrigiert, entsprechend unterscheiden sich diese beiden Code-Fragmente, welche exakt die gleiche Aufgabe haben, nun voneinander: es herrscht Inkonsistenz.
Der entsprechende Entwickler hätte nun also prüfen müssen, ob dieses Snippet noch öfter vorkommt und entsprechend jede Instanz mit dem Bugfix versehen müssen. Oder das ganze einem Refactoring unterziehen müssen. Beides bedeutet zusätzlicher Aufwand und zwar mehr als es gekostet hätte es direkt ordentlich zu machen.
Ein Tool, das beim Finden von doppelten Code-Fragmenten hilft, ist die so genannte Copy'n'Paste-Detection. Dies ist in den meisten Continous Integration Systemen enthalten und hilft ungemein, den Code zu verbessern.
Fazit: Doppelte Code-Fragmente, welche durch Copy'n'Paste quer im Projekt verteilt werden, erzeugen schnell Inkonsistenzen, erhöhen die Fehleranfälligkeit und sind Gift für die Wartbarkeit eines Projekts. Bei jedem Programmierer sollten also alle Alarmglocken läuten, wenn er die selbe Funktionalität mehr als einmal benötigt. Hier sollte immer eine neue Methode/Funktion implementiert werden.



Daniel says:
Sehr guter Artikel, danke. Ich kenne dieses Prinzip, bin aber der Meinung, dass ich es erst ab zwei Wiederholungen einsetzen sollte. Mein Problem mit DRY ist die zusätzliche Abstraktionsebene, die erst ab einem gewissen Zeitpunkt sinnvoll ist.
Bei einer Wiederholung kommen die verwendeten Stellen und Zeilen so in meine Dateien:
/* DUPLICATE CODE: project/path/file.php @ Line 92 */
in die andere Datei kommt der Gegenpart.
Bei einer Wiederholung ist das ok, bei mehr kann ich dann problemlos erkennen wo ich eine weitere Abstraktionsebene einführen muss. Viele Abstraktionsebenen machen ein Programm dazu nicht unbedingt lesbarer. Man sollte dabei immer den Aufwand/Nutzen im Auge behalten.
ghost says:
Danke.
Das Argument mit den Abstraktionseben ist natürlich vollkommen richtig. Je mehr Klassen/Methoden/Funktionen beteiligt sind, desto schwerer ist es ein Programm zu lesen.
Das ist auch tatsächlich die Schattenseite von DRY. Bleibt abzuwägen, was man lieber in Kauf nimmt: Zusätzliche Abstraktionsebenen oder doppelten Code