Gehypte Lösungsansätze können nur zufällig als Lösung für die eigene Situation passen. Beispiel Microservices: Eine Bank ist nicht Netflix und hat auch nicht das Problem, sehr dynamisch hoch- und herunterskalierbare Infrastruktur für Videostreaming bereitstellen zu müssen.
Kontext ist entscheidend
In IT-Magazinen und auf Konferenzen lassen sich aber viele der kontextspezifischen Entscheidungen, die bei der Entwicklung einer Architektur ablaufen, nicht einfach kommunizieren. Dadurch rücken Abwägungen zu Architekturentscheidungen im Vergleich zu leichter greifbaren technologischen oder methodischen Beiträgen in den Hintergrund. Pointierte Inhalte lassen sich leicht konsumieren, auch ohne viel Verständnis für den Kontext aufzubringen. So ist ein Lösungsmuster nach einiger Zeit in aller Munde.
Dabei ist Kontext in der Softwarearchitekturarbeit alles. Die Anforderungen und Rahmenbedingungen unserer Stakeholder an Lösungen sollten in unsere Entscheidungen einfließen. Erst wenn wir verstanden haben, können wir einen Architekturstil oder eine Technologie wählen.
Architekturentscheidungen
Architekturentscheidungen können per Definition nur sehr aufwendig und deshalb teuer revidiert werden (vgl. [1]). Darunter fällt neben der Wahl eines Architekturstils oder -musters auch die Wahl von Kerntechnologien. Architekturentscheidungen leiten die Erstellung eines Systems und bestimmen maßgeblich, wie es entwickelt, ausgerollt, betrieben, gepflegt und natürlich verwendet wird.
Zwar können wir versuchen, diese Entscheidungen durch Kapselung in einem bestimmten Baustein zu verbergen und dadurch aufzuschieben oder später einfacher zu revidieren, aber auch dann müssen wir damit rechnen, dass sich gewisse Aspekte der konkreten Lösung nicht sauber abstrahieren lassen. Joel Spolsky nennt das „Leaky Abstractions“ [2] (siehe Kasten 1).
Abstraktionen sind manchmal nicht perfekt darin, Implementierungsdetails zu verbergen. Haben wir beispielsweise ein Datenbanksystem hinter einem abstrakten „Repository“-Interface versteckt, kann das Datenbankmanagementsystem doch seine Implementierungsdetails bemerkbar machen, indem es sich bei nebenläufigen Konflikten oder beim Umgang mit Fehlern auf eine gewisse Weise verhält, die alle Ersatzimplementierungen ebenfalls imitieren müssten. Diese Implementierungsdetails „lecken“ sozusagen durch die Abstraktion hindurch. |
Manche Entscheidungen lassen sich zudem weniger gut kapseln. Daher lassen sich Entscheidungen schlecht für sich isoliert betrachten. Wir müssen die Auswirkungen auf der Systemebene in Anbetracht der relevanten Qualitätsziele sowie der Prinzipien guter Softwarearchitektur bewerten.
Zudem bestimmen auch Architekturentscheidungen, die wir gar nicht selbst getroffen haben, die Natur unserer IT-Systeme, nämlich dann, wenn wir sie in Form von 3rd-Party-Komponenten einbinden. Dabei können sich die Entscheidungen als für unseren Kontext ungeeignet herausstellen. Die Türen auf der Star Trek Enterprise haben eine deutlich andere Verwendungspragmatik als unsere einfachen Smart-Lock-Tür-Mechanismen in unserem Büro.
Technologieentscheidungen
Ob Hype oder nicht Hype: Niemand kann zuverlässig voraussagen, wie langfristig tragfähig eine Technologie gepflegt wird. Firmen kommen und gehen. Interoperable Standards werden gebrochen. Lizenzmodelle ändern sich. Anforderungen wachsen. Technologien verrotten, wenn das Know-how beim Hersteller durch Fluktuation verloren geht.
Deshalb sollten wir bei der Technologieauswahl bestimmen, wie die Architekturentscheidung in einer idealen Umgebung aussehen würde. Welche Bausteine sind für welche Aufgaben zuständig? Welche Informationen werden dafür benötigt? Wo kommen diese Informationen her? Werden sie angefragt oder übergeben? Und so weiter.
So können wir mit geringem Aufwand Technologie-Migrationen oder Ablösungen planen, damit die Architektur diese überdauern kann.
Neu bedeutet nicht immer besser
Nur weil etwas neu(er) ist, bedeutet das nicht automatisch, dass es auch besser ist als alles, was davor kam. Häufig ist der Auslöser zur Entwicklung einer bestimmten Technologie die Unzulänglichkeit einer anderen, älteren Technologie. Systeme, die vor 15 Jahren oder 20 Jahren oder noch früher entwickelt wurden, unterlagen Limitationen, die heutzutage kaum noch eine Rolle spielen. Inzwischen ist es zum Beispiel sehr selten erforderlich, jeden Teil des Codes durch Mikro-Optimierungen auf eine effiziente Ausnutzung von CPU, Arbeitsspeicher und Massenspeicher zu optimieren.
Die Architekturtrends der letzten Jahre adressierten häufig Elastizität und Skalierbarkeit, um eine Verschiebung von fixen zu nutzungsspezifischen Kostenmodellen zu unterstützen. Architekturen, die eine Kostenoptimierung bei Schwankungen im laufenden Geschäft unterstützen, folgen anderen Qualitätszielen als traditionelle IT der 2000er. Ihren Hype haben die Technologien ihrer praktisch beliebigen, verzögerungsfreien Skalierbarkeit zu verdanken: Cloud-Computing, NoSQL-Datenbanken, Kafka usw.
Nicht wenige Firmen wollen ihre in die Jahre gekommene IT direkt „auf den neusten Stand“ bringen. Nun kann kaum eine Firma von sich behaupten, ihre IT-Systeme wären zu einfach – das Gegenteil ist häufig der Fall: Die Komplexitäten wachsen uns über den Kopf. Dummerweise ist gerade der unbedarfte Einsatz modernster Technologien eher Treiber der Komplexität. Deshalb ist bei der Planung und Wahl Vorsicht geboten: Nicht jede Lösung passt auch zu dem vorhandenen Problem.
Feindbild: Komplexität
Nehmen wir beispielsweise an, wir möchten in einem System Komponenten „asynchron“ miteinander kommunizieren lassen und dafür zur Ausfallsicherheit einen Message Broker einsetzen. Mit Apache Kafka als zurzeit vermeintlich „beste“ Lösung sollten wir auf der sicheren Seite und für alle Zukunftsszenarien gefeit sein. Kafka kann hohe schreibende Last verarbeiten, ohne zu blockieren. Dafür ist der Betrieb nicht trivial. Auch wenn wir nur wenige Nachrichten über den Broker verschicken möchten, müssen wir uns dennoch mit der Komplexität herumschlagen.
Manchmal kaufen wir uns so Komplexität für Eventualitäten ein. Eine bessere Wahl wäre es vielleicht, eine simple Message Oriented Middleware (MOM) wie RabbitMQ oder ActiveMQ zu verwenden oder gleich den ganzen Betrieb des Messagings an einen Cloud-Provider outzusourcen und zum Beispiel auf AWS SQS oder Azure Service Bus zu setzen. Leider werden solche Optionen im Vorfeld häufig nicht ernsthaft in Betracht gezogen, weil „man heute Kafka nimmt“.
Das ist problematisch. Alle Technologien bringen ihre Eigenheiten und Einschränkungen mit. Wir können unterstellen: Je mächtiger die Technologie, desto größer wird ihr Beitrag zur Lösungskomplexität. Auch wenn diese zusätzliche Lösungskomplexität uns nicht dabei hilft, unsere fachlichen Anforderungen zu erfüllen, müssen wir sie managen, um dann das eigentliche, fachliche Problem adressieren zu können. Haben wir bereits eine inhärent komplexe fachliche Domäne, sollte es unser Ziel sein, die Lösungskomplexität so klein wie möglich zu halten, um nicht in einem Meer der Komplexitäten zu ertrinken.
Probleme erst zu adressieren, wenn sie sich in der Praxis abzeichnen, mag kurzsichtig wirken. Dabei lässt sich ein Mittelweg zwischen dem Vorbereiten auf die Wachstumsszenarien und dem naiven Entwickeln ohne Weitblick finden – mit einer einfachen Architektur, die Optionen zur Erweiterung oder Veränderung vorsieht (vgl. Kasten 2).
Im Optionshandel der Börse werden vergleichsweise günstige Wertpapiere (Optionen) gehandelt, die den Besitzer mit dem Recht ausstatten, ein Wertpapier zu einem späteren Zeitpunkt zu einem bestimmten Preis zu kaufen. Bei Unsicherheit kann man also durch den Kauf einer Option verhindern, dass man sich zu einem späteren Zeitpunkt ärgert, zum Beispiel eine Aktie nicht gekauft zu haben. In unserer Architekturarbeit haben wir die Möglichkeit, etwas Ähnliches zu machen, indem wir uns Alternativen offen halten und nicht zu früh auf Architekturentscheidungen festlegen. Statt beispielsweise ein bestimmtes DBMS zum Projektbeginn zu wählen, können wir eine komplette Business-Logik-Schicht bauen, die über ein Interface auf die Implementierung durch eine Map zurückgreift, um so den Anschein von Persistenz während der Laufzeit zu erwecken. Dadurch können wir über die Fachdomäne lernen, welche Daten in welcher Form gespeichert werden müssen, bevor wir uns für ein DBMS entscheiden müssen. Da das Interface strukturell keine Abhängigkeiten zur Datenbank in unseren Kern einführt, können wir die Technologie einfach austauschen. Dieses als „Ports und Adapters“ bekannte Architekturmuster erlaubt, technologische Entscheidungen spät und mit mehr Informationen zu treffen oder vergleichsweise günstig zu revidieren. Vorsicht ist jedoch vor dem allzu breiten Einsatz dieses Musters geboten, denn das Hohpesche Gesetz besagt: „Unsägliche Komplexität ist die Strafe für alle die, die sich für nichts entscheiden können.“ [3] |
Wie gut ein Architekturmuster oder eine Technologie für unseren Kontext passt, hängt nicht nur von ihren guten, sondern auch von ihren schlechten Seiten ab. Dabei hilft insbesondere auch der Blick auf die Konsequenzen, die eine Technologie mit sich bringt.
Neue Architekturen – alte Einschränkungen?
Bei der Optimierung komplexer Systeme kommt es darauf an, die „Flaschenhälse“ zu finden, die das System in einer wesentlichen Eigenschaft einschränken. Wenn wir an einer anderen Stelle als an einem Flaschenhals optimieren, haben wir tatsächlich keine Verbesserung, sondern nur die Illusion von Fortschritt erzielt (vgl. [4]). Übertragen auf die Modernisierung von IT-Systemen durch neue Technologien und Architekturen stellt sich also die Frage: „Welche Limitation kann diese Technologie oder diese Architektur aufheben?“ (Vgl. [5])
Beispiel: Modularisierung in flexiblen Architekturen
Starten wir mit Modularisierung. Bei einem System ohne hinreichende Modularisierung werden früher oder später Änderungen an der Software nur noch mit großen Abstimmungs- und Testaufwänden möglich sein. Ein System, das hingegen aus lose gekoppelten Modulen aufgebaut ist, hilft dabei, Änderungs- und Testaufwände zu kanalisieren und so mit mehr als einem Team weitgehend unabhängig eine Software zu ändern, ohne dass diese unerwünschte Seiteneffekte einführen oder viel Aufwände in die Koordinierung der Teams gesteckt werden müssen. Modularisierung löst so die Limitation, dass nur eine beschränkte Menge an Personen ungehindert und kollaborativ an einem Softwaresystem arbeiten kann. Dabei ist es noch gar nicht zwingend notwendig, ein verteiltes System zu bauen – ein modularer Monolith, nennen wir ihn Modulith –, hat bereits zur Entwicklungszeit alle Vorteile einer Modularisierung. Allerdings wird man ihn nur „im Ganzen“, also mit allen beteiligten Modulen, bauen können.
Hier kommen komplexere Architekturmuster wie Microservices oder Self-contained Systems ins Spiel. Sie helfen dann, wenn wir die Software darüber hinaus auch noch unabhängig deployen und vielleicht sogar Continuous Delivery mit mehr als einem Team praktizieren möchten.
Haben wir keines dieser Probleme, weil an der Software beispielsweise nur ein siebenköpfiges Team arbeitet, wird eine Umstellung auf eine „moderne“ Architektur keine nennenswerten Vorteile in der Praxis erzielen. Im Gegenteil, sie wird hohe Kosten (vgl. [6]) ohne wesentlichen Gegenwert verursachen.
Beispiel: Single-Page App als neues Frontend
Ein zweites Beispiel: Wenn wir eine stark formulargetriebene Internetanwendung, wie zur Eröffnung eines Kontos, von Server Side Rendering (kurz SSR) plus jQuery auf eine Single-Page Application (SPA, z. B. mit ReactJS) „modernisieren“, ist unklar, welche Limitation wir dadurch aufheben. Vielleicht ist es das Erschließen eines Talentpools (für ReactJS-Entwicklung), der uns hilft, diese Anwendung zu bauen.
Sicherlich werden wir aber in die Situation geraten, dass viele Validierungen, die vormals allein serverseitig stattgefunden haben, erst mal dupliziert und auch clientseitig implementiert werden müssen (eine neue Limitation!). Dazu kommen neue Komplexitäten, wie das Management von UI State beim Wechsel zwischen Seiten und das Handling von Deep Links, um die man sich bei einer SSR-Applikation keine Gedanken machen muss.
Wir hoffen, es wird klar: Entscheidungen für bestimmte Technologien oder bestimmte Architekturansätze bringen eine gewisse Komplexität mit. Diese äußern sich durch Wechselwirkungen zwischen Qualitätszielen, aber auch durch Nebenläufigkeiten zur Laufzeit oder durch Abhängigkeiten innerhalb der Organisation. Wir sollten daher darauf achten, dass wir trotz der entstehenden Komplexität auch die richtigen Probleme lösen, nämlich die eigentlich geforderten Qualitäten zu erreichen.
Worauf es wirklich ankommt: die Qualitätsanforderungen unserer Stakeholder
Manche der impliziten Anforderungen unserer Stakeholder sind auch ohne Erwähnung klar. Wir können getrost für die meisten Kontexte unterstellen, dass eine kurze Umsetzungszeit – eine kurze Time-to-Market – einerseits sowie eine möglichst einfache Softwarelösung andererseits gefordert ist. Meist jedoch finden wir darüber hinaus bei Stakeholdern noch Erwartungen, dass unsere Software gewisse Attribute wie eine Benutzerfreundlichkeit oder eine hohe Performance unter bestimmten Bedingungen aufweist, die nirgendwo spezifiziert oder mit ihren Wechselwirkungen austariert wurden.
Wir gehen der Einfachheit halber mal davon aus, dass diese Zielvorstellungen unserer Stakeholder an die Qualität der Software einigermaßen stabil sind, sodass wir unsere Architekturentscheidungen auf ein gewisses Ziel hin optimieren können – zum Beispiel mit der Quality Driven Software Architecture [7]. Dieser Ansatz konzentriert sich darauf, zuerst die architekturrelevanten Qualitätsziele (siehe auch Kasten 3) priorisiert zu ermitteln und damit den Kontext für die Architekturentscheidungen systematisch zu bestimmen.
Von einer qualitativen Software sprechen wir, wenn diese mindestens die Erwartungen unserer Stakeholder im Hinblick auf alle relevanten Qualitätsattribute wie beispielsweise Performance, Sicherheit oder Benutzerfreundlichkeit erfüllt (Manchmal werden solche Anforderungen auch als: „nicht funktionale Anforderungen“ bezeichnet). Die wichtigsten und herausforderndsten Qualitätsattribute, die unsere Stakeholder erreichen möchten, handeln wir gemeinsam mit den Stakeholdern als die Qualitätsziele der Softwarearchitektur aus. Damit wir dabei genau bestimmen können, ob wir diese Ziele erreicht haben, ist eine Konkretisierung in Form eines Qualitätsszenarios hilfreich. In einem solchen Szenario wird eine messbare Aussage getroffen, wie stark und in welchem Kontext eine Eigenschaft ausgeprägt sein soll. So könnte ein Beispiel für ein konkretes Usability-Szenario für eine Ticketing-App etwa lauten: „Ein(e) ungelernte Nutzer:in benutzt die App das erste Mal. Sie ist in der Lage, innerhalb von weniger als 5 Minuten ein Ticket zu kaufen und es per Kreditkarte zu bezahlen.“ |
Erst wenn diese Qualitätsattribute feststehen, werden mögliche Lösungsoptionen dem Qualitätsattribut gegenübergestellt, etwa in Form einer Tabelle, die beides einander zuordnet (siehe Tabelle 1).
Prio | Q-Merkmal | Szenarien | Mögliche Lösungen |
---|---|---|---|
1. | Wartbarkeit |
• Eine neue API soll durch die Software angeboten werden, sie kann ohne große Anpassungen hinzugefügt werden. • Ein neues Team wird zur Weiterentwicklung eingestellt. Das neue Team kann einen Teil der Software weitgehend unabhängig übernehmen, ohne dass es sich mit anderen Teams regelmäßig abstimmen muss. |
Architekturmuster: Ports & Adapters Fachliche Modularisierung Einsatz von statischer Codeanalyse Einheitliche Editor-Config |
2. | Performance | • Massenbearbeitung von 250.000 Bilddateien (je 10 MByte) in unter 4 Stunden |
Wir setzen zur Bildbearbeitung eine Library ein, die in Rust geschrieben ist Auslagerung der Bildbearbeitung an eine GPU |
3. | Sicherheit | ... | ... |
Ein ähnlicher Ansatz ist aus einigen Architekturbewertungsmethoden bekannt und eignet sich hervorragend für den Softwareentwurf und die Gegenüberstellung von Architekturentscheidungsoptionen auf verschiedenen Abstraktionsebenen.
Aber nicht nur die vereinbarten Qualitätsziele beeinflussen unsere Entscheidungsmöglichkeiten für den Architekturentwurf. Auch die bisher umgesetzte Architektur und die Rahmenbedingungen in Bezug auf unsere Umsetzungskompetenz und -kapazität beeinflussen Risiko und Aufwände, die mit der Realisierung einer Option verbunden sind.
Es hat sich bewährt, bei verschiedenen Architekturoptionen erst einmal auf die Prinzipien und abstrakten Lösungsoptionen zu schauen, bevor konkrete Technologieentscheidungen getroffen werden. Erst wenn eine „idealisierte“ Architektur tragfähig für die geforderte Qualität ist, lohnt es sich, die Einschränkungen von dazu passenden Technologien zu prüfen.
Bewährte Universalwerkzeuge für den Architekturentwurf
Für uns ist Architekturarbeit Handwerk und Disziplin, die sich in erster Linie um die Lösung der Probleme dreht, die unsere Stakeholder im Sinne hatten. Es geht nicht darum, einkaufslistengetrieben Technologien auszuwählen, das Architektur zu nennen, nur um dann die Probleme zu lösen, die uns eine verfrühte Technologieentscheidung einbringt. Es gibt keinen allmächtigen, universellen Architekturansatz, der immer zum Ziel führt.
Vielmehr helfen uns viele verschiedene, bewährte Werkzeuge, eine bessere Architektur zu entwickeln. Wer laufende Systeme bauen, erweitern, ändern, migrieren oder bewerten muss, braucht viele unterschiedliche Ansätze für verschiedene Aufgabenstellungen und Rahmenbedingungen, die wir im Folgenden kurz anreißen möchten.
Mit szenarienbasierten Bewertungsmethoden [8] können wir sowohl anlassbezogen die allgemeine Qualität unserer Software oder Architekturentwürfe bewerten als auch kontinuierlich während des Entwerfens. Deshalb passt die bereits vorgestellte Quality Driven Software Architecture gut in unseren Werkzeugkasten für die Architekturarbeit.
Der Fokus auf die fachliche Lösung und das Fachverständnis ist immer noch ein sehr wichtiger Ansatz in der Architekturarbeit, auch wenn es heute anscheinend viele gibt, die sich statt an der fachlichen Lösung an der richtigen Deutung der DDD-Literatur [9] versuchen. Letzteres halten wir für wenig zielführend für Softwerker:innen.
Ein gutes Vorgehen, um Wissen über neuralgische Punkte der Architektur (sowohl fachliche als auch technische) im Team zu verteilen, bieten moderne Ansätze zur kollaborativen Modellierung mit Domänenexpert:innen, die gern in der DDD-Community propagiert werden (vgl. Kasten 4).
Das Bauen von Modellen ist eine der Techniken, die selbst einem Hype-Cycle zum Opfer gefallen sind. War es in den 2000er Jahren noch sehr populär, Systeme durch Modelle wie die UML zu beschreiben und dadurch verständlicher zu kommunizieren, wie diese aufgebaut sind und funktionieren, haben viele Teams diese Vorgehensweise inzwischen aufgegeben. Dabei hilft es unserer Erfahrung nach ungemein, bei der Architekturarbeit durch Modelle abstrakte Dinge greifbarer zu machen. Hier setzen Techniken der kollaborativen Modellierung wie Event Storming oder Domain Storytelling [10] (um nur einige zu nennen) an, indem sie leichtgewichtige und zugängliche Alternative zu den „formalen“ Modellen der UML bieten. Auf diese Weise können wir zusammen mit Fachexpert:innen Modelle verwenden, um knifflige Probleme und gute Lösungen noch vor der ersten Zeile Code zu analysieren. |
Auch eine Zurückbesinnung auf die Grundprinzipien guter Softwarearchitektur hilft beim Entwurf von Modulen und Bausteinen. Wir möchten in der Regel lose Kopplung durch Information Hiding und eine Separation of Concerns erreichen. Die Architekturentwicklung lässt sich immer noch gut durch hierarchische Zerlegung der Software in ihre Bausteine leiten. Dadurch können wir Sollbruchstellen, Synergien, Teamautonomie oder auch Make-or-Buy-Entscheidungen für verschiedene Systemteile vorbereiten.
Wir müssen die Software anpassen, bauen, ausrollen und betreiben. Dafür können geeignete Architekturstile und Referenzarchitekturen helfen, die mit klaren Regeln für die Entwicklung das Verteilen und Betreiben unterstützen. Hier sind Ansätze wie Containerisierung und Continuous Integration/Deployment/Delivery stets sinnvoll. In Verbindung mit Microservices und Self-contained Systems basierten Landschaften wird man kaum an Continuous Deployment oder Delivery vorbeikommen.
Zu guter Letzt möchten wir allen nahelegen, systematisch Qualitätssicherung mit einem hohen Automatisierungsgrad zu betreiben. Dafür dienen uns statische Analyseverfahren sowie Software- und Architektur-Reviews und Architecture Fitness Functions [10].
Für viele dieser Vorgehensweisen, Werkzeuge und Ansätze, um eine Softwarearchitektur zu bauen, ist der Hype abgeflacht. Sie sind unsere „Basics“ geworden. Arbeitsmittel, die von alten und jungen Architekt:innen zugleich geschätzt und täglich verwendet werden, um großartige Architekturen zu entwickeln. Wir denken, dass sie für den Erfolg oder Misserfolg einer Softwarearchitektur entscheidender sind, als die Frage, wie „trendy“ die Lösungen sind, die wir einsetzen.
Den eigenen Werkzeugkasten füllen – ohne jedem Trend zu folgen
Als Architekt:in können wir immer auf der Suche nach besseren Lösungen sein – gut. Aber wir müssen deren spezifische Limitationen berücksichtigen, um die richtigen Lösungen für die richtigen Probleme zu finden.
Die Fachmagazine und Konferenzen helfen uns dabei, IT-Trends zu entdecken, unsere Heuristiken zu überdenken und Kandidaten für Technologien zu empfehlen. Wir verpassen nichts, wenn wir eine Technologie nicht verwenden, die gerade prominent in aller Munde ist und vermeintlich erfolgreich überall eingesetzt wird.
Wir verpassen etwas, wenn wir Geschäftsmodelle nicht mehr unterstützen können, weil unsere zentralen Architekturentscheidungen (wie zum Beispiel der Fokus auf Tagesendverarbeitung) mittlerweile unpassend geworden sind. Wir verpassen etwas, wenn die Implementierung langwierig wird und wir nicht mehr zuverlässig Features bauen können, ohne die Systemintegrität über das tolerable Maß hinaus zu korrumpieren. Wir verpassen etwas, wenn wir uns nicht mehr mit den wesentlichen Fragen für unsere Systemerstellung und -pflege beschäftigen, sondern mit den Problemen der jüngsten Technologie, die noch gar nicht geeignet ist, das Problem zu lösen.
Fazit
Vielleicht wird unsere IT-Branche irgendwann erwachsen und blickt ein bisschen peinlich berührt auf ihre wilde Jugend zurück, als sie jedem neuen Architektur-Pop-Idol nacheifern wollte. Vielleicht werden wir aber auch immer eine Branche bleiben, in der die Angst davor, etwas zu verpassen, zu suboptimalen Entscheidungen führt.
Wir hoffen auf ein Erwachsenwerden. Die Freiheit, Entscheidungen im Sinne der maßgeblichen Stakeholder zu treffen, mag vielleicht nicht so aufregend sein, wie ständig neue Technologien zu erlernen und auf der Arbeit täglich mit neuen, schicken Tools zu experimentieren, aber eine Softwarearchitektur, die Probleme sehr elegant und ohne überflüssige Lösungskomplexität löst, ist nicht nur wirtschaftlich, sondern macht nachhaltig Freude.
Literaturhinweise
[1] M. Fowler, Design – Who needs an architect?. in: IEEE Software, 2003
[2] J. Spolsky, 2002,
siehe: www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions
[3] G. Hohpe, Cloud Strategy – A Decision-Based Approach to Successful Cloud Migration, Independently published, 2019
[4] E. M. Goldratt, The Goal: A Process of Onging Improvement, 1. Auflage 1984
[5] E. M. Goldratt, Beyond the Goal: Eliyahu Goldratt Speaks on the Theory of Constraints, AudioCD, 2011
[6] M. Fowler, Microservice Premium, siehe: martinfowler.com/bliki/MicroservicePremium.html
[7] G. Starke, Quality Driven Software Architecture, siehe: www.innoq.com/de/articles/2012/04/quality-driven-software-architecture/
[8] R. Kazman et al., Scenario-Based Analysis of Software Architecture, in: IEEE Software, 1996
[9] E. Evans, Domain-driven Design, Pearson, 2003
[10] S. Hofer, H. Schwentner, 2023, Domain Storytelling, dpunkt.verlag, 2023
[11] N. Ford et al., Building Evolutionary Software Architectures, O‘Reilly, 2nd Edition, 2023