Softwareentwicklung: Erst denken, dann tippen
Dieser Text ist eine Übersetzung. Das Original des Entwicklers Jordan Kaye ist am 11. Oktober 2023 hier erschienen(öffnet im neuen Fenster) .
In den Best Practices der Softwareentwicklung wird immer wieder betont, wie wichtig iterative Arbeit ist. Es wird dazu aufgerufen, so zu arbeiten, dass Entscheidungen stets neu getroffen und an veränderte Umstände angepasst werden. Dieser Grundsatz ist quasi allgegenwärtig und scheint für erfolgreiche Entwicklungsarbeit in großen Projekten notwendig zu sein.
Manchmal wird das Prinzip aber derart strapaziert, dass es nicht mehr hilfreich ist. Obwohl es fast immer eine gute Idee ist, schnell zu iterieren und die eigene Meinung zu hinterfragen(öffnet im neuen Fenster) , heißt das nicht, dass man sich keine Zeit zum Nachdenken nehmen sollte, bevor man aktiv wird.
Wenn man mit einem Problem konfrontiert wird, ist es oft effektiver, sich zunächst einen Überblick über mögliche Lösungen zu verschaffen, als sich sofort zu fragen: Wie kann ich das Problem mit Code lösen? Wenn der Code in den Editor getippt wird, sollte man bereits eine Vorstellung vom Gesamtplan haben: Worauf wird eigentlich hingearbeitet? Welche Konzepte werden im Entwicklungsprozess befolgt?
Sollten grundlegend neue Konzepte in dieses Codesegment eingeführt werden, um die Implementierung zu erleichtern? Welche bestehenden Konzepte müssen geändert werden? Hat man auf diese und ähnliche Fragen keine Antwort, kann es schnell passieren, dass man sich quasi durchwurstelt, dass unvorhergesehene Probleme auftreten und dass man am Ende eine Lösung findet, die zwar gut genug ist, aber besser hätte sein können.
Je unerfahrener ein Entwickler ist, umso seltsamer mag das für ihn oder sie klingen. Schließlich ist es der Job, Code zu schreiben. Warum also soll Denken besser sein als das tatsächliche Programmieren? Die für mich beste Antwort darauf ist dieses Zitat, dessen Quelle ich nicht gefunden habe:
"Wochenlanges Coden kann Ihnen Stunden an Planung ersparen."
Der Punkt ist, dass es keine Rolle spielt, wie schnell jemand Code schreibt, wenn er Code aus den verkehrten Gründen schreibt. Besonders unangenehm ist es für Entwickler, wenn sie Tage oder Wochen mit etwas zubringen, nur um dann zu erfahren, dass es ganz anders hätte sein sollen. Natürlich ist daran normalerweise nicht nur der Entwickler schuld. Agile Methoden sollten eigentlich dabei helfen, solche Probleme recht früh zu erkennen. Aber es bleibt eine Tatsache, dass jeder immer mehr machen kann, um die Probleme bestmöglich zu lösen.
In der Praxis ist das häufig schwierig umzusetzen, denn
- wenn das Problem völlig neu ist, kann es durchaus helfen, etwas Code zu schreiben, um es besser zu verstehen,
- Code zu schreiben macht vielen Entwicklern mehr Spaß als herumzusitzen und über abstrakte Probleme nachzudenken,
- abstraktes Denken birgt große Unsicherheit: Woher soll man wissen, dass man über die richtigen Dinge nachdenkt?,
- verbringt man zu viel Zeit mit Nachdenken und Planen, kann das auch ergebnislos sein.
Woher soll man also wissen, wann es Zeit ist, mit dem Planen aufzuhören und mit dem Machen anzufangen?
Kopplung und Kohäsion
Einer meiner Lieblingsansätze ist es, die Kernkonzepte zu ermitteln, die dem jeweiligen Problem zugrunde liegen. Viele Probleme lassen sich in kleinere Komponenten zerlegen, die mehr oder weniger unabhängig voneinander sind. Die meisten Entwickler kennen das, denn es ähnelt den wichtigen Entwicklungskonzepten der Kopplung(öffnet im neuen Fenster) und Kohäsion(öffnet im neuen Fenster) .
Während die Entkopplung ein überwiegend technischer Prozess ist, ist die Identifizierung der Kernkonzepte ein theoretischer Prozess. Das Ziel besteht darin, nach den Konzepten im Problem selbst zu suchen, um dann die technischen Prozesse entlang der konzeptionellen Grenzen aufbauen zu können, die das Problem vorgibt. Am besten wird das Ergebnis, wenn die Unterkonzepte lose miteinander gekoppelt sind, aber eine hohe Kohärenz aufweisen.
Ein praktisches Beispiel ist eine Kommandozeilenanwendung, die Devcontainer-Spezifikationen durch deklarative Kombination von Tools für Nutzer generieren kann, so dass sie nicht gezwungen sind, die Konfigurationsdateien von Hand zu schreiben. Devcontainer-Spezifikationen und dazugehörige Dockerdateien selbst zu schreiben, kann wegen unerwarteter Wechselwirkungen zwischen Container und Entwicklungsumgebung des Benutzers mühsam sein.
Beispielsweise sollte die Zeitzone des Containers mit der des Nutzers synchronisiert werden, die UID des Nutzers im Container sollte mit der UID des externen Benutzers übereinstimmen und die SSH-Passthrough-Authentifizierung sollte funktionieren.
Das sind keine Funktionen, die Devcontainer(öffnet im neuen Fenster) für die Anwender bereitstellt. Die Idee ist daher, dass das Tool eine vereinfachte Konfigurationsdatei verwendet, die es Nutzern ermöglicht zu sagen: Ich möchte Rust, Git, Vim und die Oil-Shell(öffnet im neuen Fenster) verwenden. Dann drücken sie nur einen Knopf und erhalten eine vollständig instrumentierte und reproduzierbare Entwicklungsumgebung.
Denkt man über das Problem nach, stellt man sich folgende Frage: Um welche Kernkonzepte herum sollte man dieses Werkzeug sinnvollerweise entwickeln? Ich beschreibe im nächsten Absatz, wie ich diese Frage beantworten würde. Sind Ihre Konzepte andere als meine? Vielleicht habe ich etwas übersehen.
Meine Kernkonzepte
- Repository: Das Repository ist das höchste Konstrukt, das von dem Tool unterstützt wird – in der Regel ein versioniertes, kontrolliertes Quellcode-Repository, das eines oder mehrere Projekte enthalten kann.
- Projekt: Das Projekt ist die gewünschte Entwicklungsarbeit. Es steht in Verbindung mit einer Teilmenge des Repositories und hat zu jeder Zeit eine einzige Konfiguration.
- Konfiguration: Die Konfiguration ist eine zeitlich begrenzte Instanz eines Projekts. Jede Konfiguration erzeugt eine einzelne Devcontainers-Spezifikation und ein zugehöriges Docker-Image.
- Host: Damit ist die Host-Umgebung gemeint, von der aus das Tool ausgeführt wird und die als Quelle für Informationen dient, die in eine Konfiguration eingespeist werden.
- Umgebung: Die Umgebung ist eine aktive Instanz einer Konfiguration, die normalerweise vom Editor verwaltet wird.
- Editor: Gemeint ist der Quellcode-Editor, der für die Ausführung des Devcontainers verwendet wird.
- Tool: Das Tool ist ein einzelnes Funktionselement, das mit anderen Tools zu einer Entwicklungsumgebung kombiniert werden kann.
Es ist eine vereinfachte Liste, aber sie zeigt, dass es hier um Konzepte geht, die mit dem Problem selbst zusammenhängen, und nicht um einzelne technische Entscheidungen. Nichts in der Liste schreibt vor, wie das Tool mit diesen Konzepten umzugehen hat, sondern nur, dass es sie gibt und dass sie bei der Entwicklung berücksichtigt werden sollten. Einer der wichtigsten Gründe ist es nämlich, zuerst zu denken und dann zu coden: zu vermeiden, dass unser Denkprozess darum kreist(öffnet im neuen Fenster) , was wir in der Vergangenheit gemacht haben.
Aus der Betrachtung der Konzepte ergeben sich weitere technische Fragen:
- Sollten Repositories nur ein einziges Projekt enthalten dürfen? Wie könnte sich das auf die Nutzer von Monorepos(öffnet im neuen Fenster) auswirken?
- Es ist möglich, dass Umgebungen von der aktuellen Konfiguration abweichen, wenn eine Umgebung nach der Änderung der Konfiguration weiterläuft; ist das wichtig?
- Die Konfiguration sollte die verschiedenen von dem Tool unterstützten Editoren verstehen; wie macht man das?
- Wie sollte das Tool mit verschiedenen Host-Plattformen umgehen?
- Wie können die Tools beim Erstellen einer endgültigen Spezifikation kombiniert werden?
Entwickler-Schwierigkeiten Fachfremden verständlich machen
Von hier aus kann es wie üblich mit der iterativen Entwicklung weitergehen.
Ich möchte betonen, dass ich nicht (!) für Design by Committee, für das Wasserfallprinzip, für Architekturastronauten oder andere Konzepte eintrete, die Entwickler frustrieren, die etwas zustande bringen wollen.
Nachzudenken und dann zu tippen ist kein Konzept, sondern etwas, das jeder Entwickler für sich tun kann, um das Ergebnis seiner Arbeit zu verbessern. Etwas Code zu schreiben, um den Problembereich zu verstehen, kann gut sein, birgt aber die Gefahr, sich auf einem einzelnen Pfad zu verirren. Vor allem, wenn der Zweck eines Prototyps darin besteht, Probleme zu entdecken, ist die Gefahr des XY-Problems(öffnet im neuen Fenster) allgegenwärtig.
Ein weiterer nützlicher Aspekt ist, dass dieser Ansatz dazu beitragen kann, weniger technisch versierten Personen, insbesondere Interessenvertretern und Führungskräften, einige Schwierigkeiten näherzubringen, die Entwickler haben. Die Leistung von Entwicklerteams zu messen, ist ein heißes Thema, nachdem die DORA-Metriken(öffnet im neuen Fenster) , das relativ neue SPACE-Framework(öffnet im neuen Fenster) und das unselige McKinsey-System(öffnet im neuen Fenster) einige Bedenken bei erfahrenen Entwicklungsleitern hervorgerufen haben(öffnet im neuen Fenster) .
Insbesondere SPACE eignet sich gut, um zu zeigen, dass es bei der Softwareentwicklung um mehr geht als um den Code. Obwohl es schwierig sein kann, jedes Detail des Entwicklungsprozesses zu verstehen, ist es Aufgabe einer technischen Führungskraft, sich für seine Teams einzusetzen und den Stakeholdern beizubringen, wofür die Zeit aufgewendet wird, und warum die Dinge so lange dauern, wie sie dauern.
Sich auf die Bedeutung von Planung, Design und Denken zu konzentrieren, kann Führungskräften helfen, diese Konzepte in Begriffen zu erklären, die jeder verstehen sollte – unabhängig vom jeweiligen technischen Verständnis.
Softwareentwicklung ist meist kreativ. Deswegen ist es schwierig, die tägliche Arbeit eines Entwicklers auf jene Metriken zu reduzieren, die viele Führungskräfte gern sähen – vor allem jene, die mit dem Entwicklungsprozess nicht so vertraut sind.
Ein Glue Engineer(öffnet im neuen Fenster) zum Beispiel mag für die Gesamtfunktion seines Teams entscheidend sein; aber jeder Versuch, den Einfluss dieser Person zu messen, indem man sich auf die Zahl der erledigten Probleme oder die Commit-Historie konzentriert, ist zum Scheitern verurteilt. Deshalb konzentrieren sich erfahrene technische Leiter mehr auf die Ergebnisse als auf den Output(öffnet im neuen Fenster) .
Reizthema Leistungsmessung
Zudem ist es umso schwieriger, die Leistung zu messen, je älter der Entwickler ist. Je erfahrener und einflussreicher jemand ist, desto wahrscheinlicher ist es, dass sein Einfluss auf immateriellen Faktoren beruht, zum Beispiel auf der Fähigkeit, andere zu inspirieren.
Es gibt einen guten Grund dafür, dass sich viele Open-Source-Frameworks für den technischen Fortschritt auf ihren höchsten technischen Ebenen eher auf den Einfluss als auf den Output konzentrieren(öffnet im neuen Fenster) . All das kann dazu beitragen, diese Art von Verständnis für den Softwareentwicklungs-Lebenszyklus (Software Development Life Cycle, SDLC) im gesamten Unternehmen zu verankern.
Es hilft somit, sich immer wieder daran zu erinnern: Bei der Softwareentwicklung geht es ums Denken, nicht ums Tippen.
- Anzeige Hier geht es zum Handbuch für Softwareentwickler bei Amazon Wenn Sie auf diesen Link klicken und darüber einkaufen, erhält Golem eine kleine Provision. Dies ändert nichts am Preis der Artikel.