Es ist ein Klassiker in der täglichen Entwicklungsarbeit: Copy & Paste. Jeder hat schon häufiger Snippets von Stack Overflow übernommen. Aber Duplikate entstehen auch um Dinge aus der Codebasis wiederzuverwenden, die nicht direkt erreichbar sind – sei es aufgrund von Abhängigkeiten oder fehlenden Schnittstellen. Es geht schnell und die akuten Aufgaben oder Probleme sind gelöst. Doch auf lange Sicht birgt es die Gefahr der Erosion der Codebasis.
Wann ist doppelter Code ein Problem?
Jeder Entwickler hat das DRY-Prinzip (Don’t Repeat Yourself) verinnerlicht und hat eine antrainierte Abneigung gegen doppelten Code. Dieses Prinzip gleicht schon fast einem Mantra, so dass Entwickler normalerweise doppelten Code durch Refactorings beseitigen. Aber nicht immer ist doppelter Code ein Problem. Es gibt noch weitere Prinzipien aus der Clean Code Community, die ebenfalls beachtet werden müssen. Weitere Abstraktion und Wiederverwendung macht den Code eben auch komplizierter. Das heißt man sollte nicht gleich bei jeder Dopplung entrüstet aufspringen. Wiederverwendung hat ebenfalls seinen Preis, es gilt jeden Fall gesamthaft zu betrachten.
In unseren Fall ist Dopplung ein bewusstes Pattern in der Entwicklung von Versicherungsprodukten. Die Kalkulation von Versicherungsprodukten folgt oft ähnlichen Prinzipien und Abläufen, ist aber in den Details immer ein bisschen anders. Dem begegnen wir dadurch, dass wir hier flexibel die konkreten Formeln verknüpfen können. Allerdings gilt auch, dass die Kalkulation von produktiven Versicherungsprodukten im Nachhinein nicht mehr geändert werden darf. Wenn wir also in neuen Produkten nun eine etwas abweichende Kalkulation brauchen, kommt es immer mal wieder vor, dass es eine bestehende Formel erweitert werden muss. Sobald dies zu große Eingriffe erfordert, wird auch aus Risikogründen die Formel kopiert und dann angepasst.
Wie kann ich doppelten Code finden?
Das klappt natürlich gut für die Neuentwicklung, die dadurch beschleunigt wird. Über die Zeit häufen sich jedoch ähnlichen Klassen, die das Gesamtsystem komplexer machen. Jeder Entwickler hat auch sein eigenes Maß, wann es sich lohnt neue Kopien anzulegen oder doch bestehenden Code anzupassen. Reviews helfen hier zwar, eine bessere gemeinsame Sicht zu bekommen. Aber auch andere Faktoren – wie der aktuelle Projektdruck – beeinflussen die Entscheidung.
Mein Ziel ist es, die Dopplungen statistisch auszuwerten und den Entwicklungsteams transparent zu machen, damit hier eine sinnvolle Diskussion entstehen kann. Auf der Suche nach einem Werkzeug um Code Dopplungen zu finden, habe ich mich nach freien Werkzeugen umgeschaut.
Jscpd- One to Rule Them All
Jscpd findet doppelte Codeblöcke in der Codebasis. Dabei ist die Sprache relativ egal – 150 Programmiersprache bzw. Datenformate werden unterstützt. Es lässt sich steuern, wie „sensibel“ jscpd auf Dopplungen reagiert. Letztlich ist jscpd über npm installierbar und lässt sich über die Kommandozeile nutzen:
Jscpd braucht nur einen Pfad und ein Pattern der Dateien, die es scannen soll. Die Option -l beispielsweise steuert, dass eine Dopplung erst ab 5 ähnlichen Zeilen erkannt wird. Neben der Auflistung aller erkannten Kopien, gibt jscpd auch eine Statistik aus. Damit lassen sich gut Auswertung über die verschiedenen Module über die Zeit machen.
Allerdings hat jscpd nicht besonders viel semantische Logik, es arbeitet aus meiner Sicht mit einer reinen text- bzw. tokenbasierten Erkennung auf Basis des Rabin-Karp-Algorithmus. Das führt zum Beispiel dazu, dass auch 5 gleiche Import-Blöcke als Kopie erkannt wird. Das kommt aber durchaus auch häufiger vor, wenn z.B. zentrale Framework-Klassen genutzt werden.
PMD CPD – Der Klassiker
PMD zur statischen Codeanalyse kennen vermutlich die meisten. Was zumindest mir nicht bewusst war: PMD bietet mit CPD auch einen Copy & Paste Detektor.
Auch hier muss neben dem Pfad angegeben werden, wie sensibel CPD reagieren soll. Außerdem sind verschiedene Formate vorgesehen, die ausgegeben werden können. CPD bietet leider keine statistische Zusammenfassung wie jscpd. Dafür ignoriert CPD aber unwichtige Tokens wie Import Statements oder auch Package Deklarationen.
Duplicate Code Detection Tool – Alle guten Dinge sind 3
Einen ganz anderen Ansatz für die Darstellung und Auswertung wählt dieses Python-Skript. Zu jeder Datei wird angezeigt, wie ähnlich anderen Dateien in der Codebasis sind. Es zeigt also nicht die konkret erkannten Zeilen oder Tokens, sondern liefert eher eine statistische Auswertung.
Die Option ignore-threshold hilft gerade bei einer großen Codebasis mit sehr vielen Dateien, so dass in diesem Fall nur die Dateien aufgelistet werden, die mehr als eine 10%-ige Ähnlichkeit haben. Ansonsten wird die Ausgabe sehr groß und unübersichtlich.
Nur ein Anfang
Es gibt zahlreiche Werkzeuge um sich dem Problem zu nähern. Es gibt sicher noch mehr, zum Teil auch proprietäre Tools. Auch moderne IDEs können hier unterstützen. Vermutlich kann auch eine Kombination sinnvoll sein, je nachdem, was genau man braucht. Das Tool ist natürlich nur der Anfang, letztlich müssen wir uns jetzt überlegen, was diese Zahlen für uns bedeuten und was wir damit machen. Das ist dann was für einen weiteren Blog-Artikel.
Welche Tools nutzt ihr? Lasst es mich gerne wissen auf LinkedIn.