5 Developer-Unsitten

Was Entwickler dringend abstellen sollten

01.08.2024
Von 
Jens Bürger ist IT-Consultant bei der Conciso GmbH. Der Autor ist seit über 15 Jahren in der Software-Entwicklung tätig. An der TU Dortmund und der Universität Koblenz-Landau hat er zu langlebigen Softwaresystemen geforscht und ist im Projektgeschäft vielfach mit dem Abbau technischer Schulden betraut.
Diese schlechten Entwickler-Angewohnheiten führen in Softwareprojekten schnell zu dauerhaften und kostspieligen Problemen.
Oft sind es kleine Dinge (respektive Unsitten) die im Bereich der Softwareentwicklung für nachgelagerte Probleme sorgen.
Oft sind es kleine Dinge (respektive Unsitten) die im Bereich der Softwareentwicklung für nachgelagerte Probleme sorgen.
Foto: Jacob Lund - shutterstock.com

Entwickler können vielen Problemen in Softwareprojekten ohne großen Aufwand aus dem Weg gehen - wenn Sie sich bestimmte Unsitten ab- beziehungsweise gar nicht erst angewöhnen. Die folgenden fünf beispielsweise, die regelmäßig zu technischen Schulden und damit verbundenem, weiterem Übel führen.

1. TODO-Flickenteppich im Quellcode

Es kommt immer wieder vor, dass Code, der im Rahmen eines Tickets entstanden ist, nicht hundertprozentig fertig ist. Die Gründe dafür sind vielfältig: Übergangslösungen, die zum Beispiel aufgrund externer Abhängigkeiten gebaut werden mussten oder Library-Funktionen, für die ein Workaround erforderlich ist.

Der erste Schritt, derartige Stellen im Code mit einem TODO zu kennzeichnen, ist richtig. In der Hektik des Alltags kann ein solcher Kommentar mitunter sehr knapp ausfallen. So kann es dazu kommen, dass im Laufe der Zeit immer mehr TODOs auftauchen. Manchmal handelt es sich bei den Kommentaren aber auch schlicht um Überbleibsel aus der Entwicklungsphase eines Tickets, das das Code Review überstanden hat.

Problem: TODO-Kommentare zeigen an, dass es im Code noch etwas zu tun gibt. Egal, ob agiles oder klassisches Projektmanagement: Die Personen, die entscheiden, was als nächstes zu tun ist, sind nicht einzelne Entwickler. Solche "Restarbeiten" müssen den Entscheidern sichtbar gemacht werden, damit sie den Überblick behalten und gezielt Raum für Wartungsarbeiten, Rückbau von Workarounds oder Ähnliches geben können. Oft manifestiert sich ein Problem auch nicht nur an einer einzigen Stelle im Code, sondern es gibt einen größeren Zusammenhang. Dieser lässt sich mit vereinzelten TODOs im Code kaum sinnvoll herstellen.

Tipp: TODO-Kommentare sind ein erster wichtiger Schritt, um darauf aufmerksam zu machen, dass es noch etwas zu tun gibt. Sobald sich abzeichnet, dass ein TODO über die Implementierung des Tickets hinaus Bestand haben wird, sollte ein neues Ticket angelegt werden. Das schafft einen Anker, über den man alle TODOs als zueinander zugehörig kennzeichnen kann. Wenn TODO-Kommentare zudem immer nach der gleichen Syntax aufgebaut sind, lassen sich mit einer IDE sehr einfach finden. TODOs, die während der Entwicklung entstehen, sollte man ebenfalls umgehend mit der Ticket-ID versehen. Das beschleunigt die Eigenkontrolle und das Code Review.

2. Code-Dokumentation zum Selbstzweck

Ein dokumentierter Sourcecode ist wichtig - so wird es immer wieder gepredigt. Tools für statische Codequalitätsanalysen werden gern mit Regeln bestückt, die vollständig kommentierte Methodensignaturen und Attribute erwarten.

// the name

private String name;

Problem: Dokumentation sollte nie zum Selbstzweck erfolgen. Ein nichtssagender Kommentar schadet im Zweifel eher. Denn der Code wirkt dann so, als wäre er dokumentiert (was durch statische Analysen so auch bestätigt wird). Faktisch kann ein Teammitglied jedoch nichts aus dem Kommentar lernen, was nicht auch dadurch klar wird, dass Attributnamen und Methodensignaturen gelesen werden.

Tipp: Nur Code-Dokumentation, die substanziell zum Verständnis des Codes beiträgt, hat einen Wert. Sie sollte nicht erst dann erfolgen, wenn ihre Nichtexistenz durch ein Codequalitäts-Tool auffällt. Daraus können Entwickler auch eine persönliche Herausforderung machen: Ein Feature ist dann gut implementiert, wenn die Qualitätsanalyse keine fehlenden Kommentare bemängelt. Ebenso kann man gezielt Code Reviews für Tickets in Bereichen des Projektes durchführen, in denen man sich selbst nicht so gut auskennt. So lässt sich auf Basis der Dokumentation ein Bild davon erlangen, welches Verhalten man von einer bestimmten Methode erwartet - bevor man sich mit der Implementierung beschäftigt.

3. Knowhow im Silo aufbauen

"Klaus, du bist doch der Experte für Message Queues. Das Ticket 4711 dreht sich um Message Queues, möchtest du das dann übernehmen?" - ein Satz, wie er in Sprint-Plannings immer wieder fällt. Es lässt sich nicht vermeiden, dass es Themenkomplexe gibt, die manchen Teammitgliedern mehr liegen als anderen oder in denen ein Teammitglied Erfahrung aus Vorgängerprojekten mitbringt. Da Klaus immer wieder Aufgaben zu seinem Lieblingsthema bearbeitet, wird er darin gut und effizient. Das Team weiß, dass es sich auf ihn verlassen kann, weil er Themen auf "seinem" Gebiet schnell zum Erfolg bringt.

Problem: Wenn Aufgaben aus einem Themenbereich immer wieder oder gar ausschließlich dieselbe Person im Team bearbeitet, bilden sich Wissensinseln aus. Die Fallhöhe steigt mit der Zeit, und das Team hat keine Chance, gemeinschaftlich Expertise aufzubauen. Code Reviews gestalten sich zunehmend schwierig, wenn nicht noch mindestens eine zweite Person im Team ist, die ähnlich viel Wissen vorweisen kann. Fehlt der Experte zeitweise oder dauerhaft, ist es sehr aufwändig, den Rückstand aufzuholen, und das kann zu kritischen Situationen führen.

Tipp: Experten ohne Backup auszubilden, ist unbedingt zu vermeiden. Andere Teammitglieder sollten gezielt mit einbezogen werden - zum Beispiel, indem Tickets kleiner geschnitten werden. So können sich auch Nicht-Experten mit Basisarbeiten oder Teilaspekte davon befassen. Eine solche Wissensstreuung lässt sich aktiv fördern, indem Tickets beispielsweise im Pair Programming bearbeitet werden.

4. (Noch) nicht benötigte Strukturen coden

Ein Softwareprojekt lebt von Struktur und Ordnung. Der berühmte "Spaghetticode" ist dabei eher kontraproduktiv und führt zu vielen Problemen. Wird bei der Implementierung eines neuen Features festgestellt, dass es sich in die bestehende Infrastruktur nicht so recht einfügen lässt, ist man daher schnell geneigt, "Unordnung" gar nicht erst aufkommen lassen zu wollen. Statt einfach nur eine Klasse zu implementieren, wird zuallererst ein Interface definiert. Die Klasse selbst ist dann vielleicht nicht nur die Implementierung des Interfaces, sondern das Problem lässt sich in verschiedenen Dimensionen kapseln und generalisieren. Statt eines Interfaces gibt es dann vielleicht eine Interface-Hierarchie, und auch bei Klassen lassen sich mit Generalisierung und abstrakten Klassen noch diverse "Abzweigungen" nehmen. Am Ende ist das Feature komplett durchstrukturiert, in alle denkbaren Richtungen von seiner Umgebung abstrahiert und generalisiert.

Problem: Implementiert man ein Feature, das im Code einen neuen Teilbereich eröffnet, ist vielleicht gar nicht klar, ob das lange Bestand haben wird. Und selbst wenn sich abzeichnet, dass in Zukunft noch weitere Anwendungen folgen, ist das nicht notwendigerweise jetzt der Fall. Dennoch hat man bereits eine Last erzeugt, die mindestens Debugging und Wartung erschwert. Der "Sweet Spot" zwischen zu wenig und zu viel Struktur wird oft nicht getroffen.

Tipp: Je einfacher, desto besser. Martin Fowler hat in seinem Buch die "Rule of three" vorgeschlagen, dort eigentlich im Zusammenhang mit Refactoring-Tätigkeiten. Diese direkt bei der Codeerstellung anzuwenden, ist empfehlenswert. Sind drei Anwendungen für die angedachte Struktur nicht absehbar? Dann sollte man erst einmal ohne arbeiten und den Aufwand für eine Struktur verschieben, bis die dritte Anwendung konkret dazu kommt. Bis dahin ist das Produkt gegebenenfalls auch anderweitig gereift und es ist klarer, was benötigt wird.

5. Commit-Messages für Eingeweihte

Es ist schon eine Menge geschafft und jetzt Zeit, die Änderungen zu committen. "Was habe ich denn verändert?", mag die Frage lauten, die sich anbietet, und so scheint es naheliegend, genau das auch knapp in die Commit-Message zu schreiben. Aber ist das wirklich zielführend?

Problem: Wenn Recherche im Code erforderlich ist und die Frage "Wie kam es dazu?" gestellt wird, ist die Git-Historie eines der zentralen Werkzeuge. Das ist aber nur hilfreich, wenn die Commit-Messages sinnvolle Inhalte enthalten. Vor allem rein technische, deskriptive Commit-Messages wie "Klasse XY angelegt" oder "Konfiguration aktualisiert" bieten keinen Mehrwert. Sie beschreiben lediglich das "Was", aber nicht das "Wie" oder "Warum".

Tipp: Jede Commit-Message sollte mit der Ticket-ID beginnen, in deren Rahmen der Commit entstanden ist. Wird ein Code-Stück in einem Debugging relevant, hat man so direkt die Information, im Rahmen welches Tickets die Änderung entstanden ist und kann sich dort weitere Informationen einholen. Als Kompromiss haben sich Conventional Commits bewährt. Werden in der verbreiteten Arbeitsweise mit Git Feature-Branches per Merge integriert, dann lassen sich einem ehemaligen Feature-Branch zugehörige Commits nicht mehr zuordnen. Auch hier ist ein "Ticket-ID-Präfix" in jeder Commit-Message hilfreich und vereinfacht Suchen deutlich. (mb/fm)