12 Aspekte für bessere Software

Teams und Unternehmen, die die Qualität ihrer Softwareentwicklung verbessern wollen, finden wertvolle Hilfe in den 12 Aspekten aus dem "Joel Test".

In Pocket speichern vorlesen Druckansicht 2 Kommentare lesen
Lesezeit: 14 Min.
Von
  • Golo Roden
Inhaltsverzeichnis

Viele Teams und Unternehmen fragen sich regelmäßig, wie sie die Qualität ihrer Softwareentwicklung verbessern können. Die Antwort auf diese Frage umfasst 12 Aspekte, die jedes Team und jedes Unternehmen umsetzen sollte. Welche Aspekte sind das, worauf ist bei ihrer Implementierung zu achten, und warum sind sie wichtig?

Viele Teams und Unternehmen fragen sich regelmäßig, wie sie die Qualität ihrer Softwareentwicklung verbessern können. Die Antwort auf diese Frage fällt unterschiedlich aus, nämlich in Abhängigkeit davon, wie bereits entwickelt wird. Trotzdem gibt es 12 Aspekte, die jedes Team und jedes Unternehmen umsetzen sollte.

Diese Aspekte klingen in der Theorie zunächst einfach, doch die Umsetzung in der Praxis gestaltet sich oft schwieriger als gedacht. Teams und Unternehmen können sie als Messlatte annehmen, um eine Selbsteinschätzung vorzunehmen, und um die Qualität der eigenen Softwareentwicklung zu hinterfragen und zu bewerten.

Empfohlener redaktioneller Inhalt

Mit Ihrer Zustimmmung wird hier ein externes YouTube-Video (Google Ireland Limited) geladen.

Ich bin damit einverstanden, dass mir externe Inhalte angezeigt werden. Damit können personenbezogene Daten an Drittplattformen (Google Ireland Limited) übermittelt werden. Mehr dazu in unserer Datenschutzerklärung.

Das Ganze ist in Anlehnung an den "Joel Test" entstanden, der von Joel Spolsky (dem ehemaligen CEO von StackOverflow) entwickelt wurde. Dieser Test stammt bereits aus dem Jahr 2000 und ist daher inzwischen nicht mehr zeitgemäß, doch die grundlegende Idee ist nach wie vor gut. Insofern war es an der Zeit, diesen Test zu modernisieren.

Der erste Aspekt ist die Frage, ob im Team wirklich verstanden wurde, worum es aus fachlicher Sicht geht? Das heißt, gibt es Domänenexpertinnen und -experten im Team, und bestehen ein gemeinsames fachliches Verständnis und eine gemeinsame fachliche Sprache? Lässt sich sicherstellen, dass alle im Team beteiligten Personen tatsächlich miteinander reden, statt aneinander vorbei?

All diese Fragen mögen überraschen, tatsächlich kommt es in der Praxis aber relativ selten vor, dass ein Team derart interdisziplinär aufgestellt ist. Weitaus häufiger trifft man auf ein reines Entwicklungsteam, das von der Fachabteilung isoliert ist und irgendwie vor sich hin arbeitet. Obwohl auf der Hand liegt, dass das nicht gut funktionieren kann, ist es vielfach gängige Praxis.

Der Grund, warum das auf dem Weg nicht funktionieren kann, ist, weil Software entwickelt wird, um fachliche Probleme zu lösen und nicht um der Technologie Willen. Deshalb ist gute Softwareentwicklung nicht ohne detailliertes Fachwissen der zu Grunde liegenden Domäne möglich.

Wenn die Fachlichkeit verstanden wurde und ein gemeinsames fachliches Verständnis und eine gemeinsame fachliche Sprache entwickelt wurden, kommt der zweite Aspekte hinzu: Werden die fachlichen Anforderungen "gut" formuliert und aufgeschrieben? "Gut" bedeutet an dieser Stelle, dass die Anforderungen verständlich, zielführend, kompakt und vollständig sind.

In der Praxis ist immer wieder überraschend, wie wenig auf diese Punkte geachtet wird – oder, was noch schlimmer ist, wie häufig ohne jegliche fachlichen Anforderungen entwickelt wird. Das bedeutet dann üblicherweise, dass man sich darauf verlässt, dass die Entwicklerinnen und Entwickler sich das Besprochene gemerkt und es auch richtig interpretiert und verstanden haben.

Hält man die Intention der Anwenderinnen und Anwender nicht fest, fehlt in der Entwicklung dementsprechend der rote Faden, es gibt keine Abnahmekriterien und es wird letztlich auf Zuruf entwickelt, was praktisch nicht funktioniert.

All das nützt allerdings nur dann etwas, wenn die Arbeit im Anschluss auch strukturiert erfolgt – also nicht, wie gerade erwähnt, auf Zuruf. Für die meisten Teams bedeutet das, in Sprints zu arbeiten, was nicht zuletzt der Verbreitung von Scrum geschuldet ist. Allerdings weisen Sprints auch zahlreiche Nachteile auf, insbesondere ihre Planbarkeit betreffend.

Da der zeitliche Umfang eines Sprints per Definition festgelegt ist, muss gemäß dem magischen Dreieck (beziehungsweise dem Teufelsquadrat) der inhaltliche Umfang flexibel sein, soll die Entwicklung im Zweifelsfall nicht zu Lasten der Qualität gehen.

Genau das ist jedoch häufig nicht der Fall, da für einen Sprint in aller Regel konkrete Stories eingeplant werden. Das wird spätestens dann zum Problem, wenn Unvorhergesehenes passiert, also beispielsweise kritische Fehler auftreten, die sofort behoben werden müssen.

Daher ist es eine gute Idee, nicht in Sprints, sondern auf der Basis kontinuierlicher Streams, ähnlich wie in Kanban, zu arbeiten. Das bringt nämlich nicht nur Ruhe in die Entwicklung, sondern ermöglicht zugleich auch eine hohe Flexibilität und hervorragende Planbarkeit.

Der vierte Aspekt betrifft Technologieentscheidungen. Die sollten erst dann getroffen werden, wenn die fachlichen Anforderungen bekannt sind. In den meisten Fällen passiert das jedoch umgekehrt, da die einzusetzenden Technologien von Anfang an feststehen. Es wird nicht evaluiert, welche Technologien sich besonders gut eignen würden und welche ihre Stärken besonders gut ausspielen könnten.

Das betrifft dabei nicht nur Programmiersprachen und Plattformen, sondern vor allem auch Infrastruktur, beispielsweise Datenbanken und Message Queues. Auch die Serverumgebung ist häufig von Anfang an in Stein gemeißelt, weil zum Beispiel bereits feststeht, dass nicht mit Containern und Kubernetes gearbeitet werden kann.

In gewissem Sinne ist das auch in Ordnung, da man ansonsten Gefahr läuft, sich zu verzetteln. Es gilt aber, eine ausgewogene Balance zu finden zwischen der bereits bekannten Welt einerseits und neuen Ansätzen andererseits. Dazu gehört auch, Kosten und Nutzen neuer Technologien gegenüber den alten abzuwägen.

Kommt man dabei zum Ergebnis, beim bereits bekannten zu bleiben, ist das in Ordnung – aber es sollte eben eine bewusste, explizite Entscheidung sein.

In dem Zusammenhang fällt übrigens auch immer wieder auf, dass Lösungen zu kompliziert gedacht werden. Der fünfte Aspekt ist daher, zu versuchen, stets nach dem einfachsten Ansatz zu streben. Eine gute Prämisse ist an der Stelle "make simple things simple and complex things possible". Die meisten Werkzeuge scheitern in der Regel an mindestens einem von beidem.

Entweder sind sie nicht "simple", was die initiale Hürde hoch legt und damit den Einstieg erschwert, oder sie lassen per se keine komplexen Lösungen zu, was letztlich sogar noch schlimmer ist, da man sich auf dem Weg technologisch in eine Sackgasse manövriert. Werkzeuge, die beides erfüllen, sind selten. Daher ist es so wichtig, Technologien gezielt und bewusst auszusuchen.

Der sechste Aspekt sollte inzwischen eigentlich eine Selbstverständlichkeit sein, ist er aber leider immer noch nicht: nämlich der Einsatz einer zeitgemäßen Versionsverwaltung und einer passenden Branch-Strategie.

In der Formulierung sind letztlich drei Forderungen enthalten, nämlich erstens, dass überhaupt eine Versionsverwaltung zum Einsatz kommt, zweitens, dass sie zeitgemäß ist (also beispielsweise Git und nicht Subversion (SVN) oder der Team Foundation Server (TFS)), und drittens, dass ein Plan vorliegt, wie das Team mit Branches umgeht.

Das größte Problem in der Praxis ist dabei in der Regel der dritte Punkt. Allerdings lässt sich das verhältnismäßig einfach durch den Einsatz eines Standard-Verfahrens wie "git flow" lösen.

Der siebte Aspekt betrifft die Qualität, an der im Alltag häufig gespart wird – was allerdings ein gravierender Fehler ist. Der häufigste Grund, warum gespart wird, ist in der Regel die Zeit, weil eine höhere Entwicklungsgeschwindigkeit gewünscht wird. Warum ist das ein Fehler? Weil man damit eine Lose-Lose-Situation schafft.

Zum einen verlieren die Kundinnen oder Kunden, weil die Software die geforderten Qualitätsansprüche nicht erfüllt. Zum anderen verliert aber auch das Team, weil es ein instabiles Fundament aufbaut. Das Vorgehen wird in der Regel damit entschuldigt, dass man sich um die Qualität später kümmere – doch dabei werden direkt die nächsten beiden Fehler begangen.

Zum einen wird die falsche Annahme getroffen, dass später mehr Zeit für die Qualität zur Verfügung stünde, zum zweiten wird die ebenfalls falsche Annahme getroffen, dass Qualität ein Feature sei, das man später noch problemlos nachrüsten könne. Features lassen sich zwar tatsächlich auch im weiteren Verlauf nachrüsten, allerdings gilt das für Qualität nicht beziehungsweise nur mit enorm erhöhtem Aufwand und entsprechend hohen Kosten.

Eine Möglichkeit, umfassend zu hoher Qualität beizutragen, besteht darin, zunächst Fehler zu beheben bevor neue Funktionen entwickelt werden. Das ist vergleichbar mit dem Ansatz, sich zunächst um ein stabiles Fundament zu bemühen, bevor man darauf ein Haus errichtet. Eigentlich gebietet das bereits der gesunde Menschenverstand, dennoch trifft man das in der Praxis immer wieder anders an.

Der achte Aspekt betrifft die Qualitätssicherung. Wenn Code geschrieben wird, liegt der Fokus genau darauf, nämlich auf dem Schreiben an sich. Code wird allerdings nur einmal geschrieben, dafür aber umso häufiger gelesen, von ganz unterschiedlichen Personen. Das heißt, dass ein Team langfristig weitaus mehr Zeit mit dem Lesen als mit dem Schreiben von Code verbringt – beispielsweise bei jeder Änderung, Erweiterung oder Anpassung.

Die Lesbarkeit ist deshalb so wichtig, weil sie ein gutes Verständnis und eine hohe Nachvollziehbarkeit des Codes ermöglicht, doch ergibt sie sich nicht einfach so im Vorbeigehen. Vielmehr muss ganz gezielt und bewusst darauf geachtet werden, gute Lesbarkeit sicherzustellen. Das lässt sich entweder durch Reviews erreichen oder durch Pair-Programming, das nichts anderes als ein kontinuierlicher Review in Echtzeit ist.

Der neunte Aspekt führt das Vorangegangene noch einen Schritt weiter, indem er fordert, die Qualitätssicherung zu automatisieren. Als Entwicklerin und Entwickler beziehungsweise als Reviewerin und Reviewer sollte man sich auf das Wesentliche (also die korrekte Umsetzung der Fachlichkeit im Code) konzentrieren können. Worum es nicht oder zumindest kaum gehen sollte, ist die äußere Form des Codes, beispielsweise dessen Formatierung.

Die ist für die Lesbarkeit und Verständlichkeit des Codes zwar ebenfalls enorm wichtig, anders als die korrekte Umsetzung der Fachlichkeit lassen sich äußere Faktoren aber weitestgehend automatisiert überprüfen, beispielsweise durch den Einsatz einer statischen Codeanalyse wie ESLint.

Was ebenfalls dazu gehört ist das Schreiben und Ausführen von Tests, wobei es wiederum verschiedene Testarten wie Unit-, Integration-, Komponenten- und UI-Tests gibt. Das Ausführen der Tests sollte ebenfalls automatisiert erfolgen, da es nicht nur Zeit spart, sondern auch weniger fehleranfällig ist als testen von Hand.

Für all das verwendet man üblicherweise einen Buildserver beziehungsweise eine CI-Umgebung, die sich auch gleich für andere Dinge nutzen lässt, wie automatisierte Lizenzüberprüfungen der verwendeten Module.

Der zehnte Aspekt führt noch einen Schritt weiter: zum automatisierten Build und Deployment. Dabei wird die CI-Umgebung noch um Funktionen zum kontinuierlichen Deployment (CD) ergänzt, damit zum einen automatisch kompiliert und gebaut, zum anderen auch automatisch veröffentlicht und verteilt werden kann.

So lässt sich die Notwendigkeit einer manuellen Verteilung und Installation vermeiden, die häufig langsam, umständlich und fehleranfällig ist. Da man von Hand eher selten deployed, gerät jedes manuelle Deployment zu einem Risiko. Denn dabei ist die Wahrscheinlichkeit relativ hoch, dass etwas Unvorhergesehenes passiert und das Deployment fehlschlägt. Wenn man im Vergleich dazu jedoch mehrere Male pro Tag automatisiert deployed, verliert das Deployment seinen Schrecken.

Besonders gut funktioniert das aus naheliegenden Gründen mit Containern, Docker und Kubernetes, doch lässt sich ein automatisiertes Deployment prinzipiell auch mit herkömmlichen Techniken bewerkstelligen.

Auch der elfte Aspekt betrifft die Automatisierung, nämlich die automatisierte Verwaltung von Abhängigkeiten. Der Entwicklungsprozess bezieht sich in aller Regel nur darauf, was derzeit aktuell entwickelt wird. Viele Entwicklerinnen und Entwickler achten dabei sehr darauf, welche Abhängigkeiten sie initial eingehen, doch kaum jemand achtet langfristig darauf, diese Abhängigkeiten auch zu pflegen und zu aktualisieren.

Das ist jedoch enorm wichtig, da veraltete Abhängigkeiten ein potenzielles Sicherheitsrisiko darstellen. Die Frage lautet allerdings häufig, wer sich regelmäßig darum kümmern soll, sämtliche Abhängigkeiten zu überprüfen und gegebenenfalls zu aktualisieren.

Die einfache Antwort auf diese Frage: es gibt Werkzeuge wie Dependabot und Renovate, die sich im Hintergrund als Bot ausführen lassen und im Fall des Falles automatisch einen Pull Request schicken. Wenn dann auch die Qualitätssicherung automatisiert ist, weiß man direkt, ob die neuen Versionen der Abhängigkeiten funktionieren und ob man gefahrlos mergen kann oder nicht.

Der zwölfte und letzte Aspekte ist, dass man stets so entwickeln sollte, als wäre die eigene Software Open Source. Tatsächlich veröffentlichen die wenigsten Teams und Unternehmen ihre Arbeit als Open Source, doch lässt sich das entsprechende Mindset auch auf Closed Source anwenden. Das heißt, Code sollte aufgeräumt, kommentiert und dokumentiert sein, er sollte sich an Standards und Best-Practices halten, und sich jederzeit problemlos kompilieren und ausführen lassen.

Man sollte ihm einfach anmerken, dass er mit Liebe zum Detail entwickelt wurde, und da gehören die zuvor genannten Punkte alle dazu. Man sollte merken, dass es jemandem wichtig war beziehungsweise ist, wie der Code entwickelt wurde, sodass man letztlich auch stolz auf das sein kann, was man erschafft.

Der Grund dafür ist schlichtweg, dass man Open Source häufig auch für andere Entwicklerinnen und Entwickler schreibt, und man sich daher ein bisschen mehr Mühe gibt, verständlichen, ordentlichen und nachvollziehbaren Code zu schreiben – einfach weil man bei Anderen einen guten Eindruck hinterlassen möchte. Wenn man diese Einstellung nun auf jeglichen Code anwendet, entsteht letztlich insgesamt besserer Code.

Selbstverständlich sind die zwölf genannten Aspekte nicht die einzigen Kriterien, die über die Qualität der Softwareentwicklung eines Teams oder eines Unternehmens entscheiden. Aber es sind zwölf Kriterien, die eine solide Grundlage bieten. Bleiben ein oder mehrere Aspekte unberücksichtigt, schadet das der Softwareentwicklung langfristig mit hoher Wahrscheinlichkeit.

Ein guter Anfang ist daher, zu hinterfragen, wie gut es um das eigene Team beziehungsweise Unternehmen bestellt ist. Setzt man alle zwölf Aspekte um? Elf? Zehn? Welche Aspekte fehlen, und warum? Wie könnte man deren Anforderungen erfüllen? Wer sich ernsthaft mit diesen Fragen auseinandersetzt, hält im Anschluss nicht nur eine Bewertung in den Händen, sondern verfügt auch über einen Plan, wie sich der Status Quo verbessern lässt. ()