(Bild: erzeugt mit KI durch iX)
Automatisiertes Refactoring klingt verlockend – doch lässt sich Codequalität wirklich auf Knopfdruck verbessern, oder braucht es am Ende doch den Menschen?
Heute habe ich eine große Ankündigung für Sie – eine, die für viele Entwicklerinnen und Entwickler wohl einem echten Traumszenario gleichkommt. Ein Gedanke, der so bestechend einfach klingt, dass man sich fragen könnte, warum es so etwas nicht schon längst gibt. Sicher kennen auch Sie Gespräche im Team, in denen dieser Wunsch immer wieder auftaucht – meist mit ironischem Unterton, aber manchmal durchaus mit einem Funken Hoffnung.
Stellen Sie sich vor, Sie könnten Ihren kompletten Codestand einfach in eine ZIP-Datei packen, per HTTP an einen Service hochladen – und wenige Minuten später erhalten Sie ihn vollständig refactored zurück: besser strukturiert, mit klaren Abhängigkeiten, sinnvoll modularisiert, mit sprechenden Namen, nachvollziehbarer Architektur und aussagekräftigen Tests. Inklusive aktualisierter Dokumentation, vollständig durchgelintet und formatiert. Einmal hochladen, und der Code sieht anschließend aus, als hätte ein erfahrenes Senior-Architekturteam drei Wochen intensiv daran gearbeitet. Genau das haben wir jetzt Realität werden lassen und nennen es: "Refactoring as a Service".
Die Idee ist so einfach wie genial: Haben Sie ein Repository, dessen Zustand nicht mehr ganz optimal ist? Kein Problem: Sie laden den Code einfach über unsere API hoch oder verweisen auf ein Git-Repository mit einem gültigen Token – der Rest passiert automatisch im Hintergrund. Unser Service analysiert den Code mit statischen und dynamischen Verfahren, führt eine kombinierte AST- und Graphanalyse durch, identifiziert strukturelle Schwächen, erkennt Anti-Patterns, bewertet essenzielle Metriken wie zyklomatische Komplexität, Kohäsion, Kopplung, Testabdeckung und Architekturkonformität – und erstellt daraus ein kontextsensitives, semantisch fundiertes Refactoring-Konzept, das automatisiert umgesetzt wird. Die resultierende Codebasis ist nicht nur schöner und verständlicher, sondern auch modularer, wartbarer und besser getestet. Selbstverständlich integriert sich das Ganze nahtlos in CI/CD-Prozesse und ist über eine OpenAPI-Schnittstelle vollständig automatisierbar.
Weil uns das noch nicht genug war, wird zusätzlich eine KI-gestützte Kommentierung vorgenommen, die basierend auf Codeverständnis sowie Projektkontext passgenaue Kommentare und Erläuterungen hinzufügt – sowohl auf Code- als auch auf Modul- und Architekturebene. Die Testabdeckung wird nicht nur erhöht, sondern zielgerichtet erweitert, mit besonderem Augenmerk auf Pfadabdeckung, Grenzfälle, Randbedingungen und semantisch relevante Kombinationen. All dies orchestriert ein auf Kubernetes skalierendes Service-Backend, das selbst größere Projekte in kurzer Zeit bewältigt. Für besonders kritische Projekte bieten wir zudem eine Audit-Funktion: Jede Änderung bleibt einzeln nachvollziehbar, jeder Commit wird semantisch kommentiert, jeder Refactoring-Schritt dokumentiert. Kurz gesagt: Der perfekte Begleiter für Softwareteams, die Qualität ernst nehmen, dabei aber ihren Fokus auf die eigentliche Entwicklung legen wollen.
Die eigentliche Magie entsteht durch die Kombination verschiedener Technologien und Ansätze: Statische Analyse alleine hilft wenig, wenn sie den fachlichen Kontext nicht berücksichtigt. LLMs alleine schreiben zwar Code, wissen aber nicht, ob dieser wirklich zu Ihrem Projekt passt. Clean-Code-Prinzipien sind essenziell, lösen aber nicht das grundlegende Problem der strukturellen Überarbeitung. Erst die systematische Verbindung dieser Ansätze schafft etwas, das sich wirklich als Refactoring im engeren Sinne bezeichnen lässt. Genau das macht "Refactoring as a Service" nicht nur zu einem interessanten Tool, sondern zu einem echten Gamechanger.
Natürlich – und das war uns von Anfang an bewusst – ersetzt "Refactoring as a Service" nicht den Menschen. Unser Ziel war es nie, die Expertise erfahrener Entwicklerinnen und Entwickler überflüssig zu machen. Ganz im Gegenteil: Wir wollten diese Expertise entkoppeln, also ermöglichen, dass sie unabhängig von individueller Verfügbarkeit, Projektkontext oder Zeitdruck eingesetzt werden kann. Deshalb haben wir all unser Wissen, unsere Erfahrungen und Prinzipien in diesen Service einfließen lassen – damit andere Teams davon profitieren können, ohne dass wir immer persönlich involviert sein müssen.
Das ist nicht nur für Entwicklerinnen und Entwickler spannend, sondern gleichermaßen interessant für Softwarearchitektinnen und -architekten, Teamleads und CTOs sowie alle, die sich intensiv mit Softwarequalität und Wartbarkeit auseinandersetzen. Denn Refactoring ist nicht nur ein technisches Hilfsmittel, sondern ein strategisches Instrument. Es entscheidet maßgeblich über Lebensdauer, Änderbarkeit und Erweiterbarkeit – und damit letztlich über den wirtschaftlichen Erfolg eines Projekts. Genau deshalb möchten wir mit "Refactoring as a Service" dazu beitragen, dass mehr Teams die Möglichkeit erhalten, ihre Codebasis auf ein solides und wartbares Fundament zu stellen.
An dieser Stelle fragen Sie sich vermutlich bereits: Klingt vielversprechend – doch wie viel kostet das Ganze? Wann und wie kann ich es ausprobieren? Die Antwort auf diese Fragen lautet leider: gar nicht. Denn heute ist der 1. April, und "Refactoring as a Service" existiert nicht.
Doch bevor Sie enttäuscht sind: Die Idee hinter "Refactoring as a Service" – also der Wunsch nach automatisiertem, reproduzierbarem und skalierbarem Refactoring – ist real und absolut verständlich. Wer von uns kennt nicht den Frust, sich durch Altlasten zu kämpfen, zu fragen, was sich jemand bei einem Stück Code gedacht haben könnte, und den Wunsch, einfach einen Knopf drücken zu können: "Jetzt Refactor" – klick, fertig. Leider ist es nicht ganz so einfach, und dafür gibt es gute Gründe.
Refactoring ist eben nicht nur eine technische Tätigkeit, sondern eine bewusste Entscheidung: eine Entscheidung darüber, wie Code strukturiert werden soll. Welche Konzepte getrennt, welche zusammengeführt werden müssen. Welche Benennungen welche Bedeutung tragen. Welche Architekturprinzipien zum Einsatz kommen, wann bestimmte Patterns sinnvoll sind und wann man bewusst darauf verzichten sollte. All das hängt unmittelbar mit einem fundierten fachlichen Verständnis zusammen: Sie können keine gute Struktur aufbauen, wenn Sie nicht wissen, was diese Struktur abbilden soll. Sie können keine Struktur sinnvoll bewerten, wenn Sie nicht verstehen, welche Anforderungen diese erfüllen muss. Genau deshalb ist Refactoring auch nichts, was sich rein nach Schema F automatisieren ließe. Es handelt sich eben nicht um einen rein technischen Akt, sondern um einen analytischen und diskursiven Prozess.
Natürlich gibt es Tools, Plug-ins und LLMs. Doch keines dieser Hilfsmittel kann Ihnen beantworten, ob eine Methode in einen Service oder in einen Controller gehört. Keines erkennt zuverlässig, ob eine bestimmte Implementierung noch zur aktuellen Realität passt oder lediglich ein Relikt früherer Feature-Iterationen darstellt. Keines entscheidet für Sie, ob ein Name tatsächlich treffend oder nur historisch gewachsen ist. Kein Tool abstrahiert Fachlichkeit umfassend, ersetzt Kommunikation oder übernimmt Verantwortung. All diese Dinge erfordern Erfahrung, Kontextverständnis, Empathie – also letztlich Menschen.
Deshalb ist gutes Refactoring stets gute Teamarbeit. Es bedeutet, innezuhalten, Code bewusst erneut zu lesen, zu verstehen, was er ausdrücken möchte, und anschließend in kleinen, wohlüberlegten Schritten etwas Besseres daraus zu machen. Etwas Klareres und Stabileres, das den Alltag erleichtert und nicht erschwert. Genau darin liegt auch die Verantwortung beim Refactoring. Wer refactored, entscheidet sich für langfristige Qualität – und gegen kurzfristige Bequemlichkeit. Das ist nicht immer einfach.
In vielen Teams fehlt dafür oft Zeit, Mut oder Rückendeckung. Features werden entwickelt, Stories geliefert und der Durchsatz optimiert – doch der Boden, auf dem alles steht, wird selten stabilisiert. Je länger das andauert, desto brüchiger wird das Fundament. Irgendwann wächst Refactoring dann zu einem Mammutprojekt heran, das niemand mehr anfassen möchte – obwohl anfangs nur wenige kleine Schritte nötig gewesen wären. Genau das darf nicht passieren.
Was also ist der bessere Weg? Sehen Sie Refactoring nicht als einmalige, große Aufgabe, sondern als kontinuierlichen Prozess. Machen Sie Refactoring zum festen Bestandteil Ihres Alltags, jeder Story, jedes Features, jedes Sprints. Refactoring ist nicht etwas, das man macht, wenn gerade Zeit übrig bleibt – sondern etwas, das man stets tun sollte, um sich die Zukunft deutlich einfacher zu gestalten. Das bedeutet konkret: kleine Schritte, regelmäßige Reviews, klare Verantwortlichkeiten, Mut zur Veränderung und ein gemeinsames Verständnis im Team, dass gute Software niemals Zufall ist, sondern das Ergebnis von Haltung, Prinzipien und kontinuierlicher Pflege.
URL dieses Artikels:
https://www.heise.de/-10333543
Links in diesem Artikel:
[1] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[2] mailto:mai@heise.de
Copyright © 2025 Heise Medien
(Bild: Shutterstock/Milos Milosevic)
CloudEvents schafft Interoperabilität für Event-basierte Systeme. Warum der Standard sinnvoll ist und wie er funktioniert, behandelt dieser Blogpost.
Es heißt oft, Event-basierte Systeme seien besonders leistungsfähig, weil sich Events hervorragend dazu eignen, Informationen über fachliche Ereignisse zwischen verschiedenen Systemen auszutauschen und diese so zu integrieren. In der Realität zeigt sich jedoch häufig ein ganz anderes Bild: Jedes System verwendet seine eigene Variante von Events, die Formate sind nicht kompatibel, und die erhoffte Integration über Events scheitert dadurch schnell. Was hier eindeutig fehlt, ist ein standardisiertes Format – ein allgemeingültiger Standard, der definiert, welche Daten ein Event enthalten soll, wie es strukturiert ist und wie es übermittelt wird.
Glücklicherweise hat sich die Cloud Native Computing Foundation [1] (CNCF) dieser Herausforderung angenommen und genau einen solchen Standard geschaffen: CloudEvents [2]. Für jede Entwicklerin und jeden Entwickler, die mit Event-basierten Systemen arbeiten, ist dieses Thema von großer Relevanz. Daher möchte ich Ihnen in diesem Blogpost einen genaueren Einblick geben.
Vielleicht fragen Sie sich zunächst, was ich überhaupt unter dem Begriff "Event" verstehe. Eine präzise Antwort würde an dieser Stelle den Rahmen sprengen. Daher empfehle ich Ihnen meinen Blogpost zum Thema Event Sourcing [3], der vor einigen Wochen erschienen ist. Es lohnt sich, sich zunächst damit vertraut zu machen und erst anschließend hier weiterzulesen.
Wenn Sie bereits wissen, was mit Events gemeint ist, dann kennen Sie vermutlich auch das Problem: Jedes Event-getriebene System definiert sein eigenes Format für Events, was den Austausch und die Integration zwischen verschiedenen Systemen erheblich erschwert. Der theoretische Vorteil einer gemeinsamen Kommunikationsform durch Events bleibt in der Praxis oft ungenutzt, da die Formate schlicht nicht zueinander passen. Solange es keinen verbindlichen Standard gibt, bleibt der Nutzen solcher Events für die Systemintegration begrenzt.
Genau hier setzt das Konzept von CloudEvents an. Die dahinterstehende Idee ist einfach: Es geht darum, ein standardisiertes Format für Events zu schaffen, um die Interoperabilität zwischen verschiedenen Systemen zu ermöglichen. Entwickelt wurde dieser Standard, wie gesagt, von der Cloud Native Computing Foundation, einer gemeinnützigen Organisation, die von nahezu allen großen Cloud-Anbietern wie Microsoft, Amazon und Google unterstützt wird.
Das Ziel von CloudEvents ist es, einheitliche Metadaten für Events zu definieren, damit diese zumindest in ihrer äußeren Struktur kompatibel zueinander gestaltet werden können. Zusätzlich sollen plattform- und transportschichtunabhängige Strukturen ermöglicht werden – zum Beispiel soll JSON über HTTPS genauso einsetzbar sein wie XML über MQTT. Der Standard definiert dabei zentrale Begriffe wie "ID", "Source", "Type" und weitere essenzielle Felder.
Warum sollte man auf diesen Standard setzen? Der naheliegende Vorteil liegt in der Reduktion des Aufwands für Konvertierungen und Parsings sowie in einer deutlich verbesserten Interoperabilität zwischen Systemen. Zudem unterstützt CloudEvents verschiedene Protokolle und lässt sich dadurch flexibel transportieren – unabhängig vom konkreten Übertragungsweg. Das ist nicht nur für Anwendungen relevant, sondern auch für Router und Broker, da sich Events durch die standardisierten Metadaten wesentlich besser analysieren, filtern und verteilen lassen. Außerdem verbessert sich durch die strukturierte Beschreibung der Events die Nachvollziehbarkeit, etwa hinsichtlich Ursprung und Zeitpunkt des Ereignisses. Auf dieser Basis lassen sich generische Werkzeuge für Events realisieren – ein Aspekt, der insbesondere für Microservices, Serverless-Funktionen und vergleichbare Architekturen von Bedeutung ist. Und wenn man diesen Gedanken weiterführt, dann wäre CloudEvents sogar als Persistenzformat für Event Sourcing gut geeignet.
Natürlich stellt sich die Frage, welche Herausforderungen oder Einwände gegen die Nutzung von CloudEvents sprechen könnten. Ein zentrales Problem besteht darin, dass bisher noch nicht viele Systeme diesen Standard unterstützen. Das heißt, es existieren derzeit nur wenige Anwendungen, die direkt kompatibel sind. Bestehende, proprietäre Event-Formate müssen daher weiterhin unterstützt werden – zumindest ergänzend. Das verursacht zusätzlichen Aufwand, den man eigentlich vermeiden möchte. Dies betrifft nicht nur kleinere Systeme, sondern auch Dienste wie die Amazon EventBridge von AWS oder das Event Grid von Microsoft Azure.
Ein weiterer Punkt ist, dass CloudEvents lediglich die Metadaten vereinheitlicht. Die Nutzdaten – also die Payload – bleiben weiterhin spezifisch für die jeweilige Anwendung. Das ist systemimmanent, denn der fachliche Inhalt eines Events lässt sich nicht generisch definieren. Hinzu kommt, dass CloudEvents durch ihre strukturierte Form möglicherweise mehr Overhead verursachen als einfachere proprietäre Formate, insbesondere wenn nicht alle vorgesehenen Felder genutzt werden.
Trotzdem halte ich CloudEvents für einen großen Schritt in die richtige Richtung. Ohne klare Regeln ist es unnötig aufwendig, Event-basierte Systeme miteinander zu koppeln. Ein gemeinsames Vokabular erscheint hier ausgesprochen sinnvoll. Positiv hervorzuheben ist auch, dass sich CloudEvents gut mit anderen Standards kombinieren lässt – etwa mit AsyncAPI [5] oder OpenTelemetry [6]. Alles in allem ist der Standard darauf ausgelegt, den Einstieg möglichst einfach zu gestalten und die Integration in bestehende Systeme zu erleichtern.
Daraus ergibt sich die Frage, wie man CloudEvents sinnvoll umsetzt. Zunächst sollte man klären, ob der Einsatz für die eigene Anwendung überhaupt sinnvoll ist. Meiner persönlichen Einschätzung nach lautet die Antwort eindeutig: Sobald Sie mit Events arbeiten und sobald Sie auch nur ansatzweise darüber nachdenken, Ihre Software mit anderen Systemen zu koppeln oder zu integrieren, sollten Sie CloudEvents in Betracht ziehen. Natürlich können Sie auch ein eigenes Format definieren – gewinnen werden Sie dadurch allerdings wenig. Der einzige "Nachteil" besteht darin, dass man sich einmal mit dem CloudEvents-Standard vertraut machen muss. Nach meiner Erfahrung ist das sehr gut machbar: Der Standard ist verständlich und überschaubar.
Wenn Sie sich dafür entscheiden, CloudEvents zu nutzen, dann sollten Sie es auch korrekt tun. Das bedeutet vor allem, sich mit der Bedeutung und dem Format der einzelnen Felder auseinanderzusetzen. Es wäre wenig hilfreich, das Format formal zu unterstützen, dabei aber inkorrekte Werte zu verwenden – insbesondere, wenn sich solche Fehler erst Monate später im Integrationsfall zeigen. Felder wie "source", "subject" oder "type" erfordern dabei besondere Aufmerksamkeit. Es ist nicht kompliziert, erfordert jedoch eine sorgfältige Lektüre der Spezifikation [7].
Falls Sie bereits ein Event-basiertes System im Einsatz haben, das den CloudEvents-Standard bislang nicht berücksichtigt, ist das kein Grund, das Thema abzulehnen. Sie können mit vergleichsweise geringem Aufwand Wrapper, Konverter oder Middleware einsetzen, um zwischen bestehenden Formaten und dem Standard zu übersetzen. Das lohnt sich vor allem langfristig, da Sie auf diese Weise einen einheitlichen Austauschstandard etablieren und den Bedarf an individuellen Adaptern reduzieren. Besonders relevant wird das, wenn Sie CloudEvents auch als Basis für Event Sourcing nutzen – dann sind die Events bereits im Kern standardisiert.
Bleibt abschließend die Frage, ob sich CloudEvents langfristig als Standard etablieren wird. Ich bin in dieser Hinsicht optimistisch. Die Unterstützung durch Cloud-Anbieter wächst, ebenso wie die Verbreitung in Open- und Closed-Source-Anwendungen. Darüber hinaus dient CloudEvents bereits als Grundlage für weitere Standards, etwa CDEvents [8], die sich speziell auf Continuous-Delivery-Prozesse konzentrieren. Diese Entwicklung verdeutlicht, dass CloudEvents als tragfähige und zukunftsfähige Basis angesehen werden.
Ich kann Ihnen daher nur empfehlen, sich intensiv mit CloudEvents zu beschäftigen. Der Standard ist hilfreich, durchdacht und vor allem praxisnah. Je stärker Sie mit Event-basierten Architekturen arbeiten – sei es in der Entwicklung, in der Infrastruktur oder in anderen Bereichen –, desto relevanter wird dieses Konzept für Sie.
Wenn Sie bereits Erfahrungen mit CloudEvents gesammelt haben oder planen, sich damit auseinanderzusetzen, freue ich mich über Ihre Rückmeldung. Und falls Sie generell mehr über Event-basierte Systeme lernen möchten: Neben der bereits erwähnten Einführung in Event Sourcing finden Sie weiterführende Informationen auch in dem Blogpost "CQRS als Grundlage für moderne, flexible und skalierbare Anwendungsarchitektur [9]".
URL dieses Artikels:
https://www.heise.de/-10325241
Links in diesem Artikel:
[1] https://www.cncf.io/
[2] https://cloudevents.io/
[3] https://www.heise.de/blog/Event-Sourcing-Die-bessere-Art-zu-entwickeln-10258295.html
[4] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[5] https://www.asyncapi.com/
[6] https://opentelemetry.io/
[7] https://github.com/cloudevents/spec
[8] https://cdevents.dev/
[9] https://www.heise.de/blog/CQRS-als-Grundlage-fuer-moderne-flexible-und-skalierbare-Anwendungsarchitektur-10275526.html
[10] https://www.mastering-gitops.de/?wt_mc=intern.academy.dpunkt.konf_dpunkt_clc_gitops.empfehlung-ho.link.link
[11] https://www.mastering-gitops.de/veranstaltung-83006-se-0-gitops-auf-allen-ebenen-mit-crossplane-&-argocd.html?wt_mc=intern.academy.dpunkt.konf_dpunkt_clc_gitops.empfehlung-ho.link.link
[12] https://www.mastering-gitops.de/veranstaltung-83394-se-0-gitops-evolution-moderne-infrastruktur-pipelines-mit-pulumi-und-argo-cd.html?wt_mc=intern.academy.dpunkt.konf_dpunkt_clc_gitops.empfehlung-ho.link.link
[13] https://www.mastering-gitops.de/veranstaltung-83008-se-0-praxisbericht-zwei-jahre-gitops-mit-fluxcd-in-produktion.html?wt_mc=intern.academy.dpunkt.konf_dpunkt_clc_gitops.empfehlung-ho.link.link
[14] https://www.mastering-gitops.de/veranstaltung-83446-se-0-effiziente-multi-tenant-architekturen-gitops-mit-argo-cd-in-der-praxis.html?wt_mc=intern.academy.dpunkt.konf_dpunkt_clc_gitops.empfehlung-ho.link.link
[15] https://www.mastering-gitops.de/veranstaltung-83445-se-0-gitops-pattern-fuer-verteilte-deployment-pipelines-mit-kargo.html?wt_mc=intern.academy.dpunkt.konf_dpunkt_clc_gitops.empfehlung-ho.link.link
[16] https://www.mastering-gitops.de/tickets.php?wt_mc=intern.academy.dpunkt.konf_dpunkt_clc_gitops.empfehlung-ho.link.link
[17] mailto:mai@heise.de
Copyright © 2025 Heise Medien
(Bild: Erstellt mit KI (Midjourney) durch iX)
Der TypeScript-Compiler wird ab Version 7 nicht mehr in TypeScript, sondern in Go geschrieben sein. Was verspricht sich Microsoft davon, und warum gerade Go?
Seit Microsoft TypeScript im Oktober 2012 vorgestellt und veröffentlicht hat, ist die Sprache aus der modernen Webentwicklung nicht mehr wegzudenken. Kaum jemand, der an Web-basierten UIs arbeitet, dürfte in den vergangenen zehn Jahren an TypeScript vorbeigekommen sein. Doch die Kritik an TypeScript wächst: Immer häufiger werden Stimmen laut, die die schlechte Performance des TypeScript-Compilers bemängeln.
Immerhin war ursprünglich ein wesentlicher Aspekt der Webentwicklung, dass man nicht ständig auf einen Compiler warten musste. TypeScript hat das erfolgreich zunichtegemacht. TypeScript hat den Umgang mit JavaScript – gerade in großen Teams und in komplexen Anwendungen – zwar deutlich verbessert, aber zugleich auch die Geschwindigkeit und die Leichtigkeit der Webentwicklung gebremst.
Doch damit ist jetzt Schluss! Microsoft hat am 11. März angekündigt [2], die Performance des TypeScript-Compilers um den Faktor zehn zu beschleunigen. Und zwar, indem sie ihn komplett neu schreiben oder besser gesagt, portieren. Überraschenderweise jedoch nicht nach Rust, C# oder C++, sondern nach Go. Das wirft die Frage auf: Warum ausgerechnet Go?
Microsoft hat vor rund einer Woche unter dem Titel "A 10x Faster TypeScript" einen Blogpost [3] und auch ein Video [4] veröffentlicht, in dem Anders Hejlsberg erläutert, was Microsoft mit dem TypeScript-Compiler in der nahen bis mittleren Zukunft plant. Anders Hejlsberg ist dabei nicht irgendein Entwickler bei Microsoft, sondern federführender Sprachdesigner für TypeScript und C#. Er hat also umfassende Erfahrung in der Entwicklung von Programmiersprachen und im Compilerbau. Er kündigte an, dass der TypeScript-Compiler, wie wir ihn heute kennen, durch eine neue Implementierung in Go ersetzt werden wird. Microsoft wird dabei jedoch nicht alles von Grund auf neu schreiben, sondern die bestehende Codebasis – die derzeit in TypeScript geschrieben ist – nach Go portieren.
Ja, Sie haben richtig gelesen: TypeScript ist aktuell in TypeScript geschrieben, zukünftig wird es in Go geschrieben sein. Microsoft verspricht sich davon eine um den Faktor zehn bessere Performance, eine weitaus höhere Speichereffizienz sowie bessere Stabilität und Verlässlichkeit. Das wirft direkt Fragen auf: Was bedeutet das für mich? Warum gerade Go? Wie sieht es nach dem Umbau mit bestehenden Werkzeugen und generell dem Ökosystem aus?
Um diese Fragen zu beantworten, muss zunächst die bisherige Situation betrachtet werden. Der TypeScript-Compiler ist aktuell in TypeScript geschrieben. Das ist einerseits ein Vorteil, weil ein Compiler damit quasi direkt beweist, dass er funktioniert, indem er sich selbst übersetzt. Andererseits bedeutet es aber auch, dass der TypeScript-Compiler wie jede in TypeScript geschriebene Anwendung nach JavaScript übersetzt wird und in einer entsprechenden Laufzeitumgebung wie Node.js ausgeführt werden muss. Das ist zwar nicht interpretiert, sondern immerhin JIT-kompiliert, aber dennoch nicht so schnell, wie es mit nativem Code sein könnte.
Vor allem bei großen und komplexen Anwendungen führt das dazu, dass das Kompilieren unnötig langsam wird, weil der Compiler selbst langsam ist beziehungsweise zumindest nicht so schnell, wie er theoretisch sein könnte. Das zeigt sich deutlich an Visual Studio Code: Microsoft gibt für ein Referenzsystem eine Kompilierzeit von rund 78 Sekunden an – fast anderthalb Minuten. Visual Studio Code ist zwar ein großes Projekt, umfasst aber trotzdem "nur" 1,5 Millionen Zeilen Code, was für ein Real-World-Projekt nicht allzu umfangreich ist.
Mit dem neuen Compiler, der aktuell als Vorabversion verfügbar ist, dauert der gleiche Vorgang nur noch 7,5 Sekunden – eine Beschleunigung um den Faktor zehn. Dieser Effekt ist reproduzierbar: So benötigt das Kompilieren von Playwright statt 11 Sekunden nur noch eine Sekunde. Bei date-fns sinkt die Zeit von 6,5 auf 0,7 Sekunden. Mal ist der Effekt etwas stärker, mal etwas schwächer, doch im Schnitt entspricht er dem Faktor zehn. Und das ist erst die erste Preview – es könnte also noch weitere Optimierungspotenziale geben.
Zusätzlich sinkt der RAM-Bedarf durch den neuen Compiler um rund 50 Prozent. Das mag auf einem lokalen Entwicklungsrechner nicht besonders relevant sein, aber für CI/CD-Pipelines ist das ein massiver Gewinn. Der neue Compiler ist also nicht nur schneller, sondern auch deutlich sparsamer. Das ist beeindruckend.
Doch wie erreicht Microsoft diese Verbesserung? Die Antwort ist einfach: Nativer Code läuft deutlich schneller und sparsamer als Code, der zur Laufzeit von einem JIT-Compiler übersetzt werden muss.
Dennoch war die Ankündigung überraschend: Viele hätten erwartet, dass Microsoft TypeScript in Rust neu implementiert. Die Wahl von Go sorgt daher für Diskussionen. Microsoft begründet die Entscheidung klar: Rust bietet zwar hervorragende Performance, doch seine Speicherverwaltung mit Konzepten wie Borrowing und Ownership wäre für eine 1:1-Portierung des bestehenden Codes ein unnötiges Hindernis. Ähnlich verhält es sich mit C++: Obwohl C++ bezüglich Performance kaum zu schlagen ist, gilt die Sprache als altmodisch, fehleranfällig und schwer wartbar. C# hätte wiederum den Nachteil, dass der Compiler auf die .NET-Runtime angewiesen wäre, was unpraktisch ist, da ein Compiler idealerweise als statisch gelinkte Binary lauffähig sein sollte. Der AOT-Compiler von .NET würde zudem nicht alle gewünschten Zielplattformen unterstützen. Daher fiel auch C# aus der Auswahl.
Warum also Go? Vor allem, weil es konzeptionell TypeScript ähnelt und die Portierung daher vereinfacht. Die Speicherverwaltung erfolgt über eine Garbage Collection, sodass keine manuelle Speicherverwaltung erforderlich ist. Go kann zudem statisch gelinkte Binaries für alle gängigen Plattformen erzeugen, die keine weiteren Abhängigkeiten zur Laufzeit haben. Zudem ist Go auf Performance und Parallelisierung optimiert – essenzielle Aspekte für einen Compiler.
Microsoft hat sich also nicht deshalb für Go entschieden, weil es die "beste" oder "schnellste" Sprache wäre, sondern weil es die beste Balance zwischen Performance, Wartbarkeit und einfacher Portierung bietet. Das ist eine nachvollziehbare Entscheidung, die sachlich fundiert ist.
Was bedeutet das für Sie als TypeScript-Entwicklerin oder -Entwickler? Kurzfristig bleibt alles wie gewohnt. Als Nächstes erscheint TypeScript 5.9. Die darauffolgende 6er-Reihe wird schrittweise einige Features als "deprecated" markieren und Breaking Changes einführen – als Vorbereitung auf den neuen Compiler. Dieser wird mit TypeScript 7.0 veröffentlicht. Ein konkretes Datum gibt es noch nicht, doch bisher lagen zwischen zwei Major Releases meist zwei bis drei Jahre. Daher ist frühestens 2027 mit der Veröffentlichung zu rechnen. Das ist zwar noch lange hin, gibt aber ausreichend Zeit für eine schrittweise Migration. Vorausgesetzt, man ignoriert nicht alle kommenden Versionen bis zur 7.0 und handelt erst, wenn der Wechsel unvermeidlich ist.
Was bringt die Umstellung? In erster Linie schnellere Builds – sowohl lokal als auch in der CI/CD-Pipeline. Auch das Feedback des TypeScript-Language-Servers dürfte spürbar schneller erfolgen, was eine bessere IDE-Performance ermöglicht. Zudem wird ab TypeScript 7 kein installiertes Node.js mehr für den Compiler benötigt – ein theoretischer Vorteil, der in bestimmten Situationen jedoch tatsächlich hilfreich sein könnte.
Allerdings sind noch Fragen offen. Wie wird TypeScript künftig in andere Anwendungen und Webbrowser integriert? Bisher war das kein Problem, da der Compiler zu JavaScript kompiliert wurde. Theoretisch könnte dies über WebAssembly erfolgen, was Go unterstützt, doch die praktische Umsetzung bleibt abzuwarten. Zudem müssen Entwicklerinnen und Entwickler von Erweiterungen für den TypeScript-Compiler ihre Tools anpassen. Noch ist unklar, ob es nach Version 7 eine JavaScript-basierte Variante des Compilers geben wird oder ob Microsoft einen harten Wechsel durchführt.
Die Ankündigung war überraschend, insbesondere der Wechsel zu Go. Microsoft hat jedoch klargemacht, dass diese Entscheidung endgültig ist. Die Wahl von Go ist ein intelligenter Kompromiss zwischen Performance und Wartbarkeit.
Was halten Sie von dieser Entwicklung? Begrüßen Sie die Portierung? Und wie stehen Sie zur Wahl von Go? Schreiben Sie Ihre Meinung in die Kommentare!
URL dieses Artikels:
https://www.heise.de/-10317343
Links in diesem Artikel:
[1] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[2] https://www.heise.de/news/Microsoft-Native-Portierung-nach-Go-soll-TypeScript-zehnmal-schneller-machen-10312947.html
[3] https://devblogs.microsoft.com/typescript/typescript-native-port/
[4] https://www.youtube.com/watch?v=pNlq-EVld70
[5] https://enterjs.de/index.php?wt_mc=intern.academy.dpunkt.konf_dpunkt_vo_enterJS.empfehlung-ho.link.link
[6] https://enterjs.de/veranstaltung-78876-0-typescript--eine-anleitung-zum-ungluecklichsein.html?wt_mc=intern.academy.dpunkt.konf_dpunkt_vo_enterJS.empfehlung-ho.link.link
[7] https://enterjs.de/veranstaltung-72524-0-4-kritische-antipatterns-in-derreact-typescript-entwicklung.html?wt_mc=intern.academy.dpunkt.konf_dpunkt_vo_enterJS.empfehlung-ho.link.link
[8] https://enterjs.de/veranstaltung-78869-0-von-der-vision-zum-code-functional-domain-modeling-mit-typescript.html?wt_mc=intern.academy.dpunkt.konf_dpunkt_vo_enterJS.empfehlung-ho.link.link
[9] https://enterjs.de/tickets.php?wt_mc=intern.academy.dpunkt.konf_dpunkt_vo_enterJS.empfehlung-ho.link.link
[10] mailto:rme@ix.de
Copyright © 2025 Heise Medien
(Bild: tomertu/Shutterstock.com)
Wer Software entwickelt, muss die zugrunde liegende Fachlichkeit verstehen. Dabei hilft eine geeignete Modellierung der Fachdomäne.
75 Prozent aller Softwareprojekte scheitern! Dazu habe ich im vergangenen Oktober bereits einen Beitrag geschrieben [1]. Darin habe ich auch ein essenzielles und grundlegendes Problem angesprochen: Viele Softwareprojekte scheitern nämlich nicht an der Technik, sondern viel eher an einem fehlenden Verständnis der zugrunde liegenden Fachlichkeit. Denn es kommt äußerst selten vor, dass Entwicklerinnen und Entwickler sowie Fachexpertinnen und Fachexperten die gleiche Sprache sprechen. Allerdings ist damit nicht eine natürliche Sprache wie Deutsch, Englisch oder Französisch gemeint, sondern vielmehr das Fehlen einer gemeinsamen Fachsprache (und letztlich eines gemeinsamen Verständnisses, worum es bei der zu entwickelnden Software inhaltlich überhaupt geht).
Dass dies zu impliziten Annahmen, zu Missverständnissen und zu fehlerhaften Interpretationen führt, haben wir in dem erwähnten Video ausführlich erläutert. Das bedeutet letztlich nichts anderes, als dass Entwicklerinnen und Entwickler eine Software immer so bauen, wie sie diese verstehen – und nicht unbedingt so, wie das Business die Software benötigt. Folglich stellt sich die Frage, was man dagegen unternehmen kann: Eine mögliche Antwort ist eine wirklich gute Modellierung der Fachlichkeit. Wie eine solche Modellierung entwickelt wird, das erläutere ich Ihnen heute in diesem Blogpost.
Als allererstes sollte man zunächst verstehen, wo das Problem der fehlenden gemeinsamen Sprache und des fehlenden gemeinsamen Verständnisses überhaupt herkommt. Denn eigentlich sollte man meinen, dass es nicht so übermäßig schwierig sein kann, miteinander zu sprechen. Das Problem ist jedoch, dass hier unterschiedliche Welten aufeinandertreffen, die beide nie gelernt haben, mit der jeweils anderen Disziplin zu kommunizieren:
Das Problem lautet jedoch: Wie entwickeln Sie eine Software, die ein fachliches Problem lösen soll, wenn das fachliche Problem gar nicht verstanden wurde? Ganz einfach: Das funktioniert nicht.
Das Erschreckende ist jedoch, dass zu viele Teams und Unternehmen dies einfach ignorieren oder, was ich persönlich noch viel schlimmer finde, dass ihnen diese Diskrepanz nicht einmal bewusst ist. Da wird dann wochen- oder monatelang diskutiert, ob man Programmiersprache X oder doch lieber Framework Y einsetzen sollte, aber niemand kommt auf den Gedanken, sich einmal gezielt mit der Fachlichkeit auseinanderzusetzen.
Dann wird irgendwann drauflos entwickelt, und das geht ein paar Monate oder vielleicht auch ein oder zwei Jahre gut, aber schließlich erkennt man über kurz oder lang, dass die Software nicht genau das tut, was ursprünglich einmal gewünscht war. Und dann muss nachgebessert werden: Alles dauert auf einmal länger, alles wird teurer, und selbstverständlich ist das Fundament (weil falsche Annahmen getroffen wurden) in eine völlig unpassende Richtung entwickelt worden, sodass die Anpassungen jetzt nur sehr umständlich und damit auch wieder äußerst kostspielig möglich sind.
Mit hoher Wahrscheinlichkeit kommt dann jemand um die Ecke und behauptet:
"Ich hab’s Euch ja von vornherein gesagt: Hätten wir nicht auf Technologie X, sondern auf Technologie Y gesetzt, dann hätten wir das Problem jetzt nicht!"
Der Punkt ist jedoch: Das Problem wäre genauso vorhanden, nur auf einer anderen technologischen Basis. Denn das ist der springende Punkt: In den seltensten Fällen ist die Technologie an sich das Problem (womit ich nicht sagen möchte, dass es nicht bessere und schlechtere Technologieentscheidungen gäbe, in der Regel wird nur der Einfluss der Technologiewahl auf den Erfolg eines Projekts massiv überschätzt).
Das bedeutet: Wenn Sie sicherstellen möchten, dass Sie eine zum zugrunde liegenden fachlichen Problem passende Software entwickeln, und das sogar noch zielgerichtet, funktioniert es letztlich nur, wenn Sie von Anfang an verstehen, worum es aus fachlicher Sicht überhaupt geht. Das mag trivial erscheinen – die Praxis sieht leider allzu oft anders aus.
Oft steht uns Entwicklerinnen und Entwicklern nämlich etwas im Weg, das wir leider von klein auf beigebracht bekommen haben: Das Denken in Datenbanktabellen. Wir alle haben in unserer Ausbildung oder in unserem Studium gelernt, Daten in relationalen Strukturen abzulegen. Um mit diesen Strukturen zu arbeiten, kennen wir vier Verben, nämlich Create, Read, Update und Delete, häufig abgekürzt als CRUD. Wir haben gelernt, dass wir damit de facto alles modellieren können, und aus technischer Sicht ist das auch durchaus korrekt.
Aber das ändert selbstverständlich nichts daran, dass es sich bei diesen Wörtern um die Fachsprache der Datenbank handelt. Create, Read, Update und Delete sind nämlich rein technische Begriffe, die von Datenbanken genutzt werden. Da wir häufig mit Code zu tun haben, der auf Datenbanken zugreift, sind wir dazu übergegangen, diese vier Verben auch in unserem Code zu verwenden: So entstehen dann Funktionen mit Namen wie beispielsweise UpdateBook.
Aus technischer Sicht mag das sogar durchaus passend sein, wenn diese Funktion den Datensatz für ein Buch in der Datenbank aktualisiert. Das Problem besteht jedoch darin, dass dies nicht den fachlichen Use Case widerspiegelt. Denn warum wird das Buch beziehungsweise dessen Datensatz aktualisiert? Diese Information liefert der Funktionsname leider nicht. Das Problem ist außerdem, dass sich hinter diesem Update alles Mögliche verbergen kann. Ich bin mir sicher, dass wenn Sie an dieser Stelle kurz innehalten und sich überlegen, wie viele Gründe Ihnen spontan einfallen, warum man ein Buch aktualisieren können sollte, Sie keine Schwierigkeit haben, rasch auf zehn oder zwanzig unterschiedliche Gründe zu kommen.
Ich bin mir außerdem sicher, dass Sie – je nachdem, für welche Fachlichkeit Sie sich entscheiden – die Anwendung durchaus unterschiedlich entwickeln würden: Ein System zum Verwalten der ausgeliehenen Bücher in einer Bibliothek unterscheidet sich klar von einem System für einen großen Onlineshop, und beide sind wiederum etwas ganz anderes als ein System, das Autorinnen und Autoren beim Schreiben von Romanen unterstützen soll.
In allen drei Fällen kann es notwendig sein, ein Buch früher oder später zu aktualisieren, doch der gesamte Workflow darum ist jeweils ein völlig anderer, und abhängig davon würden vermutlich einige Dinge auch unterschiedlich gehandhabt. Ohne vertiefte Kenntnisse des umgebenden Prozesses ist es daher schwierig, Code zu schreiben, der das Richtige tut, und es greift zu kurz, einfach nur UpdateBook umzusetzen.
Langer Rede, kurzer Sinn: Wenn wir ohne die Prozesse zu kennen den Code für die Anwendung nicht adäquat und zielgerichtet schreiben können, sollten wir dann nicht vielleicht versuchen, diese Prozesse zunächst besser zu verstehen? Zu verstehen, worum es bei der gesamten Thematik überhaupt geht? Wer etwas macht? Was diese Person macht? Warum sie das macht? Wann und wie oft sie es macht? Welchen Zweck das Ganze hat? Welche Konsequenzen es nach sich zieht? Und so weiter.
Falls Sie jetzt denken:
"Stimmt, das wäre sinnvoll!"
Dann müssten wir als Nächstes überlegen, wie man Prozesse angemessen beschreiben kann. Eines kann ich Ihnen schon vorab verraten: Die Begriffe Create, Read, Update und Delete sind dabei ziemlich fehl am Platz. Tatsächlich ist die Denkweise in diesen vier Verben sogar ein Antipattern [3].
Doch wenn wir CRUD nicht verwenden können, um fachliche Prozesse zu beschreiben, was machen wir dann stattdessen? Benötigt wird dafür eine Methode, um Geschäftsprozesse als das darzustellen, was sie wirklich sind – nämlich eine Abfolge von Ereignissen. Stellen Sie sich vor, Sie kommen abends nach Hause und Ihre Partnerin oder Ihr Partner fragt, wie Ihr Tag war, woraufhin Sie erzählen, dass zuerst dieses und dann jenes geschehen sei. Sie berichten von Ereignissen, die Sie im Laufe des Tages erlebt haben – und genau das geschieht auch in einem Geschäftsprozess.
Nehmen wir als Beispiel die vorhin bereits kurz erwähnte Bibliothek. Wir können überlegen, welche Prozesse dort überhaupt auftreten: Welche Aktionen finden aus fachlicher Sicht in einer Bibliothek statt?
Man erkennt rasch, dass einer der wichtigsten Vorgänge darin besteht, dorthin zu gehen, um ein Buch zu leihen. Geliehene Bücher müssen über kurz oder lang natürlich auch wieder zurückgegeben werden, doch die Ausleihe kann verlängert werden, sofern niemand anderes das Buch vorbestellt hat. Wer zu spät mit der Rückgabe ist, muss möglicherweise eine Strafe zahlen, und die Bibliothek nimmt regelmäßig neue Bücher in den Bestand auf und entfernt alte, die nicht mehr in gutem Zustand sind.
Hier bemerken Sie bereits, wie reichhaltig die Sprache an dieser Stelle ist und wie viele Verben wir dabei verwenden: Ausleihen, zurückgeben, verlängern, vorbestellen, bezahlen, aufnehmen, entfernen und so weiter.
Vielleicht denken Sie jetzt, es sei doch logisch, auf diese Weise darüber zu sprechen, und im Grunde stimmt das auch. Doch warum findet man dann im Code höchstwahrscheinlich nur eine technisch benannte Funktion (nämlich UpdateBook) und nicht fachlich benannte Funktionen, etwa BorrowBook, RenewBook und ReturnBook?
Das ist eine berechtigte Frage, denn hätten wir diese Funktionen, könnten sie intern selbstverständlich immer noch ein Update oder eine andere Datenbankoperation ausführen, doch unser Code würde plötzlich eine fachliche Geschichte erzählen. Es wäre sehr viel einfacher, im Gespräch mit einer Fachexpertin oder einem Fachexperten nachzuvollziehen, was gemeint ist, weil sich die verwendeten Begriffe auch im Code wiederfinden würden.
Und das möglicherweise nicht nur im Code, sondern sogar auch in der API und in der UI. Wie viel besser könnte ein System gestaltet sein, wenn es auf diesen Begriffen basieren würde, anstatt stets nur von UpdateBook zu sprechen? Wie viel besser könnte eine UI sein? Wie viel effektiver könnte man Anwenderinnen und Anwender in ihrer Intention abholen und unterstützen?
An dieser Stelle kommen wir zum entscheidenden Punkt: Wenn wir zu der Erkenntnis gelangen, dass es besser ist, in unserem Code, in der API, in der UI und auch überall sonst mit fachlichen Begriffen zu arbeiten, anstatt mit technischen, warum modellieren wir dann nicht einfach die fachlichen Ereignisse so, wie sie wirklich stattfinden?
Was in der Realität geschieht, sind nämlich keine Updates, sondern Ereignisse, die wir in der Software nachbilden möchten. Genau aus diesem Grund sollten wir nicht nur in fachlichen Funktionen denken, sondern auch in fachlichen Events. Wenn wir unsere Software so gestalten, dass sie von echten Events angetrieben wird, verfügen wir nämlich plötzlich über eine Architektur und eine Codebasis, die die Realität widerspiegeln, anstatt nur ein unzureichendes technisches Abbild zu sein, das eine sprachliche Kluft und viel Raum für Missverständnisse und Interpretationen hinterlässt.
Genau an dieser Stelle setzt die Event-Modellierung an. Wenn wir akzeptieren, dass unsere Software die fachliche Realität widerspiegeln sollte und dass Events dafür das Mittel der Wahl sind, müssen wir uns zwangsläufig fragen: Wie finden wir die richtigen Events? Welche Ereignisse sind tatsächlich relevant? Welche beschreiben eine Veränderung? Auf welche Weise schneide ich meine Events so, dass sie fachlich sinnvoll sind?
Deshalb möchte ich das Ganze nun anhand eines konkreten Beispiels erläutern, nämlich an unserer bereits bekannten Stadtbibliothek.
Bevor Sie dort überhaupt etwas leihen dürfen, benötigen Sie zunächst einen Ausweis, eine sogenannte Library Card. Viele Entwicklerinnen und Entwickler würden vermutlich damit beginnen, dass man eine Library Card erstellen muss, also mit CreateLibraryCard – und schon befindet man sich wieder in der Denkweise von Create, Read, Update und Delete. Auch wenn das technisch später vielleicht korrekt sein mag, geht es zunächst doch darum, den Prozess aus fachlicher Sicht zu beschreiben.
Niemand würde eine Bibliothek betreten und sagen:
"Created mir bitte einen Bibliotheksausweis!"
Stattdessen würde man wohl fragen, wie ein solcher Ausweis beantragt werden kann. Genau dies ist der erste Schritt unseres Prozesses. Die Frage lautet also: Welcher Begriff trifft das Ganze fachlich am besten? Die Formulierung "Ausweis beantragen" passt aus meiner Sicht schon recht gut. Allerdings ist "Ausweis beantragen" noch kein Event. Es müsste nämlich in der Vergangenheitsform stehen, also "Ausweis wurde beantragt".
Das ergibt Sinn, denn wenn Sie sich vorstellen, abends nach Hause zu kommen und gefragt zu werden, wie Ihr Tag war, würden Sie ebenfalls in der Vergangenheitsform erzählen. Bei Bedarf lässt sich das Ganze dann schlussendlich noch ins Englische übertragen, was dann einem "Applied for a Library Card"-Event entsprechen würde.
Als Nächstes würde der Ausweis vermutlich ausgestellt. Vielleicht denken Sie jetzt:
"Alles klar, dann haben wir aber jetzt ein Create."
In der Vergangenheitsform wäre das ein "Library Card Created"-Event. Rein sprachlich wäre das korrekt, allerdings hatte ich erwähnt, dass der Ausweis ausgestellt wird. Einen Ausweis auszustellen bedeutet jedoch nicht "Create a Library Card", sondern eher "Issue a Library Card". Daher hätten wir also eher ein "Library Card Issued"-Event.
Vielleicht wenden Sie nun ein, dass das letztlich Wortklauberei sei. Ob nun create oder issue – das sei doch egal, man wisse schließlich, was gemeint ist. Der springende Punkt ist jedoch: Das weiß man eben gerade leider nicht. Wir hatten gerade selbst die Situation, dass wir zwei verschiedene Ereignisse – nämlich das Beantragen und das Ausstellen des Ausweises – zunächst beide als create bezeichnen wollten. Hätten wir das getan, hätten wir nun bereits zwei Prozessschritte, die wir sprachlich nicht voneinander unterscheiden könnten.
Indem wir versuchen, fachlich passende und semantisch ausdrucksstarke Wörter zu finden, präzisieren wir unsere Sprache. Wir erhalten dadurch nicht nur ein genaueres Verständnis darüber, worum es fachlich geht, sondern nähern uns sprachlich auch der Fachabteilung an. Genau diese Kombination führt dazu, dass wir besser miteinander kommunizieren, Wünsche und Anforderungen besser verstehen und auf diese Weise letztlich in der Lage sind, bessere Software in kürzerer Zeit zu entwickeln.
Wie viel hilfreicher ist nämlich bitte die Frage:
"Okay, wir haben jetzt implementiert, dass man Ausweise beantragen kann und dass diese anschließend ausgestellt werden können, was ist der nächste Schritt?"
im Vergleich zu der Aussage:
"Wir haben jetzt CreateAusweis implementiert, wir machen dann als Nächstes UpdateAusweis.“
Ersteres bietet eine hervorragende Basis für ein zielgerichtetes Gespräch mit einer fachkundigen Person, während Letzteres eine vage, technische Äußerung darstellt, die kaum etwas aussagt und wahrscheinlich jede weitere Kommunikation verhindert.
Dieses Prinzip, sprachlich präzise zu sein und fachliche statt technischer Begriffe zu verwenden, sollten wir konsequent fortführen: Ein Bibliotheksausweis allein bringt noch nicht viel, er bildet lediglich die Voraussetzung dafür, dass wir überhaupt Bücher ausleihen dürfen. Und genau das wäre vermutlich der nächste Schritt im Prozess: Ein Buch auszuleihen.
Nun stellt sich erneut die Frage, wie dieses Event genannt werden sollte. Sprechen wir einfach von einem BookBorrowed-Event? Oder existieren möglicherweise Unterschiede? Wird ein Buch beispielsweise sofort ausgeliehen, oder muss es erst reserviert werden, um es später abzuholen? Welche Bedingungen müssen erfüllt sein, damit die Ausleihe tatsächlich stattfindet? All das sind Überlegungen, die wir nur anstellen, wenn wir sprachlich präzise bleiben und uns eng an der Fachsprache orientieren, da uns genau das dazu zwingt, uns inhaltlich mit der Fachlichkeit auseinanderzusetzen. Dies ist gut. Auf diese Weise entstehen nach und nach die verschiedenen Events, die in der jeweiligen Fachdomäne eine Rolle spielen.
Ein weiterer Vorteil besteht darin, dass sich dies wunderbar gemeinsam umsetzen lässt: Die Entwicklungsabteilung und die Fachabteilung kommen zusammen, sodass ein Gespräch entsteht und beide in eine gemeinsame Richtung arbeiten. Es handelt sich nicht um ein Gegeneinander (wie es sonst so häufig der Fall ist), sondern um ein Miteinander. Die Fachabteilung hat schließlich ein Interesse daran, dass die Entwicklung versteht, worum es geht, denn nur dann kann sie eine adäquate und zielgerichtete Software erstellen. Dies gilt selbstverständlich auch in umgekehrter Richtung. Genau diese Herangehensweise – die Fachlichkeit in den Vordergrund zu rücken – macht das Prinzip so mächtig.
Vielleicht fragen Sie sich jetzt, ob es dafür nicht bereits einige fertige Workshop-Formate gibt. Tatsächlich existiert eine ganze Reihe, etwa Event Storming, Event Modeling oder Domain Storytelling. Diese Formate verfolgen jeweils einen etwas anderen Ansatz: Domain Storytelling eignet sich beispielsweise sehr gut dafür, überhaupt erst einmal einen Fuß in eine Fachdomäne zu setzen, während Event Storming und Event Modeling sehr in die Tiefe gehen und teils auch technische Details beleuchten.
Deshalb würde ich zumindest anfangs zu Domain Storytelling raten: Es ist zum Glück leicht zu erlernen, und es gibt ein interessantes Buch zu diesem Thema [4].
Letztlich spielt es jedoch keine große Rolle, welche dieser Methoden Sie verwenden oder ob Sie überhaupt eine davon nutzen. Wichtig ist nur, dass Sie eine gemeinsame Basis schaffen – mit einer gemeinsamen Sprache und einem gemeinsamen Verständnis. Der Weg dorthin ist letztlich zweitrangig. Nehmen Sie daher einfach das, was Ihnen am ehesten zusagt. Wählen Sie das, womit Sie sich wohlfühlen. Entscheiden Sie sich für das, wo Sie möglicherweise schon jemanden kennen oder finden, der Sie dabei unterstützt und den Prozess anleitet oder moderiert.
Vielleicht fragen Sie sich zum Schluss noch, warum Sie das alles speziell in dieser Event-Form gestalten sollten. Man könnte anstelle von "Ausweis wurde beantragt", "Ausweis wurde ausgestellt", "Buch wurde ausgeliehen" und so weiter ebenso gut Formulierungen im Indikativ verwenden, also in der Grundform, beispielsweise "Ausweis beantragen", "Ausweis ausstellen", "Buch ausleihen" und so weiter.
Die fachlichen Verben wären dort schließlich ebenfalls enthalten. Das ist im Grundsatz richtig, aber es gibt gewissermaßen noch einen Bonus, wenn Sie die Event-Form verwenden. Es ist sozusagen die sprichwörtliche Kirsche auf der Torte. Sobald Sie diese geschäftlichen Ereignisse in der Event-Form ausdrücken, erhalten Sie die ideale Ausgangsbasis, um die Events in einem geeigneten Protokoll zu speichern, ähnlich einem Logbuch.
Dies wiederum bietet eine Vielzahl von Vorteilen von einer deutlich besseren Transparenz darüber, was wann und warum von wem durchgeführt wurde, über ein integriertes Audit-Log bis hin zu sehr flexiblen Möglichkeiten für Analysen und Reports. Das kann man sich leicht vorstellen: Wenn Sie nur wissen, dass ein Buch gerade ausgeliehen ist, kennen Sie diesen Zustand, aber sonst nichts. Wenn Sie jedoch die komplette Historie kennen, die im Laufe der Zeit zum aktuellen Status quo geführt hat, können Sie unzählige Fragen beantworten, auch wenn Ihnen zuvor nicht klar war, dass diese Informationen später von Interesse sein würden. Dazu zählen Fragen wie:
Diese Art der Datenspeicherung nennt man Event Sourcing, und dazu habe ich vor einigen Wochen bereits einen Beitrag geschrieben [5]. Der Vorteil daran ist, dass Sie gleich drei Fliegen mit einer Klappe schlagen, wenn Sie fachliche Prozesse konsequent als Events formulieren:
Übrigens war ich vor ungefähr zehn Tagen in einem sehr interessanten Podcast zu Gast – dem Engineering Kiosk [7] –, wo wir uns eineinhalb Stunden lang ausführlich über das Zusammenspiel all dieser Themen unterhalten haben. Wenn Sie das interessiert, schauen oder hören Sie dort gerne einmal vorbei.
URL dieses Artikels:
https://www.heise.de/-10292363
Links in diesem Artikel:
[1] https://www.heise.de/blog/75-Prozent-aller-Softwareprojekt-scheitern-was-tun-9979648.html
[2] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[3] https://www.youtube.com/watch?v=MoWynuslbBY
[4] https://www.youtube.com/watch?v=EaKWQ1rsaqQ
[5] https://www.heise.de/blog/Event-Sourcing-Die-bessere-Art-zu-entwickeln-10258295.html
[6] https://www.youtube.com/watch?v=hP-2ojGfd-Q
[7] https://engineeringkiosk.dev/podcast/episode/183-event-sourcing-die-intelligente-datenarchitektur-mit-semantischer-historie-mit-golo-roden/
[8] mailto:rme@ix.de
Copyright © 2025 Heise Medien
(Bild: Erstellt mit KI (Midjourney) durch iX-Redaktion)
Viele Unternehmen sparen an der Codequalität: zu aufwendig und zu teuer. Diese Argumentation ist nicht nur falsch, sondern langfristig auch gefährlich.
Ich nehme an, Sie kennen das Phänomen: Sie arbeiten an einem Softwareprojekt und entdecken einen Fehler. Eigentlich sollten Sie ihn gleich beheben, doch Sie sind derzeit mit einem Feature beschäftigt, das ohnehin schon verspätet ist. Um den Fehler zu beheben, müssten Sie zudem eine Abhängigkeit aktualisieren, was allerdings nicht ohne Weiteres möglich ist, weil Sie dann in einigen Bereichen des Codes Anpassungen vornehmen müssten.
Da Sie ohnehin schon spät dran sind, treffen Sie die einzig denkbare Entscheidung: Sie verschieben den Bugfix auf "später". Der springende Punkt dabei ist jedoch: Dieses "später" tritt nie ein. Das bedeutet, nach einiger Zeit stehen Sie vor einem großen Berg technischer Schulden und fragen sich: Wie konnte es überhaupt jemals so weit kommen?
Diese Situation ist keineswegs neu. Sie trägt sogar einen Namen: die "Broken-Windows-Theorie [1]". Damit ist nicht gemeint, dass das Betriebssystem Windows erneut defekt ist, sondern der Begriff stammt aus der Stadtplanung. Die zugehörige Idee ist simpel und zugleich wirksam: Es geht darum, warum in bestimmten Stadtteilen Kriminalität offenbar ungebremst um sich greifen kann. Die These der Broken-Windows-Theorie besagt, dass dies geschieht, wenn Stadtteile vernachlässigt werden. Wenn zum Beispiel Gebäude dauerhaft leer stehen und nicht – wie möglicherweise lange geplant – abgerissen werden.
Als Symbol dafür wählten die US-amerikanischen Sozialforscher James Wilson und George Kelling in den frühen 1980er-Jahren das zerbrochene Fenster: Wenn eine Fensterscheibe zerbricht und niemand sie ersetzt, zeigt das, dass sich niemand darum kümmert. Da jedoch niemand neben einem leer stehenden Haus mit einer dauerhaft zerbrochenen Scheibe leben möchte, ziehen bald darauf die ersten Nachbarn fort.
Daraus folgen weitere leer stehende Häuser, und jemand wirft dort vermutlich früher oder später ebenfalls eine Fensterscheibe ein. So entsteht langsam eine Kettenreaktion, in der das Viertel weiter verfällt, der soziale Zusammenhalt nachlässt und es irgendwann sehr schwierig werden kann, noch etwas zu ändern, selbst wenn es jemand möchte. Dadurch sinkt die Hemmschwelle gegenüber Kriminalität, was letztlich den gesamten Prozess nur weiter beschleunigt.
Die entscheidende Frage lautet nun, wie sich eine solche Entwicklung wieder unter Kontrolle bringen lässt. Tatsächlich gibt es darauf eine Antwort, die in der Vergangenheit bereits funktioniert hat, etwa in New York in den 1990er-Jahren. Dort beschrieb die eingangs geschilderte Lage ziemlich genau den Status quo, und der damalige Bürgermeister (von 1994 bis 2001 war dies Rudolph Giuliani, den Sie vielleicht als ehemaligen Rechtsberater von Donald Trump kennen) verfolgte eine sogenannte "Zero-Crime-Tolerance"-Strategie.
Dabei geht es, wie der Name erahnen lässt, darum, bei jeglichen Verstößen – auch bei kleineren Vergehen wie Falschparken – keinerlei Nachsicht walten zu lassen. Das hatte insofern Erfolg, als die Kriminalitätsrate in den folgenden Jahren stark sank. Allerdings sollte man nicht unterschlagen, dass diese konsequente Polizeipräsenz wiederum kritisiert wurde, da sie manchem zu weit ging. Gerade aus den USA hört man immer wieder von Polizeigewalt und rassistischem Vorgehen, was man natürlich genauso wenig möchte. Zusammengefasst ist es also schwierig, die richtige Balance zu finden, doch eine Null-Toleranz-Strategie trägt natürlich wesentlich dazu bei, wuchernde Kriminalität einzudämmen.
Was hat das nun mit Softwareentwicklung zu tun? Nun, die Broken-Windows-Theorie lässt sich hervorragend auf Softwareprojekte übertragen. Zusammengefasst: Jeder nicht behobene Fehler ist ein zerbrochenes Fenster. Jede Codezeile, die gepflegt werden müsste, aber nicht wird, ist ein zerbrochenes Fenster. Jede veraltete Abhängigkeit, die nicht aktualisiert wird, ist ein zerbrochenes Fenster. Und so weiter. Anders ausgedrückt: Wenn Sie sich nicht konsequent mit einer Null-Toleranz-Strategie um die eigene Codebasis kümmern, führt dies zwangsläufig zu einer Abwärtsspirale in Ihrem Projekt.
Warum ist das so? Weil sich Fehler und technische Schulden addieren. Das bedeutet, dass der Aufwand, sie irgendwann zu beheben, stetig größer wird. Gleichzeitig steigt auch das Risiko, dabei etwas kaputtzumachen. Beides zusammen sorgt dafür, dass niemand sich mehr an den Code wagt, was wiederum nur zu weiteren Fehlern und noch mehr technischen Schulden führt. Man errichtet so ein Fundament, das von Beginn an instabil ist, baut darauf immer weiter auf und macht dieses Gebilde dadurch noch fragiler, bis es zu einem Kartenhaus verkommt, das unweigerlich in sich zusammenfallen muss.
Zusätzlich besteht dann die Angst, bestehende Module anzupassen oder zu erweitern, weil man nicht weiß, ob eine Funktion möglicherweise eine tragende Karte dieses fragilen Konstrukts ist. Folglich umschiffen alle den vorhandenen Code, was die Entwicklung kompliziert, langsam und teuer macht. Und aufgrund dieser Instabilität will sich auch niemand mehr an externe Abhängigkeiten heranwagen, weil dies Aufwand bedeutet. Also bleibt man lieber bei jenen Versionen, die augenscheinlich funktionieren, was jedoch auf lange Sicht die Aktualisierungsmöglichkeiten verbaut und rasch zu Sicherheitslücken oder nicht behobenen Problemen führt.
Offensichtlich ist es riskant, sich nicht um die Codequalität eines Projekts zu kümmern. Doch es kommt noch ein weiterer Faktor hinzu: Denn wer sind die ersten Nachbarn, die eine Gegend mit zerbrochenen Fenstern verlassen? Das sind stets jene, die sich das problemlos leisten können. In Softwareprojekten sind es folglich häufig die besonders fähigen Entwicklerinnen und Entwickler, die als Erste gehen – und das sind leider genau die Personen, die Sie am dringendsten bräuchten, um die Situation noch zu retten, da sie über umfassendes Fachwissen und Erfahrung verfügen.
Das klingt überaus dramatisch. Aber so stellt sich die Realität dar. Selbstverständlich können Sie die Augen davor verschließen und sich einreden, bei Ihrem eigenen Projekt sei alles vollkommen anders. Vermutlich finden Sie auch zahlreiche Argumente, weshalb die Entwicklung bei Ihnen gar nicht anders laufen könne. Doch genau damit reden Sie sich die Lage schön. Die Augen zu schließen und zu glauben, andere könnten Sie dann nicht mehr sehen, das ist ein Verhalten, das vielleicht im Kindergarten Sinn ergibt, aber in der Softwareentwicklung schlicht nicht funktioniert. Erschreckend finde ich, wie viele Unternehmen genau diesen Ansatz trotzdem immer und immer wieder wählen.
Möglicherweise fragen Sie sich jetzt, woran Sie konkret erkennen, dass in Ihrem Softwareprojekt bereits einige Scheiben zerbrochen sind. Daher möchte ich Ihnen ein paar typische Anzeichen nennen. Diese Liste hat keine festgelegte Reihenfolge, ich führe sie schlicht so auf, wie sie mir in den Sinn kommt.
Indizien für zerbrochene Fenster sind beispielsweise auffallend lange und womöglich weiter ansteigende Build- und Deployment-Zeiten. Auch Code, der immer öfter Kommentare wie "TODO" oder "FIXME" enthält, sollte Sie nachdenklich stimmen. Wenn Sie regelmäßig Workarounds und provisorische Lösungen umsetzen, anstatt Probleme gründlich zu beseitigen, ist dies ein Warnsignal. Sinkt die Testabdeckung im Laufe der Zeit, treten Fehler erneut auf, die schon einmal behoben worden waren, existiert keine Dokumentation oder ist sie fehlerhaft beziehungsweise veraltet, dann sind das alles Anzeichen für zerbrochene Fenster.
Wenn es Codebereiche gibt, die niemand anfassen will, wenn Ihre Dependencies nicht auf dem neuesten Stand sind, wenn immer mehr Tickets für technische Aufgaben auflaufen – das alles sind Hinweise, dass etwas nicht stimmt. Und all diese Vorkommnisse sind wie Eisberge: Was Sie zuerst sehen, ist immer nur die Spitze, und das wahre Ausmaß bleibt verborgen. Unterschätzen Sie die Lage also nicht, indem Sie sie als unwichtige Kleinigkeiten abtun. Oft ist das tatsächliche Problem viel größer, als es zunächst scheint.
Das erste typische Gegenargument lautet:
"Ach, das sind doch alles nur Kleinigkeiten!"
Genau diesen Einwand habe ich eben schon vorweggenommen. Interessant ist aber, dass es zahlreiche solche Bedenken gibt. Hier sind wir an dem Punkt, dass sich viele Unternehmen die Problematik schönreden. Und was sind verbreitete Einwände?
Sehr verbreitet ist beispielsweise:
"Ja, grundsätzlich stimmt das alles, aber wir haben keine Zeit. Wir müssen eine Deadline einhalten."
Diese Aussage lässt sich üblicherweise auf zwei Situationen zurückführen:
Ein weiteres häufiges Gegenargument lautet:
"Regelmäßige Codepflege können wir uns nicht leisten, das wäre zu teuer!"
Auch das ist nicht haltbar, denn hier zeigt sich, dass das eigentliche Problem schon vor etlichen Jahren seinen Lauf nahm. Codepflege ist nämlich nur dann kostspielig, wenn sie zu lange hinausgezögert wurde. Natürlich gibt es Bereiche, die mehr Aufwand bedeuten, doch wenn Sie diese von Beginn an zeitnah erledigen, fallen die Kosten viel niedriger aus, als wenn Sie sie wiederholt vertagen, um sie irgendwann inmitten anderer dringender Aufgaben angehen zu müssen, ohne Zeit und Planung.
Vergleichbar ist das mit einem Haushalt, der nie aufgeräumt wird, stets mit dem Argument, es sei jetzt zu viel Aufwand, bis Sie irgendwann gar kein sauberes Geschirr mehr besitzen und die Wohnung voller Müll liegt, sodass Sie darüber stolpern, hinfallen und sich verletzen. Genau in diesem Moment stellen Sie fest, dass gerade in der Küche ein Feuer ausgebrochen ist, weil dort unbeaufsichtigt ein Topf auf dem Herd stand. Und schon wird die Angelegenheit richtig teuer, womöglich erfordert sie sogar eine Renovierung. War der Plan "sofortiges Aufräumen ist zu viel Aufwand" also wirklich so sinnvoll? Ganz bestimmt nicht.
Gerne wird auch argumentiert:
"Alles funktioniert doch im Großen und Ganzen – wir werden tätig, sobald tatsächlich etwas kaputtgeht."
Das wird gerne noch mit "Never Touch a Running System" unterstrichen. Selbstverständlich sollten Sie nicht ohne konkreten Anlass an funktionierendem Code herumbasteln. Aber es geht nicht ums bloße "Herumbasteln", sondern darum, vorhandene technische Schulden abzutragen, um langfristige Schäden zu vermeiden. Häufig steckt hinter diesem Einwand schlicht die Sorge, bei Umbauten könnte etwas kaputtgehen. Und diese Angst ist in gewisser Weise berechtigt. Doch woher rührt sie? Liegt es daran, dass zu wenige automatisierte Tests existieren? Oder vielleicht gar keine? Gibt es auch kein strukturiertes Testkonzept?
In einem solchen Kontext würde wohl niemand unnötige Änderungen riskieren. Dennoch sollte es normal sein, Code zu revidieren, zu überarbeiten und anzupassen. Die einzige Möglichkeit, sicherzustellen, dass dabei nichts zerbricht, sind umfangreiche Tests, am besten automatisiert, damit sie jederzeit effizient wiederholbar sind. Dass viele Projekte darauf weitgehend verzichten, liegt oft daran, dass jemand meinte, Tests seien zu aufwendig und deshalb nicht so wichtig.
Ein weiteres verbreitetes Argument lautet, dass es zu viel Druck aus dem Fachbereich gäbe. Meistens sind das schlicht unrealistische Erwartungen, verbunden mit wenig Verständnis für die Abläufe in der Softwareentwicklung. Das ist grundsätzlich nachvollziehbar: Denn woher soll ein Fachbereich ohne technische Vorerfahrung es besser wissen? Häufig fehlt dann eine Person, die die Interessen der Entwicklung angemessen vertritt und erklärt, wie Softwareentwicklung funktioniert.
Dieser Effekt zeigt sich meist in Unternehmen, deren Kerngeschäft nicht die Softwareentwicklung an sich ist, sondern beispielsweise in Versicherungen, Baukonzernen, dem Einzelhandel und so weiter, wo Software nur ein notwendiges, aber ungeliebtes Hilfsmittel ist. Dort gilt meist "Umsatz vor Grundsatz". Der Fachbereich setzt sich also oft durch, sodass die Softwareentwicklung mit ihren Qualitätsansprüchen außen vor bleibt. Wird dies nicht klar kommuniziert, entsteht massiver Druck von dieser Seite.
Man könnte diese Liste beliebig fortsetzen, aber ich denke, hier wird bereits ein Muster deutlich. Das Muster lautet: Kurzfristiges Denken hat zu oft Vorrang vor langfristigen Überlegungen. Viel zu häufig geht es um eine rasche, günstige Fertigstellung, ohne den Blick auf langfristige Stabilität und Wartbarkeit. Dieses Problem entsteht nicht erst nach und nach, sondern es existiert meist schon ab dem ersten Tag eines Softwareprojekts, bleibt anfangs aber unbemerkt.
Jeder Schritt, bei dem nicht auch an die spätere Weiterentwicklung gedacht wird, führt in die falsche Richtung. Das resultiert unweigerlich in zerbrochenen Fenstern. Wenn es dann wirklich brennt, möchte niemand eine abrupte Kehrtwende vornehmen, denn schließlich hat doch bis gestern scheinbar alles funktioniert. Das Hinauszögern setzt sich also fort, und das Problem verschlimmert sich noch mehr. Erst wenn irgendwann unübersehbar ist, dass es so nicht weitergehen kann, folgt das große Klagen und die Hoffnung, nun eine einfache Lösung zu finden. Doch eine solche existiert nicht – und das will dann verständlicherweise niemand hören.
Welche Lehre lässt sich aus all dem ziehen?
Erstens: Wenn Sie früh genug dran sind und Ihr Projekt noch auf der sprichwörtlichen grünen Wiese beginnt, sollten Sie von Tag 1 an eine echte Null-Toleranz-Strategie im Hinblick auf Codequalität verfolgen. Das bedeutet, Sie benötigen ein äußerst strenges Projektsetup. Dazu gehören beispielsweise streng konfigurierte Linter-Regeln, automatisierte Formatierung, angemessene Tests sowie eine CI/CD-Pipeline. Es dürfen keinerlei Warnungen von Linter oder Compiler akzeptiert werden: Entweder ist der Code rundum fehlerfrei, oder der Build schlägt fehl. Dazwischen gibt es nichts.
Ebenso sollte kontinuierliches Refactoring einen hohen Stellenwert haben, und Fehler sollten sofort beseitigt werden. Natürlich wird es niemals vollkommen fehlerfreie Software geben, doch sobald ein Fehler bekannt ist, genießt dessen Behebung oberste Priorität. Solange dieser Bug nicht korrigiert ist, wird kein neues Feature entwickelt, eben konsequent gemäß dem Prinzip "Null Toleranz".
Falls nun jemand behauptet, dies wäre ein Freibrief für die Entwicklung, sich in Details zu verlieren, ist das wahre Problem nicht die Null-Toleranz-Strategie, sondern tief sitzendes Misstrauen gegenüber dem Verantwortungsbewusstsein der Entwickler. Das ist ein viel grundlegenderes Thema, das gern ignoriert wird, weil es wesentlich einfacher scheint, Symptome zu bekämpfen als Ursachen.
Zweitens sollten Sie alles, was möglich ist, automatisieren: Tests, Deployments, Updates und so weiter. Letztlich greift hier alles ineinander. Stellen Sie sich vor, es erscheint ein Update für eine Abhängigkeit: Zunächst müssten Sie erfahren, dass es dieses Update gibt. Danach müssten Sie es testweise einspielen, prüfen, ob weiterhin alles funktioniert, einen Branch erstellen, den Commit vornehmen, pushen, einen Pull-Request anlegen und jemanden finden, der das Ganze prüft und freigibt. Natürlich wird sich niemand regelmäßig diesen Aufwand antun wollen.
Wenn jedoch ein Bot automatisch einen Pull-Request stellt, der dann eine CI/CD-Pipeline anstößt und sämtliche Tests ausführt, Sie über die Ergebnisse informiert werden, und Ihre einzige Aktion (zumindest in 95 Prozent der Fälle) darin besteht, den erfolgreich durchgelaufenen Pull-Request durchzuwinken, dann bleibt Ihr Zeitaufwand minimal. Gleichzeitig bleiben Ihre Dependencies auf dem aktuellen Stand, und Sie haben nun auch die zeitlichen Kapazitäten, sich um jene 5 Prozent zu kümmern, bei denen tatsächlich manuelles Eingreifen nötig ist, etwa wegen Breaking Changes. Dies funktioniert aber nur, wenn Sie die betreffenden Prozesse entsprechend automatisiert haben.
Damit komme ich zum letzten Punkt, den ich Ihnen heute mitgeben möchte: Code-Reviews und das Vier-Augen-Prinzip ab Tag 1. Nur so ist sichergestellt, dass jede Änderung geprüft wird und es zudem kein Inselwissen gibt. Nach einem Review haben zumindest zwei Personen den Code durchgesehen und sich damit auseinandergesetzt. Alternativ können Sie auch Pair-Programming nutzen, denn das ist im Grunde lediglich ein Live-Review. Wahrscheinlich hören Sie jetzt schon das Argument, dass dies zu kostenintensiv sei und keine Zeit dafür bleibe, wegen Deadlines, Fachbereich und so weiter. Aber vielleicht haben Sie durch diesen Blogpost ein paar Argumente an der Hand, um all dem zukünftig souveräner zu begegnen.
Unter dem Strich bleibt die Erkenntnis, dass eine dauerhafte, regelmäßige Pflege des Codes langfristig zu weit stabileren und damit auch günstigeren Projekten führt, selbst wenn es anfangs gegen die Intuition sprechen mag.
URL dieses Artikels:
https://www.heise.de/-10284004
Links in diesem Artikel:
[1] https://de.wikipedia.org/wiki/Broken-Windows-Theorie
[2] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[3] mailto:rme@ix.de
Copyright © 2025 Heise Medien
(Bild: erzeugt mit KI durch iX)
Man hört oft, komplexe Systeme basierten auf CQRS. Doch was genau ist das eigentlich, CQRS? Was verbirgt sich hinter dem Akronym, und wie kann man es nutzen?
Vor zwei Wochen habe ich einen Blogpost als Einführung in Event-Sourcing [1] geschrieben. Das Thema ist bei vielen von Ihnen auf sehr großes Interesse gestoßen, es gab sehr viel Feedback dazu, und natürlich gab es auch eine ganze Reihe von Fragen. Im heutigen Blogpost greife ich viele dieser Fragen auf und beantworte sie. Sie bekommen aber vor allem auch eine weitere Einführung in ein mit Event-Sourcing zusammenhängendes Konzept: Heute geht es nämlich auch um ein Architektur-Pattern namens CQRS. Was das ist, wofür es gut ist, wie es funktioniert, was die Anwendungsfälle sind, wie Sie es mit Event Sourcing kombinieren können, und so weiter – all das erfahren Sie heute.
Fangen wir einmal, ganz kurz, mit einer Klarstellung an: Vielleicht haben Sie von CQRS schon gehört, und Sie würden nun gerne wissen, was genau es damit auf sich hat, aber vielleicht haben Sie den Blogpost zu Event Sourcing vor zwei Wochen nicht gelesen. Da stellt sich nun die Frage: Können Sie den heutigen Post trotzdem "einfach so" lesen, oder sollten Sie sich zuerst mit dem Thema Event Sourcing beschäftigen?
Nun, dafür ist ganz wichtig: CQRS und Event Sourcing sind zwei Konzepte, die unabhängig voneinander existieren. Das heißt, Sie können CQRS durchaus umsetzen, ohne Event Sourcing nutzen zu müssen, und Sie können Event Sourcing auch umsetzen, ohne CQRS nutzen zu müssen, und insofern könnten Sie diesen Blogpost auch als in sich geschlossenes Thema ansehen.
Aber: Die beiden Konzepte ergänzen einander ausgesprochen gut. Insofern werden Sie sie in der Praxis eher selten isoliert voneinander vorfinden, sondern in der Regel gemeinsam. Deshalb baue ich in diesem heutigen Blogpost auf dem auf, was ich vor zwei Wochen geschrieben habe. Sollten Sie jenen Blogpost [2] also noch nicht gesehen haben, dann würde ich Ihnen empfehlen, das jetzt nachzuholen. Alternativ können Sie ihn sich auch als Video [3] ansehen.
Doch was ist CQRS überhaupt? Das Akronym steht für "Command Query Responsibility Segregation", also für die Trennung der Verantwortlichkeiten für Commands und Queries.
Tatsächlich ist das sehr viel einfacher, als es zunächst klingt. Die Kernidee von CQRS ist, dass es für den Zugriff auf Anwendungen nur zwei Arten von Interaktionsmustern gibt: Entweder führt die Anwenderin oder der Anwender eine Aktion aus, mit der Absicht, im System etwas zu verändern, oder sie oder er möchte etwas wissen. Mehr Möglichkeiten gibt es nicht. Das heißt, entweder teilen Sie einer Software mit, dass sie dies oder jenes für Sie erledigen soll, dann geben Sie ihr quasi einen Befehl (das ist dann ein sogenannter "Command") – oder Sie fragen die Software nach einer Information, Sie stellen also eine Frage oder führen eine Abfrage durch (und das ist dann eine sogenannte "Query").
Das eine, also ein Command, zieht üblicherweise eine Veränderung und damit einen Schreibvorgang nach sich, das andere, also eine Query, greift hingegen nur lesend zu. Man könnte also auch sagen: Es gibt schreibende und lesende Zugriffe. Das CQRS-Entwurfsmuster besagt nun, dass Sie Ihre Anwendung zweiteilen sollten: in einen Teil, der sich um Schreibvorgänge kümmert, und in einen anderen Teil, der sich um Lesevorgänge kümmert. Sie sollen also, und genau das war meine ursprüngliche Aussage, die Verantwortlichkeit für das Schreiben von der für das Lesen trennen.
Worüber dieses Design-Pattern jedoch nichts aussagt, ist, auf welche Art Sie diese Trennung bewerkstelligen sollen. Es ist also erst einmal völlig offen, ob das einfach nur bedeutet, dass Sie gedanklich zwischen schreibenden und lesenden API-Routen trennen, oder ob Sie zwei getrennte APIs bauen, oder ob das zwei getrennte Services sind, oder sonst etwas. Das ist, wie es im Englischen so schön heißt, "up to interpretation". Darauf kommen wir nachher jedoch näher zu sprechen.
Die erst einmal viel spannendere Frage ist: Warum sollte man das überhaupt machen? Also, warum gibt es diese Empfehlung in Form des CQRS-Patterns überhaupt?
Nun, dahinter steckt eine sehr einfache Überlegung, und sie hat erst einmal sehr wenig mit APIs zu tun, sondern viel mehr mit Datenbanken: Wenn wir über klassische Architektur sprechen, haben wir normalerweise eine UI, eine irgendwie geartete API und am Ende eine Datenbank. Obwohl die Datenbank dabei buchstäblich nicht im Mittelpunkt der Entwicklung steht, beschäftigen wir uns in der Softwareentwicklung üblicherweise sehr ausführlich mit ihr, und häufig hat das in der Datenbank gewählte Datenmodell deutliche Auswirkungen darauf, wie die Geschäftslogik in der API gebaut wird. Das heißt, eine essenzielle Frage lautet: Wie sieht ein gutes Datenmodell aus?
Die akademische Welt hat darauf eine passende Antwort: In der Datenbanktheorie gibt es nämlich verschiedene Normalformen. Das kann man sich so ein bisschen vorstellen wie einen Satz von Regeln, wie man Datenmodelle gestalten sollte. Konkret gibt es davon fünf verschiedene Varianten, und die fünfte Normalform entspricht ein wenig dem heiligen Gral: Wenn man sie umsetzt, dann bedeutet das nichts anderes, als dass alles sehr sauber und ordentlich strukturiert ist, dass keinerlei Information dupliziert wird, dass es keine Redundanzen in den Daten gibt, und so weiter. Das ist deshalb erstrebenswert, weil sich dann Konsistenz- und Integritätsregeln sehr leicht umsetzen lassen. Die fünfte Normalform ist so gesehen also ein Traum, wenn es darum geht, Daten zu schreiben.
Ein wenig unglücklich ist nur, dass man Daten in der Regel auch wieder lesen muss. Das ist in der fünften Normalform natürlich möglich, nur muss man hierfür meist sehr komplexe Abfragen ausführen, und man braucht dann, um zum Beispiel etwas Simples wie die Stammdaten einer Anwenderin auszulesen, auf einmal 27 Joins. Das heißt, Lesen ist durchaus machbar, aber es ist völlig ineffizient und langsam. Das ist natürlich sehr unpraktisch und im Alltag wenig nützlich. Also, kurz gesagt: Die fünfte Normalform ist gut zum Schreiben geeignet, aber eine Katastrophe zum Lesen.
Das andere Extrem wäre die erste Normalform: Hier wird einfach für jede View, die es in der UI gibt, eine passende Tabelle angelegt, und die Daten werden überall dorthin verteilt, wo man sie gerade braucht. Das heißt, die Daten werden komplett denormalisiert, was das Lesen rasend schnell macht: Denn mehr als ein SELECT * FROM xy ist dann in der Regel nicht erforderlich, schließlich gibt es ja per Definition für jede View eine passende Tabelle. Insofern ist die erste Normalform ein Traum, wenn es um das Lesen von Daten geht.
Allerdings ist das Schreiben in diesem Fall eher schwierig, denn man muss dieselbe Information mehrfach ablegen, man muss sie mehrfach pflegen, und es ist deshalb sehr kompliziert, Konsistenz und Integrität zu wahren. Man könnte also festhalten, dass die erste Normalform genau das Gegenteil der fünften ist: Die erste ist gut zum Lesen, aber schlecht zum Schreiben.
Wie sieht es nun in der Realität aus? In der Regel nimmt man weder die fünfte noch die erste Normalform, sondern man wählt die Dritte: Das ist der übliche Kompromiss zwischen den beiden Welten, und ich persönlich würde sagen, dass man damit letztlich das Modell nimmt, das weder zum Schreiben noch zum Lesen besonders gut geeignet ist. Man hat nämlich weder einfache Abfragen mit hoher Performance noch die gewünschte Konsistenz und Integrität. Das heißt, mit anderen Worten: Man bekommt das Schlechteste der beiden Welten.
Und was hat das Ganze nun mit CQRS zu tun? Nun, die Aussage war ja, dass man das Schreiben vom Lesen trennen sollte. Und genau das kann man hier nun wunderbar auf Datenbankebene machen: Anstatt zu versuchen, die ganz unterschiedlichen Anforderungen des Schreibens und des Lesens mit einem einzigen Datenmodell zu erfüllen (was, wie gesagt, nicht besonders gut funktioniert), nimmt man schlichtweg zwei Datenmodelle – nämlich eines, das auf das Schreiben optimiert ist, und eines, das auf das Lesen optimiert ist. Dann hat man beim Schreiben die gewünschte Integrität und Konsistenz, und beim Lesen hat man effiziente und performante Abfragen. Der einzige Haken ist dabei nur, dass man natürlich die Änderungen, die im Schreib-Modell erfolgen, irgendwie in das Lese-Modell überführen muss, aber dazu kommen wir nachher noch.
Bevor wir nun weiter in die Details gehen, möchte ich erst einmal ein kleines Beispiel vorstellen, das das Ganze ein wenig veranschaulicht: In dem Blogpost vor zwei Wochen hatte ich als Fachdomäne eine Bibliothek angesprochen, also zum Beispiel eine Stadtbibliothek, in der man sich Bücher ausleihen kann. Ich hatte außerdem geschrieben, dass der Schwerpunkt beim Event Sourcing weniger auf den Substantiven liegt, sondern vielmehr auf den Verben – also mit anderen Worten: auf den Prozessen.
Und welche Prozesse gibt es in einer Bibliothek? Richtig: Man kann Bücher ausleihen, man kann die Ausleihe verlängern, man kann Bücher zurückgeben, man kann sie (aus Versehen oder absichtlich) beschädigen, und so weiter.
All diese Aktionen resultieren, wenn wir uns das als Software vorstellen, in Commands: Als Anwenderin oder Anwender möchte ich zum Beispiel ein Buch ausleihen, also suche ich es im System heraus, prüfe, ob es verfügbar ist, und wenn ja, tippe ich einen Button an, auf dem steht: "Buch ausleihen". Genau das ist mein Command: "Dieses Buch jetzt ausleihen!". Das klingt schon wie ein Befehl. Das System führt dann in Folge Geschäftslogik aus, befolgt dabei die hinterlegten Business-Regeln, prüft, ob ich das Buch ausleihen darf, und entscheidet dann, was passiert. Und damit hat sich dann der Zustand des Systems verändert, was wiederum genau die Definition eines Commands war: ein Schreibvorgang, der den Zustand des Systems ändert.
Wir haben bereits vor zwei Wochen darüber gesprochen, dass sich zum Erfassen dieser Veränderungen Event-Sourcing ganz wunderbar anbietet. Und die Datenbank, in der ich all diese Events im Lauf der Zeit sammle, also ein Append-Only-Log, ist unser Schreib-Modell.
Nun möchte die Bibliothek aber vielleicht gerne wissen, welche Bücher gerade ausgeliehen sind. Oder: Welche Bücher wurden im vergangenen Jahr am häufigsten verlängert? Oder: Gibt es Bücher, die in den vergangenen sechs Monaten gar nicht ausgeliehen wurden? Wie viel Prozent der ausgeliehenen Bücher wurden beschädigt zurückgegeben? Und so weiter.
Diese Liste an Fragen kann man beliebig verlängern.
Nun ist aber der Punkt: All diese Fragen lassen sich zwar auf Basis der Events beantworten, nur leider ist das nicht besonders effizient. Denn wenn ich zum Beispiel wissen will, welche Bücher derzeit alle verliehen sind, dann kann ich theoretisch alle Events von Anfang an durchgehen und eine Liste führen, in der ich jedes Mal, wenn ein Buch ausgeliehen wurde, einen Eintrag mache, und immer dann, wenn ein Buch zurückgegeben wurde, diesen Eintrag wieder streiche. Und wenn ich das von Anfang bis Ende durchziehe, weiß ich am Schluss, welche Bücher aktuell ausgeliehen sind.
Das Gute daran ist also: Ich bekomme diese Information aus meinen Events heraus. Das nicht ganz so Gute daran ist: Es ist ziemlich aufwendig.
All diese Fragen werden gemäß CQRS als Queries angesehen, weil ich etwas wissen möchte und dadurch nicht den Zustand des Systems verändere. Um diese Fragen effizient und performant beantworten zu können, wäre es viel einfacher, wenn ich ein dediziertes Lesemodell hätte. Stellen wir uns also ganz kurz vor, wie das am leichtesten wäre: Die einfachste Möglichkeit wäre eine Tabelle, in der alle aktuell ausgeliehenen Bücher aufgeführt sind. Wenn ich dann nämlich wissen will, welche Bücher gerade verliehen sind, wäre das wirklich nur ein SELECT * FROM xy. Oder, wenn ich wissen möchte, ob ein bestimmtes Buch gerade ausgeliehen ist, könnte ich ebenfalls auf diese Tabelle zugreifen und sagen: SELECT * FROM xy WHERE titel = abc. Entweder bekomme ich einen Treffer, und dann ist das Buch aktuell verliehen, oder eben nicht. Hier wäre also tatsächlich ein denormalisiertes Datenmodell die perfekte Lösung.
Die spannende Frage ist nun: Wo bekomme ich eine solche Tabelle her? Denn die einzigen Daten, die wir aktuell speichern, sind die Events. Die Antwort auf diese Frage ist tatsächlich sehr einfach: Wir bauen die Liste, so wie eben beschrieben, einfach nebenher auf. Also immer, wenn ein Event vom Typ "Buch wurde ausgeliehen" gespeichert wird, speichern wir nicht nur dieses Event, sondern wir tragen das Buch auf Basis der in diesem Event enthaltenen Informationen auch in unsere Liste der aktuell ausgeliehenen Bücher ein.
Immer, wenn ein Event vom Typ "Buch wurde zurückgegeben" gespeichert wird, entfernen wir das Buch wieder von der Liste der ausgeliehenen Bücher. Und immer, wenn ein Event vom Typ "Buch wurde verlängert" gespeichert wird, machen wir mit unserer Tabelle der ausgeliehenen Bücher gar nichts, denn das Verlängern eines Buches ändert nichts daran, dass es bereits verliehen ist.
Sollte nun jemand kommen und uns fragen, welche Bücher aktuell ausgeliehen sind, dann können wir diese Frage ganz einfach beantworten, denn wir haben die Antwort quasi schon vorbereitet.
Und das Beste daran ist, dass wir nicht von Anfang der Entwicklung an wissen müssen, dass uns irgendwann einmal jemand fragen wird, welche Bücher aktuell gerade ausgeliehen sind: Wir können diese Lesemodelle nämlich auch nachträglich noch aufbauen, indem wir alle bereits gespeicherten Events abspulen. Wir können ein Lesemodell also auch im Nachhinein noch anpassen und es einfach neu aufbauen lassen. Wir können auch weitere Lesemodelle ergänzen, oder auch diejenigen, die wir nicht mehr brauchen, einfach entfernen.
Das heißt, wir haben zum Lesen kein statisches Schema mehr, sondern wir können uns gezielt für die relevanten Fragen passende Antwortmodelle zurechtlegen, damit wir sie im Bedarfsfall ad-hoc griffbereit haben. Das beschleunigt das Lesen enorm.
Es wird aber noch besser: Denn nicht jeder Lesevorgang hat dieselben technischen Anforderungen. Für die Liste der gerade ausgeliehenen Bücher eignet sich zum Beispiel eine relationale oder auch eine NoSQL-Datenbank hervorragend. Wenn ich aber zum Beispiel zusätzlich noch eine Volltextsuche über alle Bücher anbieten will, dann müsste ich, immer wenn das Event "Buch wurde neu in den Bestand aufgenommen" gespeichert wird, das Buch indexieren und diese Informationen an beliebiger Stelle ablegen.
Dafür ist aber weder eine relationale noch eine NoSQL-Datenbank à la MongoDB sonderlich gut geeignet, sondern dafür würde sich vielleicht Elasticsearch empfehlen. Dem Prozess, der auf das Event reagiert und daraus ableitet, wie die Lesetabellen zu aktualisieren sind, ist es aber völlig gleichgültig, ob er das für eine, zwei oder mehr Tabellen erledigt. Außerdem ist ihm auch egal, ob diese Tabellen in derselben Datenbank liegen oder ob wir mit verschiedenen Datenbanken sprechen. Mit anderen Worten: Ich kann mir ein Lesemodell, das auf einen bestimmten Use Case abzielt, nicht nur passgenau für diesen aufbauen, sondern ich kann das sogar mit der am besten geeigneten Technologie umsetzen, ohne vorher wissen zu müssen, dass diese Anforderung irgendwann einmal auftauchen wird. Damit wird das Ganze schon sehr flexibel.
Doch man kann es sogar noch weiter treiben: Da sich die Lesemodelle jederzeit aus den Events wieder rekonstruieren lassen, müssen sie theoretisch nicht einmal persistiert werden. Man könnte, zumindest, sofern sie nicht zu groß werden, die Lesemodelle auch einfach im RAM halten. Das ist übrigens gar nicht so abwegig, wie es vielleicht zunächst klingt. Zum einen deshalb nicht, weil Lesezugriffe damit natürlich noch einmal einen enormen Performanceschub erhalten, denn technisch gesehen kann der Zugriff kaum noch schneller erfolgen.
Zum anderen, weil inzwischen einige Systeme auf dem Markt sind, die genau so arbeiten, wie zum Beispiel Memgraph [5] oder DuckDB [6] (zu dem ich vor einigen Monaten auch einen Blogpost geschrieben hatte: "Ente gut, alles gut? [7]").
Das Ganze ist übrigens auch, wenn Sie in Richtung eines Data-Meshs gehen möchten, eine unglaublich gute Ausgangsbasis: Bei einem Data-Mesh geht es ja letztlich darum, dass ein Team, das eine bestimmte fachliche Verantwortung hat, anderen Teams seine Daten passend zur Verfügung stellen kann (als sogenanntes "Data Product"). Und genau dieses "passend zur Verfügung stellen" ist häufig gar nicht so einfach, denn wie oft entspricht schon das interne Datenmodell genau dem, woran jemand anderes interessiert ist?
Das Tolle an Event Sourcing und CQRS ist nun, dass Sie für ein anderes Team einfach ein passendes Lesemodell aufbauen können. Das hat keinerlei Einfluss auf das interne Datenmodell oder auf die Datenmodelle für andere Teams. Und Sie können ein solches Datenmodell auch jederzeit wieder ändern oder entfernen, ohne befürchten zu müssen, dass Sie irgendjemandem etwas kaputtmachen, weil Sie ja einfach für jeden ein eigenes Lesemodell bereitstellen können. Insofern kann ich Ihnen nur raten, wenn das Thema Data-Mesh für Sie relevant ist, sich Event Sourcing und CQRS unbedingt genauer anzusehen.
Und übrigens, nur um es ganz kurz erwähnt zu haben: Auch unterschiedliche Zugriffsrechte lassen sich damit sehr elegant abbilden. Sie bieten für verschiedene Rollen einfach unterschiedliche Lesemodelle an, und die Rolle mit höheren Rechten erhält ein Lesemodell, das mehr Daten enthält, wohingegen die Rolle mit niedrigeren Rechten ein Lesemodell mit weniger Daten erhält. Auch hier können Sie sich das Leben deutlich vereinfachen, im Vergleich dazu, alles in einer einzigen Tabelle mit zig verschiedenen und entsprechend komplexen Abfragen steuern zu müssen.
Nun fragen Sie sich vielleicht:
"Alles schön und gut, aber das bedeutet ja, dass die Last auf meiner Leseseite unter Umständen ganz schön ansteigt. Habe ich da nicht das Problem, dass meine Lese-API mittelfristig überlastet wird?"
Die einfache Antwort lautet: Nein. Denn Sie können nicht nur verschiedene Lesemodelle parallel zueinander betreiben, sondern Sie können auch dasselbe Lesemodell auf mehrere Datenbank- und Server-Instanzen verteilen. Schließlich gilt auch hier wieder: Dem Mechanismus, der auf Events reagiert und dementsprechend die Lesetabellen aktualisiert, ist es egal, ob das unterschiedliche Lesetabellen sind oder ob es mehrere Kopien derselben Tabelle auf unterschiedlichen Servern gibt.
Das heißt, Sie können die Leseseite praktisch ohne Overhead beliebig skalieren, indem Sie einfach parallelisierte Kopien des Lesemodells vorhalten, und das sogar individuell pro Lesemodell, je nachdem, auf welches Lesemodell viel und auf welches eher wenig zugegriffen wird. Das heißt, CQRS ermöglicht es Ihnen, genau dort und nur dort zu skalieren, wo die Last am höchsten ist.
Wie auch schon bei Event Sourcing möchte ich Ihnen natürlich auch bei CQRS die Herausforderungen nicht verschweigen. Denn es ist nicht so, dass es keine gäbe: Auch CQRS ist keine magische Wunderlösung, die alle Ihre Probleme "einfach so" löst.
Das Hauptproblem ist, dass die erforderliche Synchronisation zwischen der Schreib- und der Leseseite Zeit benötigt. Ich habe Ihnen diesen Mechanismus so beschrieben, dass er auf gerade gespeicherte Events reagiert und dann die Lesemodelle anpasst. Nun ist klar, dass wenn wir hier über ein verteiltes System mit verschiedenen Datenbanken sprechen, zwischen dem Speichern des Events und dem Aktualisieren des Lesemodells ein wenig Zeit vergeht. Das wird im Normalfall nicht allzu viel sein (meist handelt es sich um ein paar Millisekunden), aber es bedeutet eben, dass die Leseseite immer ein kleines Stück hinterherhinkt.
Es ist dabei jedoch nicht so, dass die Leseseite nicht konsistent wäre: Das ist sie schon, nur ist sie das eben nicht sofort, sondern sie benötigt einen kurzen Augenblick. Das nennt man, in Abgrenzung zur "strong consistency" dann "eventual consistency". Doch da muss man aufpassen, denn das wird im Deutschen gerne als "eventuell konsistent" übersetzt – was jedoch falsch ist. Tatsächlich heißt "eventually consistent" nämlich so viel wie letztlich oder schlussendlich konsistent. Die Frage, die sich also stellt, lautet: Wie gravierend ist dieser kleine zeitliche Versatz in der Praxis?
Die Antwort lautet: "Es kommt darauf an."
Tatsächlich ist das nämlich keine technische Frage, sondern eine fachliche: Wie hoch ist die Wahrscheinlichkeit, dass dieser geringe zeitliche Versatz zu einem Problem führt, wie sähe dieses Problem aus, wie groß ist das Risiko im Falle des Falles, und was könnten wir dann unternehmen?
Je nachdem, wie Sie diese Fragen beantworten, ergibt sich, ob Eventual Consistency ein Problem darstellt oder nicht. Um es noch einmal zu betonen, weil das so gerne missverstanden wird: Das ist keine technische Frage. Das ist nichts, was Entwicklerinnen und Entwickler entscheiden könnten. Das ist etwas, was der Fachbereich entscheiden muss. Und der Punkt dabei ist natürlich, dass es durchaus Alternativen zu Eventual Consistency gibt (zum Beispiel durch eine einzige große verteilte Transaktion), nur hätte das dann andere Nachteile. Und falls Sie schon einmal mit verteilten Transaktionen in verteilten Systemen zu tun hatten, dann wissen Sie, dass das alles ist, nur kein Vergnügen.
Insofern: Es geht nicht darum, zu sagen, Eventual Consistency sei grundsätzlich gut oder schlecht, oder Strong Consistency sei grundsätzlich gut oder schlecht, sondern es geht darum, herauszufinden, welches Konsistenzmodell für den konkreten fachlichen Use Case besser geeignet ist.
Da sagen viele:
"Nein, also auf Strong Consistency können wir unter gar keinen Umständen verzichten!"
Und ja, natürlich gibt es Szenarien, in denen das so ist: Das ist aus meiner Erfahrung vor allem dann der Fall, wenn die nationale Sicherheit betroffen sein könnte oder wenn es um den Schutz von Leib und Leben geht. In 99,9 Prozent aller Business-Anwendungen ist das meiner Erfahrung nach aber völlig nebensächlich, da reicht Eventual Consistency in aller Regel mehr als aus.
Um hier das gängige Lehrbuch-Beispiel anzuführen: Ein Geldautomat, der die Netzwerkverbindung verliert, wird Ihnen trotzdem noch für eine gewisse Zeit Bargeld auszahlen. Denn die meisten Menschen heben ohnehin keine besonders hohen Beträge ab, und die meisten Menschen machen dies nur, wenn sie wissen, dass genug Geld auf ihrem Konto ist. Das heißt, die Wahrscheinlichkeit und das Risiko, dass die Bank Geld herausgibt, das Ihnen nicht zusteht, ist äußerst gering.
Selbst wenn das passiert, dann holt die Bank es sich eben mit Zinsen und Zinseszinsen zurück. Das heißt, aus dem netzwerktechnischen Ausfall zieht die Bank im Zweifelsfall sogar noch einen Vorteil. Dieses Vorgehen ist aus Geschäftssicht für die Bank weitaus besser, als die vermeintlich naheliegende technische Lösung zu wählen und den Geldautomaten offline zu schalten – denn dann würde am nächsten Tag möglicherweise auf Seite 1 der Boulevardzeitung stehen:
"Skandal! Multimilliardär stand vor dem Geldautomaten und konnte keine 50 Euro abheben! Ist das die neue Service-Wüste?"
Und das möchte garantiert niemand.
Ich glaube, damit haben Sie einen ganz guten Überblick darüber, was hinter CQRS steckt und auch, warum CQRS und Event Sourcing so gut zusammenpassen: Sie ergänzen sich einfach sehr, sehr gut, weil das Append-Only-Prinzip von Event Sourcing ein sehr einfaches Modell zum Schreiben von Daten ist, aus dem sich dann äußerst flexibel beliebige Lesemodelle generieren lassen.
Unterm Strich wirkt das Ganze vielleicht anfangs ein wenig einschüchternd. Das kann ich gut nachvollziehen, denn mir ging es vor mehr als zehn Jahren, als ich anfing, mich mit diesen Themen zu beschäftigen, nicht anders. Aber eigentlich sind diese Themen gar nicht so übermäßig kompliziert, sondern sie sind nur sehr anders als das, was die meisten von uns gewohnt sind. Und das dauert einfach, weil man sich komplett umgewöhnen muss und vieles, was man bislang über Softwareentwicklung gedacht und geglaubt hat, quasi entlernen muss.
Wenn man das aber einmal geschafft hat, wirkt diese "neue Welt" sehr viel intuitiver und sinnvoller als die klassische, herkömmliche Entwicklung. Viele, die sich daran gewöhnt haben, fragen sich hinterher, wie sie jemals der Meinung sein konnten, klassisch zu entwickeln, sei eine gute Idee gewesen. Mir ging das so, und vielen unserer Kunden, die wir bei the native web [8] bei der Einführung von Event Sourcing und CQRS beraten und unterstützt haben, ebenfalls.
Also lassen Sie sich davon bitte nicht abschrecken. Es wird Ihnen am Anfang schwierig erscheinen, weil Ihnen die Erfahrung fehlt, doch nach einer Weile werden Sie zurückblicken und denken:
"Wow, das war eine der besten Entscheidungen in meinem Leben als Entwicklerin oder Entwickler, mich auf diese Themen einzulassen."
Wenn Sie mehr wissen möchten, und Sie diesen Blogpost (und den vergangenen zu Event Sourcing) spannend fanden, dann habe ich eine gute Nachricht für Sie: Ich werde in den kommenden Wochen und Monaten noch einige weitere Blogposts zu diesen Themen schreiben, und dabei nach und nach auch mehr ins Detail und mehr in die Praxis gehen. Und wir werden auf unserem YouTube-Kanal [9] über kurz oder lang auch einen Livestream dazu machen.
In diesem Sinne: Bleiben Sie gespannt!
URL dieses Artikels:
https://www.heise.de/-10275526
Links in diesem Artikel:
[1] https://www.heise.de/blog/Event-Sourcing-Die-bessere-Art-zu-entwickeln-10258295.html
[2] https://www.heise.de/blog/Event-Sourcing-Die-bessere-Art-zu-entwickeln-10258295.html
[3] https://www.youtube.com/watch?v=ss9wnixCGRY
[4] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[5] https://memgraph.com/
[6] https://duckdb.org/
[7] https://www.heise.de/blog/Ente-gut-alles-gut-DuckDB-ist-eine-besondere-Datenbank-9753854.html
[8] https://www.thenativeweb.io/
[9] https://www.youtube.com/@thenativeweb
[10] mailto:mai@heise.de
Copyright © 2025 Heise Medien
(Bild: Andrey Suslov/Shutterstock.com)
Viele Unternehmen setzen auf UI-Libraries – und kämpfen über kurz oder lang mit den damit verbundenen Nachteilen. Warum ist das so und wie macht man es besser?
Ich hätte nie gedacht, dass dieser Tag einmal kommt, aber er ist da: Wir arbeiten aktuell mit einer Behörde zusammen, und diese hat etwas geschafft, woran 99 Prozent aller Unternehmen scheitern. Sie haben eine ganz bestimmte Entscheidung strategisch richtig getroffen: Sie haben sich nämlich nicht einfach wahllos für eine UI-Library für ihre Entwicklung entschieden, sondern erst einmal ihre fachlichen Anforderungen durchdacht und darauf basierend dann technologische Entscheidungen getroffen.
Doch leider ist das die absolute Ausnahme. Denn in den meisten Fällen läuft es genau umgekehrt. Und da fangen die Probleme an. Und genau deshalb, weil das so verbreitet ist und weil man es so viel besser machen kann, als es die meisten Unternehmen da draußen tun, geht es heute um den Einsatz von UI-Libraries.
Ein typisches Szenario: Ein Unternehmen plant eine neue Software und hat bereits ein paar Ideen. Trotzdem ist es manchmal ganz gut, ein wenig Unterstützung zu haben, um von außen validieren zu lassen, dass man von vornherein in die richtige Richtung läuft. Genau dafür gibt es Beratungsunternehmen, wie ja nicht zuletzt auch wir eines sind. Da wir bei the native web [1] auf Web- und Cloud-Entwicklung spezialisiert sind, kommt natürlich auch immer wieder das Thema UI zur Sprache. Und da überlegen sich viele Unternehmen, dass sie für ihre UI doch auf eine Library setzen könnten, zum Beispiel Material UI, und sie glauben, damit wäre die Frage beantwortet, wie (also mit welcher Technologie) sie ihre UI bauen sollten.
Das scheint zunächst einmal sinnvoll zu sein: Immerhin sparen UI-Libraries in der Entwicklung einiges an Zeit und Aufwand. Zumindest scheint das auf den ersten Blick so. Und genau deshalb entscheiden sich Unternehmen auch so gerne dafür: Sie möchten die versprochenen Vorteile nutzen und ihre Entwicklung beschleunigen. Das – und das muss ich an dieser Stelle vielleicht noch einmal explizit betonen – ist ein völlig legitimer Wunsch und eine völlig legitime Überlegung.
Viele Unternehmen sehen aber nicht, dass dieser Ansatz seinen Preis hat. Konkret sind es vor allem drei Risiken, die man sich damit ungewollt einkauft:
Und nur, damit es nicht missverstanden wird: Auch wenn ich hier schon ein paar Mal Material UI erwähnt habe, liegt das Problem nicht an Material UI! Material UI ist eine tolle UI-Library, solange Sie zufällig genau das Design wünschen, das Material UI vorgibt.
Was wir regelmäßig erleben, ist, dass wir um eine Einschätzung gebeten werden, wie wir die Idee beurteilen, auf Material UI (oder eine andere UI-Library) zu setzen. Denn das wäre ja alles bereits vorhanden, wäre entsprechend günstig, und man käme damit sehr zügig voran, und so weiter. Viele Unternehmen sind dann überrascht, dass wir darauf vielleicht nicht ganz so begeistert reagieren.
Wir erklären dann oft, dass wir eher davon abraten würden, eine solche Library einzusetzen, einfach um zu vermeiden, dass man sich in eine große Abhängigkeit begibt, sich den Weg in die Zukunft verbaut und sich die Möglichkeit für individuelle Anpassungen nimmt. Das bedeutet, wir empfehlen in sehr vielen Fällen, die eigenen Controls zu entwickeln, und daraufhin kommt praktisch immer das Standard-Gegenargument, das sei ja so fürchterlich teuer: Denn man müsse ja auch Mobile berücksichtigen, und man müsse ja ebenfalls Accessibility berücksichtigen, und so weiter.
Aus eigener Erfahrung kann ich sagen, dass dies zum einen gar nicht so teuer ist, wie viele immer annehmen, und dass die größten Kosten in Bezug auf Mobile, Accessibility und so weiter nicht in der Implementierung, sondern in der Konzeption der Benutzerführung anfallen. Und diese Kosten entstehen ja ohnehin, ob nun mit oder ohne UI-Library. Nur glauben Unternehmen dies oft nicht, weil es für sie häufig nicht wirklich greifbar ist, da sie beispielsweise keine Erfahrung mit UX-Design haben. Sie wissen jedoch, dass Entwicklung teuer ist, also versuchen sie, an dieser Stelle Kosten zu sparen.
Das Ganze endet dann meist damit, dass wider den Rat von außen doch eine UI-Library eingesetzt wird. Und ironisch wird es dann (und das habe ich tatsächlich schon einige Male erlebt), wenn schon nach wenigen Wochen die ersten Wünsche laut werden: Controls sollen bewusst anders aussehen, sich bewusst anders verhalten, das Ganze soll mit einem eigentlich nicht kompatiblen CSS-Framework kombiniert werden und so weiter.
Dann geschieht genau das Gegenteil von dem, was sich das Unternehmen ursprünglich erhofft hatte: Die Entwicklungskosten steigen massiv, alles dauert sehr lange, und es treten ständig merkwürdige Fehler in der UI auf, weil versucht wird, die vorgegebene Logik der Library zu umgehen. Am Ende kann das nur scheitern. Und Sie stehen dann als Berater daneben und denken sich:
"Tja, das ist genau das, was ich Euch vorhergesagt habe, aber Ihr wolltet ja keine Beratung, sondern einen Papagei, der nur "ja" sagen kann, Und eigentlich habt Ihr nur gehofft, jemanden zu finden, der Eure fragwürdige Idee von außen absegnet."
Beratung muss ehrlich sein und auch unangenehme Antworten liefern dürfen.
All das ist leider kein Einzelfall – es kommt tatsächlich ständig vor. Wie schon erwähnt, ist das eigentliche Problem aber nicht die UI-Library an sich. Das Problem besteht vielmehr darin, dass Unternehmen sich für eine bestimmte Technologie entscheiden, bevor sie ihre Anforderungen wirklich verstanden haben. Da wird dann häufig mit Zeit und Kosten argumentiert, aber der springende Punkt ist: Wenn man noch gar nicht genau weiß, was man überhaupt will, kann man auch keine Technologie wählen, um das Ziel zu erreichen, denn man kennt dieses Ziel noch nicht.
Das ist, wie wenn Sie ein Fertighaus kaufen und dann die Wände herausreißen, weil Ihnen im Nachhinein auffällt, dass Sie eigentlich viel eher einen Loft-Charakter wollten. Man kann das natürlich trotzdem machen, aber es ist und bleibt doch eher eine schlechte Idee.
Das bedeutet, die richtige Reihenfolge sollte lauten:
Von diesen vier Punkten konzentrieren sich die meisten Unternehmen jedoch auf den letzten, und insbesondere das Thema UI/UX-Konzept wird oft übergangen. Dabei ist das so ungemein wichtig. Mit anderen Worten: Bei sehr vielen Unternehmen kommt die Technik vor dem Konzept, und das führt über kurz oder lang zu absurden Workarounds.
Nun stellt sich die Frage: Wie kann man es besser angehen? Einen Punkt habe ich schon angesprochen: Es ist oft gar nicht so sinnvoll, auf eine UI-Library zu setzen, sondern man sollte viel häufiger eigene UI-Komponenten entwickeln. Das ist sehr viel weniger aufwendig als oft angenommen. Und der Vorteil ist: Man hat die volle Kontrolle, bleibt flexibel, bleibt unabhängig und vermeidet langfristig zahlreiche Probleme.
Noch wichtiger ist allerdings etwas anderes: Denn – und das habe ich oben ebenfalls erwähnt – grundsätzlich ist nichts falsch am Einsatz von UI-Libraries. Man muss sich nur im Vorfeld genau überlegen, ob das eine gute Idee ist. Passen sie wirklich zu 100 Prozent zu den Anforderungen? Oder gibt es doch Aspekte, die man gerne anders hätte, bei denen man bewusst vom getrampelten Pfad abweichen möchte, und macht man sich damit nicht auf lange Sicht das Leben schwerer, wenn man auf eine Standardlösung setzt?
Ich kann es nur wiederholen: Die initialen Kosten und der anfängliche Entwicklungsaufwand sind langfristig nahezu zu vernachlässigen. Denn allzu oft läuft es so ab:
"Ah, großartig, wir nehmen eine UI-Library, damit wir jetzt weniger Arbeit haben und schneller vorankommen!"
Ja, und drei Monate später sitzt man dann dort mit 10.000 Zeilen CSS-Hacks, aber Hauptsache, man hat anfangs zwei Tage Arbeit gespart …
So, und da kann ich nur sagen: Begehen Sie nicht denselben Fehler! Setzen Sie sich vor einer Entscheidung für oder gegen eine Technologie intensiv mit Ihren Anforderungen auseinander und prüfen Sie dies im Hinblick auf Ihre Corporate Identity und Ihr Corporate Design. Nehmen Sie sich die Zeit, ein fundiertes UI-/UX-Konzept zu entwickeln, und beschäftigen Sie sich zumindest in einem Proof of Concept damit, wie komplex und aufwendig es tatsächlich wäre, eigene UI-Komponenten zu konzipieren und umzusetzen.
Und wie zu Beginn dieses Blogposts gesagt: Es gibt Unternehmen, die das von Anfang an richtig angehen, aber die sind leider selten. Sorgen Sie also dafür, dass Ihr Unternehmen zu diesem Kreis gehört!
URL dieses Artikels:
https://www.heise.de/-10266999
Links in diesem Artikel:
[1] https://www.thenativeweb.io/
[2] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[3] https://www.youtube.com/watch?v=uRljbIxtauA
[4] mailto:rme@ix.de
Copyright © 2025 Heise Medien
(Bild: sabthai/Shutterstock.com)
Event Sourcing ist ein alternativer Ansatz für das Speichern und Verwalten von Daten. Wie funktioniert Event Sourcing und was sind die Vor- und Nachteile?
Kennen Sie das? Sie entwickeln eine Software (ganz gleich, ob für einen Kunden oder für die interne Fachabteilung), und kaum ist sie fertig, kommen schon die ersten Änderungs- und Anpassungswünsche: neue Funktionen, komplexere Analysen, mehr Reports und so weiter. Und oft fehlen entweder die richtigen Daten, oder die Code-Anpassungen sind aufwendiger und fehleranfälliger, als sie sein müssten. Und das führt zu Frust: bei Ihnen und auch bei Ihren Anwenderinnen und Anwendern.
Doch was wäre, wenn sich Software so entwickeln ließe, dass solche Änderungen und Erweiterungen deutlich einfacher und flexibler möglich sind? Genau darum geht es heute: Wir schauen uns an, warum viele Systeme für diese Herausforderungen nicht gemacht sind und wie wir das besser lösen können. Und wenn Sie bei der Softwareentwicklung flexibler und effizienter werden möchten, dann sind Sie hier genau richtig.
Was ist das Problem? Völlig gleich, mit welcher Architektur Sie arbeiten, ob Sie einen Monolithen entwickeln, ein Client-Server-System, eine Peer-to-Peer-Lösung, eine verteilte servicebasierte Anwendung oder etwas anderes – eines bleibt stets gleich, nämlich die Datenhaltung. Vielleicht würden Sie jetzt entgegnen, dass das nicht stimme, denn immerhin gäbe es nicht nur relationale Datenbanken, sondern auch NoSQL-Datenbanken oder File Storage und dieses und jenes, doch eines haben all diese Storage-Ansätze gemeinsam: Sie speichern stets den Status quo.
Wenn Sie etwa eine Software für eine Bibliothek schreiben, in der man Bücher ausleihen, verlängern und zurückgeben kann, dann ist es sehr wahrscheinlich, dass für jedes Buch ein Datensatz angelegt wird, wenn das Buch in den Bestand aufgenommen wird, und dass dieser Datensatz jedes Mal aktualisiert wird, wenn das Buch ausgeliehen, verlängert oder zurückgegeben wird, und schließlich gelöscht wird, wenn das Buch irgendwann so zerfleddert ist, dass es aus dem Bestand entfernt wird. Und das erscheint so logisch und naheliegend, dass man in der Regel gar nicht hinterfragt, ob das wirklich sinnvoll ist.
Doch warum wirkt das so logisch und naheliegend? Nun, ganz einfach: Weil wir das alle von klein auf so vermittelt bekommen haben – ganz gleich, ob Sie eine Ausbildung gemacht oder studiert haben, ob Sie an einer Fachhochschule oder an einer Universität waren, oder mit welcher Programmiersprache Sie aufgewachsen sind: Die Wahrscheinlichkeit, dass Sie das Speichern von Daten genau so gelernt haben, nämlich Datensätze anzulegen, bei Bedarf zu ändern und schließlich irgendwann zu löschen, ist nahezu immer gegeben.
Für diese Art, mit Daten umzugehen, gibt es sogar einen Fachbegriff, nämlich "CRUD": Das steht für "Create", "Read", "Update" und "Delete", also die vier Verben, mit denen wir in einer Datenbank auf Daten zugreifen können. Und das findet sich tatsächlich überall, egal, ob Sie eine relationale Datenbank wie beispielsweise PostgreSQL oder Microsoft SQL Server einsetzen oder ob Sie mit einer NoSQL-Datenbank wie etwa MongoDB oder Redis arbeiten. Und genau das meine ich: Die Art und Weise, in der wir Daten speichern und mit ihnen umgehen, ist konzeptionell stets dieselbe.
Das wirkt zunächst auch gar nicht schlimm, denn es funktioniert offensichtlich seit vielen Jahrzehnten problemlos. Und Daten werden nun einmal angelegt, geändert und gelöscht. Das ist quasi ein universelles Prinzip. Aber: Wo Licht ist, ist immer auch Schatten. Und natürlich gibt es Aspekte, die mit diesem CRUD-Ansatz einfach nicht gut funktionieren. Ich bin mir sehr sicher, dass Sie selbst schon mindestens einmal ein solches Szenario erlebt haben, nämlich: Löschen ist meistens keine besonders gute Idee.
Denn wenn etwas gelöscht wird, ist es danach – Überraschung! – weg. Doch das ist oft unerwünscht, denn vielleicht hat sich die Anwenderin oder der Anwender nur verklickt und würde das Löschen gern rückgängig machen. Das Problem ist nur: Wenn die Daten bereits fort sind, lassen sie sich nicht wiederherstellen. Was tun? Nun, man löscht einfach nicht, sondern führt ein IsDeleted-Flag ein, macht also anstelle eines Delete ein Update und setzt dieses Flag auf true.
So kann man das Löschen zum einen rückgängig machen, und zum anderen lassen sich in der restlichen Anwendung derart markierte Datensätze einfach ignorieren – es wirkt also, als wären sie tatsächlich gelöscht. Das bedeutet, wir führen technisch ein Update durch, das aus fachlicher Sicht einem Delete entspricht.
Wobei das in Wahrheit nicht ganz richtig ist, denn aus fachlicher Sicht geht es gar nicht um das "Delete" eines Buches, sondern darum, ein Buch aus dem Bestand zu entfernen. Delete ist in der Datenbanksprache lediglich das Wort, das diesem Vorgang inhaltlich am nächsten kommt, doch wenn beispielsweise jemand ein Buch stiehlt, dann muss es aus technischer Sicht ebenfalls gelöscht werden, was also auch ein Delete (oder genauer genommen ein Update) wäre – fachlich gesehen sind das jedoch zwei völlig unterschiedliche Vorgänge.
Das bedeutet, wir haben jetzt schon drei Ebenen: die fachliche, in der ein Buch aus dem Bestand entfernt wird, die technische, in der wir das IsDeleted-Flag aktualisieren, und eine dritte Ebene, die sich irgendwo dazwischen befindet und eigentlich die technische Intention ausdrückt, weil wir ursprünglich ein Delete durchführen wollten.
Und? Habe ich es bereits geschafft, Sie damit zu verwirren?
Wenn ja: Herzlichen Glückwunsch! Wenn Sie an dieser Stelle denken, dass dies für einen eigentlich trivialen Vorgang ganz schön kompliziert ist, sind Sie in guter Gesellschaft, denn vielen Entwicklerinnen und Entwicklern geht es genauso: Wir haben es geschafft, für ein banales Beispiel drei unterschiedliche sprachliche Ebenen zu erzeugen, sodass wir nun jedes Mal, wenn wir über solche Vorgänge sprechen, im schlimmsten Fall zweimal ersetzen müssen. Missverständnisse sind da natürlich vorprogrammiert.
Stellen Sie sich das nun in großem Maßstab vor, in einer wirklich großen und komplexen Anwendung. Dann kommt jemand aus der Fachabteilung und erklärt, dass ein bestimmter Vorgang erweitert werden müsse, und Sie überlegen angestrengt, was diese Person damit überhaupt meint, weil Ihnen die Fachsprache nicht geläufig ist und denken:
"Ah, bestimmt geht es um die Stelle, an der wir ein Delete ausführen!"
Anschließend sprechen Sie darüber mit jemandem, der die Datenbank verwaltet, und werden angesehen, als kämen Sie von einem anderen Stern, während Ihnen gesagt wird:
"Wir machen hier kein Delete, wir führen immer nur ein Update durch."
Viel Vergnügen dabei, das alles auseinanderzufieseln und zu klären, wo im Code nun was passiert, mit welcher Intention, wieso und warum, und wie und wo sich das letztlich auswirkt. Missverständnisse sind da geradezu vorprogrammiert, weil zwar alle irgendwie vom Gleichen reden, aber niemand das jeweilige Gegenüber wirklich versteht.
Und dann kommt die Fachabteilung und sagt:
"Ja, wir hätten da noch eine Idee. Wir möchten einen Report darüber, wie oft Bücher eigentlich verspätet zurückgegeben werden, nachdem sie bereits mindestens zwei Mal verlängert wurden."
Und Sie denken sich nur:
"Alles klar, ich melde mich dann morgen krank. Sollen sich doch andere um diesen Kram kümmern."
Denn es stellt sich heraus: Natürlich liegen Ihnen die Daten für diesen Report nicht vor, weil Sie ja nicht ahnen konnten, dass irgendwann einmal jemand danach fragen würde. Also, was tun Sie? Sie passen das Schema der Datenbank an (in der Hoffnung, dabei nichts kaputtzumachen), passen dann den vorhandenen Code an, um die neuen Veränderungen überhaupt zu erfassen (wieder in der Hoffnung, dabei nichts zu zerstören), und schreiben anschließend den Code für den neuen Report. Allerdings sind Sie damit noch nicht fertig, denn jetzt müssen Sie sechs Monate warten, bis Sie zumindest erste halbwegs belastbare Zahlen haben, mit denen Sie zur Fachabteilung gehen können – ein halbes Jahr später!
Und wie reagieren diese Personen? Wenn Sie Glück haben, sind sie schlicht verärgert: Natürlich ist es toll, dass sie nun diesen Report bekommen, aber sie hätten ihn eben gerne schon vor einem halben Jahr gehabt, nicht erst jetzt. Doch immerhin haben Sie es überhaupt hinbekommen.
Wenn Sie Pech haben, bekommen Sie entweder zu hören, dass sie den Report gar nicht mehr benötigen (aber trotzdem danke für Ihre Mühe), oder man teilt Ihnen mit, dass Sie da leider etwas falsch verstanden haben. Dann war die ganze Arbeit umsonst, Sie können quasi noch mal von vorn anfangen, es dauert wieder ein halbes Jahr, und am Ende erfahren Sie vielleicht dann, dass nun niemand den Report mehr braucht.
Erinnern Sie sich noch, wie alles begann? Richtig: Sie haben das Datenbankschema angepasst. Neue Felder eingeführt, anschließend den Code geändert und so weiter. Setzen Sie das jetzt etwa alles wieder zurück? Ganz ehrlich: Sie wären die erste Person, die ich treffen würde, die das macht. Im Normalfall bleibt so etwas dann nämlich bestehen, auch wenn es niemand mehr benötigt. Weil, und das ist das Ärgerliche daran, Sie ja nie wissen, wer diese neuen Felder inzwischen vielleicht ebenfalls verwendet, und natürlich möchten Sie nicht nach einem vergeudeten Jahr auch noch diejenige oder derjenige sein, der anderen etwas kaputtmacht. Also lassen Sie lieber die Finger davon. Und so wächst und wächst das Datenschema, und nach fünf Jahren kennt sich kein Mensch mehr darin aus.
Das ist übrigens keine ausgedachte Situation, sondern genau das erlebe ich da draußen bei sehr vielen Unternehmen in der Praxis als Regelfall. Ich glaube, das Schlimmste in dieser Hinsicht war einmal eine Versicherung, die dem Ganzen vorbeugen wollte, indem sie jeder Tabelle von vornherein vierhundert Spalten verpasste – "Value1", "Value2", "Value3" und so weiter – sodass man zumindest nie das Schema anpassen musste: Man konnte sich einfach die nächste freie Spalte für die eigenen Zwecke reservieren.
Natürlich war das nirgends dokumentiert, und alle Informationen dazu wurden nur mündlich weitergegeben, nach dem Motto:
"Wenn in Spalte 312 ein Y steht, dann bedeutet Spalte 94 die Faxnummer. Wenn in Spalte 312 aber ein J steht, dann ist Spalte 94 das Geburtsdatum. Und wenn in Spalte 207 zusätzlich der Wert NULL steht, gilt das alles nicht mehr, aber wir wissen leider nicht, was dann gilt, weil der Typ, der das vor hundert Jahren mal gebaut hat, nicht mehr bei uns arbeitet."
Uff!
Also stellt sich natürlich die Frage: Wie kann man es besser machen? Denn auf so eine Situation hat eigentlich niemand Lust. Und tatsächlich (auch wenn Sie das jetzt vielleicht überrascht) ist es eigentlich recht einfach. Der Fehler besteht nämlich darin, dass überhaupt erst der Status quo gespeichert wird. Denn wenn man das macht, muss man sich logischerweise festlegen, welche Felder man zum Status quo speichert und wann man diese Felder aktualisiert.
Das Problem dabei ist, dass man das im Vorfeld eigentlich gar nicht wissen kann. Denn Sie wissen nie, welche Fragen Ihnen morgen gestellt werden und welche Daten Sie dafür bräuchten, um diese Fragen sinnvoll beantworten zu können. Tja, und vielleicht fragen Sie sich jetzt, wie man das dann anders machen soll, schließlich kann niemand in die Zukunft blicken – und trotzdem lässt sich die Sache deutlich intelligenter angehen.
Dazu schauen wir uns an, wie ein Girokonto funktioniert. Ich wähle dieses Beispiel ganz bewusst, weil es jede und jeder von Ihnen aus eigener praktischer Erfahrung kennt.
Offensichtlich speichert die Bank nicht einfach nur zu Ihrer Kontonummer den Kontostand (also den Saldo), denn dann könnte sie Ihnen nicht erklären, wie dieser Kontostand überhaupt zustande gekommen ist. Man möchte das jedoch manchmal unbedingt wissen, wenn man sich fragt:
"Warum ist am Ende des Geldes noch so viel Monat übrig?"
Spaß beiseite: Den meisten Menschen ist es sehr wichtig, transparent nachvollziehen zu können, wofür sie Geld ausgegeben haben und wie sich der Kontostand zusammensetzt.
Und was macht die Bank dafür konkret? Zunächst einmal verzichtet sie auf das Delete, denn wir haben ja bereits festgestellt, dass es in den meisten Fällen keine gute Idee ist, Daten zu löschen, also streichen wir das einfach. Dann zeigt sich allerdings, dass auch ein Update genauso wenig geeignet ist, weil dabei ebenfalls Daten verloren gehen – nämlich die, die vorher da waren. Genau das ist der springende Punkt: Man überschreibt den bisherigen Status quo durch einen neuen Status quo. Und der alte ist anschließend weg.
Deshalb verzichtet die Bank folgerichtig auch aufs Update. Das ist übrigens in beiderlei Hinsicht hervorragend, denn so bleiben nur noch Create und Read übrig. Das bedeutet, dass eine Bank technisch gesehen einen einmal angelegten Datensatz nie wieder verändern oder gar löschen kann. Und genau das ist extrem wichtig für den Vertrauensaufbau: Stellen Sie sich einmal vor, eine Bank könnte bereits ausgeführte Buchungen nachträglich ändern! Sie würden wahrscheinlich niemals Ihr Geld dorthin bringen!
Nun stellt sich natürlich die Frage: Was lässt sich mit Create und Read schon Großartiges anfangen? Denn Daten müssen ja manchmal geändert werden. Und hier kommt der entscheidende Punkt: Wir speichern nicht mehr den Status quo, sondern stattdessen die einzelnen kleinen Veränderungen, die im Laufe der Zeit zum Status quo geführt haben. Genau das ist es, was Sie auf Ihrem Kontoauszug sehen: Die Bank erzeugt für jede Transaktion, die auf Ihrem Konto stattfindet, einen neuen, unveränderlichen Eintrag. Per Create.
Und diese immer länger werdende Liste können Sie sich anschließend per Read ausgeben lassen – das ist Ihr Kontoauszug. Wenn ich dann wissen möchte, wie Ihr aktueller Kontostand ist, kann ich hingehen und all Ihre Kontoauszüge seit der Eröffnung des Kontos nehmen und Transaktion für Transaktion durchrechnen, bis ich am Ende weiß, wie Ihr heutiger Saldo ausfällt.
Und was passiert nun, wenn etwas schiefläuft? Dann kann man Daten doch gar nicht korrigieren, oder? Doch, kann man! Denn die Bank versucht gar nicht erst, eine fehlgeschlagene Transaktion zu ändern, sondern sie kompensiert diese einfach mit einer passenden Gegentransaktion. Wenn Sie also versuchen, 100 Euro auf ein Konto zu überweisen, das nicht existiert, streicht die Bank nicht Ihre fehlgeschlagene Überweisung aus der Historie, sondern Sie erhalten kurz darauf einfach eine Gutschrift über 100 Euro, sodass der Effekt ausgeglichen wird.
Das ändert natürlich nichts daran, dass die fehlgeschlagene Überweisung versucht wurde, aber genau so hat es sich ja auch wirklich zugetragen. Das bedeutet, die Historie wird nicht verfälscht, sondern nur die Effekte werden kompensiert.
Dieses Modell hat einen enormen Vorteil: Aus Sicht des Datenmodells ist es sehr, sehr simpel. Aber weil Sie alle Rohdaten besitzen, können Sie sämtliche Fragen beantworten, von denen Sie bis vor Kurzem nicht einmal wussten, dass sie jemals gestellt werden würden. Und das können Sie nicht nur ad hoc tun, sondern Sie können es auch ad hoc über sämtliche Daten der Vergangenheit tun!
Also zum Beispiel: Wie viel Prozent Ihres Gehalts geben Sie für die Miete aus? Nun, wenn Sie mir Ihren Kontoauszug geben, kann ich das einfach ausrechnen, auch wenn es dafür kein eigenes Feld gibt. Sie möchten wissen, ob sich Lottospielen lohnt? Dann geben Sie mir bitte Ihren Kontoauszug, und ich rechne das für Sie gern aus. Sie möchten wissen, ob der durchschnittliche Kontostand des Jahres 2024 höher oder niedriger war als der von 2023 und falls ja, um wie viel? Nun, geben Sie mir Ihren Kontoauszug, und ich rechne Ihnen das gerne aus. Wie oft im Monat gehen Sie essen? Leben Sie eher sparsam oder eher verschwenderisch? Geben Sie direkt nach Geldeingang größere Beträge aus, oder warten Sie bis zum Monatsende, wenn Sie wissen, wie viel übrig ist? Haben Sie einen Zweitwohnsitz? Wie viel sind Ihre Ausgaben für Lebensmittel im Vergleich zu vor fünf Jahren gestiegen? Und so weiter und so fort …
Ich könnte diese Liste praktisch endlos erweitern. Und das Entscheidende ist: Ich kann Ihnen jede dieser Fragen beantworten, nur mithilfe der vorhandenen Transaktionen der vergangenen Jahre, ohne dass wir dazu das Datenmodell anpassen müssten. Ohne dass wir dafür den Code ändern müssen, der die Transaktionen ausführt. Ohne dass wir sechs Monate warten müssen. Ohne dieses, ohne jenes.
Und das gilt nicht nur für Banken. Das funktioniert ebenfalls für unsere eingangs erwähnte Bibliothek: Statt für jedes Buch einen Datensatz zu führen, den wir immer wieder aktualisieren und am Ende trotzdem nichts Genaues wissen, legen wir einfach für jede Veränderung einen Datensatz an: Ein Buch wurde neu in den Bestand aufgenommen, ein Buch wurde ausgeliehen, ein Buch wurde verlängert, ein Buch wurde zurückgegeben, ein Buch wurde beschädigt und so weiter.
Auch daraus können Sie alle möglichen Fragen ableiten: Wie oft wird ein Buch pro Jahr ausgeliehen? Wie oft wird es verlängert? Welches sind die Top 10 der am häufigsten ausgeliehenen Bücher? Welcher Anteil der Bücher wird mehr als einmal von derselben Person ausgeliehen? Und so weiter. All das funktioniert in jeder Fachdomäne.
Vielleicht ist es Ihnen bereits aufgefallen: Wir haben uns, ganz nebenbei, vom rein technischen Vokabular entfernt und reden nicht mehr von Create, Update und Delete, sondern plötzlich von der Fachlichkeit – Ausleihen, Verlängern, Zurückgeben und so weiter.
Das bedeutet, wenn jetzt jemand aus der Fachabteilung mit einem Wunsch hinsichtlich der Rückgabe von Büchern zu Ihnen kommt, wissen Sie sofort, worum es geht, weil Sie dasselbe Vokabular verwenden. Und wenn Sie nun sagen:
"Na gut, man müsste das ja nicht so machen, ich kann doch weiterhin mit Create, Read, Update und Delete arbeiten."
dann bekämen Sie sinngemäß einen Kontoauszug, auf dem steht:
Da erkennt man, wie unglaublich dünn das übliche, verbreitete Vokabular in Anwendungen ist. Und man merkt, wie hilfreich und sinnvoll es sein kann, nicht immer nur dieselben vier technischen Verben zu verwenden, sondern endlich einmal semantisch gehaltvolle Begriffe aus der Fachlichkeit einzuführen. Das Ganze steht und fällt also damit, dass man inhaltlich sinnvolle Begriffe wählt. Und genau das ist in der Softwareentwicklung ohnehin von essenzieller Bedeutung: Dinge richtig zu benennen.
Wenn man das nicht macht, entsteht solcher Unsinn wie der böse Wolf, der das IsDeleted-Flag des Rotkäppchens aktualisiert, weil er es ja nicht löschen darf, sonst könnte der Jäger kein "Undelete" durchführen. Dabei geht es eigentlich doch um Gefressen- und Gerettet-Werden, aber hey – ein rein technisches Update und Delete sind so viel einfacher.
Übrigens: Ich habe mich schon häufiger über CRUD ausgelassen, und wenn Sie sich das CRUD-Märchen tatsächlich einmal in voller Länge ansehen wollen, empfehle ich Ihnen dieses Video [2].
Jetzt wissen Sie, wie das System konzeptionell funktioniert. Was noch fehlt, ist ein Name für das Ganze. Die einzelnen Einträge in dieser immer weiter wachsenden Liste (übrigens nennt man sie eine "Append-Only-Liste", weil stets nur am Ende angehängt werden darf) stehen in der Vergangenheitsform, denn sie sind ja bereits geschehen: Ein Buch wurde ausgeliehen, ein Buch wurde verlängert, ein Buch wurde zurückgegeben und so weiter. Und weil das Ereignisse sind, die stattgefunden haben und nicht mehr rückgängig gemacht werden können (wie gesagt, man kann nur ihre Effekte kompensieren), spricht man hier von "Events".
Da diese Events sozusagen die Quelle für sämtliche Auswertungen, Abfragen, Analysen, Reports und Co. sind, sind sie die "Source" von allem, weshalb man bei diesem Datenhaltungskonzept von "Event Sourcing" spricht. Vielleicht haben Sie den Begriff schon einmal gehört und sich gefragt, was das eigentlich ist. Die kurze Antwort lautet: Das, was Ihr Girokonto macht, das ist Event Sourcing, beziehungsweise, das ist ein Beispiel dafür. Das heißt, Sie verwenden es tagtäglich, und zwar schon seit Jahren, nur kannten Sie vermutlich den Namen nicht.
Allerdings ist die historische Analysemöglichkeit von Daten nicht der einzige Vorteil, den Event Sourcing bietet. Sie erhalten, ohne dafür aktiv etwas machen zu müssen, quasi "kostenlos" ein Audit-Log: Sie können jederzeit nachvollziehen, welches Event (also welche fachlich relevante Aktion) wann und von wem und mit welchen Parametern ausgelöst wurde. Das ist natürlich generell schon sehr praktisch, aber besonders interessant wird es, wenn Sie Software für eine Branche entwickeln, in der das Führen eines Audit-Logs vorgeschrieben ist, etwa aus Sicherheitsgründen.
Wenn Sie dann sagen können, dass das Audit-Log nicht nachträglich angeflanscht wurde, sondern von Anfang an im Kernkonzept der Datenhaltung mitgedacht ist, verschafft es Ihnen einen deutlichen Wettbewerbsvorteil.
Sie interessieren sich für "Was-wäre-wenn"-Analysen? Kein Problem: Beim Abspielen der Events (was man übrigens "Replay" nennt) müssen Sie nicht zwangsläufig alle Events berücksichtigen. Sie können auch einige davon weglassen und sehen, wie sich dadurch das Ergebnis verändert. Oder Sie fügen bei einem Replay simulierte Events hinzu und beobachten, was im Laufe der Zeit geschehen wäre.
Das kann Ihnen helfen, weit bessere Einblicke zu gewinnen, Ihr (auch wenn sich das merkwürdig anhören mag) Business besser zu verstehen und auf dieser Grundlage möglicherweise bessere Entscheidungen zu treffen. Allein die Möglichkeit, die Vergangenheit auf unterschiedliche Weise zu interpretieren, ist so mächtig, dass Sie sich das, falls Sie es noch nie erlebt haben, kaum vorstellen können.
Bevor ich es vergesse: Auch für Fehlersuche und Debugging ist Event Sourcing hervorragend geeignet. Mit Events können Sie problemlos nachvollziehen, wie ein System bei einem Kunden in diesen merkwürdigen Zustand geraten ist, in dem es sich gerade befindet.
Und das ist keineswegs eine neue Idee: Es gibt ein Interview mit John Carmack, dem ehemaligen leitenden Entwickler bei id Software, der maßgeblich an DOOM beteiligt war, und in diesem Interview erwähnt er, dass DOOM im Kern mit Event Sourcing arbeitet (auch wenn er es nicht so nennt, weil der Begriff damals noch nicht existierte, es aber de facto genau das ist).
Übrigens ist das zum Beispiel auch für Maschinensteuerung oder ganz allgemein IoT- und Industriebereiche interessant: Wie ist eine Maschine in den Zustand geraten, in dem sie sich befindet, und was können wir daraus lernen?
Und natürlich können Sie aus den Events jede beliebige andere Darstellung erzeugen, denn letztlich ist das nur eine Frage der Interpretation. Wenn Sie zum Beispiel häufig den aktuellen Kontostand benötigen, wäre es sehr ineffizient, jedes Mal ein komplettes Replay durchzuführen – stattdessen können Sie zusätzlich eine kleine Tabelle mit dem Kontostand pflegen, die Sie ganz klassisch nach CRUD aktualisieren, sobald ein Event auftritt, das Auswirkungen auf den Kontostand hat.
Theoretisch müssten Sie diese Tabelle nicht einmal auf der Festplatte sichern, denn falls das System abstürzt, könnten Sie sie jederzeit aus dem Replay neu aufbauen. Das bedeutet natürlich auch, dass Sie das gleiche Prinzip für jede beliebige andere Tabelle oder Darstellung anwenden können: Die Events bleiben stets Ihre Single Source of Truth, und was Sie daraus an speziell optimierten Lesemodellen ableiten, liegt ganz bei Ihnen.
Es gilt natürlich: Wo Licht ist, ist stets auch Schatten. Ich möchte Event Sourcing nicht als eine Lösung darstellen, in der es nichts gibt, worüber man nachdenken sollte, und spreche deshalb kurz einige typische Einwände an. Erstens wird oft angeführt, dass eine Append-Only-Liste im Laufe der Zeit zunehmend mehr Speicher verbraucht. Das stimmt grundsätzlich, aber zum einen sollen Sie ja nicht jeden einzelnen Sensormesswert als Event erfassen, sondern nur geschäftsrelevante Fachereignisse. Davon haben Sie in der Regel nicht 100.000 pro Sekunde.
Zweitens sind Events meist deutlich kleiner, als man intuitiv annimmt, weil man nur die Deltas speichern muss.
Und drittens ist Speicherplatz heutzutage praktisch kein Kostenfaktor mehr. Letztlich ist das eine einfache Rechenaufgabe, und natürlich hängt die Antwort stark von der jeweiligen Fachdomäne ab, doch erfahrungsgemäß sind das oft weit weniger Daten als zunächst vermutet. Und außerdem könnte man alte Events irgendwann archivieren. Natürlich ließen sich dann deren Historien nicht mehr abrufen, aber das ginge bei einem klassischen Datenhaltungsmodell ebenfalls nicht.
Der zweite häufige Einwand lautet, dass Replays im Laufe der Zeit immer länger dauern: Das ist logisch, denn wenn das System rege genutzt wird, sammeln sich immer mehr Events an, und ein Replay benötigt dann naturgemäß mehr Zeit. Der springende Punkt ist jedoch, dass man dem mit sogenannten Snapshots hervorragend entgegenwirken kann: Ein Replay über die ersten 10.000 Events führt ja stets zum gleichen Ergebnis, gerade weil es kein Update und kein Delete gibt, das heißt, anstatt dieses Ergebnis immer wieder neu zu berechnen, lässt es sich in einem Cache als bereits vorgefertigter Wert hinterlegen.
Im Zweifelsfall müssen Sie dann lediglich ein Replay ab dem letzten Snapshot durchführen, was bei regelmäßig erzeugten Snapshots flott geht. Außerdem haben Sie es in der Hand, wie schnell das Ganze sein soll: Letztlich ist das nur eine Frage der Häufigkeit, mit der Sie Snapshots erzeugen.
Der dritte Einwand betrifft häufig die DSGVO: Wie kann ein System, das darauf ausgelegt ist, Daten niemals zu ändern oder zu löschen, überhaupt mit der DSGVO vereinbar sein, insbesondere mit Artikel 17 zum Recht auf Vergessenwerden? Tatsächlich existieren dafür verschiedene Lösungswege, die unterschiedlich aufwendig zu implementieren sind, aber auch unterschiedlich hohen Anforderungen und Datenschutzklassen gerecht werden.
Was jeweils der richtige Ansatz ist, muss individuell für das jeweilige Projekt erarbeitet werden. Das lässt sich nicht pauschal beantworten, weil es beispielsweise einen Unterschied macht, ob Sie hochsensible medizinische Daten verarbeiten oder nur die Stammdaten des örtlichen Kanarienvogel-Züchtervereins. Das sind einfach verschiedene Welten.
Und vielleicht denken Sie jetzt:
"Klasse, das klingt alles sehr vielversprechend, besonders das mit den historischen Daten, dem Audit-Log, der stärkeren Fokussierung auf die Fachlichkeit, den vielfältigen Analysemöglichkeiten und Reports und so weiter – das möchte ich unbedingt einmal ausprobieren. Aber wo fange ich an?"
Dann ist mein allerwichtigster Rat: Beginnen Sie mit einem kleinen Projekt. Event Sourcing ist ein unglaublich mächtiges Werkzeug, das Ihnen völlig neue Türen öffnen kann, doch wie bei jedem mächtigen Werkzeug sollte man nicht gleich mit dem größten Projekt starten, das man hat. Suchen Sie sich also zuerst etwas wirklich Kleines heraus und beschäftigen Sie sich, bevor Sie mit einer Implementierung beginnen, zunächst einmal mit der Frage, welche Events überhaupt existieren. Denn das ist der Dreh- und Angelpunkt: Da Sie nichts mehr ändern oder löschen können, sollten Sie zumindest halbwegs sicherstellen, dass Sie in die richtige Richtung loslaufen.
Welches Tooling Sie dann später nutzen, welche Datenbank Sie verwenden und so weiter, ist im ersten Schritt völlig unerheblich. Natürlich wird das später eine sehr wichtige Frage sein, aber zuerst sollten Sie sich mit der Fachlichkeit befassen und erst dann mit den technischen Fragen, nicht umgekehrt. Nach einer Weile werden Sie dann irgendwann feststellen: Event Sourcing ist am Ende gar nicht so kompliziert, wie Sie vielleicht zunächst vermuten – es fehlt häufig einfach an Übung und Erfahrung, aber die sammelt man mit der Zeit.
URL dieses Artikels:
https://www.heise.de/-10258295
Links in diesem Artikel:
[1] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[2] https://www.youtube.com/watch?v=MoWynuslbBY
[3] mailto:rme@ix.de
Copyright © 2025 Heise Medien
(Bild: Erstellt mit KI (Midjourney) durch iX-Redaktion)
Wer in Visual Basic programmiert, wird gerne belächelt, immerhin sei Basic eine "schlechte" Programmiersprache. Warum ist das eigentlich so und was ist da dran?
Vor ein paar Tagen habe ich einen Entwickler kennengelernt, und natürlich (wie das unter Entwicklern eben so ist) kam relativ schnell die Frage auf, mit welcher Programmiersprache man denn jeweils unterwegs sei. Ich habe dann ein bisschen erzählt, was wir bei the native web [1] so machen, womit wir uns beschäftigen und womit wir arbeiten.
Und natürlich habe ich ihn dann gefragt, wie das denn bei ihm sei. Da kam dann ein leicht verschämtes:
"Naja, ich arbeite nur mit Visual Basic."
Diese Antwort war ihm sichtlich unangenehm, und ich habe ihn dann gefragt, warum das so sei. Er erzählte mir, dass er schon oft die Erfahrung gemacht hätte, dass andere Entwicklerinnen und Entwickler ihn nach dieser Antwort nicht mehr so ganz ernst nehmen, sondern ihn eher belächeln würden. So nach dem Motto:
"Ach guck mal, wie niedlich, da arbeitet jemand tatsächlich noch mit Visual Basic!"
Zugegeben: Visual Basic hat keinen besonders guten Ruf. Eher im Gegenteil: Die Sprache gilt als veraltet, als minderwertig, kurzum als "schlecht". Doch da stellt sich natürlich die Frage: Was ist da dran? Ist Visual Basic wirklich so eine katastrophal schlechte Sprache? Um das beantworten zu können, muss man die Frage etwas allgemeiner stellen, nämlich: Was zeichnet eine gute oder eine schlechte Programmiersprache überhaupt aus?
Bevor wir loslegen, möchte ich noch ein paar Hinweise geben. Zuallererst: Auf diese Frage gibt es nicht die eine wissenschaftlich fundierte und absolut objektive Antwort. Schon die Definition von "gut" und "schlecht" ist eine Frage der Interpretation. Ich werde mir daher zwar große Mühe geben, das Ganze objektiv anzugehen, nicht emotional zu argumentieren und meine Behauptungen an Fakten festzumachen. Dennoch ist das, was hier steht, meine persönliche Sicht der Dinge. Bevor Du also in den Kommentaren mit Kritik um Dich wirfst, wäre es nett, wenn Du das berücksichtigen könntest.
Zweitens: Es geht mir in diesem Blogpost nicht speziell um Visual Basic. Vielmehr versuche ich, zu erklären, woran ich festmache, ob ich eine Sprache als gut oder schlecht empfinde. Dabei liefere ich die Kriterien, die ich für wichtig halte, und erkläre, aus welchen Gründen ich sie für wichtig erachte. Es ist völlig in Ordnung, wenn Du sagst, dass diese Kriterien für Dich nicht greifen oder Du sie anders bewertest. Denn immer da, wo es um Qualität geht, spielt auch das eigene Wertesystem eine Rolle. Und das sieht bei Dir sicher anders aus als bei mir, allein schon deshalb, weil wir unterschiedliche Erfahrungen gemacht haben.
Drittens: Generell möchte ich darum bitten, in den Kommentaren nett zueinander zu sein und konstruktiv miteinander umzugehen. Auch wenn Dir die Sprache, die jemand anderes bevorzugt, nicht gefällt, macht das die entsprechende Person nicht zu einem schlechten Menschen. Es ist völlig in Ordnung, Technologien kritisch zu hinterfragen. Anderen Menschen sollten wir trotz Kritik respektvoll begegnen.
Damit kommen wir nun endlich zum eigentlichen Thema: Was macht eine Programmiersprache gut oder schlecht?
Eine häufig genannte Antwort lautet: Eine Sprache ist dann gut, wenn man mit ihr das jeweils gesteckte Ziel erreichen kann. Nach dem Motto: Wenn eine Sprache den Zweck erfüllt, dann kann sie nicht schlecht sein. Für mich persönlich ist das allerdings kein besonders überzeugendes Argument. Denn bloß, weil ein Werkzeug eine Aufgabe erfüllt, ist es noch lange kein gutes Werkzeug – es ist dann zunächst einmal nur ein für diese Aufgabe passendes oder geeignetes Werkzeug.
Ob es auch gut ist, steht auf einem anderen Blatt. Das merkt man spätestens dann, wenn es mehrere Werkzeuge für dieselbe Aufgabe gibt. Denn dann gibt es oft Unterschiede. Insofern gilt für mich, dass "gut" und "geeignet" zwei verschiedene Paar Schuhe sind. Umgekehrt ist eine Sprache nicht per se schlecht, nur weil sie für ein Problem ungeeignet ist. Sie ist dann einfach nur für dieses Problem ungeeignet. "Gut" oder "schlecht" sind für mich Begriffe, die sich auf eine qualitative Bewertung der Sprache an sich beziehen, unabhängig von ihrer Tauglichkeit für ein bestimmtes Problem.
Ein ähnlicher Punkt ist das Feature-Set einer konkreten Implementierung einer Sprache. Es hieß früher zum Beispiel oft, dass C# eine schlechte Sprache sei, weil sie nur unter Windows lauffähig war. Das ist falsch. Die Sprache an sich ist zunächst nur eine Syntax mit einer Semantik, wie man sich ausdrücken kann. Ob es dafür eine passende Laufzeitumgebung oder einen passenden Compiler für eine konkrete Plattform gibt, ist unabhängig von der Idee der Sprache. Heute ist es ja problemlos möglich, C# auch auf macOS oder Linux auszuführen. Insofern sind auch das keine Kriterien dafür, ob eine Sprache gut oder schlecht gestaltet wurde. Es sagt nur etwas über die Verfügbarkeit von Implementierungen aus.
Ein weiterer Punkt: Eine Sprache ist nicht dasselbe wie ihre Funktions- oder Klassenbibliothek. Auch das ist ein Implementierungsdetail. Es kann für ein und dieselbe Sprache unterschiedliche Umgebungen geben, die unterschiedlich viel an "Drumherum" zur Verfügung stellen. Das kennt man zum Beispiel aus .NET oder Java mit unterschiedlich umfangreichen Runtimes. Es geht mir also wirklich nur um das, was direkt zur Sprache an sich gehört.
Allein darüber könnte man nun lange diskutieren, ob diese Abgrenzung sinnvoll ist oder nicht. Für heute möchte ich sie so machen, weil es in meinen Augen die sinnvollste Definition ist, wenn man über das Design einer Sprache sprechen will.
Damit ist umrissen, was ich überhaupt bewerten will. Jetzt ist die Frage, was geeignete Kriterien sind. Das wichtigste Kriterium für mich ist die Ausdrucksstärke einer Sprache. Eine Programmiersprache ist ein Werkzeug, um das umzusetzen, was eine Entwicklerin oder ein Entwickler im Sinn hat. Das sollte möglichst zielgerichtet und ohne unnötige Umstände möglich sein. Das macht das Schreiben und Lesen von Code einfacher. Je weniger eine Sprache mich zwingt, Konzepte umzuformulieren, desto einfacher und direkter lassen sich Ideen ausdrücken. Sprachen, die für jedes gedankliche Konzept ein entsprechendes Konzept in der Sprache bieten, empfinde ich als gelungen.
Ein Beispiel: In der Mathematik ist 1 die Fakultät von 1, und die Fakultät von n ist n * fac(n - 1). Hier handelt es sich also um eine rekursive Definition. Eine Sprache ist dann ausdrucksstark, wenn sie Rekursion unterstützt, weil ich die Fakultät dann genau so ausdrücken kann, wie sie in meinem Kopf definiert ist. Das klingt trivial, aber Rekursion gab es tatsächlich nicht schon immer in Programmiersprachen. Sie musste erst einmal eingeführt werden, und das war mit Lisp im Jahr 1958 [3]. Das im Jahr zuvor entstandene Fortran kannte keine Rekursion. Und genau das meine ich mit Konzepten: Eine gute Sprache holt mich auf der konzeptionellen Ebene dort ab, wo ich stehe, und bürdet mir keine unnötige Denkarbeit auf.
Die Ausdrucksstärke ist aber nicht das einzige Kriterium. Das zweite wichtige Kriterium aus meiner Sicht ist Minimalismus: Für jedes Konzept sollte es nur genau einen einzigen Weg geben, um ans Ziel zu kommen. Ich will mich nicht zwischen mehreren gleichwertigen Wegen entscheiden müssen. Zu viele Alternativen führen nämlich zu Inkonsistenzen im Code und erhöhen die Komplexität. Ein Beispiel: JavaScript kennt zig Wege, eine Iteration auszudrücken – unter anderem sieben verschiedene Schleifentypen:
for als klassische Zählschleifefor ... in um über Objekte zu iterierenfor ... of eine Art for … eachfor await ... of als asynchrone Variante davonwhile als abweisende Schleifedo ... while als nicht abweisende SchleifeforEach als Schleifen-Funktion an ArraysIch bin mir sicher, dass ich die eine oder andere Variante vergessen habe, aber dass es überhaupt sieben verschiedene Schleifentypen in JavaScript gibt, die im Prinzip alle das Gleiche machen und sich lediglich in Details unterscheiden, das ist schon erschreckend. Vergleicht man das mit Go, dann kommt Go mit einer einzigen Schleife aus – nämlich der for-Schleife, die gegebenenfalls noch um das range-Schlüsselwort ergänzt wird. Das war's, und das führt zu viel weniger Diskussionen und Verwirrung.
Das dritte Kriterium ist Konsistenz: Konzeptionell gleiche Dinge sollten syntaktisch gleich formuliert werden. Das senkt die kognitive Belastung und fördert die Lesbarkeit. In Go (nachdem ich die Sprache gerade positiv erwähnt habe, nenne ich nun auch ein Manko) stolpere ich regelmäßig darüber, dass Parameter einer Funktion per Komma separiert werden, Felder eines Struct jedoch nicht. Das ist unlogisch, weil man in beiden Fällen eine Auflistung von Namen und Typen vornimmt, und warum dieses – aus konzeptioneller Sicht – gleiche Muster mit unterschiedlichen Syntaxvarianten ausgeführt wird, erschließt sich mir nicht.
Viertens ist mir eine gewisse Explizitheit wichtig. Sprachen sollten dazu führen, dass man sich präzise ausdrücken muss. Ich bin ein großer Fan von expliziten Konvertierungen und kein Freund von impliziten. Explizitheit sorgt für mehr Klarheit und weniger Fehler. Je gefährlicher eine Aktion ist, desto expliziter sollte sie sein. Und hier kann man Go wieder als Positivbeispiel nennen: Der unsichere (weil direkte) Zugriff auf den Speicher erfolgt hier über das unsafe-Paket, das heißt, man muss explizit hinschreiben, dass es sich um unsicheren Code handelt.
Nun gehen da natürlich manchmal die Meinungen auseinander, was gut und was schlecht ist. Und da fragt man sich dann vielleicht, wie sehr Sprachdesigner auf die Community hören sollten. Meine klare Antwort ist: Eigentlich gar nicht. Denn es äußern sich oft nur wenige aus der Community, die dann aber sehr lautstark auftreten. Wirklich gutes Sprachdesign ist unglaublich schwer, und bloß weil es einige laute Schreihälse gibt, heißt das noch lange nicht, dass ihre Forderungen sinnvoll oder durchdacht seien. Tatsächlich denken viele Entwicklerinnen und Entwickler an der Stelle zu kurz und übersehen langfristige Konsequenzen, die eine Sprache aufweichen, verwässern und inkonsistent machen können.
Außerdem gilt: Wenn man zu einem neuen Feature erst einmal "ja" gesagt hat, kann man es nicht wieder entfernen, ohne einen Breaking-Change zu haben. Deshalb sollte man sich sehr genau im Vorfeld überlegen, welche Features wirklich in eine Sprache aufgenommen werden sollten. Mit anderen Worten: Weniger Optionen fördern die Standardisierung von Code und damit seine Lesbarkeit. Letztlich geht es um die richtige Balance zwischen Ausdrucksstärke, Minimalismus, Explizitheit und Konsistenz. Vielleicht auch noch um Fehlervermeidung.
Und eine Sprache, die das alles vereint, würde ich persönlich als gelungen bezeichnen.
Wenn ich auf meine eigene Reise zurückblicke, sehe ich, wie sich die von mir genutzten Sprachen entwickelt haben. Meine erste große Sprache war Basic: Zunächst GW-Basic, später QuickBasic und schließlich Basic PDS, alles unter MS-DOS. Und Basic ist eigentlich das Gegenteil von dem, was ich beschrieben habe. Es ist nicht ausdrucksstark, nicht minimalistisch, nicht explizit. Es war bestenfalls halbwegs konsistent. Fehlervermeidend war es schon gar nicht, man denke nur an das unsägliche ON ERROR GOTO NEXT.
Danach habe ich zehn Jahre lang sehr intensiv mit C# gearbeitet. C# ist in fast allen Belangen besser als Basic: Es ist ausdrucksstärker, expliziter und weniger fehleranfällig. Nur minimalistisch ist es nicht, auch in C# gibt es zu viele Wege, dasselbe zu machen. Aber im Vergleich zu Basic war es trotzdem eine deutliche Verbesserung.
Dann kam JavaScript, mit dem ich wiederum zehn Jahre sehr viel gearbeitet habe. JavaScript kann tatsächlich minimalistisch genutzt werden, das macht es aber nicht zu einer minimalistischen Sprache. Tatsächlich gibt es auch in JavaScript sehr viele Schlüsselwörter und es ist weniger konsistent und gleichzeitig deutlich fehleranfälliger als C#. Unterm Strich sind die beiden Sprachen also durchaus unterschiedlich, aber ich würde sie letztlich als "gleichwertig" bezeichnen, nur eben als "anders".
Seit einigen Jahren arbeite ich nun hauptsächlich mit Go. Go ist eine viel kleinere Sprache als alle zuvor genannten: Es ist minimalistischer, konsistenter, weniger fehleranfällig und trotzdem ausdrucksstark. Ich fühle mich momentan mit Go sehr wohl, aber es wird wohl nicht die letzte Sprache sein, mit der ich mich jemals beschäftigen werde.
Wenn ich diese Reise von Basic über C# und JavaScript zu Go Revue passieren lasse, dann sehe ich, wie die von mir bevorzugten Sprachen immer mehr in die Richtung dessen gehen, was ich als gutes Sprachdesign empfinde. Das sagt allerdings absolut noch nichts über die Standardbibliothek, das Tooling oder ähnliches aus – es geht nur um die Sprache an sich.
Und: Was für mich funktioniert, muss nicht für jeden passen. Ich habe versucht, objektive Kriterien zu nennen, aber die Frage, ob eine Sprache gut oder schlecht ist, hängt immer vom eigenen Wertesystem ab. Selbst wenn Du die gleichen Kriterien anwendest wie ich, musst Du nicht zum gleichen Ergebnis kommen. Unterschiedliche Sprachen haben unterschiedliche Stärken und Schwächen.
Ich nehme aber an, dass niemand sagen würde, alle Sprachen seien gleich gut, denn sonst würden wir alle immer noch dieselbe Sprache nutzen, mit der wir irgendwann einmal angefangen haben. Die Tatsache, dass wir das nicht tun, zeigt, dass wir eine andere Sprache für gelungener hielten (oder dass wir uns in eine Nische weiterentwickelt haben, in der wir um eine bestimmte Sprache nicht herumkommen, unabhängig davon, ob wir sie gut oder schlecht finden).
Was für mich bleibt, sind vor allem zwei Dinge: Erstens kann ich auf Basis meines persönlichen Wertesystems argumentativ erläutern, warum ich bestimmte Sprachen gegenüber anderen bevorzuge, und warum ich zum Beispiel Go für gelungener halte als C#. Zweitens ist mir bewusst, dass diese qualitative Einschätzung von jeder Entwicklerin und jedem Entwickler anders getroffen werden kann, da der eigene Hintergrund jeweils ein anderer ist – und das macht eine objektive Darstellung so schwierig.
Hinzu kommt noch, dass man eine Sprache letztlich nur nach diesen Kriterien auswählt, sondern eben auch nach Tauglichkeit für das vorliegende Problem, nach Tooling, nach Funktions- und Klassenbibliothek, und, und, und.
Und deshalb macht man es sich zu leicht, wenn man jemanden belächelt, weil sie oder er mit Visual Basic programmiert: Ja, auch in meinen Augen ist Visual Basic keine besonders gelungene Sprache. Trotzdem kann es sein, dass sie für den eingangs erwähnten Entwickler genau das Richtige ist, aus einer Vielzahl von Gründen. Und statt darüber zu urteilen, sollten wir vielleicht eher neugierig und überrascht nachfragen: Warum? Denn vielleicht können wir dabei etwas lernen.
URL dieses Artikels:
https://www.heise.de/-10248069
Links in diesem Artikel:
[1] https://www.thenativeweb.io/
[2] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[3] https://www.youtube.com/watch?v=JxF5cv9LNIc
[4] mailto:rme@ix.de
Copyright © 2025 Heise Medien
(Bild: Erstellt mit KI (Midjourney) durch iX-Redaktion)
Je erfahrener ein Entwickler oder eine Architektin ist, desto besser die Ergebnisse – sollte man meinen. Doch tatsächlich ist häufig das Gegenteil der Fall.
Vielleicht kennen Sie die Situation: Sie öffnen ein Projekt, das jemand anderes entwickelt hat, und schon nach wenigen Minuten denken Sie sich:
"Das ist aber ganz schön kompliziert implementiert!"
Je mehr Code Sie lesen, desto stärker beschleicht Sie das Gefühl, dass vieles unnötig komplex ist. Häufig sind es Abstraktionsebenen, die Dinge verschleiern, die eigentlich pragmatisch und einfach hätten gelöst werden können. Solche Ansätze machen den Code schwer verständlich – und das gilt nicht nur für den Code, sondern auch für die Architektur eines Projekts. Vielleicht haben auch Sie schon einmal das Gefühl gehabt, dass weniger darauf geachtet wurde, guten Code zu schreiben, sondern dass jemand sich an einer übertriebenen Komplexität verkünstelt hat.
Genau darum geht es heute: Architektur sollte im Idealfall unsichtbar sein. Doch was bedeutet das genau? Und wie können Sie dieses Prinzip für sich nutzen?
Fangen wir mit der Frage an, was es bedeutet, dass eine gute Architektur unsichtbar ist. Ein Vergleich mit der Realität hilft, das zu verdeutlichen. Denken Sie an beeindruckende Bauwerke: vielleicht an eine moderne Villa, bei der jedes Detail passt und alle Entscheidungen nahtlos ineinanderfließen. Oder an ein historisches Bauwerk wie den Kölner Dom, das architektonisch ebenfalls fasziniert. Der entscheidende Punkt ist: Sie bewundern in beiden Fällen das Bauwerk als Ganzes. Sie wissen zwar, dass dahinter eine durchdachte Architektur steckt, diese drängt sich Ihnen aber nicht auf. Vielmehr wirkt alles wie ein schlüssiges Gesamtbild, bei dem man spürt, dass alle Details durchdacht sind. Das heißt, gute Architektur tritt in den Hintergrund und fordert nicht ständig Ihre Aufmerksamkeit.
Natürlich ließe sich alternativ auch ein Bauwerk schaffen, bei dem jede architektonische Entscheidung überdeutlich sichtbar wird. Das mag zwar schick aussehen, würde aber den Eindruck einer überambitionierten Studie vermitteln, die mehr Selbstzweck als Grundlage für ein großartiges Bauwerk ist. Und genau das meine ich, wenn ich sage: Gute Architektur ist unsichtbar. Sie schafft Strukturen, ohne sich in den Vordergrund zu drängen.
Dieses Prinzip gilt nicht nur für Bauwerke, sondern auch für Software. Auch hier ist Architektur kein Selbstzweck. Sie sollte ein solides Fundament liefern, auf dem eine gut strukturierte, wartbare und langfristig nutzbare Software entstehen kann. Wenn eine Architektur diese Ziele erfüllt, ohne sich selbst zu wichtig zu nehmen, ist sie gelungen. Wenn sie diese Ziele hingegen verfehlt oder unnötig in den Vordergrund rückt, ist sie schlecht.
Bis hierhin klingt das alles vielleicht recht einleuchtend. Doch wenn es so einfach wäre, würden wir nicht so häufig auf Projekte stoßen, bei denen wir uns denken:
"Was ist das denn? Was hat sich da bloß jemand gedacht?"
Über die Jahre fällt dann ein Muster auf: Menschen, die gerade erst mit der Programmierung beginnen, entwickeln oft einfache und pragmatische Lösungen – allein schon deshalb, weil sie es nicht anders können. Mit wachsendem Wissen neigen Entwicklerinnen und Entwickler jedoch dazu, Probleme immer stärker zu abstrahieren. Das wird uns in der Ausbildung schließlich so beigebracht: Der Versand einer Word-Datei wird abstrahiert zu "Dateiversand", dieser wiederum zur Nachricht eines Senders an einen Empfänger – und am Ende reden wir nur noch abstrakt über "Messaging". Dabei wollte man ursprünglich einfach nur eine Word-Datei per E-Mail versenden.
Das Problem dabei ist oft zu viel und vor allem zu frühe Abstraktion. Jede Abstraktion führt zu einer weiteren Indirektion, die den Code schwerer verständlich macht. Statt den eigentlichen Gedankengang der Entwicklerin oder des Entwicklers im Code nachvollziehen zu können, muss man diesen gedanklich zunächst auf eine andere Ebene übersetzen. Je mehr solche Ebenen es gibt, desto schwieriger wird es, den Code zu verstehen. Dabei wird Code jedoch nur einmal geschrieben, aber viele Male gelesen. Der Fokus sollte daher viel eher auf Lesbarkeit, Nachvollziehbarkeit und Verständlichkeit liegen, nicht auf möglichst vielen Abstraktionen. Das "You Ain’t Gonna Need It"-Prinzip (YAGNI) ist nicht ohne Grund ein Leitmotiv in der Softwareentwicklung: Keep it simple! Dieses Prinzip gilt für Code genauso wie für Architektur.
Ein zentraler Aspekt ist die klare Definition von Verantwortlichkeiten: Welche Funktion, Klasse oder welcher Service ist wofür zuständig? Die Prinzipien der niedrigen Kopplung und der hohen Kohäsion helfen hier: Einzelne Elemente sollten möglichst unabhängig voneinander existieren, während alles, was zu einer Aufgabe gehört, an einem Ort zusammengeführt wird. Wenn Sie also einen Fehler beheben müssen, sollte die Änderung an einer Stelle genügen, ohne andere Teile des Systems zu beeinflussen.
Ein Beispiel aus der Praxis verdeutlicht das: In einem Code-Review stieß ich auf eine unnötige Abstraktion in einer Go-Codebasis. Anstatt einen Pointer zu verwenden, um auszudrücken, dass ein Wert optional ist, hatte die Entwicklerin einen Maybe-Typ eingeführt – ein Konzept aus der funktionalen Programmierung. Dieser Typ war jedoch nur an einer einzigen Stelle im Code verwendet worden, was weder konsistent noch sinnvoll war. Ein einfacher Pointer hätte denselben Zweck erfüllt und wäre deutlich verständlicher und weniger fehleranfällig gewesen.
Das Problem unnötiger Abstraktion tritt nicht nur auf Code-, sondern auch auf Architekturebene auf. So wird manchmal ein Microservice eingeführt, nicht weil er notwendig ist, sondern um das Konzept eines Microservices umzusetzen. Das führt zu unnötiger Komplexität und verfehlt das eigentliche Ziel, die Struktur und Verständlichkeit der Software zu verbessern.
Warum verkünsteln sich erfahrene Entwicklerinnen und Entwickler so oft? Ein Grund ist der Wunsch nach Perfektion, ein anderer das Streben nach Anerkennung. Es ist wichtig, sich diesen Effekt bewusst zu machen und den eigenen Code und die eigene Architektur zu reflektieren. Code-Reviews und Pair-Programming können hier helfen, denn sie fördern pragmatische Ansätze und die Verständlichkeit für andere.
Architektur und Code sind Mittel zum Zweck, kein Selbstzweck. Sie sollten die fachlichen Anforderungen und die Bedürfnisse des Teams in den Mittelpunkt stellen. Lösungen sollten iterativ und pragmatisch entwickelt werden. Fragen Sie sich stets: Braucht das Team diese Abstraktion wirklich, oder verkompliziert sie die Dinge nur unnötig?
URL dieses Artikels:
https://www.heise.de/-10225156
Links in diesem Artikel:
[1] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[2] mailto:rme@ix.de
Copyright © 2025 Heise Medien
(Bild: Erstellt mit KI (Midjourney) durch iX)
Architektur wirkt oft wie eine dunkle Magie, die nur in den elitären Kreisen der Wissenden diskutiert wird. Das ist nicht nur falsch, sondern auch gefährlich.
"Architektur ist überbewertet" wirkt auf den ersten Blick wie ein typischer Clickbait-Titel, aber ich will kurz erklären, was genau ich mit diesem Titel meine. Architektur hat ein Problem, über das meiner Meinung nach viel zu wenig gesprochen wird, das aber auf uns als Entwicklerinnen und Entwickler gravierende Auswirkungen hat.
Es geht um die ständige Idealisierung und die überhöhte Wahrnehmung von Architektur, von Architekten und all dem, was damit zusammenhängt und einhergeht, wie zum Beispiel einer ganzen Reihe von Prinzipien, Konzepten und nicht zuletzt auch von einigen Personen.
Das schreckt ab, denn auf dem Weg wird Architektur nicht mehr als das wahrgenommen, was sie eigentlich ist – nämlich als die Kunst, Software adäquat zu strukturieren –, sondern sie wird auf einmal als Selbstzweck wahrgenommen. Das jedoch ist nicht nur falsch, sondern auch gefährlich.
Architektur hat ein Problem: Sie wird idealisiert und überhöht. Wenn Sie nicht genau wissen, was ich damit meine, stellen Sie sich vor, wie über typische Prinzipien und Konzepte aus der Architektur gesprochen wird: Da geht es nicht um ein paar hilfreiche Leitplanken und nützliche Wegweiser, die Sie bei Ihren Bemühungen zu einer gut strukturierten Software unterstützen. Nein, da geht es zum Beispiel um Clean Code (und ja, mir ist bewusst, dass das Thema für viele nicht unter Architektur fällt, im Sinne einer besseren Strukturierung von Software gehört aber auch Clean Code dazu).
Allein durch die Namensgebung sprechen wir nicht mehr nur auf einer technischen Ebene, sondern es schwingt noch etwas ganz anderes mit, etwas Emotionalisiertes: Wenn Sie sich nicht an diese Regeln halten, dann schreiben Sie Code, der schmutzig, ungepflegt und minderwertig ist. Wollen Sie so etwas etwa wirklich? Wo die Frage nach gut strukturiertem Code explizit auf der emotionalen Ebene exkludiert, fällt eine rein sachliche Diskussion schwierig.
Ein weiteres Beispiel sind die SOLID-Prinzipien. Auch suggeriert allein der Name bereits ein stabiles Fundament, ein Fels in der Brandung. Und wehe, Sie setzen sie nicht ein: Dann stehen Sie da wie ein Grashalm, der beim leichtesten Windhauch umknickt. Wollen Sie das?
Bei diesen Beispielen kann man sich sehr gut den erhobenen Zeigefinger vorstellen: Passen Sie bloß auf, sonst enden Sie wie all die anderen vor Ihnen – als Versager.
Tatsächlich ist es jedoch nicht die Namensgebung allein: Das ist nur das, was als Erstes auffällt. Es geht noch weiter: Versuchen Sie einmal, Clean Code zu kritisieren. Sofort kommen zahlreiche Befürworterinnen und Befürworter, die Clean Code mit Leidenschaft verteidigen und als das Nonplusultra darstellen. So nach dem Motto:
"Wie können Sie es wagen, Clean Code zu hinterfragen, zu kritisieren oder gar infrage zu stellen? Was bildet Sie sich ein, wer Sie sind? Und übrigens: Sie haben damit auch Uncle Bob beleidigt, also entschuldigen Sie sich gefälligst!"
Vielleicht finden Sie das jetzt übertrieben, und natürlich verhält sich nicht jede Anhängerin und jeder Anhänger von Clean Code, SOLID & Co. derart. Das Problem ist jedoch: Es lässt sich nicht leugnen, dass um diese Themen ein gewisser Kult betrieben wird, inklusive eines ausgeprägten Personenkults. Ich behaupte nicht, dass das nur Uncle Bob alias Robert C. Martin betrifft, aber bei ihm ist es besonders auffällig. Und so etwas ist immer problematisch, denn dann wird nicht mehr sachlich über die Inhalte diskutiert. Stattdessen werden diese mit unsachlichen Emotionen und persönlichen Befindlichkeiten aufgeladen und untrennbar verknüpft.
Wenn sich das über Jahre und Jahrzehnte verfestigt, hat das natürlich Folgen. Architektur und lesbarer Code werden dann nicht mehr als etwas wahrgenommen, womit sich jede und jeder beschäftigen sollte, sondern als etwas für die Eliten. Genau so erlebe ich oft die Meinung von weniger erfahrenen Entwicklerinnen und Entwicklern: Sie sagen, sie hätten von Architektur keine Ahnung, aber eines Tages würden sie das gerne in ihrem Jobtitel stehen haben, "Distinguished Senior Solution Architect" oder etwas Ähnliches.
So entsteht eine mystische Aura um dieses Thema, als wäre es nur für sehr erfahrene Menschen zugänglich, die es geschafft haben, Teil dieses elitären Kreises zu werden. Was genau eine Architektin oder ein Architekt eigentlich macht, wird dabei oft nicht mehr klar. Es scheint nur eines sicher: Es handelt sich um eine intellektuell anspruchsvolle Aufgabe, der Normalsterbliche vermeintlich nicht gewachsen sind. Dementsprechend beschäftigt man sich nicht mit Architektur, überlässt es den Weisen, entwickelt sich nicht weiter und bleibt jahrelang in dem Traum gefangen, selbst irgendwann ein Teil dieses elitären Zirkels zu sein, ohne den Weg dorthin zu kennen.
Das eigentliche Problem ist, dass Architektur oft als Selbstzweck betrachtet wird: Sie wird um ihrer selbst willen betrieben und nicht als praktisches Werkzeug, das einer größeren Aufgabe dient. Nein, die Architektur selbst wird zur höheren Aufgabe erhoben. Das ist jedoch Unsinn. Clean Code kann durchaus kritisiert werden, und Robert C. Martin ist kein Heiliger. Die SOLID-Prinzipien sind, wenn wir ehrlich sind, fünf relativ beliebig ausgewählte Prinzipien, die in der Objektorientierung mehr oder weniger sinnvoll und manchmal nützlich sind.
Warum es ausgerechnet diese fünf Prinzipien geworden sind und nicht irgendwelche anderen, bleibt Spekulation. Vermutlich hat sich jemand ein schickes Akronym ausgedacht (eben "SOLID") und dazu Prinzipien zusammengesucht, die ansatzweise sinnvoll erschienen. Wenn man sich diese Prinzipien genauer anschaut, sind die meisten davon weder besonders elegant formuliert (im Sinne von anschaulich und greifbar), noch sind sie besonders hilfreich im Alltag. Ich kann mich zumindest nicht erinnern, wann ich das letzte Mal dachte:
"Wie praktisch, dass ich das Liskovsche Substitutionsprinzip kenne, ohne das wäre diese Struktur deutlich schlechter."
Dennoch wird vermittelt, dass die SOLID-Prinzipien die fünf wichtigsten Prinzipien der objektorientierten Programmierung seien. Das sind sie jedoch nicht, da die meisten viel zu spezifisch sind.
Das heißt, sie sind keine absolute Wahrheit, die nicht hinterfragt werden dürfte. Sie sind nur Mittel zum Zweck. Architektur (und dazu zähle ich Clean Code und diese Prinzipien wie oben schon erwähnt) hat letztlich nämlich nur ein einziges konkretes Ziel: Sie soll helfen, eine gute Struktur für Code zu schaffen, sodass dieser langfristig verständlich, überschaubar, wartbar und erweiterbar bleibt.
Wann hat Code diese Struktur? Eigentlich ist das ganz einfach: immer dann, wenn zwei Grundprinzipien erfüllt sind. Code ist gut strukturiert, wenn er zum einen eine geringe Kopplung und zum anderen eine hohe Kohäsion aufweist. In dem Video zu Kopplung und Kohäsion [2] erkläre ich die beiden Prinzipien im Detail.
Diese beiden Prinzipien – geringe Kopplung und hohe Kohäsion – sind der Leitstern, der uns überall im Code Orientierung gibt, egal ob bei Funktionen und Klassen im Kleinen oder im Großen bei den zahlreichen Microservices einer verteilten Anwendung. Diese Prinzipien machen eine gute Architektur aus. Darüber nachzudenken und daran zu arbeiten erfordert keinen Titel wie "Distinguished Senior Solution Architect". Auch Praktikantinnen und Praktikanten können sich damit beschäftigen. Vielleicht fehlt ihnen etwas Erfahrung, aber sie sind durchaus intellektuell in der Lage, darüber nachzudenken.
Die entscheidende Frage lautet: Wo sollte ich mich um was kümmern, wer ist wofür verantwortlich? Das ist letztlich alles.
Die Entscheidungen müssen ein höheres Ziel unterstützen: die Fachlichkeit. Denn genau darum geht es in der Softwareentwicklung. Wir entwickeln nicht deshalb Software, weil es Spaß macht (auch wenn es tatsächlich Spaß macht), sondern um ein tieferliegendes fachliches Problem zu lösen. Software ist kein Selbstzweck, sondern ein Werkzeug, um einen fachlichen Zweck zu erfüllen. Und Architektur muss sich daran messen lassen.
Es geht nicht darum, ob wir alle fünf SOLID-Prinzipien umgesetzt oder möglichst viele Design-Patterns verwendet haben. Was am Ende zählt, ist, dass die Architektur das fachliche Problem unterstützt und es uns erleichtert, die Software langfristig zu warten und weiterzuentwickeln. Apropos Design-Patterns: Auch diese halte ich für überbewertet [3].
Mit diesem Mindset trifft man jedoch oft auf Projekte, in denen die Architektur schon feststand, bevor die fachlichen Anforderungen bekannt waren. Das halte ich für eine schlechte Idee, genauso wie die Wahl von Technologien, bevor Architektur und Anforderungen klar sind. Was ich in Teams oft erlebe, sind Argumente wie:
"Wir sind aber nicht Netflix. Wir brauchen keine Microservices, kein CQRS, kein Event-Sourcing, keine komplexe Architektur."
Stattdessen setzt man auf eine einfache Drei-Schichten-Architektur mit einem Monolithen und Dependency Injection. Missverstehen Sie mich nicht: Es gibt Projekte, wo das angemessen ist. Viel zu oft werden solche Entscheidungen jedoch mit unpassenden Argumenten und aus den falschen Gründen getroffen. Bei Microservices etwa ist die Frage nicht:
"Sind Sie Netflix?"
Stattdessen geht es (eigentlich) um geringe Kopplung und hohe Kohäsion bei ausreichend komplexer Fachlichkeit. Diese Anforderungen kann auch ein Drei-Personen-Start-up haben. Das hängt nicht davon ab, ob man Netflix ist, sondern vom jeweiligen Business.
Die klassische Drei-Schichten-Architektur im Monolithen hat einige gravierende Nachteile: Fachlicher und technischer Code sind oft nicht sauber getrennt, was Anpassungen erschwert. Beim Testen merkt man das besonders: Es ist kaum möglich, die Geschäftslogik zu testen, weil immer die Datenbank mit dranhängt. Statt die Architektur zu hinterfragen, setzen viele dann auf Mocking. Doch Mocking ist eine der schlechtesten Ideen im Testen, weil es grüne Tests liefert, ohne sicherzustellen, dass die Mocks die Realität abbilden. Mit anderen Worten: Mocking wird zum Workaround für schlechte Architekturentscheidungen.
Tatsache ist: Es gibt deutlich bessere Ansätze. Gerade bei komplexer Geschäftslogik bietet sich etwa eine hexagonale Architektur an, die die Fachlichkeit in den Mittelpunkt rückt – ohne Abhängigkeiten zu externen Ressourcen. Doch auch hier heißt es oft:
"Wir sind doch nicht Netflix."
Solche Aussagen basieren oft auf Angst vor Veränderung. Das Problem sind nicht sachliche Argumente, sondern emotionale Bedenken:
"Das haben wir noch nie gemacht, also bleibt alles beim Alten."
Oft bekommen dann Berater den Auftrag, die beruhigende Botschaft zu verbreiten, ein Monolith reiche aus, denn man sei nicht Netflix. Das wird dann nach und nach zum gefährlichen Mantra.
Jahre später stellt man dann fest, dass die Technologie veraltet ist, aber ein Wechsel kaum möglich ist, weil alles miteinander verwoben ist. Technologiewechsel werden so zu Alles-oder-Nichts-Entscheidungen. Dabei treten viele Probleme auf: schlechte Testbarkeit, keine Skalierbarkeit, fehlende APIs für externe Systeme oder unklare Verantwortlichkeiten bei Master-Data-Management. All das hätte man vermeiden können, wenn man früher über eine fachlich sinnvolle Architektur nachgedacht hätte.
Der Sinn einer Architektur liegt darin, eine tragfähige Struktur für die Software zu schaffen, die geringe Kopplung und hohe Kohäsion gewährleistet. Wie man das erreicht, ist zweitrangig. Wichtig ist, dass die Fachlichkeit unterstützt wird. Unsachliche Diskussionen über Werkzeuge wie Clean Code, SOLID oder Design-Patterns helfen dabei nicht. Stattdessen sollten wir mehr darüber sprechen, warum wir Software entwickeln und wie die Fachlichkeit unsere Entscheidungen beeinflusst. Wer sich weiterhin hinter emotionalen und unsachlichen Argumenten versteckt, wird langfristig viel Schaden anrichten.
Fragen Sie sich daher immer, ob Ihre Architektur das fachliche Problem löst oder eher behindert. Und wenn Letzteres der Fall ist, denken Sie über Alternativen nach – losgelöst von dem, was in Lehrbüchern steht oder als Standard gilt. Architektur ist mehr als das. Jede Entwicklerin und jeder Entwickler kann dazu beitragen, denn Programmieren bedeutet, Strukturen zu schaffen.
URL dieses Artikels:
https://www.heise.de/-10191624
Links in diesem Artikel:
[1] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[2] https://www.youtube.com/watch?v=kWP432pXP-U
[3] https://www.youtube.com/watch?v=oC-9HZ0r3e4
[4] https://shop.heise.de/ix-developer-praxis-softwarearchitektur-2024/print?wt_mc=intern.shop.shop.ix-dev-softwarearchitektur24.dos.textlink.textlink
[5] mailto:rme@ix.de
Copyright © 2024 Heise Medien
(Bild: Sergey Nivens/Shutterstock.com)
Low-Code- und No-Code-Plattformen versprechen Fachabteilungen, geschäftsrelevante Software selbst entwickeln zu können. Doch ist das wahr?
Stellen Sie sich für einen kurzen Augenblick vor, Sie würden nicht in der Softwareentwicklung arbeiten, sondern wären vielleicht Domänenexpertin oder -experte für Versicherungs-Policen. Sie arbeiten bei einer Versicherung in der Fachabteilung. Programmierung und Softwareentwicklung sind so gar nicht Ihre Themen, aber Sie kennen sich dafür bestens mit all den inhaltlichen Aspekten wie Policen, Schäden, Haftung und Regress aus.
Nun benötigen Sie ein kleines Stück Software: Vielleicht ein einfaches Tool, um die Daten von Kundinnen und Kunden effizienter zu erfassen, oder einen Report, der Ihnen ermöglicht, Ihre Policen für das nächste Jahr besser zu optimieren. Was es konkret ist, spielt letztlich keine Rolle. Es geht um etwas Kleines und Einfaches, das Ihnen und Ihren Kolleginnen und Kollegen das Leben erleichtert und Ihr Business voranbringt.
Wie kommen Sie nun zu dieser Software? Klar, Sie könnten natürlich zur hausinternen IT-Abteilung gehen und nett fragen. Wenn Sie Glück haben, sagt Ihnen die freundliche Kollegin aus der IT, dass das kein Problem sei. Sie würde sich darum kümmern und Ihnen das nebenbei bauen. Natürlich stellt sich nachher heraus, dass sie leider nicht ganz so viel Zeit erübrigen kann wie gedacht, und sie wusste vielleicht auch nicht ganz so genau, was Sie eigentlich im Detail wollten.
Deshalb macht die Software am Ende nicht ganz das, was sie sollte. Aber hey, beschweren Sie sich nicht: Immerhin haben Sie überhaupt etwas bekommen! Es hätte nämlich auch schlimmer kommen können: Wären Sie statt an die freundliche und hilfsbereite Kollegin an ihren grummeligen Kollegen geraten, hätte er Ihnen wahrscheinlich sehr deutlich zu verstehen gegeben, dass für so einen Quatsch keine Zeit da sei, die IT ohnehin völlig überlastet sei und Sie ohne eine um 27 Ecken eingeholte Budgetfreigabe gar nicht erst wieder ankommen bräuchten.
Wie schön wäre es, wenn Sie die IT einfach gar nicht bräuchten, sondern sich das, was Sie benötigen, einfach selbst hätten zusammenbauen können – ganz ohne jegliche Programmierkenntnisse? Willkommen bei der Welt der Low-Code- und No-Code-Plattformen!
Das, was ich Ihnen gerade geschildert habe, beschreibt letztlich das Werbeversprechen von Low-Code- und No-Code-Umgebungen. Die Idee dahinter ist, dass viele Vorgänge in Fachanwendungen mehr oder weniger immer gleich ablaufen: Formulareingaben, Datenabrufe aus einem SharePoint, tabellarische oder grafische Visualisierungen – all das sind immer wiederkehrende Muster. Die Plattform stellt nun solche Aktivitäten als Bausteine zur Verfügung, und Sie können sich daraus Ihre eigene Anwendung zusammenbauen, ohne wissen zu müssen, wie die technischen Details funktionieren.
Ich selbst habe das vor einiger Zeit einmal ausprobiert, gemeinsam mit einem Freund, auf Basis der Microsoft Power Platform, genauer gesagt mit Power Automate. Es ging um einen simplen Anwendungsfall: Daten von einer HTTP-API abrufen und anzeigen. Nach drei bis vier Stunden hatten wir dann allerdings keine Lust mehr, weil wir immer wieder auf Probleme stießen. Entweder waren wir zu zweit zu unfähig (was ich bezweifle), oder unser Anwendungsfall lag geringfügig außerhalb der vorgesehenen Nutzungspfade. Schlussendlich zogen wir einen Kollegen hinzu – einen zertifizierten "Microsoft Power Platform Developer". Ein Entwickler also für eine Plattform, die Entwickler angeblich überflüssig machen soll – an Absurdität lässt sich das kaum überbieten!
Dieser Vorfall ist natürlich nicht repräsentativ für alle Low- und No-Code-Plattformen. Aber er zeigt ein grundlegendes Problem auf: Die Plattformen machen große Versprechungen, schüren hohe Erwartungen – und die Realität bleibt dahinter zurück: Fachabteilungen können nicht plötzlich auf magische Weise alles selbst lösen. Sie können nicht auf die IT-Abteilung und Entwickler verzichten. Und sie sparen am Ende oft weder Zeit noch Geld. Im ungünstigsten Fall passiert sogar genau das Gegenteil.
Woran liegt das? Programmieren bedeutet, eine Sprache zu beherrschen. Egal, ob Sie Französisch oder eine Programmiersprache lernen: Sie müssen Vokabeln und Grammatik lernen, lesen, schreiben, sprechen – und üben. Entwicklerinnen und Entwickler haben sich all dieses Wissen in jahrelanger, mühsamer Arbeit angeeignet. Und nun kommt eine Plattform daher, die behauptet:
"Das brauchen Sie alles nicht!"
Stattdessen bekommen Sie Bausteine, die Sie anordnen sollen. Aber diese Bausteine reichen oft nicht aus, um komplexe Anforderungen abzubilden. Die fachliche und technische Komplexität bleibt bestehen – sie wird nur unsichtbar. Und spätestens, wenn eine Anwendung nicht performant läuft, Race Conditions auftreten oder der Datenverkehr das Netzwerk lahmlegt, kommen Sie ohne grundlegende Programmierkenntnisse nicht weiter.
Hinzu kommt, dass viele Plattformen proprietär sind. Sobald Sie eine Anwendung auf Basis einer solchen Plattform entwickeln, schaffen Sie einen Vendor-Lock-in. Die IT wird sich hüten, solche Anwendungen zu supporten. Das erinnert nämlich zu sehr an Microsoft Access, das in vielen Unternehmen bis heute Probleme verursacht. Das Problem ist also nicht neu – nur die Technologien haben sich geändert.
Darüber hinaus wissen Fachabteilungen oft selbst nicht, wie ihre Prozesse im Detail aussehen oder was sie genau wollen. Deshalb gibt es Business-Analysten und Requirements Engineers, die diese Anforderungen gemeinsam mit den Fachabteilungen erarbeiten. Fachabteilungen haben das fachliche Know-how, aber sie sind meist nicht darauf vorbereitet, dieses Wissen zielführend und nachhaltig in digitale Prozesse umzusetzen.
Trotz aller Kritik haben Low-Code-Plattformen aber natürlich auch ihre Berechtigung. Sie können die Kommunikation zwischen Entwicklung und Fachabteilung erleichtern, indem die Fachabteilung beispielsweise eigenständig Prototypen erstellt. Für einfache Anforderungen – wie "Formular ausfüllen und Daten per E-Mail senden" – können sie zudem durchaus ausreichen. Bei komplexeren Aufgaben würde ich jedoch zur Vorsicht raten.
Was mich an dem ganzen Thema aber mit Abstand am meisten stört, ist das Narrativ von "Entwicklung gegen Fachabteilung". Es geht nicht um "wir gegen die", und dieses Narrativ war noch nie konstruktiv oder gar zielführend, sondern führt stets nur zu Zwist und Schuldzuweisungen. Am Ende des Tages sind wir doch eigentlich dann erfolgreich, wenn wir unsere unterschiedlichen Fähigkeiten und Kenntnisse konstruktiv zusammenbringen und gemeinsam und partnerschaftlich auf ein gemeinsames Ziel hinarbeiten: Es geht um Partnerschaft auf Augenhöhe. Und Low-Code-Plattformen sollten diese Partnerschaft unterstützen, nicht spalten – doch genau das ist es, was sie letztlich machen.
Langer Rede, kurzer Sinn: Gehen Sie kritisch mit solchen Plattformen um. Verstehen Sie deren Grenzen und setzen Sie auf eine solide Zusammenarbeit zwischen Entwicklung und Fachabteilung. Nur so profitieren letztlich alle Beteiligten – außer vielleicht der Hersteller der Plattform.
URL dieses Artikels:
https://www.heise.de/-10184237
Links in diesem Artikel:
[1] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[2] mailto:rme@ix.de
Copyright © 2024 Heise Medien
(Bild: fizkes/Shutterstock.com)
Im Sommer 2025 veranstaltet die the native web GmbH eine eintägige Konferenz zum Thema professionelle Web- und Cloud-Entwicklung.
Das Jahr 2024 ist noch nicht ganz vorüber, aber es neigt sich allmählich dem Ende entgegen. Für meine Kolleginnen und Kollegen der the native web GmbH [1] und mich bedeutet das, dass in diesem Jahr nur noch ein paar wenige Posts in diesem Blog und auch Videos auf YouTube vor uns liegen, bevor wir uns in den Weihnachtsurlaub verabschieden werden. Es bedeutet aber auch, dass wir bereits fleißig mit der Planung für das kommende Jahr beschäftigt sind.
Was Sie im nächsten Jahr genau erwartet, das verrate ich Ihnen heute noch nicht im Detail, aber ich möchte zumindest schon einmal ein paar Worte über das vergangene Jahr verlieren.
Rückblickend war 2024 für uns ein großartiges Jahr. In den vergangenen elf Monaten haben wir sage und schreibe 26 Blogposts geschrieben, 47 Videos veröffentlicht, fünf Livestreams veranstaltet und 36 Webinare im Rahmen unserer tech:lounge Masterclass durchgeführt. Und ganz gleich, was wir gemacht haben – eine Sache war immer gleich: Ihr Feedback!
Sie haben uns in so vielen Kommentaren, E-Mails, Telefonaten, persönlichen Gesprächen, auf Discord und sogar per Post (!) geschrieben und gesagt, wie ungemein wichtig unsere Videos und Artikel für Sie sind: für lebenslanges Lernen, für kontinuierliche Weiterbildung, für den Alltag. Sie haben uns mitgeteilt, dass wir Sie mit unserem Content unterstützt haben, sich weiterzuentwickeln, endlich den neuen Job zu bekommen, anderen weiterzuhelfen und vieles mehr.
Das macht uns unglaublich stolz und wir sind sehr dankbar für dieses Feedback, denn es zeigt uns, dass das, was wir machen, nicht einfach nur das nächste x-beliebige Content-Schnippsel im Internet ist, sondern dass wir wirklich etwas zum Guten bewirken können und einen positiven Einfluss auf Ihr Leben haben. Das ist alles andere als selbstverständlich. Und darüber bin ich sehr froh.
Lebenslanges Lernen ist gerade in der IT ein wichtiges Thema. Nur wer sich dauerhaft und kontinuierlich weiterbildet, wird auch nachhaltigen Erfolg in der Softwareentwicklung haben. Deshalb haben wir uns auch für das kommende Jahr einiges vorgenommen. Was das alles im Detail sein wird, möchte ich an dieser Stelle noch nicht verraten, aber zwei Neuigkeiten möchte ich doch schon mit Ihnen teilen.
Zum einen werden wir im Sommer 2025 zum ersten Mal seit der Pandemie wieder eine Vor-Ort-Veranstaltung durchführen: Wir werden eine kleine, schnuckelige, eintägige Konferenz rund um das Thema der professionellen Web- und Cloud-Entwicklung bei uns in Freiburg im Breisgau veranstalten. Vom Morgen bis in den späten Abend hinein wird es am 4. Juli 2025 um Themen wie Architektur, Algorithmen, Protokolle, Skalierbarkeit und Ausfallsicherheit gehen.
Da wir die Veranstaltung direkt neben unserem Büro abhalten, ist das auch die perfekte Gelegenheit, meine Kolleginnen und Kollegen (und natürlich auch mich) einmal persönlich kennenzulernen. Wie das bei Veranstaltungen in der Realität leider so ist, ist der Platz natürlich begrenzt, das heißt, die Teilnahme ist auf 150 Personen limitiert. Ein Ticket kostet 399 Euro (zuzüglich 19 % Umsatzsteuer), und Sie können es ab sofort auf unserer Website buchen [2], um bei der tech:lounge Live! vor Ort dabei sein zu können. Und natürlich würde ich mich sehr freuen, Sie dort begrüßen zu dürfen!
Das ist jedoch noch nicht alles. Pünktlich zum Jahresende haben wir noch ein ganz besonderes Spezialangebot für Sie: Wir haben uns überlegt, dass wir auch im kommenden Jahr wieder Webinare anbieten werden, und zwar 24 Stück. Normalerweise kostet ein einzelnes Webinar 179 Euro, und ein Dreierpaket kostet 399 Euro. Bei 24 Webinaren wären das also insgesamt über 4.200 Euro.
Weil wir aber wissen, dass viele von Ihnen regelmäßig bei unserer tech:lounge Masterclass zu Gast sind, bieten wir Ihnen bis zum 31. Dezember dieses Jahres an, die Teilnahme an allen 24 Webinaren, die im kommenden Jahr stattfinden werden, für lediglich 999 Euro zuzüglich 19 % Umsatzsteuer zu buchen. Das sind über 75% Rabatt, und damit möchten wir Ihnen für Ihre Treue und auch für das Vertrauen danken, das Sie in den vergangenen Monaten und Jahren in uns gesetzt haben. Auch hier wissen wir, dass das alles andere als selbstverständlich ist.
Wir nennen dieses Angebot tech:lounge 360°, denn – und das ist anders als bisher – alle 24 Webinare folgen einem durchgängigen roten Faden. Das bedeutet, wir werden ab März bis einschließlich Dezember gemeinsam eine komplette Anwendung entwickeln. Dabei sind nicht nur alle möglichen Themen enthalten, wie zum Beispiel Konzeption, Modellierung, Architektur, Entwicklung, APIs, Services, Deployment, Operations, Data-Management, UIs und vieles mehr, sondern wir fügen das alles auch noch zu einem einzigen, großen, durchgängigen praktischen Beispiel zusammen.
So können Sie innerhalb eines Jahres praxisnah verfolgen, wie nach und nach eine moderne und skalierbare Web- und Cloud-Anwendung entsteht. All das in über 80 Stunden Training, verteilt auf 24 Termine, für gerade einmal 999 Euro. Auch das Ticket hierfür können Sie ab sofort auf unserer Website buchen [3]. Es lohnt sich jedoch, schnell zu sein: Das vergünstigte Angebot gilt nur bis zum 31. Dezember 2024, danach gelten die regulären Konditionen und Preise. Auch hier würde ich mich natürlich sehr freuen, Sie begrüßen zu dürfen!
PS: Einen letzten Livestream für dieses Jahr wird es in ungefähr zwei Wochen übrigens auch noch geben, nämlich am 12. Dezember, wie immer ab 18 Uhr auf unserem YouTube-Kanal [4].
URL dieses Artikels:
https://www.heise.de/-10159636
Links in diesem Artikel:
[1] https://www.thenativeweb.io/
[2] https://techlounge.io/
[3] https://techlounge.io/
[4] https://www.youtube.com/@thenativeweb
[5] mailto:rme@ix.de
Copyright © 2024 Heise Medien
(Bild: erstellt mit KI (Dall-E) von iX-Redaktion)
Ein neuronales Netz von Grund auf selbst zu entwickeln, trägt enorm zum Verständnis von KI bei. Das richtige Buch hilft, diesen Wunsch zielführend umzusetzen.
Manchen mag es heute so gehen wie mir vor acht Jahren: Ich wollte unbedingt mein eigenes neuronales Netz bauen, hatte jedoch von Künstlicher Intelligenz ungefähr so viel Ahnung wie eine Kuh vom Fahrradfahren. Zum Glück gibt es Bücher, mit denen man sich weiterbilden kann. Das große Problem besteht in der Regel allerdings darin, ein Buch zu finden, das auch wirklich weiterhilft: Es soll praktisch sein, aber auch die grundlegende Theorie vermitteln. Es darf nicht zu akademisch sein, sondern sollte alltagstauglich bleiben. Es soll dies, es sollte das, es sollte jenes.
Damals stieß ich dann durch Zufall auf ein außergewöhnlich gutes Buch, das mir sehr geholfen hat, ein fundiertes Verständnis und eine gute Vorstellung von neuronalen Netzen zu bekommen. Und ich habe im Anschluss tatsächlich mein erstes neuronales Netz gebaut. Dieser Blogpost eignet sich vor allem für diejenigen, die den gleichen Wunsch haben wie ich damals.
Was eine Künstliche Intelligenz ist, davon hatte ich schon seit meiner Kindheit eine recht genaue Vorstellung: Für mich war das immer ein Computer, der mithilfe seiner Schaltkreise "denken" kann. Einer, der in der Lage ist, Menschen und seine Umwelt zu verstehen, zu lernen, logische Schlüsse zu ziehen, und so weiter. Geprägt wurde diese Vorstellung bei mir ganz klar durch den berühmten Roman von Arthur C. Clarke und den gleichnamigen Film von Stanley Kubrick: "2001: Odyssee im Weltraum [1]".
Der darin vorkommende Computer HAL 9000 ist für mich der Inbegriff von Künstlicher Intelligenz, und ich habe als Kind davon geträumt, eines Tages mit einem solchen Computer interagieren zu können. Oder noch besser, eines Tages selbst einen solchen Computer zu entwickeln. Insofern sind Arthur C. Clarke und Stanley Kubrick in gewissem Sinne mitschuldig daran, dass ich den Weg in die Informatik eingeschlagen habe. Tatsächlich hat HAL bis heute nichts von seiner Faszination auf mich verloren, im Gegenteil. Allerdings bin ich mir nicht mehr so sicher wie damals, ob ich ihn in der Realität wirklich haben wollen würde …
Der Punkt ist: So wie es mir damals ging, geht es Ihnen vielleicht heute auch. Soll heißen: Vielleicht tragen auch Sie schon seit einer Weile den Wunsch mit sich herum, eine eigene Künstliche Intelligenz zu entwickeln. Es muss ja vielleicht nicht gleich ein Supercomputer à la HAL 9000 sein, aber so ein kleines, schnuckeliges neuronales Netz wäre vielleicht doch ganz cool. Die gute Nachricht ist: Das ist gar nicht so schwer, wie Sie vielleicht denken.
Die zweite gute Nachricht ist: Neuronale Netze sind die Grundlage von so vielem heutzutage, dass es ungemein praktisch ist, zu verstehen, wie sie funktionieren. Also nicht nur, sie anwenden zu können, sondern wirklich zu begreifen, was ein neuronales Netz ist, warum es auf eine gewisse Art aufgebaut wird, wie und warum es funktioniert, und so weiter. Ich bin der festen Überzeugung, dass es, trotz all der KI-Frameworks wie TensorFlow, Keras, PyTorch & Co., die das Anwenden von Künstlicher Intelligenz sehr einfach machen, eine sehr gute Idee ist, auch zu verstehen, wie das Ganze überhaupt funktioniert.
Nun ist das Problem, dass es kaum gute Literatur oder andere Quellen gibt. Entweder sind die Materialien, die man findet, viel zu akademisch und mathematisch oder sie streifen die Grundlagen und die zugrunde liegende Theorie nur kurz und konzentrieren sich auf die Anwendung. Ersteres sind zum Beispiel die von Stanford verfügbaren Online-Kurse, und Letzteres sind die ganzen Bücher mit Titeln wie "Keras: Machine-Learning in der Praxis" oder "Einführung in die KI mit TensorFlow".
(Bild: O'Reilly)
Genau an diesem Punkt stieß ich vor vielen Jahren auf ein fantastisches Buch: Es hieß "Make Your Own Neural Network" und stammte aus der Feder von Tariq Rashid. Das Wort "Buch" ist hier fast schon zu hoch gegriffen: Es war eher eine umfangreiche Broschüre, da der Autor es damals selbst verlegt hatte, ohne einen professionellen Verlag dahinter. Dem Inhalt hat das jedoch keinen Abbruch getan, im Gegenteil: Ich war sehr beeindruckt, wie anschaulich und greifbar er erklärt hat, wie man ein eigenes neuronales Netz entwickelt, und zwar wirklich von Grund auf, also ohne die genannten Frameworks, aber eben auch ohne dafür Mathematik studiert haben zu müssen.
Im vergangenen Juni stellte ich nun fest, dass O’Reilly das Ganze als Buch herausgebracht hat. Da der Vertrieb von O’Reilly im deutschsprachigen Raum vom dpunkt.verlag übernommen wird, und mein Unternehmen (the native web [3]) mit diesem wiederum eine Kooperation hat, habe ich die Neuausgabe als Rezensionsexemplar kostenlos zur Verfügung gestellt bekommen. Das heißt jedoch nicht, dass ich das Buch schönreden muss: Ich teile hier ganz unabhängig meine Meinung und sage, was mir an dem Buch gefällt und was nicht. Ich werde nicht dafür bezahlt, und es gibt keine Vereinbarung, dass ich das Buch in den Himmel loben müsste. Ich sage das nur deshalb so explizit dazu, um offen, ehrlich und transparent zu sein, denn das ist uns sehr wichtig.
Die Frage lautet also nun: Wie fangen Sie an, wenn Sie ein eigenes neuronales Netz bauen möchten? Eigentlich ist das ganz klar: Zuerst einmal müssen Sie einige grundlegende Konzepte kennenlernen. Sie müssen wissen, welche Arten von neuronalen Netzen es gibt: Es gibt Netze, die versuchen, einen konkreten Wert vorherzusagen, und solche, die versuchen, einen gegebenen Wert zu kategorisieren, oder genauer gesagt, zu klassifizieren. Natürlich gibt es noch weitere Arten, aber das sind die beiden grundlegenden Typen.
Dann stellt sich die Frage: Was ist überhaupt ein Neuron? Wie ist es intern aufgebaut und wie funktioniert es? Was ist eine Aktivierungsfunktion? Wie formt man aus einzelnen Neuronen eine Schicht und daraus wiederum ein Netz? Wie lernt ein solches Netz überhaupt, was es tun soll? Und so weiter.
Es gibt also viele Fragen, die noch gar nicht darauf abzielen, wie man ein neuronales Netz schlussendlich baut, sondern erst einmal darauf, zu verstehen, was überhaupt die Bauteile eines solchen Netzes sind. Das Schöne ist: Um das zu erklären, braucht man nicht viel. Im Prinzip reichen ein Blatt und ein Stift aus, um das Ganze aufzumalen, und die Mathematik, die man benötigt, hat man (und das meine ich ernst) weitestgehend bereits in der Grundschule gelernt.
Viel mehr als Addition, Multiplikation und ein bisschen lineare Gleichungen ist es in weiten Teilen nämlich nicht. Wenn man es effizient machen möchte, braucht man vielleicht noch die Matrizenmultiplikation, aber auch das ist am Ende nur eine Kombination von Addition und Multiplikation. Und das Einzige, wofür man tatsächlich etwas mehr Mathematik benötigt, ist das eigentliche Lernen oder Trainieren der Netze mit dem sogenannten Backpropagation-Algorithmus, für den man dann Ableitungen braucht.
Aber auch das ist kein Universitätswissen, sondern Schulstoff der gymnasialen Oberstufe. Mit anderen Worten: Jede Schülerin und jeder Schüler der 11. Klasse bringt das Wissen und das mathematische Handwerkszeug mit, das man für neuronale Netze im Wesentlichen braucht.
Vielleicht mag das jetzt nach viel klingen. Tatsächlich ist es aber gar nicht so umfangreich, denn Tariq Rashid beschreibt das alles im ersten Kapitel des Buches auf gerade einmal 90 Seiten. Auch das klingt vielleicht viel, aber zum einen sind dort viele Beispiele und Abbildungen enthalten (die übrigens in Farbe gedruckt sind, was ich schön finde), und zum anderen nimmt er sich wirklich viel Zeit für die Erklärungen, sodass man gut folgen kann.
Um es anders zu formulieren: Nach 90 anschaulichen, gut verständlichen und kurzweiligen Seiten haben Sie die komplette Basis verstanden, wie neuronale Netze arbeiten – von einfachen Netzen bis hin zu den Transformern in modernen Sprachmodellen, denn auch diese basieren letztlich auf neuronalen Netzen, wenn auch sehr komplexen. Aber 90 Seiten, das war’s.
Das heißt, wenn Sie all das kennengelernt haben, dann haben Sie ein intuitives Grundverständnis dafür, was ein neuronales Netz ist und wie und warum es funktioniert. Vielleicht wird das Ganze ein wenig ernüchternd wirken, denn es ist keine dunkle Magie oder etwas Mystisches: Es sind nur ein paar mathematische Formeln. Im Prinzip so etwas wie
f(x) = x^2
in komplexerer Form. Allein das ist aus meiner Sicht schon eine durchaus wichtige Erkenntnis, denn genauso wenig, wie diese einfache Funktion ein Bewusstsein hat oder die Weltherrschaft anstrebt, macht das irgendeine andere mathematische Formel, selbst wenn sie komplexer ist und mit mehr Variablen arbeitet. Verstehen Sie mich dabei bitte nicht falsch: Damit will ich mitnichten sagen, dass von Künstlicher Intelligenz keine Gefahr ausgehen könnte, aber das typische Schreckensszenario à la
"Wir werden alle sterben, weil die KI sich selbstständig macht."
ist Blödsinn. Die KI an sich, oder das neuronale Netz an sich, ist letztlich einfach nur eine komplexe Formel, nicht mehr und nicht weniger.
Nun muss man das Ganze natürlich auch umsetzen können. Genau das passiert im zweiten Kapitel des Buches, auf insgesamt rund 70 Seiten: Dort erklärt Tariq Rashid zuerst im Schnelldurchlauf die Programmiersprache Python. Ob Sie das Ganze letztlich in Python oder in einer anderen Sprache nachbauen, ist für das Verständnis nebensächlich – mit Python wird es Ihnen jedoch leichter gemacht, wenn Sie später doch mit Frameworks arbeiten möchten, da die meisten davon für Python verfügbar sind.
Python als Sprache selbst hat keinerlei besondere Eigenschaften, die sie besonders gut für Künstliche Intelligenz geeignet machen. Es liegt viel eher am Ökosystem drumherum. Für den Anfang ist das jedoch relativ egal, ich selbst habe das Ganze damals mit JavaScript auf der Basis von Node.js umgesetzt.
Nach dieser kurzen Einführung ist das zweite Kapitel dann im weiteren Verlauf ziemlich geradlinig: Sie müssen einfach das, was Sie in Kapitel 1 gelernt haben, in Programmcode umsetzen. Das ist vor allem eine Fleißaufgabe und hat wenig mit Verständnis zu tun, denn die notwendige gedankliche Vorarbeit haben Sie in Kapitel 1 schon lange geleistet. Natürlich stellt sich die spannende Frage: Wie gut ist denn ein neuronales Netz, das man selbst baut?
Um das beurteilen zu können, braucht man ein konkretes Beispiel. Der Autor verwendet dafür den MNIST-Datensatz, eine Sammlung von handgeschriebenen Ziffern, die als Einzelbilder vorliegen. Damit trainiert er dieses erste Netz. Ziel ist es, mit möglichst hoher Erkennungsrate vorherzusagen, welche Ziffer auf einem gegebenen Bild zu sehen ist. Er erreicht mit diesem ersten Netz ohne weitere Optimierung eine Erfolgsrate von rund 97 %.
Das finde ich schon ziemlich beeindruckend. Natürlich mussten die Daten dafür vorbereitet werden, aber auch das erklärt Rashid ausführlich und anschaulich, sodass man versteht, dass es normal ist, dass Daten für eine KI immer in der einen oder anderen Form aufbereitet werden müssen.
Die übrigen 40 Seiten des Buches sind relativ schnell abgehakt: Im dritten Kapitel geht es noch um die Frage, wie man das Training verbessern könnte, das ist aber wirklich nur ein Ausblick. Das vierte und letzte Kapitel gibt dann eine Einführung, wie man das Ganze mit PyTorch umsetzen könnte, einfach weil Sie in der Praxis vermutlich eher mit einem solchen Framework arbeiten werden, als alles von Hand zu programmieren. Trotzdem – und das war mein Punkt am Anfang dieses Blogposts – ist es hilfreich zu wissen, wie das Ganze unter der Haube zusammenhängt und funktioniert. Im Anhang gibt es dann noch eine kurze Einführung in die Analysis, weil vielleicht doch nicht jede Entwicklerin und jeder Entwickler eine Ableitung "mal eben so" berechnen kann.
Und das ist dann das gesamte Buch mit seinen rund 250 Seiten. Das Erstaunliche dabei ist, dass eigentlich nur die ersten 160 Seiten wirklich wichtig für den Einstieg und das Verständnis sind. Der Rest ist eher eine nette Beigabe. Wenn Sie sich vertieft mit der Anwendung beschäftigen möchten, würde ich Ihnen ohnehin ein anderes Buch nahelegen, nämlich "Deep Learning illustriert [4]" von Jon Krohn, Grant Beyleveld und Aglaé Bassens, das ich vor rund einem Jahr vorgestellt und besprochen habe.
So oder so: Ich wünsche Ihnen viel Spaß und Erfolg bei Ihrem ersten eigenen neuronalen Netz!
Tariq Rashid
Neuronale Netze selbst programmieren: Ein verständlicher Einstieg mit Python [5]
O'Reilly, 2. Auflage 2024
448 Seiten
ISBN (Print): 978-3-96009-245-2
[Anmerkung d. Red.: Der dpunkt.verlag als Herausgeber des Buches ist wie heise online Teil der heise group]
URL dieses Artikels:
https://www.heise.de/-10002704
Links in diesem Artikel:
[1] https://de.wikipedia.org/wiki/2001:_Odyssee_im_Weltraum
[2] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[3] https://www.thenativeweb.io/
[4] https://www.youtube.com/watch?v=rE2xwBBZflA
[5] https://dpunkt.de/produkt/neuronale-netze-selbst-programmieren-2/
[6] mailto:rme@ix.de
Copyright © 2024 Heise Medien
(Bild: erstellt mit KI (Dall-E) durch iX)
Version 2.0 bricht mit vielen ehemaligen Idealen des Deno-Projektes. Doch ist das gar nicht so schlimm, da Deno dadurch erst massentauglich wird.
Seit über vier Jahren veröffentlichen wir annähernd jede Woche ein neues Video auf dem YouTube-Kanal meines Unternehmens [1], und im Laufe der Zeit habe ich dabei auch die eine oder andere Einschätzung zu der einen oder anderen Technologie abgegeben. Dabei gehe ich nicht leichtfertig vor, sondern mache mir im Vorfeld intensiv Gedanken, welche Technologien in der Zukunft funktionieren könnten und welche eher nicht, worauf der Markt anspringen wird und worauf eher nicht, und so weiter. Ohne mich selbst loben zu wollen, würde ich sagen, dass ich ein passables Händchen dafür habe, zukünftige Trends und Entwicklungen frühzeitig zu erkennen und entsprechend vorherzusagen. Trotzdem liege auch ich natürlich gelegentlich daneben.
Das kann zum einen passieren, wenn mir aller Sorgfalt zum Trotz doch eine Fehleinschätzung unterläuft, weil ich zum Beispiel einen wesentlichen Aspekt nicht gesehen habe. Das kann aber auch passieren, weil sich manche Technologien im Laufe der Zeit dermaßen stark verändern, dass ich sie nach einer Weile eigentlich neu bewerten und meine bisherige Meinung gegebenenfalls revidieren muss. Und genau das ist heute der Fall: Heute müssen wir nämlich einmal über die neu erschienene Version 2 von Deno [2] sprechen.
Wer unsere Videos schon länger verfolgt, weiß, dass die ersten Videos zu Deno fast auf den Tag genau vier Jahre zurückliegen. Ausgangspunkt war damals der Vortrag von Ryan Dahl auf der JSConf EU 2018 mit dem Titel "Ten Things I Regret About Node.js [3]". Dazu habe ich damals eine erste Einschätzung [4] abgegeben: Im Unterschied zu vielen anderen konnte ich seiner Argumentation nicht viel abgewinnen. Daran hat sich bis heute nichts geändert: Ich fand seinen Vortrag, um ehrlich zu sein, inhaltlich schwach und die genannten Argumente dürftig.
Die damalige Ankündigung von Deno wirkte auf mich maßlos überzogen. Ja, es gab ein oder zwei interessante Aspekte, wie das konsequente Nutzen der V8-Sandbox, aber es gab genug Punkte, die bereits damals überholt, irrelevant oder einfach nicht durchdacht waren. Oft habe ich danach kritisiert, wie sich Ryan Dahl verhalten hat: Wäre es ihm wirklich darum gegangen, die Welt für JavaScript-Entwicklerinnen und -Entwickler zu verbessern, hätte er sich (aus meiner Sicht) eher wieder bei Node.js engagieren sollen, statt das JavaScript-Ökosystem nun auch auf dem Server zu fragmentieren.
Außerdem wirkte die ganze vorgeschobene Reue auf mich wie ein Vorwand, um im Hintergrund ein Unternehmen aufzubauen – was natürlich völlig legitim ist, aber für meinen Geschmack nicht transparent genug kommuniziert wurde. Insgesamt war mir der Vortrag zu pathetisch, zu viel Drama, zu viel Show und zu wenige echte Argumente. Kurz gesagt: Ich hielt Deno damals vor allem für heiße Luft.
Tja, und was soll ich sagen? Seit der Ankündigung vor immerhin sechs Jahren ist Deno eher gefloppt. Ja, es hatte sicherlich einen gewissen Einfluss auf die Weiterentwicklung von Node.js, aber dieser dürfte doch überschaubar gewesen sein. Im Gegenzug hat Deno jedoch die Fragmentierung von JavaScript auf dem Server [6] eingeleitet, was inzwischen mit Bun noch schlimmer wurde. Apropos Bun: Auch davon hört man abseits einer sehr kleinen und überschaubaren Community nichts, und auch hier wird mir zu viel Show gemacht und zu wenig geliefert. Bis hierhin bleibt Deno für mich also vor allem viel Show, viel Gerede, wenig Substanz und vor allem eines – unnötig.
Das Interessante dabei ist, dass vieles von dem, was Ryan Dahl damals groß angekündigt hat, sich letztlich als nicht sonderlich schlaue Idee erwiesen hat, wie beispielsweise seine große Kritik an der vermeintlich ach so "bösen" package.json-Datei, in der in Node.js die Abhängigkeiten verwaltet werden. Was wurde nicht alles gesagt, was an npm schlecht sei, warum das alles ein grundlegender Designfehler sei, und so weiter. Das alles müsse man nun besser machen (und "besser" hieß vor allem anders). Turns out: npm ist sicherlich nicht perfekt, aber um Welten besser, als Ryan Dahl es damals dargestellt hat. All die Ansätze, die Deno seitdem versucht hat, um Abhängigkeiten anders zu verwalten, haben am Ende nur eines bewirkt: Inkompatibilität und – ironischerweise – neue Probleme.
Weil irgendwann dann auch das Team hinter Deno gemerkt hat, dass es keine gute Idee ist, das bestehende JavaScript-Ökosystem komplett zu ignorieren und auszuschließen, hat man bei Deno dann eine Kehrtwende vollzogen und eine provisorische Unterstützung für npm integriert. Und plötzlich war Deno nicht mehr eine völlige Insellösung, sondern man konnte immerhin ein bisschen damit arbeiten. Trotzdem funktionierte vieles nicht. Deshalb wurde die Kompatibilität zu npm und übrigens auch zu Node.js nach und nach weiter ausgebaut, denn man merkte, dass der Umstieg unattraktiv ist, wenn praktisch alle Basis-APIs fehlen, sie anders heißen oder anders funktionieren.
Deno hat sich also nach und nach von vielen seiner vermeintlichen Ideale abgewendet und versucht nun, 90 Prozent all dessen zu unterstützen, was angeblich so schlecht und fehlerhaft gewesen sei. Das gipfelte Anfang Oktober in der Veröffentlichung von Deno 2.0 [7].
Das war für mich Grund genug, meine Meinung noch einmal auf den Prüfstand zu stellen. Und ich muss sagen, ich muss einiges revidieren: Deno 2 ist die erste Version von Deno, die wirklich interessant ist, weil es endlich mehr als nur eine akademische Fingerübung darstellt, und eine Menge interessanter Punkte bietet, die es als möglichen Ersatz für Node.js positionieren könnten. Der Zeitpunkt dafür ist sogar günstig, denn bei Node.js häufen sich die Probleme: Es entwickelt sich zwar weiter, aber es gibt zu viele angefangene Baustellen und es wird immer chaotischer. Deshalb war der Titel eines unserer Videos vor rund sechs Monaten auch schon: "Node 22, lass uns Freunde bleiben [8]". Auf gut Deutsch: Ich habe keine Lust mehr auf eine Beziehung mit dir, ich mache Schluss!
Und da kommt nun eben Deno 2 ins Spiel. Das Besondere an Deno 2 ist, dass das Team dahinter sich große Mühe gegeben hat, die mangelnde Kompatibilität zu Node.js und npm zu überwinden. Ab Deno 2 ist es nun möglich, Deno als echtes Drop-in-Replacement zu nutzen. Das Versprechen lautet: Alles, was in Node.js läuft, läuft auch in Deno. Das gilt für kleine und große Anwendungen und bezieht viele Frameworks wie Next.js, Astro, Remix, Angular, SvelteKit und mehr ein – alles läuft out of the box. Aber Deno ist nicht einfach eine 1:1-Kopie von Node.js geworden, sondern ist in gewissem Sinne inzwischen "das bessere Node".
Denn Deno bringt (nicht erst seit Version 2) eine Reihe von Features mit, von denen Node.js nur träumen kann: native TypeScript-Unterstützung (die gibt es in Node.js inzwischen, allerdings ist sie noch sehr rudimentär), ein eingebauter Formatter, ein integrierter Linter, ein Type-Checker, ein Test-Framework, ein Compiler, ein sinnvolles Sicherheitskonzept, bei dem nicht jeglicher Code aus dem Internet ungefragt mit Full-Trust läuft, und so weiter. All das fehlt Node.js seit nunmehr 15 Jahren. Und dabei ist das Ganze in Deno auch noch sehr schnell und durchdacht umgesetzt.
Ein Beispiel: In Deno muss TypeScript-Code nicht von Hand kompiliert werden, das erledigt Deno automatisch, sobald die Anwendung gestartet wird. Aus Performance-Gründen wird dabei allerdings auf die Typprüfung von TypeScript verzichtet, es sei denn, sie wird explizit mit dem Parameter --check angefordert. Bei der Ausführung von Tests hingegen ist die Typprüfung standardmäßig aktiv. Das ergibt Sinn: Während der Entwicklung, wenn es nicht auf das letzte Quäntchen Performance ankommt, hat man die gewünschte Typsicherheit, bei der Ausführung dafür eine möglichst gute Performance. Und das Schöne ist, dass das Test-Framework in Deno bereits enthalten ist, es muss also nichts zusätzlich installiert werden.
Node.js bietet ein paar Aspekte davon inzwischen zwar ebenfalls, aber es hat sehr lange gedauert, und es kommt weder vom Umfang noch von der Integration an Deno heran. Und Deno endet hier nicht: Das Test-Framework geht beispielsweise deutlich weiter als das von Node, denn Deno kann direkt auch die Code-Coverage berechnen, Benchmarks ausführen und mehr.
All diese Funktionen, um Tests auszuführen, Code-Coverage zu ermitteln und Benchmarks durchzuführen, sind im Deno-Binary von Haus aus enthalten. Man braucht also nur ein einziges Tool, um all diese Dinge nutzen zu können. Darüber hinaus ist zum Beispiel aber auch noch ein Formatter integriert, der nicht nur JavaScript und TypeScript, sondern auch HTML, CSS und YAML formatiert. Ein umfangreicher Linter ist ebenfalls enthalten, eine integrierte Lösung zum Ausführen von Tasks, ein Dokumentationsgenerator und ein Compiler, um echte Binaries zu erzeugen. Letzteres ist bei Node.js zwar in der Theorie auch möglich [9], jedoch dermaßen umständlich gelöst, dass es absolut keinen Spaß macht, das Feature zu nutzen.
Deno enthält außerdem einen Webserver, Unterstützung für Jupyter-Notebooks und vieles mehr – und all das in einer einheitlichen und aufeinander abgestimmten Form, während man bei Node alles mühsam zusammensuchen und von Hand konfigurieren muss. Und das ist am Ende das, wodurch Deno 2 besonders auffällt: Einfachheit und "it just works".
Hat man beispielsweise eine Anwendung, die npm-Module verwendet, muss man bei Deno kein "npm install" mehr ausführen. Deno lädt die benötigten Module beim ersten Start der Anwendung automatisch herunter und cacht sie lokal. Das funktioniert so gut und transparent im Hintergrund, dass man beim Entwickeln nach einer halben Stunde vergessen hat, dass man jemals "npm install" ausführen und sich mit einem node_modules-Verzeichnis oder einer Lock-Datei herumschlagen musste. Und das alles geht dabei auch noch unglaublich schnell – jeder Package-Manager, den ich bisher unter Node.js gesehen habe, kann da im Vergleich einpacken. Das ist wirklich gut gelöst, und das ist der Eindruck, den Deno 2 hinterlässt: Es wirkt wie Node.js, aber neu durchdacht.
Vielleicht war Deno 1 in den vergangenen sechs Jahren so gesehen einfach nur ein Proof of Concept: Ein nicht schöner, aber notwendiger Prototyp, um herauszufinden, wohin die Reise eigentlich gehen soll, und Deno 2 ist nun die echte erste Version.
Und da muss ich ganz ehrlich meinen Respekt aussprechen, denn Deno 2 ist eine sehr gelungene zweite Version. Auf einmal macht es wieder Spaß, mit TypeScript zu entwickeln, weil man nicht hundert verschiedene Dinge installieren und konfigurieren muss, sondern einfach nur einen Editor öffnet, ein paar Zeilen schreibt und ausführt. Und formatiert. Und testet. Und so weiter. Und all das, ohne auch nur ansatzweise irgendetwas dafür installieren zu müssen.
Im Vergleich dazu, wie sich Node.js aktuell anfühlt, ist das ein großer Schritt nach vorn. Es fühlt sich endlich wieder modern und zeitgemäß an. Und insofern muss ich sagen: Sobald die passende Laufzeitumgebung da ist, macht TypeScript auf einmal wieder eine Menge Spaß. Danke, Deno 2!
URL dieses Artikels:
https://www.heise.de/-9987604
Links in diesem Artikel:
[1] https://www.youtube.com/@thenativeweb
[2] https://deno.com/blog/v2.0
[3] https://www.youtube.com/watch?v=M3BM9TB-8yA
[4] https://www.youtube.com/watch?v=7oeR1GcVK3Y
[5] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[6] https://www.youtube.com/watch?v=WLklm8JQbjo
[7] https://www.heise.de/news/JavaScript-Runtime-Deno-2-0-nimmt-es-mit-Node-js-auf-9976092.html
[8] https://www.youtube.com/watch?v=GH8gSl-z9Wg
[9] https://www.youtube.com/watch?v=6ThplMUASJA
[10] mailto:rme@ix.de
Copyright © 2024 Heise Medien
(Bild: erstellt mit KI (Dall-E) von iX-Redaktion)
Viele Softwareprojekte sprengen sowohl den zeitlichen als auch den finanziellen Rahmen und liefern dann nachher trotzdem nicht das gewünschte Ergebnis. Warum?
Wussten Sie, dass ungefähr 75 Prozent aller Softwareprojekte scheitern? Entweder dauern sie länger als ursprünglich geplant oder sie kosten mehr als erwartet (oder beides) und liefern trotzdem nicht das gewünschte Ergebnis. Das bedeutet, sie verfehlen das eigentliche Ziel. Da stellt sich natürlich die Frage: Woran liegt das eigentlich und was kann man als Team beziehungsweise als Unternehmen machen, um das bei eigenen Projekten zu vermeiden?
Bevor ich im Folgenden tiefer in das Thema einsteige, vorweg noch ein kleiner Hinweis: Die 75 Prozent sind natürlich nicht in Stein gemeißelt. Je nachdem, welche Studie man zurate zieht, sind es mal mehr, mal weniger Prozent. Aber selbst wenn es "nur" 50 Prozent wären, hieße das immer noch, dass jedes zweite Softwareprojekt Probleme hat. Und wenn man sich dann einmal überlegt, wie viel in unserer heutigen modernen Welt von Software abhängt, dann ist das so oder so schon ganz schön viel. Insofern: Nehmen Sie die 75 Prozent bitte nicht wortwörtlich, sondern als Tendenz und als ungefähre Größenordnung.
Warum also scheitern so viele Softwareprojekte und sprengen häufig zeitliche und finanzielle Rahmen? Das ist eine durchaus spannende Frage, denn an der eigentlichen Planung kann es kaum liegen: Teams und Unternehmen verbringen häufig sehr viel Zeit damit, sich Gedanken über die richtige Technologie zu machen. Da wird dann gerne wochen- oder gar monatelang diskutiert, ob nun zum Beispiel .NET oder Go vorzuziehen sei, ob React oder Web-Components die bessere Wahl sei, ob man eine SQL- oder eine NoSQL-Datenbank nehmen sollte, ob man MQTT brauchen wird oder nicht, und so weiter. Mit anderen Worten: Es wird viel Zeit mit der Evaluation und Auswahl von Technologien verbracht und daran sind üblicherweise viele kluge Köpfe beteiligt. Daher ist es eher unwahrscheinlich, dass dies das Problem ist.
Allerdings liegt es häufig auch nicht an der gewählten Architektur. Denn auch hier wird in der Regel sehr ausführlich und sorgfältig diskutiert: Es werden die Vor- und Nachteile von Monolithen, Microservices und Co. verglichen, es wird über REST, GraphQL und gRPC debattiert und architektonische Entscheidungen werden selten leichtfertig getroffen, sondern erst nach sorgfältiger Abwägung vieler Argumente. Auch die Architektur ist also häufig nicht das eigentliche Problem.
Am ehesten gerät als Nächstes dann der verwendete Entwicklungsprozess in Verdacht. Doch hier gibt es gar nicht dermaßen viele Unterschiede, wie man häufig zunächst meinen würde, denn viele Teams nutzen einfach Scrum, allein schon deshalb, weil sie Teil eines größeren Unternehmens sind und Scrum dort fest gesetzt ist. Bei Scrum im Speziellen und Agilität im Allgemeinen kann man zwar einiges falsch machen [2], aber andererseits gibt es auch immer wieder Teams, die erfolgreich agil arbeiten und bei denen man den Eindruck hat, dass Agilität verstanden wurde. Trotzdem bleibt die Softwareentwicklung am Ende oft eher mittelprächtig. Selbst wenn der Prozess nicht optimal ist, scheint er dennoch nicht das Hauptproblem zu sein.
Bleibt die Entwicklung an sich: Hier arbeiten in der Regel allerdings auch viele erfahrene und kompetente Menschen, die sich mit der gewählten Technologie gut auskennen. Wer sich beispielsweise für .NET, Web-Components und den SQL Server entscheidet, stellt in der Regel auch sein Team entsprechend so auf, dass es aus Menschen besteht, die mit diesen Technologien möglichst vertraut sind. Doch auch das garantiert erfahrungsgemäß nicht, dass die Softwareentwicklung später tatsächlich im Zeit-, Budget- und Funktionsrahmen bleibt. Wenn es also auch nicht an der Entwicklung selbst liegt – was bleibt dann noch?
Hier kommt ein Thema ins Spiel, das unglaublich gerne übersehen wird: Das Problem in der Softwareentwicklung sind in der Regel nämlich nicht die technischen Faktoren. Damit will ich nicht sagen, dass es keine technischen Schwierigkeiten gäbe, wie eine weniger geeignete Architektur oder unzureichendes technologisches Wissen. Tatsächlich ist das aber selten das Hauptproblem. Viel häufiger ist es so, dass vor lauter Technologie etwas anderes vernachlässigt wird – nämlich die Fachlichkeit. Ich kann gar nicht sagen, wie viele Teams ich schon kennengelernt habe, die technologisch topfit waren, die aber leider absolut keine Ahnung davon hatten, worum es in ihrem Projekt inhaltlich eigentlich ging.
Das merkt man immer, wenn man wie ich als externer Berater zu einem solchen Team stößt und die erstbeste Verständnisfrage stellt, wenn dann alle große Augen machen, niemand antworten kann (weil niemand die Antwort weiß) und man dann gesagt bekommt, dass diese Frage noch nie jemand gestellt hätte. Und es handelt sich dabei nicht um exotische Fragestellungen, sondern oft um elementare Grundlagen. Zum Beispiel bei einem Team, das Software für die Personalabteilung entwickelt, die Frage:
"Wie sieht der Prozess für eine Einstellung aus?"
Wenn schon diese Frage niemand beantworten kann, wie soll ein Team dann eine Software entwickeln, die dieses Thema adäquat und zielgerichtet digital abbildet? Um es kurz zu machen: Das kann nicht funktionieren!
Mit anderen Worten: Softwareentwicklung ist kein Selbstzweck. Wir als IT-Branche entwickeln Software nicht deshalb, weil es so toll ist, Software zu entwickeln, sondern weil wir ein tieferliegendes fachliches Problem lösen wollen. Damit eine Software ein Problem adäquat und zielgerichtet lösen kann, muss man jedoch als Entwicklerin oder Entwickler das zugrunde liegende fachliche Problem überhaupt erst einmal verstehen. Das heißt, man muss wissen, worum es geht, welche Prozesse es gibt, was die Rahmenbedingungen sind, wie der Kontext aussieht, um welche Daten es geht und was das alles im Detail für die Menschen bedeutet.
Das sind Fragen, die häufig nicht gestellt werden. Es wird einfach davon ausgegangen, dass das nicht so wichtig sei, dass sich das schon im Laufe der Zeit von selbst ergeben würde, dass es genüge, wenn der Product Owner Bescheid wisse und so weiter. Doch immer wieder stellt sich heraus, dass das nicht funktioniert.
Das führt dann dazu, dass in einem Team weder eine gemeinsame Sprache noch ein gemeinsames Verständnis der fachlichen Thematik existiert. Es wird zwar viel geredet, aber oft aneinander vorbei, weil niemand das Gegenüber wirklich versteht. Und anstatt nachzufragen, werden implizite Annahmen getroffen, und man lebt zu lange in dem Glauben, man wüsste, worum es eigentlich ginge. Wenn zwei Leute am selben Thema arbeiten und keine gemeinsame Sprache und kein gemeinsames Verständnis haben, wird es jedoch schwierig. Es werden unterschiedliche Begriffe für dasselbe Konzept genutzt, ohne zu wissen, ob wirklich alle das Gleiche meinen. Oder es wird ein Begriff verwendet, der von allen unterschiedlich interpretiert wird, was aber niemandem auffällt. Man bewegt sich in einer schwammigen, unklaren sprachlichen Blase und nimmt das als völlig normal hin.
Und dann wundert man sich, dass nach zwei Jahren nicht das herauskommt, was jemand anderes sich zwei Jahre zuvor vorgestellt hat. Ganz ehrlich: Es ist naiv anzunehmen, dass das jemals hätte funktionieren können. Ist es erst einmal so weit gekommen, muss nachgebessert werden. Das kostet Zeit und Geld. Und damit dauert es auf einmal länger und kostet mehr als geplant. Da man nach zwei Jahren aber nicht einfach alles über den Haufen werfen möchte, arbeitet man eher an den Symptomen als an den Ursachen.
Das heißt, wenn mit falschen Grundkonzepten gestartet wurde, bleiben diese nun erhalten, weil man sie nicht mehr überarbeiten kann, da der Aufwand dafür zu hoch wäre. So entsteht Software, die von vornherein nicht passend ist, und man startet von Anfang an mit einer Lösung, bei der alle insgeheim wissen, dass man es eigentlich viel besser hätte machen können. Nur spricht das niemand laut aus. Stattdessen kommt dann irgendjemand daher und sagt:
"Ich hab's Euch ja prophezeit: Wir hätten damals doch auf Go statt .NET setzen sollen, aber das wollte ja keiner hören!"
Und alle stehen da, nicken betroffen und denken:
"Ja, stimmt, wenn wir heute noch mal neu anfangen könnten, dann wäre alles besser!"
Aber der Punkt ist: Es wäre nur kurzfristig besser, weil man wieder ohne Altlasten auf der "grünen Wiese" starten würde, aber langfristig würde man wieder dieselbe, nicht passende Software entwickeln, weil man erneut nicht verstanden hat, was das zugrunde liegende fachliche Problem ist. Man tauscht quasi die Technologie, aber die Technologie war nie das Problem. Ich glaube, es war Albert Einstein, der (sinngemäß) einmal gesagt hat:
"Immer wieder dasselbe zu tun und ein anderes Ergebnis zu erwarten, ist die Definition von Dummheit."
Wenn wir das doch aber wissen – warum versuchen wir als Branche dann immer und immer wieder, Software ohne fachliches Verständnis zu entwickeln?
Wenn wir also bessere Software entwickeln wollen, wenn wir Software in kürzerer Zeit fertigstellen wollen, dann müssen wir weniger über Technologie und viel mehr über Fachlichkeit sprechen. Wir müssen sicherstellen, dass alle am Projekt Beteiligten von Anfang an ein gemeinsames Verständnis der Thematik haben. Damit sage ich nicht, dass wir nicht mehr über Technologien sprechen sollten. Damit sage ich auch nicht, dass jede Entwicklerin und jeder Entwickler zum absoluten Fachexperten werden muss. Aber es hilft, wenn zumindest ein solides Grundwissen vorhanden ist, weil man ein Feature viel passgenauer umsetzen kann, wenn man versteht, was es macht, wer es verwendet, welchem Zweck es dient und so weiter. Die Frage ist also: Wie schafft man es, eine solche gemeinsame fachliche Sprache und ein gemeinsames Verständnis im Team zu etablieren?
Tatsächlich ist das gar nicht so schwierig, wie man vielleicht glaubt, es ist eher nur zeitaufwendig. Das Fundament von allem ist eine gute Kommunikation, in der man sich über die Fachlichkeit austauscht: Es wird erklärt, es werden Verständnisfragen gestellt, Dinge werden hinterfragt. Und zwar übergreifend über alle im Team beteiligten Disziplinen hinweg. Also echte interdisziplinäre Zusammenarbeit und kein disziplinäres Schubladendenken.
Und es gibt so viele Hilfsmittel dafür: Das fängt beim aktiven und aufmerksamen Zuhören an, geht über kritisches Mitdenken und Nachfragen, dazu gehören Empathie, echte Neugier und ehrliches Interesse. Es gibt Werkzeuge wie Domain-driven Design, Design Thinking, das Arbeiten mit Events, das Beschäftigen mit Semantik, mit natürlicher Sprache und vieles mehr. Was all diese Punkte jedoch gemeinsam haben, ist, dass sie keine technischen Hilfsmittel sind.
Das heißt, die eine essenzielle Voraussetzung ist, dass man aus der bequemen technologischen Komfortzone herauskommt, in der man es sich seit Jahren gemütlich gemacht hat, und dass man den Sprung ins kalte Wasser wagt, sich die Blöße gibt, einzugestehen, dass man von der Fachlichkeit keine Ahnung hat – aber ehrlich interessiert ist und neugierig auf das, was da in einer neuen Welt vor einem liegt. Diesen Schritt zu machen, ist ungemein wichtig, aber er fällt vielen unglaublich schwer.
Und das liegt nicht daran, dass Entwicklerinnen und Entwickler nicht wollen würden. Sondern es liegt daran, dass das in vielen Aspekten mit dem bricht, was man in der Ausbildung gelernt hat. Plötzlich sind nicht mehr Daten und Objekte die wesentlichen Konstrukte, um einen Sachverhalt zu strukturieren. Plötzlich sind es Geschäftsprozesse und Abläufe. Es ist der Wandel von einer rein statischen, datengetriebenen Welt hin zu einer dynamischen, prozessgetriebenen Welt. Denn wir schreiben Software nicht, um Daten zu verwalten. Wir schreiben Software, um Prozesse abzubilden. Dass dafür Daten benötigt werden, versteht sich von selbst. Aber Daten spielen in dieser Welt nicht die erste Geige, genauso wenig wie die Technologie die erste Geige spielen sollte, sondern eben die Fachlichkeit. Es geht nicht um Daten, sondern um Prozesse. Das, was Software lebendig macht, sind nicht die Daten, sondern die Funktionen. Und das ist die entscheidende Änderung in der Perspektive.
Betrachten Sie die Welt als eine Ansammlung von Daten, die verwaltet werden müssen, dann wird Ihre Software letztlich immer nur Excel mit einer mehr oder weniger anderen Bedienoberfläche sein, die die Anwenderinnen und Anwender nicht wirklich in ihren Aufgaben und Intentionen unterstützt. Um das nämlich zu erreichen, müssen Sie die Intentionen verstehen, Sie müssen die Abläufe und die Prozesse verstehen. Denn nur dann können Sie die Prozesse adäquat in Ihrer Software abbilden und Menschen das Leben vereinfachen. Und darum geht es letztlich bei der Softwareentwicklung: Das Leben von Menschen in irgendeiner Form angenehmer, sicherer, komfortabler – im weitesten Sinne irgendwie "besser" zu machen. Und Technologie ist dafür ein notwendiges Werkzeug, ein Mittel zum Zweck. Aber Technologie ist kein Selbstzweck.
Wenn Sie mehr über diese Sichtweise auf die Welt der Softwareentwicklung erfahren möchten, habe ich abschließend noch zwei Tipps für Sie: Erstens, schauen Sie sich das Video "CRUD? Bloß nicht! [3]" an. Und zweitens: Raffen Sie sich auf, die rein technologische Komfortzone zu verlassen und stürzen Sie sich in die zuvor genannten Themen, um der Fachlichkeit einen höheren Stellenwert zu geben. Holen Sie sich im Zweifelsfall Unterstützung von außen, um das Vorgehen zu beschleunigen, aber egal ob mit oder ohne: Das Wichtigste ist, dass Sie den ersten Schritt in dieser Richtung machen. Viel Erfolg!
URL dieses Artikels:
https://www.heise.de/-9979648
Links in diesem Artikel:
[1] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[2] https://www.youtube.com/watch?v=iQK620MY_48
[3] https://www.youtube.com/watch?v=MoWynuslbBY
[4] mailto:rme@ix.de
Copyright © 2024 Heise Medien
(Bild: Marian Weyo/Shutterstock.com)
Es sollte selbstverständlich sein, Menschen nicht auszuschließen – doch in der IT wird genau das ständig gemacht. Ab 2025 gelten in der EU andere Regeln.
Ich bin mir ziemlich sicher, dass Sie diesen Artikel aus einem von zwei Gründen angeklickt haben. Entweder, weil Sie dachten:
"Ja, Accessibility ist wirklich ein leidiges Thema, und es kostet tatsächlich furchtbar viel, sich damit auseinanderzusetzen. Endlich spricht das mal jemand aus!"
Oder weil Sie dachten:
"Was ist das denn für eine Aussage? Natürlich kostet Accessibility Geld, aber das darf doch nicht der Maßstab sein, sich nicht mit dem Thema zu beschäftigen."
Nun, soll ich Ihnen etwas verraten? Wenn einer dieser beiden Gedanken Ihnen tatsächlich durch den Kopf gegangen ist, habe ich Sie erfolgreich auf eine falsche Fährte geführt, denn beide Interpretationen des Titels treffen nicht zu. Doch wie ist der Titel dann tatsächlich gemeint?
Vorweg möchte ich klarstellen: Natürlich kostet Accessibility Geld. Es ist definitiv aufwendiger, sich Gedanken um Barrierefreiheit zu machen, die entsprechenden Konzepte zu erlernen und diese letztlich angemessen zu implementieren und zu testen, als dies einfach zu ignorieren. Dieses Argument ist zunächst einmal legitim. Die entscheidende Frage aber ist, und das ist der zweite Punkt, den ich bereits angedeutet habe: Darf man die Entscheidung, ob man beispielsweise eine Webseite für Menschen mit Behinderungen zugänglich macht, allein auf Basis von wirtschaftlichen Überlegungen treffen? Oder ist das nicht vielmehr ethisch fragwürdig?
Letztlich handelt es sich dabei um keine technische, sondern eine philosophische Frage. Es geht um Ethik und Moral, um persönliche Überzeugungen, vielleicht sogar um die eigene Betroffenheit. Wer selbst eine Behinderung hat oder Menschen im nahen Umfeld kennt, die betroffen sind, wird vermutlich anders über dieses Thema denken als jemand, der meint, Menschen mit Behinderungen seien eine marginale Gruppe, die keine Rolle spielt.
Der entscheidende Punkt ist: Ganz gleich, welche Meinung Sie zu der Frage haben, wie viel man in Accessibility investieren sollte – ab dem kommenden Jahr stellt sich diese Frage schlichtweg nicht mehr. Ab dem 28. Juni 2025 haben Sie in vielen Fällen nämlich keine Wahl mehr. Denn ab diesem Datum tritt die neue EU-Richtlinie European Accessibility Act (EAA) in Kraft. Der EAA verpflichtet Sie, für bestimmte Produkte und Dienstleistungen Barrierefreiheit umzusetzen – unabhängig davon, ob Sie das wollen oder nicht.
Zu diesen Produkten und Dienstleistungen zählen unter anderem Webseiten. Die Liste ist jedoch viel länger und enthält viele allgemeine Kategorien, was bedeutet, dass sie vielseitig interpretierbar ist. Wenn man das ernst nimmt, betrifft der EAA am Ende viele Bereiche, in denen sich plötzlich jemand mit Accessibility beschäftigen muss. Dazu gehören neben Webseiten auch mobile Apps, E-Books, Self-Service-Terminals wie Geldautomaten oder Fahrkartenautomaten, Getränkeautomaten und vieles mehr. Auch "digitale Dienstleistungen" wie E-Commerce-Websites, Online-Shops, Online-Zahlungen und der Transportsektor, beispielsweise Buchungssysteme, sind betroffen. Die Anforderungen an all diese Systeme? Der EAA fordert eine einfache und effiziente Gestaltung, insbesondere in Bezug auf die Bedienbarkeit und den Zugang zu Informationen.
Warum sollten Sie sich für den EAA interessieren? Ganz einfach: Weil er ab dem 28. Juni 2025 als einheitlicher Standard in der gesamten Europäischen Union gilt. Wenn Sie also Software oder Hardware auf den Markt bringen, die zu den genannten Kategorien gehört und den Anforderungen des EAA nicht entspricht, drohen empfindliche Geldstrafen – und dann wird fehlende Accessibility richtig teuer. Die Geldstrafen fallen nämlich nicht gerade gering aus. Wer bereits dachte, die DSGVO sei teuer, wird vom EAA noch einmal überrascht werden.
Es wird deutlich, dass es der EU ernst damit ist, das Thema Accessibility zu fördern. Ich sehe bereits, wie sich viele darüber ärgern und sagen werden:
"Warum wird das jetzt gesetzlich vorgeschrieben?"
Doch darauf gibt es eine einfache Antwort. Zum einen ist das Ganze gar nicht so neu, wie Sie vielleicht gerade denken. Es gab auch bisher schon gewisse Verpflichtungen zur Barrierefreiheit, allerdings betraf das hauptsächlich den öffentlichen Sektor, insbesondere Behörden. Dennoch gab es bereits entsprechende Regelungen, die nun erweitert werden: In Deutschland beispielsweise das Behindertengleichstellungsgesetz (BGG) und die Barrierefreie Informationstechnik-Verordnung (BITV 2). In der EU stellt seit 2018 die Web Accessibility Directive konkrete Anforderungen an Webseiten und Apps öffentlicher Stellen.
Zudem gibt es die Behindertenrechtskonvention der Vereinten Nationen, die zwar keine technischen Maßnahmen fordert, aber doch eine allgemeine Zielsetzung vorgibt. Die EU hält sich unter anderem an diese Vorgaben, und die Mitgliedsstaaten waren und sind verpflichtet, Barrierefreiheit zu fördern. Das Einzige, was sich nun ändert, ist, dass sich diese Regelungen nicht mehr nur auf den öffentlichen Sektor beziehen, sondern auch auf die Privatwirtschaft und eine breitere Palette von Produkten. Die EU verfolgt damit das Ziel, die technischen Maßnahmen innerhalb der Mitgliedsstaaten zu harmonisieren, um unterschiedliche nationale Regelungen zu vermeiden.
Persönlich finde ich es traurig, dass es solche Gesetze und die Androhung von hohen Strafen braucht, um Veränderungen anzustoßen. Sollte das nicht von selbst passieren, weil es das Richtige ist? In welcher Welt ist es in Ordnung zu sagen:
"Wir ignorieren die Bedürfnisse und Anforderungen einer ganzen Gruppe von Menschen, nur weil es Geld kostet?"
Natürlich verstehe ich, dass das täglich so abläuft, aber das macht es nicht weniger falsch. Und natürlich weiß ich auch, dass meine rhetorische Frage überflüssig ist, denn offensichtlich passiert der Wandel nicht von selbst, sonst wäre der EAA nicht notwendig. Dennoch finde ich es bedauerlich.
Was mich daran besonders ärgert, ist, dass Accessibility oft als Thema betrachtet wird, das nur wenige Menschen betrifft und keine Rolle im Alltag der meisten spielt. Beides ist falsch. Es betrifft nicht nur wenige Menschen. Vielleicht denken Sie bei "Menschen mit Behinderung" an jemanden, der sehbehindert oder blind ist. Doch es gibt viele Abstufungen dazwischen. Ich zum Beispiel bin zwar nicht blind, aber ich habe sehr schlechte Augen. Ohne Kontaktlinsen oder Brille bin ich im Alltag stark eingeschränkt, und ich kann außerdem auch nicht dreidimensional sehen. Mein Gehirn hat es nie gelernt, aus den Bildern beider Augen ein räumliches Bild zu konstruieren. Alles, was ich sehe, ist flach wie ein Foto, weshalb ich Entfernungen nicht einschätzen kann. Hinzu kommt, dass es mir mit zunehmendem Alter schwerer fällt, kleine oder kontrastarme Schriften zu lesen. Früher war das einfacher.
Und so gibt es viele Menschen, die nicht perfekt sehen können: Sei es wegen einer hohen Dioptrien-Zahl, einer Rot-Grün-Sehschwäche, Farbenblindheit oder anderen Einschränkungen. Und das betrifft nicht nur das Sehen. Auch der Hörsinn lässt mit dem Alter nach. Wir können im jungen Alter sehr hohe Frequenzen hören, die später nicht mehr wahrgenommen werden. Das bedeutet nicht, dass jemand vollständig gehörlos sein muss, um eine Einschränkung zu erleben. Schon eine leichte Verschlechterung des Gehörs kann problematisch sein, wenn man auf sprachbasierte Systeme angewiesen ist. Und auch diesen Menschen würde eine bessere Accessibility helfen.
Gleiches gilt für einfache Sprache oder Menschen, die aufgrund einer Verletzung, beispielsweise eines gebrochenen Arms, nicht gut mit einer Maus umgehen können. Daher ist es nicht stichhaltig zu sagen, Accessibility betreffe nur wenige Menschen. Stattdessen sollten wir uns eher fragen: Wie wenige Menschen haben keinerlei Einschränkungen in ihren Sinneswahrnehmungen? Sollten wir Webseiten tatsächlich immer so gestalten, als ob alle Nutzer perfekt sehen und hören können? Oder wäre es nicht besser, wenn wir es ermöglichen, zum Beispiel ein anderes Design mit höherem Kontrast zu wählen? Oder wenn wir Audio und Video standardmäßig mit Untertiteln oder Transkriptionen anbieten würden?
Bevor Sie nun sagen, "das braucht doch niemand", denken Sie einmal kurz nach: Warum sind eigentlich fast alle Kurzvideos untertitelt? Ganz einfach: Viele Menschen schauen sich diese Videos unterwegs an, zum Beispiel im Bus oder in der Bahn, oft ohne Kopfhörer. Das zeigt, dass es oft auch einfach Situationen gibt, in denen man dankbar für visuelle Unterstützung ist, weil man den auditiven Kanal nicht nutzen kann. Mit anderen Worten: Sollte es nicht unsere moralische Verpflichtung sein, dafür zu sorgen, dass Inklusion stattfindet und wir niemanden ausschließen? Ich finde: Ja.
Tatsächlich ist es auch gar nicht so schwierig, dabei den ersten Schritt zu machen. Gerade bei Webseiten bietet es sich an, sich mit semantischem HTML zu beschäftigen, was keine willkürliche <div>-Suppe ist, sondern dazu beiträgt, die Seite strukturell zu gliedern. Das erleichtert Screenreadern die Arbeit und ist daher eine Verbesserung. Dasselbe gilt für ARIA-Attribute, die es seit Jahren in HTML gibt, die aber kaum jemand kennt, geschweige denn einsetzt. Und natürlich wird es auch immer Situationen geben, in denen man an Grenzen stößt. Das sollte aber kein Grund sein, es nicht zumindest zu versuchen und so gut wie möglich umzusetzen. Eine bessere Nutzung von semantischem HTML führt übrigens nicht nur zu einer Verbesserung für Screenreader, sondern auch zu einer besseren Verständlichkeit der Seite für Suchmaschinen.
Um einmal ein Gefühl dafür zu bekommen, wie schwierig es ist, sich in der digitalen Welt zurechtzufinden, wenn man nicht sehen kann, aktivieren Sie doch einfach einmal die Bedienungshilfen auf Ihrem Smartphone, zum Beispiel die VoiceOver-Funktion bei iOS. Ich meine, wie schwer kann es schon sein, ein Gerät, das Sie jeden Tag unzählige Male nutzen, quasi "blind" zu bedienen? Ohne das "Erlebnis" vorwegnehmen zu wollen: Ich persönlich fand es erschreckend, wie schlecht das insgesamt funktioniert. Und dabei ist das System von Apple noch eines der besten auf dem Markt.
Dennoch habe ich nicht lange durchgehalten, bevor ich das Gefühl hatte, mein Telefon aus dem Fenster werfen zu wollen. Es ist erstaunlich, wie groß die Einschränkung tatsächlich sein kann. Dass ein Unternehmen mit einem Marktwert von über drei Billionen US-Dollar keine bessere Lösung bietet, finde ich enttäuschend. Genau deshalb brauchen wir leider doch Gesetze wie den EAA, damit sich etwas bewegt.
Für mich ist die wichtigste Erkenntnis dieses Themas: Wir alle müssen uns viel mehr mit Barrierefreiheit und Inklusion beschäftigen. Denn aktuell haben es Menschen, die nicht perfekt sehen oder hören können, in der digitalen Welt sehr viel schwerer, als man gemeinhin glaubt. Und je mehr das Digitale in unseren Alltag eindringt, desto wichtiger wird es, niemanden zurückzulassen. Accessibility ist so gesehen also weit mehr als nur ein technisches Thema – es ist eine gesamtgesellschaftliche Aufgabe. Und wir als Entwicklerinnen und Entwickler haben die Chance, mit relativ wenig Aufwand einen signifikanten positiven Unterschied zu machen. Und den sollten wir nutzen.
Wenn Sie von all dem nicht überzeugt sind, dann gilt ab dem kommenden Jahr der European Accessibility Act – und spätestens dann wird niemand mehr fragen, ob Sie Accessibility für sinnvoll erachten oder nicht. Dann sind Sie dazu verpflichtet. Aber wie schön wäre es, wenn möglichst viele Menschen von sich aus erkennen, dass es eigentlich freiwillig geschehen sollte – weil es das Richtige ist. In diesem Sinne möchte ich diesen Beitrag mit dem kleinen Appell beenden: Lassen Sie uns alle dazu beitragen, die Welt zu einem etwas besseren Ort zu machen für all jene, die es im Alltag ohnehin schon unnötig schwer haben.
PS: Übrigens, auch wir bei the native web [4] machen dabei definitiv nicht alles richtig, ich möchte uns nicht auf ein Podest stellen. Unsere aktuelle Website ist sicherlich kein Vorzeigeprojekt, aber das wird sich in der nächsten Version ändern.
URL dieses Artikels:
https://www.heise.de/-9939623
Links in diesem Artikel:
[1] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[2] https://enterjs.de/accessibility.php?wt_mc=intern.academy.dpunkt.konf_dpunkt_ejs_access.empfehlung-ho.link.link
[3] https://enterjs.de/accessibility.php?wt_mc=intern.academy.dpunkt.konf_dpunkt_ejs_access.empfehlung-ho.link.link
[4] https://www.thenativeweb.io/
[5] mailto:mai@heise.de
Copyright © 2024 Heise Medien
(Bild: fizkes/Shutterstock.com)
Die the native web GmbH veranstaltet ab dem 11. November 2024 insgesamt zwölf Webinare zu den Themen Performance, Clean Code, Security und Architektur.
Im Herbst richtet die the native web GmbH [1] insgesamt zwölf Webinare aus den Themenbereichen Performance, Clean Code, Security und hexagonale Architektur aus.
Die Webinare finden ab dem 11. November jeweils montags, mittwochs und freitags von 9.00 Uhr bis 12.30 Uhr statt und vermitteln die aktuellen Themen der zeitgemäßen Softwareentwicklung auf anschauliche und verständliche Art in Theorie und Praxis. Die Themenauswahl umfasst sowohl grundlegende als auch fortgeschrittene Themen.
Performante Anwendungen entwickeln (Details anzeigen [2])
Cleaner Code, hohe Qualität (Details anzeigen [3])
Sichere Software entwickeln (Details anzeigen [4])
Hexagonale Architektur (Details anzeigen [5])
Die Webinare werden als Livestream durchgeführt, sodass man einfach und bequem teilnehmen kann – ganz gleich, ob von zu Hause oder aus dem Büro. Für Fragen steht ein Chat zur Verfügung.
Der Preis beträgt 179 Euro pro Webinar. Wer drei Webinare aus einem Themenbereich als Paket bucht, erhält etwa 25 Prozent Rabatt gegenüber der Einzelbuchung, der Preis beträgt dann 399 Euro. Darüber hinaus gelten noch einmal günstigere Konditionen für Teams. Alle Preise verstehen sich jeweils zuzüglich 19 Prozent Umsatzsteuer.
Im Preis enthalten ist neben der Teilnahme am Livestream auch der Zugriff auf die Aufzeichnung des Webinars und die Codebeispiele.
Alle weitergehenden Informationen und eine Buchungsmöglichkeit finden sich auf der Webseite der tech:lounge Masterclass [6].
URL dieses Artikels:
https://www.heise.de/-9870380
Links in diesem Artikel:
[1] https://www.thenativeweb.io/
[2] https://www.thenativeweb.io/techlounge/developing-performant-applications
[3] https://www.thenativeweb.io/techlounge/clean-code-high-quality
[4] https://www.thenativeweb.io/techlounge/developing-secure-software
[5] https://www.thenativeweb.io/techlounge/hexagonal-architecture
[6] https://www.techlounge.io/
[7] mailto:mai@heise.de
Copyright © 2024 Heise Medien
(Bild: Erstellt mit Dall-E von iX-Redaktion)
Viele Konzerne wollen das Homeoffice abschaffen. Die Politik hingegen diskutiert über ein gesetzlich verankertes Recht darauf. Was spricht dafür, was dagegen?
Finger weg vom Homeoffice! Dieser Titel ist so wunderbar zweideutig: Einerseits kann man ihn als Warnung verstehen, bloß nicht erst mit dem Homeoffice anzufangen. Andererseits lässt sich dieser Titel auch als Aufforderung deuten, das inzwischen doch weit verbreitete Homeoffice nicht anzutasten oder es in Frage zu stellen. Im Sinne von:
"Nehmt uns bloß nicht unser lieb gewonnenes Homeoffice weg!"
Und genau dieser Titel spiegelt auch wunderbar die derzeitige gesellschaftliche Lage wider: Auf der einen Seite gibt es zahlreiche Konzerne, die das Homeoffice am liebsten wieder komplett abschaffen würden. Auf der anderen Seite steht die Politik, die derzeit immerhin darüber nachdenkt, ob es nicht ein gesetzliches Recht auf Homeoffice geben sollte. Und bei so viel Hin und Her, so viel Pro und Contra, stellt sich natürlich die Frage: Wer hat denn nun eigentlich recht? Was haben wir wirklich Positives vom Homeoffice? Und welche negativen Aspekte bringt es möglicherweise mit sich? Und genau um diese Fragen geht es im heutigen Blogpost.
Bevor wir richtig loslegen, noch eine kleine Ankündigung in eigener Sache: In den vergangenen beiden Blogposts hatte ich gefragt, ob Interesse besteht, dass ich einmal den von uns bei the native web [1] gelebten Entwicklungsprozess vorstelle. Da das Feedback sehr positiv war, wundern Sie sich jetzt vielleicht, dass es heute nicht um diesen Prozess geht. Der Grund, warum wir heute nicht über unseren Prozess sprechen, ist ganz einfach: Wir glauben, dass eine umfassende Beschreibung den Umfang eines Blogposts deutlich übersteigen würde, zumal es sicherlich zahlreiche Fragen dazu geben wird.
Daher wollen wir uns für dieses Thema mehr Zeit nehmen und veranstalten am kommenden Mittwoch, 25. September, um 18 Uhr einen Livestream, in dem wir uns unserem Prozess ausführlich widmen können. Wenn Sie diesen Livestream nicht verpassen wollen, rufen Sie ihn jetzt schon einmal auf [2] und aktivieren Sie dort die Erinnerung, damit YouTube Sie rechtzeitig daran erinnern kann. Alternativ können Sie den Termin natürlich auch ganz klassisch in Ihren guten, alten Kalender eintragen. Und damit zurück zum eigentlichen Thema.
Homeoffice ist für die meisten Menschen, die in der IT-Branche tätig sind, etwas, das im größeren Stil erst seit der Corona-Pandemie existiert. Klar, auch davor war es je nach Unternehmen möglich, mal den einen oder anderen Tag von zu Hause zu arbeiten, aber die Regel war das sicherlich nicht. Tatsächlich ist das bei uns, also bei the native web, ein wenig anders. Wir arbeiten seit unserer Gründung im Jahr 2012 vollständig remote – zu 100 Prozent. Das heißt, bei uns gab es de facto noch nie etwas anderes als Homeoffice.
Sowohl meine Kolleginnen und Kollegen als auch ich schätzen die Vorteile dieser Arbeitsweise sehr: Homeoffice bietet uns allen eine viel höhere Flexibilität im Alltag. Man kann zwischendurch einkaufen gehen, man kann einen Spaziergang machen oder mit dem Hund rausgehen, man kann bei den Hausaufgaben helfen, als Familie gemeinsam zu Mittag essen, man spart sich die Zeit, die sonst für das Pendeln draufgeht, und vieles mehr. Kurz gesagt: Man hat eine ganz andere Lebensqualität.
Aber das Arbeiten von zu Hause aus hat nicht nur Vorteile. Es kann schnell zur sozialen Isolation führen. Es kann dazu führen, dass man, wenn es an Selbstdisziplin und Eigenverantwortung mangelt, den Job vernachlässigt. Es kann zu Konflikten in der Partnerschaft führen, weil man zwar körperlich, aber nicht gedanklich zu Hause ist. Es kann zu Schwierigkeiten kommen, wenn das Privatleben und die beruflichen Anforderungen miteinander kollidieren. Kurz gesagt: Homeoffice ist nicht zwangsläufig ein Zuckerschlecken, sondern kann auch sehr anstrengend werden.
Hinzu kommt, dass Homeoffice natürlich nicht für jede Branche gleichermaßen geeignet ist: Was in der Softwareentwicklung sehr gut funktionieren kann, wird in IT-Berufen, die auf Spezialhardware wie Roboter oder Ähnliches angewiesen sind, schon schwieriger. Und über Berufe außerhalb der IT müssen wir an dieser Stelle gar nicht erst sprechen: Es ist zum Beispiel völlig illusorisch anzunehmen, dass jemand in der Gastronomie oder in der Pflege von zu Hause arbeiten könnte. Im Gegenteil, dort ist die physische Präsenz oft unerlässlich. Daher beziehe ich mich im Folgenden ausschließlich auf die IT-Branche, und alle Aussagen, die ich treffe, sollten in diesem Kontext verstanden werden.
Und damit kommen wir zu einem Punkt, der seit etwa zwei Jahren immer wieder heiß diskutiert wird: nämlich die Pflicht, ins Büro zurückzukehren. Das ist ja etwas, was vor allem die größeren Tech-Konzerne gerne fordern. Wobei, um fair zu bleiben, nicht nur die Großen betroffen sind: Solche Forderungen gibt es auch im kleineren Rahmen, nur führt das dann eben nicht zu so vielen Schlagzeilen. Ein krasses Negativbeispiel sind Elon Musk und Tesla. Im Sommer 2022 stellte Musk den Tesla-Mitarbeiterinnen und -Mitarbeitern ein Ultimatum [4]: Entweder sie kehren ins Büro zurück oder sie kündigen. Wenn man sich ansieht, wie Musk generell mit seinen Angestellten umgeht, wird schnell klar, dass ihm völlig egal ist, wer jemand ist oder welche Aufgabe jemand im Unternehmen übernimmt: Wer nicht zurückkommt, wird eben entlassen, immerhin hatte man ja die Wahl. Sinngemäß: "Dein Problem, wenn Du Dich (aus seiner Sicht) falsch entschieden hast."
Nun ist es vielleicht nicht so, dass jedes Unternehmen, das die Rückkehr ins Büro fordert, direkt so hart vorgeht. Aber immer wieder hört man von Unternehmen, in denen das Thema "zu Hause arbeiten versus im Büro anwesend sein" für Spannungen sorgt. Für mich stellt sich dabei die Frage: Warum fordern so viele Unternehmen die Rückkehr ins Büro? Ich habe dazu meine eigene Theorie. Natürlich weiß ich nicht, ob sie zutrifft, und ich will auch nicht jedem Unternehmen pauschal unterstellen, dass es so ist. Aber ich kenne genug Firmen, bei denen ich mir gut vorstellen kann, dass meine Theorie ziemlich genau die Gründe trifft, warum die Rückkehr ins Büro gefordert wird.
Meine Theorie lautet: Es geht um fehlende Kontrolle. Viele Führungskräfte, die ich im Laufe der Zeit kennengelernt habe, denken: Wenn jemand nicht vor Ort ist, kann man sie oder ihn auch nicht kontrollieren. Und wenn jemand nicht vor Ort ist, woher soll man dann wissen, ob diese Person auch wirklich arbeitet? Und nur um das klarzustellen: Ich will hier nicht alle Führungskräfte über einen Kamm scheren. Es gibt auch viele fähige und gute Vorgesetzte, aber es gibt eben auch schwarze Schafe.
Persönlich halte ich von dieser Argumentation übrigens überhaupt nichts. Die bloße Tatsache, dass jemand im Büro körperlich anwesend ist, bedeutet noch lange nicht, dass diese Person tatsächlich arbeitet. Man kann, und das sage ich aus eigener Erfahrung, auch sehr intensiv im Internet surfen, an privatem Code arbeiten, Spiele spielen und so weiter, und dabei so tun, als sei man schwer beschäftigt. Wer das Ganze noch auf die Spitze treiben will, kann sich mit zwei oder drei Kolleginnen und Kollegen einen Konferenzraum buchen. Denn wer im Konferenzraum wild diskutiert, muss ja arbeiten, oder? Dass hinter verschlossener Tür vielleicht lediglich die Bundesliga-Ergebnisse vom Wochenende besprochen werden, darauf kommt natürlich niemand.
Der Punkt ist: Körperliche Anwesenheit und tatsächliches Arbeiten sind zwei völlig unterschiedliche Dinge. Und wenn ein Unternehmen Zweifel daran hat, dass jemand arbeitet, nur weil die Person nicht physisch präsent ist, dann ist das aus meiner Sicht kein Problem von "Homeoffice ja oder nein", sondern von fehlendem Vertrauen. Und wenn es eigentlich um fehlendes Vertrauen geht, dann liegt das tatsächliche Problem sehr viel tiefer.
Wenn man den Menschen, mit denen man zusammenarbeitet, nicht vertrauen kann, wird das auch nicht besser, wenn sie vor Ort sind. Dann hat man lediglich die Illusion von Kontrolle. Aber fehlendes Vertrauen ist ein gravierendes, fundamentales Problem für die Zusammenarbeit. Und ich glaube, und das ist meine Theorie, dass die meisten Unternehmen, die so vehement die Rückkehr ins Büro fordern, ein großes Vertrauensproblem in ihrer Unternehmenskultur haben. Es ist aber so viel einfacher, die Symptome zu bekämpfen, indem man fordert, die Leute sollen doch bitte zurück ins Büro kommen, als sich mit den eigentlichen Ursachen auseinanderzusetzen und zu fragen, warum das Vertrauen eigentlich fehlt.
Das Problem dabei ist, dass man Vertrauen nicht anordnen kann. Ich kann nicht befehlen, dass plötzlich Vertrauen herrscht. Es gibt keine Technologie und kein Tool, das mir dabei wirklich helfen kann. Vertrauen muss gegeben werden, es kann nicht eingefordert werden. Und ich weiß, dass es Menschen gibt, die anderen mit einem großen Vertrauensvorschuss begegnen, und andere, die sagen, dass man sich Vertrauen erst verdienen muss. Beide Ansichten sind für mich in Ordnung, aber es müssen eben beide Seiten (das Unternehmen und die Mitarbeiterinnen und Mitarbeiter) ihren Beitrag leisten, damit langfristig eine vertrauensvolle Zusammenarbeit möglich ist.
Was schafft denn Vertrauen? Aus meiner Sicht als einer der Geschäftsführer von the native web gibt es einen zentralen Punkt, den ich immens wichtig finde und der auch essenziell für unsere Unternehmenskultur ist: Vertrauen entsteht vor allem dann, wenn man sich gehört und wertgeschätzt fühlt. Wenn man merkt, dass das Gegenüber die eigenen Anliegen ernst nimmt und sich auch ernsthaft bemüht, Verbesserungen vorzunehmen, zu unterstützen und zu helfen.
Deswegen sage ich jeder neuen Mitarbeiterin und jedem neuen Mitarbeiter am ersten Tag, dass sie oder er alles, was merkwürdig, ineffizient oder unlogisch erscheint, jederzeit offen ansprechen kann. Nur so besteht die Chance, dass Dinge verbessert werden, die bislang vielleicht niemandem aufgefallen sind oder die niemand hinterfragt hat. Natürlich kann es sein, dass einer neuen Mitarbeiterin oder einem neuen Mitarbeiter etwas auffällt, das einen nicht sofort ersichtlichen tieferen Sinn hat. Aber auch das ist nicht schlimm: Wird es angesprochen, gibt es im Zweifelsfall eine gute Erklärung, warum die Dinge so sind, wie sie sind. Es gibt also entweder einen Lerneffekt (was gut ist) oder es führt zu einer Verbesserung (was ebenfalls gut ist).
Und das gilt nicht nur für technische und organisatorische Prozesse, sondern auch für alles andere. Ich möchte, dass meine Kolleginnen und Kollegen jederzeit zu mir kommen und sagen können:
"Hey Golo, mich bedrückt etwas."
oder:
"Mich beschäftigt etwas."
Natürlich mache auch ich Fehler, aber ich bemühe mich zumindest stets, auf solche Anliegen einzugehen, einen Rat zu geben oder etwas zu verändern. Außerdem frage ich oft auch von mir aus nach, wenn ich den Eindruck habe, dass jemand nicht so gut gelaunt ist wie sonst oder ich anderweitig das Gefühl habe, dass etwas nicht stimmt. Ich spreche die Person dann im Einzelgespräch an und frage, ob alles in Ordnung ist. Oft stellt sich heraus, dass alles okay ist, manchmal jedoch entsteht ein wertvolles Gespräch. Für mich ist es wichtig, auf Augenhöhe und mit Respekt miteinander umzugehen, denn das schafft eine vertrauensvolle Atmosphäre. Und das ist etwas, was wir bei the native web meiner Meinung nach ganz gut hinbekommen.
Allerdings reicht Vertrauen allein nicht aus, damit Remote-Arbeit gut funktioniert. Es braucht noch etwas anderes. Und das habe ich vorhin schon kurz erwähnt, als ich über die Vor- und Nachteile des Homeoffice gesprochen habe, nämlich Selbstdisziplin und Eigenverantwortung. Gerade weil die physische Komponente im Homeoffice fehlt, ist es wichtig, dass man sich selbst organisiert und Verantwortung übernimmt.
Wenn ich zum Beispiel an einem Problem festhänge, kann ich nicht einfach zur Kollegin oder zum Kollegen am Nachbartisch gehen und um Hilfe bitten. Ich bin erst einmal auf mich allein gestellt. Natürlich kann ich versuchen, jemanden zu erreichen, aber je nachdem, womit die anderen gerade beschäftigt sind, klappt das nicht immer sofort. Dann darf ich mich jedoch nicht einfach zurücklehnen und stundenlang nichts tun, sondern muss konstruktiv nach einer Lösung suchen. Als Vorgesetzter ist mir persönlich dabei aber gar nicht so wichtig, ob die Lösung am Ende klappt. Mir ist vielmehr die Initiative wichtig. Es ist völlig in Ordnung, wenn mir dann jemand sagt:
"Ich habe dies und das und jenes ausprobiert, aber es hat aus diesen und jenen Gründen nicht funktioniert."
Dann weiß ich nämlich: Die Person hat sich bemüht. Und das zeigt mir, dass mein Gegenüber die Arbeit ernst nimmt, auch wenn es in dieser Situation vielleicht einfacher gewesen wäre, nichts zu tun. Und das wiederum weiß ich zu schätzen.
Insofern ist das mit dem Vertrauen eine gegenseitige Angelegenheit: Meine Kolleginnen und Kollegen müssen mir vertrauen können und ich muss ihnen vertrauen können. Das ist jedoch der Punkt, der in vielen Unternehmen fehlt: gegenseitiges Vertrauen, das auf Respekt, Menschlichkeit und auf einem Umgang auf Augenhöhe basiert. Wenn dieses Vertrauen aber gegeben ist, dann spielt es keine Rolle, ob man remote oder vor Ort arbeitet. Wenn es jedoch fehlt, dann hilft es auch nicht, die Leute zurück ins Büro zu zwingen. Dann liegt das Problem viel tiefer, denn die Teamzusammenstellung oder die Arbeitskultur passt irgendwo nicht.
Dieses Vertrauen und dieser gegenseitige Respekt sind die Basis für so vieles im Unternehmensalltag. Ein Beispiel: Wir bei the native web kommunizieren viel schriftlich über Slack (also asynchron). Und es kommt vor, dass ich am Wochenende oder mitten in der Nacht eine Idee habe und diese in Slack schreibe. Nun gilt aber: Nur weil ich am Wochenende schreibe, erwarte ich von meinen Kolleginnen und Kollegen keine sofortige Antwort. Es ist völlig in Ordnung, wenn ich erst am Montagmorgen eine Antwort bekomme. Nichts ist jemals so dringend, dass ich jemanden am Feierabend, am Wochenende oder gar im Urlaub stören würde. Und das Interessante dabei: Gerade weil wir diese Grenzen respektieren, bekomme ich oft sogar am Wochenende oder abends noch eine Antwort, obwohl ich explizit geschrieben habe, dass es nicht eilig ist. Das Paradoxe ist also: Weil ich nichts fordere, wird viel eher gegeben. Und das schätze ich sehr.
Der Punkt ist aber: Mir ist jedes Mal, wenn ich dann doch schon vor Montagmorgen eine Antwort bekomme, klar, dass das keine Selbstverständlichkeit ist, dass das etwas Besonderes ist, das ich wertzuschätzen weiß und wofür ich dankbar bin. Und das äußere ich dann auch. Denn mir ist wichtig, das zu respektieren. Und eigentlich sollte all das überhaupt nicht erwähnenswert sein, aber leider sieht die Praxis in vielen Unternehmen anders aus.
Meine Rolle als Vorgesetzter sehe ich dabei nicht darin, das Team anzuführen, wie das in vielen Unternehmen der Fall ist. Ich sehe meine Aufgabe eher darin, das Team zu schützen und auf mein Team aufzupassen. Ich bin also weniger der Löwe, der mit Gebrüll vorneweg rennt und einen auf "Big Boss" macht, sondern vielmehr bin ich die Entenmama, die aufpasst, dass keinem ihrer Küken etwas passiert. "Fürsorge" ist, denke ich, hier das passende Wort. Es ist vielleicht nicht die verbreitetste Art von Management, aber es ist zumindest meine.
Und aus genau dieser Perspektive heraus hatten wir übrigens auch sehr lange keine Zeiterfassung. Wir haben immer mit Vertrauensarbeitszeit gearbeitet, und bei uns hat noch niemals jemand Überstunden gemacht. Das ist in zwölf Jahren noch kein einziges Mal vorgekommen. Natürlich kommt es vor, dass man mal ein oder zwei Stunden länger macht, weil man noch etwas fertigstellen möchte, aber: Ich sehe das eher wie eine Einladung zum Essen unter Freunden. Mal zahlt der eine, mal der andere, aber am Ende gleicht sich das aus. Genauso deshalb ist es auch völlig in Ordnung, wenn jemand mal früher Schluss macht. Es wird auch wieder Tage geben, an denen es länger dauert, und solange sich das ausgleicht, und beide Seiten fair miteinander umgehen, ist das okay.
Deshalb bin ich auch kein Freund des EuGH-Urteils zur verpflichtenden Zeiterfassung, weil es die Falschen trifft: Unternehmen wie wir, die schon vorher freiwillig darauf geachtet haben, dass niemand zu viel arbeitet, müssen sich nun mit zusätzlicher Bürokratie herumschlagen. Diejenigen, die ihre Mitarbeitenden knechten und ausbeuten wollen, werden trotzdem Mittel und Wege finden, das auch weiterhin zu tun. Aber sich aufzuregen, bringt an der Stelle leider nichts.
Nun habe ich Slack bereits mehrfach erwähnt. Es ist für uns das wichtigste Kommunikationsmittel, weil wir darüber schreiben, telefonieren und Videokonferenzen abhalten können. Aber das Wichtigste ist nicht das Tool an sich, sondern die Asynchronität. So kann jeder konzentriert arbeiten und wird nicht ständig unterbrochen. Aber ohne Selbstdisziplin und Eigenverantwortung von allen Beteiligten funktioniert asynchrone Kommunikation nicht.
Wir bei the native web sind ein Beispiel dafür, wie Homeoffice als dauerhaftes Modell gut funktionieren kann. Das Entscheidende dabei ist nicht, dass wir gerade Slack verwenden oder dass wir eine elektronische Zeiterfassung nutzen. Das Wichtige ist, dass es uns seit zwölf Jahren gelingt, die richtigen Menschen zusammenzubringen und eine vertrauensvolle Zusammenarbeit zu schaffen. Und das ist meiner Meinung nach der eigentliche Schlüssel, den man braucht, damit Homeoffice im großen Stil funktionieren kann. Denn wenn dieses Vertrauen nicht gegeben ist, dann wird es schwierig, und zwar völlig unabhängig davon, ob man remote oder vor Ort arbeitet.
Wenn Sie mich nun fragen, wie die Zukunft der Remote-Arbeit in der IT-Branche aussieht, muss ich ehrlich sagen: Ich weiß es nicht. Einerseits sehe ich großes Potenzial, das Ganze noch viel weiter auszubauen. Andererseits bin ich mir unsicher, ob allzu viele Unternehmen bereit sein werden, diesen Weg zu gehen und ein Stück ihrer (vermeintlichen) Kontrolle abzugeben. Vertrauen ist etwas, das aktiv gepflegt werden muss. Es passiert nicht einfach so. Man muss die richtigen Menschen zusammenbringen, die entsprechende Kultur etablieren und selbst mit gutem Beispiel vorangehen. Was die Politik sich dazu ausdenkt oder welche Technologien morgen in Mode sind, spielt dabei letztlich keine Rolle. Es ist am Ende immer eine Frage der Menschen. Deshalb weiß ich auch nicht, wie sich die Branche als Ganzes entwickeln wird, weil es keine Frage der Branche ist, sondern eine Frage, die jedes Team für sich selbst beantworten muss.
URL dieses Artikels:
https://www.heise.de/-9868729
Links in diesem Artikel:
[1] https://www.thenativeweb.io/
[2] https://www.youtube.com/live/sORcUbCOnBw
[3] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[4] https://www.heise.de/news/Elon-Musk-an-seine-Tesla-Fuehrungskraefte-Schluss-mit-Homeoffice-oder-Kuendigung-7129308.html
[5] mailto:rme@ix.de
Copyright © 2024 Heise Medien