Mächtige Softwarefunktionen und wie man sie meistert

2 Juni 2021

Jeder liebt neue mächtige Softwarefunktionen. Die Stakeholder wollen sie, weil sie ihr Produkt für die Nutzer attraktiver machen. Dies wiederum impliziert, dass die Softwarefunktion zum Wohlgefallen der Benutzer gestaltet sind. Entwickler haben Spaß am Programmieren, und mächtige Softwarefunktionen sind in der Regel mit viel Programmierarbeit verbunden - eine perfekte Kombination, oder?

Doch mit einer mächtigen Softwarefunktion geht in der Regel auch eine große Komplexität einher. Die Änderungen erstrecken sich in der Regel über Tausende von Codezeilen, die man bald nicht mehr im Kopf behalten kann. Ein Entwickler muss nicht nur alle bestehenden Funktionen finden, die angepasst werden müssen, alle Sonderfälle, Einschränkungen und Nebeneffekte durchdenken, sondern auch seinen Kollegen ein überprüfbares Ergebnis zur Codeüberprüfung vorlegen. Wie kann man all dies erreichen und dabei nicht verrückt werden?

Ich möchte meinen Ansatz, der nur einer von vielen ist, die es gibt, mit euch teilen. Hier sind die Schritte, denen ich folge.

#1 Versteh die Softwarefunktion

Stell sicher, dass du die Softwarefunktion wirklich verstehst. Lies dir die Anforderungen sehr sorgfältig durch und nimm dir Zeit dafür, schlaf vielleicht sogar eine Nacht darüber. Stell auf jeden Fall alle Fragen, die du hast, denn Fragen kostet in der Regel nichts, ganz im Gegenteil, denn eine falsche Annahme in diesem Schritt könnte bedeuten, dass die gesamte weitere Arbeit abgebrochen werden muss.

#2 Kenn die Ausgangslage

Mach dich mit dem Status quo vertraut. Analysiere alle relevanten bestehenden Funktionen, die Organisation des bestehenden Codes und die Datenbankstruktur. Du musst die Ausgangsbedingungen kennen, um den Fahrplan für die Umsetzung zu erstellen.

Sobald du weißt, was du hast und erreichen musst, musst du nur noch von Zustand A zu Zustand B gelangen. Die Frage ist nur wie?

#3 Entwirf die Datenbank

Ich beginne immer mit dem Entwurf der Datenbank. Mit einem durchdachten Datenmodell ist in der Regel schon die halbe Schlacht gewonnen. In diesem Schritt plane ich die Tabellen, die Tabellenstruktur, die Datentypen der Spalten, die Beziehungen zwischen den Tabellen und die Konsistenzbeschränkungen. Dabei neige ich dazu, Entity-Relationship-Diagramme zu zeichnen. Ich bin ein Mensch, der ständig kritzelt, während eines Telefonats, in einer Besprechung oder einfach, wenn ich einen Stift vor mir liegen habe. So ist das Zeichnen von DB-Diagrammen eine sehr produktive Art des Kritzelns. Ich vergleiche die verschiedenen Entwürfe, notiere ihre Vor- und Nachteile und wähle schließlich denjenigen aus, der alle meine Anforderungen erfüllt.

djangster data model

So würde ich djangsters modellieren – Entwickler mit einer starken Vorliebe für Fedoras und ☕.

#4 Plan die Code-Struktur

Plan die Organisation des Codes, die Abstraktionen und Schnittstellen, ohne dich bereits mit den Implementierungsdetails zu befassen.

#5 Informier das Team

Ich fasse meinen vorgeschlagenen Datenbankentwurf und die High-Level-Codestruktur in einer technischen Spezifikation zusammen - ein Dokument, in dem beschrieben wird, wie man ein technisches Problem durch den Entwurf einer Lösung angehen will. Dann würde ich die Spezifikation mit meinen Teamkollegen teilen, um ihre Meinung und ihren Rat zu dem Ansatz einzuholen. Wenn sie jetzt mit dem Projekt vertraut sind, wird die künftige Überprüfung des Codes einfacher und fruchtbarer.

#6 Teil die Implementierung schrittweise auf

Nachdem du dir einen Überblick über die endgültige Lösung verschafft hast, plane, wie du die Implementierung in kleine Schritte aufteilen kannst, sodass jeder Schritt in sich konsistent ist, wenn möglich unabhängig von den anderen Änderungen und klein genug, um überprüfbar zu sein.

Manchmal ist es möglich, eine neue Softwarefunktion zu entwickeln, während die alte Lösung noch eine Weile im Code bleibt. Dies ist der einfachere Fall und man kann einfach wie angegeben vorgehen: zuerst die neue Softwarefunktion schrittweise implementieren und dann die veraltete Softwarefunktion schrittweise entfernen. Während der Übergangsphase kann eine gewisse Duplizierung von Daten oder Logik notwendig sein, aber ich finde das als vorübergehende Komplikation völlig akzeptabel.

In anderen Fällen kann die alte Funktionalität nicht mit der neuen koexistieren, z. B. wenn sich die Softwarefunktionen logisch widersprechen. Dann ist der Übergang komplexer, da man die bestehende Softwarefunktion abreißen und gleichzeitig eine neue aufbauen muss. In diesem Fall sind kleine Schritte schwieriger, aber immer noch möglich.

#7 Es ist Zeit zum Coden

Mit den Möglichkeiten von git ist die Verwaltung aller Inkremente und ihrer Abhängigkeiten fast ein Kinderspiel. Ich würde einen Basisbranch für die Softwarefunktion als Ganzes und einen Branch für jedes Inkrement erstellen, gefolgt von einem Pull Request für jedes Inkrement, das mein Team überprüfen kann. Die genehmigten Pull Requests werden anschließend unter Beachtung der Reihenfolge der Abhängigkeiten in den Basisbranch eingefügt, sodass am Ende eine vollständig entwickelte und überprüfte Softwarefunktion vorliegt.

Erfolg!

Die mächtige Softwarefunktion ist nun implementiert und keine Entwickler kamen dabei zu Schaden.

Fazit

Unterteil umfangreiche Änderungen in kleinere Teile. Das kostet zwar etwas zusätzliche Zeit in der Planungsphase, wird aber durch eine schnellere Entwicklung aufgrund kleinerer Schritte sowie durch einfachere und effektivere Code-Reviews wieder wettgemacht.

Tipps

  • Wenn du das Gefühl hast, dass ein Inkrement zu groß wird, mache eine Pause und beginne mit der Planung des Umfangs von vorne. Ich habe festgestellt, dass die Inkremente größer werden, je müder ich werde.
  • git wirkt Wunder beim Umschreiben der History, es wählt die benötigten Commits automatisch und ist somit eine große Hilfe bei der Verwaltung von Branchen für die inkrementellen Änderungen. Besonders erwähnenswert sind der interaktive Rebase mit git rebase -i und git rebase --onto, das Commits von einem Zweig in einen anderen „verpflanzt“ (mehr dazu in Englisch unter https://git-scm.com/docs/git-rebase).
  • Überspringe nicht das Schreiben von Tests, während du inkrementelle Entwicklung betreibst. Das Schreiben von Tests zusammen mit den logischen Änderungen hilft beim Auffinden von Fehlern und macht die History der Änderungen informativer.
  • Du kannst Feature-Flags verwenden, wenn du alte Funktionalität ersetzen willst, was einen sauberen Übergang ermöglichen würde.

djangsters GmbH

Vogelsanger Straße 187
50825 Köln