Architekturdesign mit dem Architecture Decomposition Framework (ADF)
Version 1.0.0
Dieser Artikel fĂŒhrt in das Thema Architektur-Design ein, gibt dazu allgemeine RatschlĂ€ge und erklĂ€rt den ADF-Architekturdesignprozess.
Inhalt
- EinfĂŒhrung
- Ăberblick ĂŒber den Architekturdesignprozess
- Runtime first! (Laufzeit zuerst)
- System-Kontext-Abgrenzung
- System-Zerlegung
- QualitÀtsattribute zur Laufzeit
- Abbildung der Laufzeit auf die Entwicklungszeit und Entwicklungszeit-Zerlegung
- QualitÀtsattribute zur Entwicklungszeit
- Zusammenfassung
EinfĂŒhrung
Um ein System mit einer geeigneten Softwarearchitektur zu entwerfen, sind vor allem drei Dinge erforderlich:
- Erfahrung
- Erfahrung
- Erfahrung
Und natĂŒrlich etwas KreativitĂ€t, um diese Erfahrung auf neue Situationen anzuwenden.
WĂ€hrend man gut lernen kann, wie man sein Architekturdesign verstĂ€ndlich dokumentiert (z.B. durch die Verwendung des ADF und der ADF-Dokumentationsvorlage), braucht man zum Sammeln von Erfahrung mit Softwaresystem meist deutlich lĂ€nger. Man muss an einer Vielzahl unterschiedlicher Systeme arbeiten, um ein erfahrener Softwarearchitekt zu werden. DarĂŒber hinaus können sich Softwaresysteme stark unterscheiden. Eine Softwarearchitektur, die fĂŒr ein System geeignet ist, kann fĂŒr ein anderes System völlig ungeeignet sein.
Daher werden wir in diesem Dokument keine konkreten RatschlĂ€ge geben. Wir werden keine Aussagen treffen wie: âMicroservices sind derzeit das beste Architekturpatternâ, âTypeScript ist die beste Technologie fĂŒr die Client-Entwicklungâ oder âDas Hauptsystem sollte immer aus zwei oder drei Teilsystemen bestehenâ.
Wir wissen jedoch aus der Praxis, dass in vielen Softwareentwicklungsprojekten die Rolle des Softwarearchitekten:in nicht explizit zugewiesen wird. Oft ist es die Aufgabe des leitenden Entwicklers/der leitenden Enwicklerin, Entscheidungen ĂŒber die Softwarearchitektur zu treffen. Die meisten dieser Entscheidungen sind implizit und undokumentiert (d.h. auĂer durch den Quellcode des Projekts).
In diesem Dokument beschreiben wir einen generischen Architekturdesignprozess, der sowohl
- Softwareentwickler:innen und unerfahrene Architekt:innen anspricht, die nicht wissen, wie sie mit der Softwarearchitektur beginnen sollen, indem wir Ideen bieten, wie man das System als Ganzes betrachtet und es in handhabbare Teile zerlegt, bevor man mit dem Coden beginnt, als auch
- erfahrene Softwarearchitekt:innen, um ihnen eine bessere Strategie zur Gestaltung eines Systems zu zeigen, bei der sie immer die gewĂŒnschten QualitĂ€tsattribute im Auge behalten können.
Ăberblick ĂŒber den Architekturdesignprozess
Architekturdesign erfordert viele verschiedene AktivitĂ€ten. Unser Designprozess benennt diese AktivitĂ€ten und schlĂ€gt eine Reihenfolge vor, die hilft, sich auf das Endergebnis zu konzentrieren - ein adĂ€quates (laufendes) System, das alle Anforderungen und QualitĂ€tsattribute (d.h. die Architekturtreiber) erfĂŒllt. Dies ist der vollstĂ€ndige Prozess visualisiert:
Mit Treibern sind dabei alle Architektur-relevanten Anforderungen gemeint. Diese können Kernfunktionen, QualitÀtsattribute (zur Lauf- und Entwicklungszeit), GeschÀftziele und Randbedingungen umfassen.
In den folgenden Abschnitten werden wir die verschiedenen AktivitÀten (blaue KÀstchen in der Mitte der Abbildung) genauer erklÀren. Die kreisförmigen Pfeile auf der linken Seite deuten an, dass die AktivitÀten in den meisten FÀllen nicht genau einmal linear durchschritten werden, sondern viele Iterationen und Subiterationen möglich (und nötig) sind, um ein adÀquates System zu erhalten.
Die linke Seite (in Rot) zeigt, was als Eingabe fĂŒr jeden Schritt betrachtet werden sollte, wĂ€hrend die rechte Seite das entsprechende Architekturdokumentationsartefakt darstellt, das in jedem Schritt erstellt oder aktualisiert wird. Diese Artefakte mĂŒssen konsistent sein (âKonsolidierenâ). SchlieĂlich sollte jedes neue Designinkrement im System realisierbar sein, was z.B. mit Hilfe von Prototypen getestet werden kann (âVertrauen erhöhenâ).
Runtime first! (Laufzeit zuerst)
WĂ€hrend man als Entwickler:in nach einem ersten VerstĂ€ndnis der Ideen (Anforderungen) gerne direkt mit dem Coden loslegen möchte, sollten ein:e Softwarearchitekt:in zuerst das groĂe Ganze verstehen, einschlieĂlich der wichtigsten Anforderungen und QualitĂ€tsattribute des Systems. Zu diesem Zweck ist es viel hilfreicher, sich das System bereits existierend vorzustellen und dann die Technologien, Entwicklungstools und Code-Struktur entsprechend passend auszuwĂ€hlen, als umgekehrt. Daher behandeln die folgenden Kapitel zuerst das System zur Laufzeit.
System-Kontext-Abgrenzung
Wir beginnen damit, die Rollen der Benutzer:innen zu identifizieren, die mit dem System interagieren, und den Umfang des zu entwickelnden Systems festzulegen (das kann ein System oder mehrere Systeme sein, in einer Black-Box-Ansicht). Dann spezifizieren wir, wie die Rollen mit dem System interagieren: Was wollen sie erreichen?
ZusĂ€tzlich identifizieren wir alle externen Systeme, die in irgendeiner Form mit dem zu entwerfenden System interagieren. WofĂŒr werden die System benötigt? Gibt es eine Verbindung vom externen System mit zu dem zu entwickelnden System oder umgekehrt? Oder beides?
Das Ergebnis der Kontextabgrenzung kann mit Elementen der Software@Runtime-Palette dargestellt werden und gehört zur Dimension Function@Runtime.
Dies ist ein unspezifisches Beispiel dafĂŒr, wie ein solches Diagramm aussehen kann. NatĂŒrlich hĂ€ngt die tatsĂ€chliche Anzahl der Elemente und die Art und Weise, wie die Elemente verbunden sind, stark vom tatsĂ€chlichen System ab.
System-Zerlegung
In diesem Teil des Artikels beschreiben wir, wie man ein System in kleinere, handhabbare Teile zerlegt. Die verschiedenen Zerlegungsstrategien haben keine bestimmte Reihenfolge und können sogar zu inkompatiblen Architekturstrukturen fĂŒhren, wenn sie unabhĂ€ngig voneinander ausgefĂŒhrt werden. Wir benötigen also möglicherweise nicht alle. Wenn wir jedoch nicht von Anfang an schon wissen, dass unsere Architektur von einem bestimmten Aspekt (z.B. von Daten) getrieben werden soll, probieren wir möglichst viele verschiedene Zerlegungsstrategien aus und entscheiden uns fĂŒr die am besten geeignete oder kombinieren Ideen aus allen.
Hierarchische funktionale Zerlegung
Normalerweise muss ein System verschiedene FunktionalitÀten bereitstellen, z.B. einen Kunden authentifizieren, Artikel zum Kauf anzeigen, Artikel in einen Warenkorb legen, Zahlungen vornehmen und so weiter.
Diese Zerlegungsstrategie teilt das System in kleinere, funktionale Teile auf. Wenn wir mehr als ein System entwerfen, tun wir dies fĂŒr jedes System.
Das Ergebnis der Kontextabgrenzung kann mit Elementen der Software@Runtime-Palette dargestellt werden und gehört zur Dimension Function@Runtime.
Dies ist ein unspezifisches Beispiel dafĂŒr, wie ein solches Diagramm aussehen kann. NatĂŒrlich hĂ€ngt die tatsĂ€chliche Anzahl der Elemente und die Art und Weise, wie die Elemente verbunden sind, stark vom tatsĂ€chlichen System ab.
Oft ist die funktionale Zerlegung hierarchisch, wobei Komponenten rekursiv in Unterkomponenten und sogar Unter-Unterkomponenten unterteilt werden, z.B.
- das System ist unterteilt in
- Komponente 1, die unterteilt ist in
- Komponente 1a und
- Komponente 1b
- Komponente 2, die unterteilt ist in
- Komponente 2a,
- Komponente 2b,
- Komponente 2c, die unterteilt ist in
- Komponente 2c1 und
- Komponente 2c2
- Komponente 2d, die unterteilt ist in
- Komponente 3, die unterteilt ist in
- Komponente 3a,
- Komponente 3b und
- Komponente 3c,
- âŠ
- Komponente 1, die unterteilt ist in
Dies kann durch Diagramme dokumentiert werden, die eine detaillierte Zerlegung bestimmter Komponenten wie dieses (unspezifische) Beispiel zeigen:
Dies ist viel ĂŒbersichtlicher, als alle Komponenten und Unterkomponenten in einem einzigen Diagramm darzustellen.
Datengetriebene Zerlegung
Software-Ingenieur:innen sind darin geschult, ausgeklĂŒgelte Datenmodelle zu entwickeln und sie in UML-Klassendiagrammen oder SQL-Tabellenbeschreibungen auszudrĂŒcken. WĂ€hrend diese Modelle wĂ€hrend der Entwicklung entscheidend sind, empfehlen wir, zunĂ€chst einen Schritt zurĂŒckzutreten und das gesamte System zur Laufzeit zu betrachten: Welche verschiedenen Daten gibt es im System? Können verschiedene DomĂ€nen identifiziert werden? Ein Webshop hat beispielsweise Benutzerdaten, Artikeldaten, Warenkorbdaten und Zahlungsdaten. Sobald die wichtigsten DatenentitĂ€ten identifiziert sind, können sie weiter verfeinert werden, z.B. durch Aufteilung oder HinzufĂŒgen von Attributen. Beachten Sie, dass es in diesem ersten Schritt nicht um Vererbung oder Datentypen geht, sondern um die allgemeine Struktur der Daten.
Das Ergebnis der datengetriebenen Zerlegung kann mit Elementen der Software@Runtime-Palette dargestellt werden und gehört zur Dimension Data@Runtime.
Dies ist ein unspezifisches Beispiel dafĂŒr, wie ein Diagramm mit den wichtigsten DatenentitĂ€ten aussehen kann. NatĂŒrlich hĂ€ngen die tatsĂ€chlichen EntitĂ€ten stark vom tatsĂ€chlichen System ab.
An dieser Stelle gilt es festzustellen, dass Datengetriebene Zerlegung groĂen Einfluss auf die funktionale Zerlegung haben kann. Daten existieren normalerweise nicht fĂŒr sich alleine, sondern werden erstellt und durch das System geschickt. Daher ist es sinnvoll, funktionale und Datenansichten zu verbinden, z.B. indem man den Datenfluss zwischen Komponenten angibt. Ein gĂ€ngiger Ansatz im modernen Softwaredesign ist das sogenannte Domain Driven Design, bei dem die verschiedenen DomĂ€nen (und ihre Datenmodelle) die Struktur des gesamten Systems bestimmen. Welcome to DDD von der DDD-Crew ist ein guter Ausgangspunkt, um mehr zu erfahren.
Dynamische Systembeschreibung
Je komplexer die Komponentenstruktur eines Systems ist, desto weniger offensichtlich scheint es, wie, in welcher Weise und insbesondere in welcher Reihenfolge die Komponenten miteinander interagieren. Es gibt verschiedene Möglichkeiten, diese Aspekte zu beschreiben; vorausgesetzt natĂŒrlich, dass wir bereits einige Komponenten identifiziert und spezifiziert haben.
Eine einfache Möglichkeit ist das fortlaufende Nummerieren der Beziehungen zwischen Komponenten und eine Beschreibung, was in jedem Schritt passiert. Hier ist ein unspezifisches Beispiel dafĂŒr, wie das aussehen kann:
Diese Darstellung kann jedoch leicht unĂŒbersichtlich werden, wenn kompliziertere FĂ€lle oder optionale Pfade beschrieben werden sollen. In diesem Fall eignen sich UML-Sequenzdiagramme besser (gleiches Beispiel noch mal als Sequenzdiagramm):
Das ADF-Sichten-Framework fĂŒhrt keine besondere Notation fĂŒr Sequenzdiagramme ein - wir verwenden einfach diejenige, mit der wir am besten vertraut sind (im Zweifel einfach UML).
Deployment-getriebene Zerlegung
Um das Thema Deployment (Bereitstellung) zu behandeln, betrachten wir, wie die verschiedenen FunktionalitĂ€ten des Systems zur AusfĂŒhrung gebracht werden. Viele verschiedene Deployment-Arten sind vorstellbar: (Desktop-)Client-Deployment, Server-Deployment, Zweischicht- oder Mehrschicht-Client-Server-Topologien, Peer-to-Peer-Netzwerke, monolithische Backends, Microservices, Bare-Metal- oder virtualisierte Server, containerisiertes Deployment und viele mehr. Verschiedene Deployment-Methoden bestimmen auch die Art der Kommunikation zwischen Komponenten: Methodenaufrufe, HTTP-Anfragen, Event- oder Message-Busse - um nur einige zu nennen.
Wenn unsere Software Teil einer bereits bestehenden Software oder eines Systems ist, z.B. ein Plugin einer Desktop-Software oder ein weiterer Dienst fĂŒr einen Enterprise-Service-Bus, ist es sinnvoll, zuerst die bestehende Systemlandschaft zu visualisieren und zu verstehen sowie sich zu ĂŒberlegen, wie die eigene Komponenten/das eigene System in diese Landschaft integriert (deployt) wird, bevor man die eigene Komponente weiter in Bezug auf Funktionen und Daten zerlegt.
In den meisten FĂ€llen haben wir jedoch bereits verschiedene Komponenten und deren Interaktion (funktionale Zerlegung) identifiziert, wenn wir beginnen, unser System Deployment-getrieben zu zerlegen. In diesem Fall mĂŒssen wir die funktionalen Teile des Systems auf eine oder mehrere AusfĂŒhrungsumgebungen oder Computing Nodes (âRechenknotenâ) verteilen. Es ist nicht ungewöhnlich, dass eine Deployment-getriebene Zerlegung eine weitere funktionale Zerlegung (z.B. client- und serverseitige FunktionalitĂ€t) oder eine datengetriebene Zerlegung (z.B. Request-/Response-Modell oder ein Event-Modell) auslöst.
Das Ergebnis der Deployment-getriebenen Zerlegung kann mit Elementen der Environment@Runtime-Palette dargestellt werden und gehört zur Dimension Deployment@Runtime.
Dies ist ein (immer noch ziemlich unspezifisches) Beispiel dafĂŒr, wie ein Deployment-Diagramm aussehen kann, wenn Client-Server-Architektur und zwei verschiedene Client-Apps verwendet werden. Aufgrund der zuvor erwĂ€hnten immensen Vielfalt an verschiedenen Deployment-Arten können Inhalt und Topologie von Bereitstellungsdiagrammen stark variieren.
Auswahl der Technologien zur Laufzeit
Blicken Köch:innen auf ihre verfĂŒgbaren Töpfe, Pfannen und Messer, um zu planen, was auf der nĂ€chsten Speisekarte stehen soll? Eher nicht. Ebenso empfehlen wir, keine voreiligen Technologieentscheidungen zu treffen, bevor das tatsĂ€chliche System und seine beabsichtigte Architektur verstanden sind. Allerdings sind völlig technologie-agnostische Architekturen kaum vorteilhaft. Daher sollten wir immer versuchen, Technologieentscheidungen zu treffen, die adĂ€quat sind, um das Problem/die Anforderungen zu lösen (nicht umgekehrt), und diese Entscheidungen explizit machen sowie die GrĂŒnde angeben, die zu den Entscheidungen gefĂŒhrt haben.
Technologieentscheidungen, welche die Laufzeit betreffen, gehören zur Dimension Technologies@Runtime. Sie können als eigene Ansicht modelliert oder in bestehende Ansichten integriert werden. Wir können dazu das Technologieelement verwenden, das in allen Elementpaletten verfĂŒgbar ist.
In diesem Beispiel werden zwei verschiedene Möglichkeiten zur Annotation von Technologien demonstriert: Die UML-Implementierungsbeziehung (linke Seite) und die Nutzungsbeziehung (rechte Seite). Das Technologieelement können wir in jedem Diagrammtyp verwenden.
Aufgepasst: Wir sind immer noch dabei, unser (beabsichtigtes) System zur Laufzeit zu beschreiben. Technologieentscheidungen fĂŒr die Entwicklung werden spĂ€ter in eigenen dedizierten Ansichten getroffen und dokumentiert.
QualitÀtsattribute zur Laufzeit
Nachdem wir diesen Schritt erreicht haben, sollten wir nun eine gute Vorstellung davon haben,
- wie das System die HauptfunktionalitÀt abbildet (Komponenten, Teilsysteme usw.),
- welche Daten vom System verwaltet werden und
- wie das System bereitgestellt wird.
Dabei haben wir möglicherweise bereits Technologieentscheidungen getroffenen und dokumentiert.
Jetzt ist es an der Zeit, die QualitĂ€tsanforderungen des Systems zu ĂŒberprĂŒfen. Das Erreichen bestimmter QualitĂ€tsziele kann zu einer Transformation des bisher modellierten Systems fĂŒhren. Dabei kann es notwendig sein, neue Komponenten oder zusĂ€tzliche Schichten einzufĂŒhren, bestimmte Komponenten neu zu strukturieren, wĂ€hrend der Bereitstellung zu skalieren oder andere Technologien auszuwĂ€hlen - um nur einige Beispiele zu nennen. Dieser Prozess ist stark abhĂ€ngig vom tatsĂ€chlichen System und seinen QualitĂ€tsanforderungen. Er fĂŒhrt oft zu einer Wiederholung einiger der vorherigen Zerlegungsschritte.
Nehmen wir ein konkretes Beispiel fĂŒr eine qualitĂ€tsgetriebene Transformation des Systems: Wir stellen uns vor, dass wir unser System als Client und Server entworfen haben, wobei der Server eine Linux-Maschine mit einem REST-Backend ist. Jetzt wĂ€hlen wir einen VerfĂŒgbarkeits-Treiber - eine QualitĂ€tsanforderung, die verlangt, dass 99 von 100 Anfragen nicht fehlschlagen dĂŒrfen. Um diesen Treiber zu realisieren, entscheiden wir uns, das Deployment zu Ă€ndern und zwei Linux-Maschinen mit dem Backend darauf plus einen Loadbalancer bereitzustellen, der fehlerhafte Server neu startet und Anfragen an eine noch verfĂŒgbare Serverinstanz weiterleitet. Dies ist eine Transformation der bereits bestehenden Deployment-getriebenen Zerlegung unter dem Aspekt der VerfĂŒgbarkeit. NatĂŒrlich gibt es andere Möglichkeiten, hohe VerfĂŒgbarkeit zu erreichen - dies ist nur ein Beispiel.
Abbildung der Laufzeit auf die Entwicklungszeit und Entwicklungszeit-Zerlegung
Wir haben nun ein tiefes VerstĂ€ndnis dafĂŒr gewonnen, wie unser System zur Laufzeit zusammengesetzt ist. Als nĂ€chster Schritt mĂŒssen wir unsere Entwicklungsinfrastruktur und unseren Code-Basis einrichten, der letztendlich unser System produzieren wird.
Abbildung der Laufzeit auf die Entwicklungszeit
Eine wichtige AktivitÀt besteht darin, Komponenten (zur Laufzeit) ihren realisierenden Modulen (zur Entwicklungszeit) zuzuordnen. Im Allgemeinen sind alle Arten von Beziehungen möglich, wie die folgende Abbildung zeigt.
Die gelben Elemente stammen dabei aus der Software@Runtime-Palette, wĂ€hrend die grĂŒnen Elemente aus der Software@Devtime-Palette stammen. Dies ist eine der wenigen Arten von Ansichten, bei denen die Verwendung von sowohl Laufzeit- als auch Entwicklungselementen erwĂŒnscht ist.
Wenn wir einem objektorientierten Programmierparadigma folgen, werden Module normalerweise durch Klassen realisiert. Oft werden 1:1-Beziehungen hergestellt. In diesem Fall mĂŒssen wir keine explizite Ansicht erstellen, die die Zuordnung veranschaulicht, vorausgesetzt, es wird eine konsistente Benennung verwendet. In vielen Situationen lohnt es sich jedoch, Komponenten-Modul-Beziehungen explizit zu machen, z.B. wenn eine Klasse, die eine Komponente realisiert, von einer anderen Klasse erbt (1:2), wenn eine Komponente mit zusĂ€tzlichen Klassen aus einem Framework realisiert wird oder wenn ein Modul mehrere verschiedene Komponenten realisiert.
Eine Diagramm zum Aspeket âAbbildung der Laufzeit auf die Entwicklungszeitâ kann auch beschreiben, welche Teile des Quellcodes (z.B. welches Paket) welchen Teil des laufenden Systems realisieren. Es kann sein, dass Code in einem bestimmten Paket eine bestimmte Schicht implementiert, z.B. die UI-Schicht (horizontale Zerlegung) oder ein bestimmtes Cluster, das sich mit einem bestimmten Teil der DomĂ€nendaten befasst, z.B. Benutzerdaten (vertikale Zerlegung).
Diese Abbildungen können bei komplexeren Komponentenstrukturen, der Kombination von Schichten und Clustern und der Verwendung von Unterpaketen umfangreicher werden.
Auch wenn es naheliegend ist, all diese Entwicklungszeitinformationen in bestehende Laufzeitsichten zu integrieren, erstellen wir lieber zusĂ€tzlich explizite Laufzeit-zu-Entwicklungszeit-Sichten, um bestehende Sichten nicht zu ĂŒberladen.
Zerlegung auf Entwicklungszeit-Ebene
WĂ€hrend des Prozesses der Zuordnung von Laufzeit zu Entwicklungszeit benötigen wir normalerweise mehrere Iterationen, um unsere Entwicklungszeitstrukturen sukzessive zu verfeinern. Dies ist eine weitere Zerlegung des Systems, aber jetzt fĂŒr den Entwicklungszeitteil. Die Zerlegung kann auf verschiedenen Ebenen erfolgen. Hier sind einige Beispiele:
- Erstellen verschiedener Quellcode-Repositories fĂŒr verschiedene Teile des Systems (z.B. Backend, Client-Apps, gemeinsame Bibliotheken) und Entwickeln eines Versionierungsmechanismus - oder vielleicht die Verwendung eines Monorepos fĂŒr den gesamten Code, aber dann Definieren einer wartbaren, einheitlichen Struktur innerhalb dieses Repos,
- Extrahieren von wiederverwendbarem Code aus Modulen, indem er in gemeinsame Superklassen (Vererbung) oder flexibel zusammensetzbare Funktionen (Komposition) eingefĂŒgt wird,
- Erstellen eines Datenmodells, das geeignet ist, in einer Datenbank gespeichert zu werden, indem Datentypen spezifiziert und Beziehungen zwischen EntitÀten modelliert werden (selbst wenn nicht-relationale Datenmodelle verwendet werden, sind einige EntitÀten durch eine gemeinsame ID verbunden),
- Einrichten von Build-Prozessen und Bereitstellung fĂŒr die verschiedenen Teile des Systems.
Entwicklungszeit-Zerlegungsentscheidungen gehören zu den Dimensionen Software@Devtime und Environment@Devtime und können mit der Software@Devtime-Palette und der Environment@Devtime-Palette modelliert werden.
Stellen Sie sicher, dass Sie auch alle Technologieentscheidungen fĂŒr das System zur Entwicklungszeit (und deren BegrĂŒndungen) dokumentieren: Programmiersprache(n), Frameworks, Bibliotheken, IDEs, Build-Server, Code-Checker, ⊠Dies kann Ă€hnlich wie im Abschnitt Auswahl der Laufzeittechnologie beschrieben werden.
QualitÀtsattribute zur Entwicklungszeit
Anforderungsdokumente enthalten selten viele Informationen zu QualitĂ€tsattributen zur Entwicklungszeit wie z.B. Testbarkeit, Erweiterbarkeit, AnpassungsfĂ€higkeit und Wartbarkeit. Dennoch haben diese QualitĂ€ten einen groĂen Einfluss auf die Korrektheit, ZuverlĂ€ssigkeit und PortabilitĂ€t des Systems. DarĂŒber hinaus reduziert eine gut vorbereitete CI/CD-Pipeline die MarkteinfĂŒhrungszeit neuer Funktionen drastisch.
Daher ist es entscheidend, kontinuierlich auf QualitĂ€tsattribute zur Entwicklungszeit zu achten und, wenn sie nicht von Anfang an erfĂŒllt sind, den Entwicklungszeitstruktur des Systems zu transformieren, um diese QualitĂ€tsattribute zu erfĂŒllen. Dies kann bedeuten, eine einheitliche Codeorganisation ĂŒber mehrere Module und Pakete hinweg zu etablieren, Service-Schnittstellen fĂŒr bessere automatisierte Modultests zu extrahieren, Code-Smells zu reduzieren, automatisierte Builds einzufĂŒhren und vieles mehr.
Zusammenfassung
Architekturdesign ist ein Prozess mit vielen AktivitÀten:
Je mehr Erfahrung wir haben, desto einfacher ist es fĂŒr uns, verschiedene Lösungsideen zu entwickeln und die am besten passende zu finden. Wenn wir weniger erfahren sind oder unser Hintergrund hauptsĂ€chlich in der Softwareentwicklung liegt, versuchen wir, die ersten drei AktivitĂ€ten nicht zu ĂŒberspringen, sondern
- den Systemkontext abzugrenzen,
- das System zur Laufzeit in handhabbare Teile zu zerlegen und
- QualitÀtsattribute anzuwenden,
bevor wir mit der Entwicklung beginnen.
Wir empfehlen, die Ergebnisse jedes Designschritts in einer Architekturdokumentation zu dokumentieren, z.B. der ADF-Dokumentationsvorlage. Dort ist Platz dafĂŒr vorgesehen, um die Systemzerlegung sowie Lösungskonzepte zur ErfĂŒllung der QualitĂ€tsanforderungen zu beschreiben.