Wie man sauberen Code schreibt und Java-Code-Standards durchsetzt
Heute ist mein letzter Arbeitstag bei AndroidPIT. Nachdem ich AndroidPIT aufgebaut und zehn Jahre lang weiterentwickelt habe, habe ich mich vor einigen Monaten entschieden, mich als freiberuflicher Programmierer selbstständig zu machen, um neue Erfahrungen zu sammeln.
Nachdem ich 2009 für ein paar Monate allein programmiert habe, haben wir kurz darauf begonnen zusätzliche Programmierer einzustellen. In einem Team zu arbeiten war etwas ganz anderes, denn plötzlich haben Entwickler mit unterschiedlichen Programmierstilen und unterschiedlichen Erfahrungen am gleichen Code gearbeitet. In Code Reviews waren wir einen Großteil der Zeit damit beschäftigt den Code Style zu vereinheitlichen und immer wieder ähnliche Typen von Fehlern zu beheben.
Grund genug, um zu prüfen, ob diese Arbeit irgendwie automatisiert werden kann.
Was sind die Herausforderungen im einzelnen?
Herausforderungen
Kein einheitlicher Coding Standard
Vielleicht kennt ihr das Problem: In eurem Entwicklerteam gibt es keine Code-Style-Vorgabe – oder es gibt welche, aber nicht jeder Entwickler hält sich daran. Das hat zur Folge, dass man mehr Zeit braucht, um dem Code eines anderen Entwicklers zu verstehen und dass ein Großteil eines Reviews "verschwendet" wird, um den Code an die Stilvorgaben anzupassen.
Zwar kann jede moderne IDE den Code automatisch formatieren, aber auch das muss erst einmal von jedem Entwickler im Team konfiguriert werden.
Nicht wartbarer oder fehlerhafter Code
Ein weiteres Problem ist, dass Entwickler in Teams unterschiedlich große Erfahrung haben, was z. B. Software Craftsmanship und Clean Code betrifft. Und Fehler macht sowieso jeder Mensch. D. h. der Programmcode ist unter Umständen fehlerhaft, nicht gut lesbar und/oder schlecht wartbar.
Sicherheitslücken im Code
In den meisten Entwicklerteams sitzen keine Sicherheitsexperten. Somit verursacht Programmcode oft Sicherheitslücken in der Anwendung, die unter Umständen zu schwerwiegenden Datenschutzverletzungen führen können. Und selbst wenn Sicherheitsexperten vorhanden sind, sind auch sie nur Menschen und können Fehler übersehen, oder stehen einfach vor einer so großen Codebasis, dass diese nur mit extrem hohem Aufwand detailliert geprüft werden kann.
In dieser Artikelserie werde ich folgende Fragen klären:
- Wie die Einhaltung von Coding-Style-Vorgaben sichergestellt wird
- Wie Code-Qualität verbessert und damit die Wartbarkeit erhöht wird
- Wie Softwaresicherheit erhöht und Angriffspunkte minimiert werden
Klassische Lösung: Code Reviews
Die klassische Herangehensweise, um diese Probleme zu lösen, sind regelmäßige Code Reviews. Diese sind im besten Fall Teil der "Definition of Done", d. h. kein Task ist erledigt, solange der zugehörige Programmcode nicht von einem zweiten Entwickler geprüft wurde.
Code Reviews haben allerdings – so wichtig sie auch sind – die folgenden Nachteile:
- Sie sind langwierig, aufwändig und damit teuer. Und Spaß machen sie auch nur selten. Somit werden sie – insbesondere unter Zeitdruck (unter dem wir ja ständig stehen) – entweder gar nicht gemacht oder zumindest gelegentlich ausgelassen. Besonders dann, wenn es sich entweder um sehr komplexe Änderungen handelt – oder um kleine Änderungen an bereits überprüften Codestellen.
- Sie sind fehleranfällig, da der Reviewer auch nur ein Mensch ist – mit mehr oder weniger Erfahrung – und in den allermeisten Fällen kein Security-Experte.
- Sie erfordern mindestens zwei Programmierer im Team, die sich mit der Technologie auskennen. Wobei dies optimalerweise gegeben sein sollte, um den “Bus-Faktor” (das Risiko, dass ein ausfallender Mitarbeiter das Projekt gefährdet) zu reduzieren.
Code Reviews lassen sich glücklicherweise ziemlich gut automatisieren. Die Technik hierfür lautet “Statische Code-Analyse” (englisch: “static program analysis” oder “static code analysis”).
Für die statische Code-Analyse gibt es zahlreiche sehr gute Open Source Tools, die alle zuvor genannten Probleme adressieren. Ich werde sie im dritten Teil dieser Serie detailliert vorstellen.
Hat man die entsprechenden Tools einmal aufgesetzt, können sie den Sourcecode rasend schnell überprüfen und dem Entwickler zahlreiche Empfehlungen zur Verbesserung geben – im Hinblick auf Coding Style, auf potentielle Fehler, auf Bad Practices, auf schlechte Wartbarkeit und auf potentielle Sicherheitslücken.
Was genau ist Statische Code-Analyse?
Statische Code-Analyse bezeichnet die Analyse einer Software ohne dass diese dazu ausgeführt wird. Dies geschieht durch automatisierte Untersuchung des kompletten Quelltexts im Hinblick auf einen Satz zuvor festgelegter Regeln und mit anschließender Benachrichtigung der Programmierer über die gefundenen Regelverstöße.
Die meisten statischen Code-Analyse-Tools können als Plugins in die Entwicklungsumgebung integriert werden und dort die Regelverstöße direkt im Quellcode markieren. Dies ist eine sehr mächtige Funktion, da der Entwickler so bereits während der Programmierung sofortiges Feedback über mögliche Schwachstellen oder Bad Practices erhält. Werden diese später im Entwicklungszyklus gefunden, ist die Behebung deutlich aufwändiger und damit teurer.
Ebenso können statische Code-Analyse-Tools in automatisierte Build-Prozesse integriert werden, Reports und Alerts generieren und – in Abhängigkeit von der Konfiguration – den Build fehlschlagen lassen.
Statische Code-Analyse ist somit ein sehr effektiver, automatisierter Code-Review-Prozess. Das heißt nicht, dass sie manuelle Reviews ersetzen kann. Erstens kann statische Code-Analyse nicht 100 % aller Fehler erkennen (u. a. da sie die funktionalen Anforderungen an die Software gar nicht kennt) und zweitens ist es wichtig, dass das Wissen über den Code im Team geteilt wird.
Vorteile von Statischer Code-Analyse
Höhere Geschwindigkeit
Manuelle Code Reviews sind langwierig. Die große Stärke Statischer Code-Analyse liegt in der schnellen und automatischen Prüfung der gesamten Codebasis, ohne dass der Code ausgeführt werden muss. Somit sinkt der Aufwand für das Aufspüren von Problemen im Code deutlich.
Entlastung von Entwicklern
Manuelle Code Reviews spannen Entwickler ein. Durch die Automatisierung werden Entwickler entlastet und sie können sich stärker auf die Weiterentwicklung der Software fokussieren.
Ausgezeichnete Skalierung
Statische Code-Analyse kann in den Continuous Delivery Prozess integriert und somit regelmäßig vollautomatisch ausgeführt werden. Wird ein Tool um die Erkennung neuer Probleme erweitert, können diese umgehend in der gesamten Codebasis aufgespürt werden.
Auffinden von Problemen früh im Entwicklungsprozess
Je früher ein Fehler gefunden wird, desto niedriger sind die Kosten für dessen Beseitigung. Durch die Integration der Statischen Code-Analyse-Tools in die IDE können Probleme sehr früh, nämlich bereits während der Programmierung, erkannt und behoben werden. Entwickler werden direkt im Code darauf hingewiesen – mitsamt Erklärungen und Verbesserungsvorschlägen.
Genauigkeit
Durch die Automatisierung wird der vollständige Code überprüft – also auch Codestellen, die die Entwickler selten zu Gesicht bekommen. Außerdem können statische Code Analyse-Tools sämtliche Ausführungspfade einer Applikation analysieren und überprüfen – einschließlich derjenigen, die durch Tests nicht abgedeckt sind. Menschliche Fehler können zwar bei der Konfiguration der Tools gemacht werden, nicht aber bei deren Ausführung.
Bessere Qualität bei niedrigeren Kosten
Letztendlich führen alle zuvor genannten Vorteile zu einer besseren Code- und Produktqualität bei niedrigeren Kosten für das gesamte Entwicklungsprojekt. Durch die kontinuierliche Auslieferung von sicherer, verlässlicher und wartbarer Software erhöht sich die Reputation der Entwickler und des Unternehmens, für die diese arbeiten.
Nachteile von Statischer Code-Analyse
Vorlaufkosten
Statische Code-Analyse-Tools müssen evaluiert, erlernt, installiert und konfiguriert werden. Diese Kosten werden sich allerdings nach nur wenigen Wochen amortisieren. Diese Artikelserie soll helfen die Vorlaufzeit und -kosten zu minimieren.
Rollout-Strategie nötig bei Anwendung auf bestehende Codebasis
Wenn man Werkzeuge zur statischen Code-Analyse auf bestehenden Code anwendet, werden unter Umständen Tausende von Problemen angezeigt. Das führt normalerweise dazu, dass Entwickler diese Meldungen einfach ignorieren. Daher ist eine Rollout-Strategie nötig. Am besten priorisiert man die Problemtypen und blendet zunächst nur die am höchsten priorisierten ein. Und erst wenn diese komplett behoben wurden, wird die nächstwichtige Kategorie eingeblendet und bearbeitet.
Nicht alle Fehler werden automatisch erkannt (“false negatives”)
Styleguide-Verstöße oder bestimmte Fehlermuster können zuverlässig erkannt werden. Sicherheitsprobleme hingegen – bspw. im Authentifizierungsprozess, neu aufgedeckte Sicherheitslücken in externen Libraries, neue Angriffsmuster oder fehlerhafte Konfiguration außerhalb des Quellcodes – sind schwer zu finden. Auch Fehler in der Implementierung von nebenläufigem Code, die zu Race Conditions führen können, sind durch statische Code-Analyse schwer aufzudecken.
Korrekter Code kann als fehlerhaft erkannt werden ("false positives")
Gelegentlich kommt es vor, dass korrekter Code als fehlerhaft markiert wird. Dies passiert, wenn ein Tool "unsicher" ist, bspw. wenn die Integrität von Eingabedaten nicht überprüfbar ist oder die Anwendung mit Closed-Source-Komponenten interagiert.
Was ist Dynamische Code-Analyse?
Während der Fokus dieser Artikelserie auf statischer Code-Analyse liegt, möchte ich sie zumindest in einem Satz von der dynamischen Code-Analyse abgrenzen: Im Gegensatz zur statischen Code-Analyse, welche Programmcode prüft ohne ihn auszuführen, setzt die dynamische Code-Analyse während der Laufzeit an und prüft Code während der Ausführung. Hierzu gehören bspw. Unit-Testing und Profiling.
Zusammenfassung und Ausblick
In diesem Artikel habe ich Herausforderungen bei der Softwareentwicklung beschrieben, die klassischerweise durch Code Reviews gelöst werden. Da manuelle Code Reviews aufwändig und teuer sind, können sie durch Werkzeuge zur Statischen Code-Analyse unterstützt werden.
Im nächsten Artikel werde ich erklären, welche Arten von Statischer Code-Analyse es gibt und wie man mit diesen die genannten Herausforderungen adressiert. Konkret werden folgende Fragen beantwortet:
- Wie stelle ich einen einheitlichen Coding-Standard sicher?
- Wie finde ich potentielle Fehler im Code?
- Wie verbessere ich Codequalität und Wartbarkeit?
- Wie minimiere ich potentielle Sicherheitsschwachstellen?
Im dritten und abschließenden Teil der Serie werde ich die relevantesten kostenlosen Java-Tools zur Statische Code-Analyse im Detail vorstellen.
Falls du jemand anderen kennst, der sich für diesen Artikel interessieren könnte, dann freue ich mich wie immer sehr, wenn du ihn über einen der folgenden Buttons teilst.