Software Architekturen

Dec 29, 2016

development

Eine kurze Zusammenfassung einiger Themen (nicht vollständig)

Hast du Bauch- und Kopfweh, dann schau dir spätestens jetzt das Thema Software Architekturen an. Inzwischen habe ich einige interessante Erfahrungen bzgl. dieses Themas gemacht:

  • Viele wissen nicht, was eine Software-Architektur überhaupt ist. Das Wort ist in vielen Münder - ein paar “Kastln und Linien” halt – die irgendwer vorher mal gemacht hat … Oft wird es auch mit Software-Design und Solution-Architektur verwechselt …
  • Das Thema interessiert nicht viele. Ich habe die Erfahrung gemacht, dass man am Projektbeginn kurzzeitig in die Rolle “schlüpft”. Hier und da ein paar Dokumente mit Diagrammen: “Fancy-Names” für ein paar “Boxen” - ein paar Linien, vielleicht noch ein Sequenzdiagramm über Schönwetterfälle, um das Ganze ein bisschen abzurunden. Fragt man dann Verantwortliche, ob sie sich schon Gedanken gemacht haben, wie das Protokoll zwischen den Komponenten ausschaut – Fehlanzeige. Das kommt ja im Laufe der Zeit … Emergente-Architekturen können eben auch falsch praktiziert werden …. Wohlgemerkt rede ich hier nicht von trivialen Architekturen, wo sich die Entwicklung auf das “herunter-programmieren” von e.g. Formularen beschränkt …
  • That´s just the way it is. Komplizierte Refactoring-Sprints werden oft als gegeben hingekommen. Software ist komplex. Unser Problem ist komplex. Oft vergleichbar mit dem Hausbau: Man fängt mit Erdgeschoss Zimmer 1 und Zimmer 2 an. Dann kommt man drauf, dass die Einteilung der Zimmer ungünstig ist und Zimmer 1 und 2 besser getauscht gehören. Aber kein Mensch hierzulande wird einen Hausbau ohne einen “Blue-Print” anfangen … Dass man sich an den Architekten des Vertrauens wendet ist hierzulande selbstverständlich. Und eine solcher Umbau in Bauphase würde man als sehr kritische bezeichnen – nicht so aber bei Software. Hier nimmt man es als gegeben hin …
  • Das richtige Maß finden. Wie viel Software-Architektur Up-Front Design ist genug? In welcher Form macht man es? Eine sehr schwierige Frage, die auch nicht gerne beantwortet wird, weil man sich vermutlich die Finger nicht verbrennen will. Aber auch hier sollte man recht zielsicher ans Werk gehen: das korrekte Maß an Up-Front Design sollte erkannt werden um die genannten Risiken zu eliminieren bzw. zu senken.

Aber beginnen wir am Anfang: Was ist nun Software-Architektur?

Unknown

Das Bild sagt die Wahrheit. Aber: Es gibt keine eindeutige Definition. Das zeigt auch die Sammlung von 150 Definitionen auf dieser Seite.

The software architecture of a computing system is the set of structures needed to reason about the system, which comprise software elements, relations among them, and properties of both. […] These structures, carefully chosen and designed by the architect, are the key to achieving and reasoning about the system’s design goals. And those structures are the key to understanding the architecture. [1]

Die Architektur kann durch Strukturen (Elemente, deren Verbindungen und Eigenschaften) ausgedrückt werden. Der Architekt kann diese Strukturen im Vorfeld planen. Es hilft – wie beschrieben – die Architektur zu verstehen und sie dazu zu benutzen, um gestellte Fragestellungen (im Vorfeld) beantworten zu können (siehe u.a. Diskussion).

Fairbainks [4] bringt auch eine interessante Analogie: Um die Frage zu beantworten (to reason about the U.S.A.) “Which U.S. cities can you travel to by boat?” Ist nicht ein vollständiges Modell der USA notwendig, sondern es genügt ein Modell, das es erlaubt, diese Fragen zu beantworten.

Anhand von weiteren Zitaten, welche mir sehr gut gefallen haben, will ich versuchen, den Begriff “Architektur” weiter einzugrenzen.

In this book, you will learn how to use models and abstractions to reason about your software systems, specifically about their software architecture. [4]

Wie in einen meiner letzten Blogposts erklärt: ein Model ist immer eine Abstraktion. Auch bei Architekturen bedient man sich dieser Abstraktionen um über die Architektur Schlüsse ziehen zu können (e.g. Fragestellungen beantworten).

Every application has an architecture: […] … it is evident that every building has an architecture. That is not to say that every building has an honorable, or elegant, or effective architecture […]

Unknown

Every application has at least one architect: […] The architect is the person or, in most cases, group who makes the principal decisions about the application, who establishes and (it is hoped) maintains the foundational design. […] Architecture is not a phase of development: […] In a simplistic, traditional, and inaccurate understanding, the architecture is a specific product of a particular phase in the development process that succeeds identification of requirements and that precedes detailed design. […] [2]

Auch dieses Aussagen sind essentiell: Gleich wie bei der Architektur eines Hauses: Das Haus hat immer eine Architektur – egal ob man sich im Vorfeld drüber Gedanken gemacht hat und wichtige Aspekte geplant hat oder nicht. Auch die Annahme, dass die Architektur ein Outcome aus einer Entwicklungsphase ist, ist schlichtweg falsch.

In this posting he brought out the point that architecture is a subjective thing, a shared understanding of a system’s design by the expert developers on a project. Commonly this shared understanding is in the form of the major components of the system and how they interact. It’s also about decisions, in that it’s the decisions that developers wish they could get right early on because they’re perceived as hard to change. [3]

Das shared understanding of a system’s design ist wichtig. Auch Components und Connectors ist etwas, auf das man des Öfteren stoßen wird. Was diese Elemente genau bedeuten, werde ich später noch einmal analysieren. Abschließend noch ein Klassiker [5]:

The architecture is a carrier of the earliest and hence most fundamental, hardest-to-change design decisions. Any design, in any discipline, can be viewed as a set of decisions.

Essentielle Fragen wie e.g. verteiltes System vs. Nicht-verteiltes System, Rich-Client-Application vs. Web-Application sollten vorweg getroffen werden. Aber auch die Einteilung der Komponenten kann Schmerzen bereiten, wenn sie nicht getroffen wurde. Ich finde, dass die Punkte oft nicht berücksichtigt werden und einfach drauf los entwickelt wird. Das böse Erwachen kommt je nach Komplexität aber gewiss.

Good architectural design is difficult (and still rare), and it does not just “emerge”. [6]

Architecture Drivers [5] [6]

Oreilly

Einer der besten und einleuchtendsten Ansichten die ich gefunden habe. Es sind jedoch einige Dinge zu beachten (diese werden oft nicht beachtet und führen dazu, dass man sich erst gar nicht mit Architektur-Planung beschäftigt): Es gilt nicht die optimale Lösung zu finden – es wird stets von einer acceptable solution gesprochen. Das sollte man sich vor allem zu Herzen nehmen, wenn man mit dem Argument kommt, dass das “Budget” und die “Zeit” Mangelware sind …

Mache die Dinge so einfach wie möglich – aber nicht einfacher. (Albert Einstein)

Die erste Frage dich sich stellt ist: Was ist der Unterschied zwischen Design und Architektur?

The first thing we can say is that clearly architecture is design, but not all design is architecture. … Thus, architectural decisions are ones that permit a system to meet its quality attribute and behavioral requirements. All other decisions are nonarchitectural. [2]

Entscheidungen (e.g. die Buffering Strategy) können architekturell oder nicht-architekturell sein: hat die Buffering-Strategy Einfluss auf Architecture-Drivers (e.g. nicht-funktionale Anforderungen wie Performance), so ist sie natürlich auch von Interesse. Sonst ist es eine Entscheidung, die man auch dem Entwickler überlassen kann. [6]

Architectural design generally results in the identification of only a subset of the elements that are part of the system’s structure. This is to be expected because, during initial architectural design, the architect will focus on the primary functionality of the system. What makes a use case primary? A combination of business importance, risk, and complexity considerations feed into this designation.

Auch hier steckt wieder eine Sache, die gerne vergessen wird: Wenn ich eine Gartenhütte mit meinem Kollegen baue (niedrige Business-Importance, geringes Risiko, geringe Komplexität), wird es reichen, wenn wir uns kurz hinsetzen, und auf einem A4 die Hütte freihändig skizieren, um ein Common-Understanding zu haben. Baue ich ein 3-stöckiges Mehr-Parteien Haus, werde ich schon mal mein AutoCAD anwerfen und mich mit mehreren Kollegen konsultieren und etwas mehr Aufwand hineinstecken – alleine aus dem Grund, weil das Risiko zu hoch ist, dass zum Schluss nicht das Gewünschte herauskommt. Aber ich werde nicht jedes Detail modellieren – die Detailplanung der Küche stellt bei der Konstruktion / Planung des Hauses nur ein geringes Risiko da – lediglich die Anschlüsse werden geplant. Den Rest überlässt man dem “Entwickler” …

My brother builds skyscrapers and he tells me that, in his field, the architect will usually specify some low-level details, but leave others to be decided by the construction company. The architect includes details in the architecture if they contribute to an overall quality of the building, such as its watertightness, aesthetic appeal, or constructability. Otherwise a detail is considered non-architectural. On a recent job of my brother’s, the architect insisted that the gap between windows be quite small because this detail was important for the architect’s intention about the building’s appearance. [4]

Allerdings heißt das nicht, dass man andere Teile des Systems nicht planen / designen soll. So kann ein Entwickler durchaus für Komponenten auch Klassen-Diagramme zeichnen, wenn es die Kommunikation im Team erleichtert oder es erforderlich ist (e.g. Dokumentation wegen Komplexität).

The starting point of architecture design is most often a preexisting package of design decisions. Very few architects design systems completely by closing their eyes, thinking hard, and conjuring up a brand-new design. [1]

The term “detailed design” is often used to refer to the design of the internals of modules. Although it is widely used, we really don’t like this term, which is presented as somehow in opposition to “high-level design”. We prefer the more precise terms “architectural design”, “element interaction design”, and “element internals design” [6]

Zurück zum Bilde. Die einzelnen Elemente sind wie folgt zu verstehen [6]:

  • Design Purpose: Die Architektur kann man e.g. im Vorfeld für eine Ausschreibung machen: Vor allem in Bereichen, in denen man von Ausschreibungen lebt (e.g. Software für den öffentlichen Dienst), muss man oft (Software- / Solution-)Architekturen präsentieren, um den Kunden einen besseren Einblick zu gewährleisten. Ein weiterer Grund könnte sein, dass man ein neues Software-Projekt startet, und deswegen die Architektur planen / dokumentieren will. Sehr interessant finde ich auch den Gedankengang, dass Unternehmens-Ziele (siehe auch Business-Analyse) zu Änderungen im Design-Purpose führen können (e.g. wenn Erweiterungen in Zukunft geplant werden). Wichtig – wie auch bei der Business Analyse – ist, sich zu fragen, warum betreibe ich den Effort. Wenn ich die Frage nicht beantworten kann, sollte man kritisch hinterfragen, ob man gerade das richtige macht (für mich ein Signal, dass man auf dem Weg ist, “sinnlose Dokumente” zu generieren).

Architectures exist to help achieve business goals.

  • Quality Attributes: quality attributes are defined as being measurable or testable properties of a system that are used to indicate how well the system satisfies the needs of its stakeholders. Das ist einer der wichtigsten Driver einer Architektur. Sehr interessant ist auch die Empfehlung, Scenarios als Tool für die Beschreibung zu verwenden, statt komplizierte Beschreibungen der einzelnen Attribute.

It is meaningless to say that a system will be “modifiable”, because every system is modifiable with respect to some changes and not modifiable with respect to others.

Ein Beispiel-Scenarios ist: Performance: Several time servers send traps to the management system at peak load; 100% of the traps are successfully processed and stored. Ein weiteres Beispiel: Modifiability: A new time server management protocol is introduced to the system as part of an update. The protocol is added successfully without any changes to the core components of the system. Man sieht, dass durch Szenarien die Hintergründe für Quality-Attributes klarer werden.

  • Primary Functionality: Die Funktionalität des Systems ist das, was zählt, da es dem Kunden den Mehrwert gibt. Allerdings ist es egal, wie die Funktionalität intern umgesetzt ist (Monolith vs. Modular). Die Primary-Functionality beschreibt jene Funktionalität, welche uns unsere Business Goals erreichen lassen. Die primäre Funktionalität ist wichtig, weil die Funktionalität Architektur-Elementen zugeordnet werden kann und somit e.g. nicht-funktionale Anforderungen geplant werden können (e.g. Modifybility). Auch sind manche Quality-Attribute Scenarios direkt zur Primary-Functionality verbunden. Man sieht also, dass generische Architekturen (damit meine ich nicht Architecture-Styles – sondern Copy-Paste-highscalability.com-Architekturen) oft schwer funktionieren. Man kann sich die Architekturen anschauen, weil man eventuell gerade in einer ähnlichen Domäne aktiv ist, aber man sollte die eigene Funktionalität kennen und diese auf die Architektur anwenden.
  • Architectural Concerns: Dies sind nicht klassische Requirements, werden aber im Zuge des Architektur-Designs berücksichtigt. Als Beispiele wurden aufgezählt [6]:
    • General concerns: Allokation der Module zu Teams, Start-Up-Shutdown, Updates, Delivery & Depolyment, usw.
    • Specific concerns: Exception-Management, Dependency-Management, Configuration, Logging, Authentication, Authorization, Caching, … Des Weiteren gibt es noch Internal-Requirements (betreffen das Team) und Issues (entstehen meist durch Analyse im Laufe der Zeit).
  • Constraints: Gibt Einschränkungen hinsichtlich e.g. Technologien und anderen Systemen an, welche beim Designen berücksichtigt werden müssen.

Was man auf jeden Fall sieht – und was auch zum Nachdenken anregen sollte: Der Architekt muss viele Parameter / Einflussfaktoren berücksichtigen. Je nach Projekt können diese natürlich in der Anzahl bzw. Ausprägung variieren – aber es sollte auch klar sein, dass pure emergente Architekturen nicht immer zielführend sind.

Wie viel Architektur ist genug?

Fairbanks argumentiert, dass es ein Lager gibt, welches sich für das Architecture-Focused Design ausspricht [4]. Hier versucht man ein detailliertes Design zu erstellen und zu dokumentieren. Am anderen Ende stehen die bereits erwähnten Verfechter der Emergenten-Architekturen. Was Fairbanks festhält - und wo ich ihm auch zu 100% zustimme – ist, dass keiner dieser Ansichten für alle Systeme funktionieren kann. Er stellt die Frage nach “How much explicit architectural design should one carry out for a given system?”.

There is no need for meticulous designs when risks are small, nor any excuse for sloppy designs when risks threaten your success. [4]

You should not expect any silver bullets, …, that will suddenly eliminate the difficulties of software development (Brooks, 1995). Instead, you should look for weapons that help you partition systems better, provide knowledge, and enable abstraction to reveal the essence of the problem. [4]

Das Spiral-Modell nach Böhm ist ein generisches Risk-Driven Process-Model. Wikipedia beschreibt die Schritte, welche in jedem Zyklus durchgeführt werden:

  • Festlegung von Zielen, Identifikation von Alternativen und Beschreibung von Rahmenbedingungen
  • Evaluierung der Alternativen und das Erkennen, Abschätzen und Reduzieren von Risiken, z. B. durch Analysen, Simulationen oder Prototyping
  • Realisierung und Überprüfung des Zwischenprodukts
  • Planung des nächsten Zyklus der Projektfortsetzung.

Es gibt auch ein ganzes Buch zu dem Thema – hab ich allerdings nie gelesen. Fairbanks [4] nennt auch 5 Beispiele, für ein hohes architekturelles Risiko:

  • Small solution space: Wenn der Solution-Space klein oder schwer zu erreichen ist (e.g. Aeronautik)
  • High failure risk: Wie hoch ist das Riko im Falle eines Fehlers?
  • Difficult quality attributes: Stichwort Skalierbarkeit
  • New domain: Unbekanntes Terrain birgt immer ein gewisses Risiko
  • Product lines: Hier werden Architekturen geteilt. Manche Produktvariationen werden dadurch einfacher, andere schwerer.

Dass bei diesen Beispielen ein Risiko besteht, sollte jedem klar sein. Fairbanks [4] zeigt auch 3 Ausprägungen von Designs:

  • Architecture-Indifferent Design: In diesem Ansatz wird der Architektur nur wenig Aufmerksamkeit geschenkt. Eine Ursache kann sein, dass Entwickler die Architektur ignorieren und einfach von einem vorherigen Projekt übernehmen oder eine in der Domäne übliche Architektur anwenden (Presumptive Architecture)
  • Architecture-Focused Design: Hier wählt und entwirft man die Architektur bewusst. Die Architektur wird so gestaltet, dass sie die gesetzten Ziele erfüllt und die funktionalen und nicht-funktionalen Attribute erfüllt. Der Architektur Aufmerksamkeit schenken, bedeutet nicht zwangsläufig, diese zu dokumentieren - wenngleich Dokumentation in großen Teams eine Hilfe sein kann. Auch kann der Code vom Architektur-Design abweichen.
  • Architecture Hoisting: Hier fokussiert man sich auf die Architektur, um ein Ziel (Goal) oder eine Eigenschaft des Systems zu garantieren (gleich wie bei Architecture-Focused Design). Allerdings werden die Eigenschaften des Architektur-Designs garantiert (d.h. modellierte Eigenschaften finden eine Abbildung im Code – der Entwickler muss keinen zusätzlichen Code dafür schreiben).

Die Vorgehensweise von Fairbanks [4] findet sich in der Literatur oft wieder:

  • Risiken identifizieren: Auch hier empfiehlt sich die Beschreibung anhand testbarer Szenarien.
  • Techniken auswählen und anwenden: Ähnlich dem Konzept von oben [6] – dort wird von Konzepten gesprochen – aber im Prinzip das gleiche: man greift auf Wissen zurück und wiegt (wenn mehrere Techniken zur Auswahl stehen) Techniken ab.
  • Evaluieren: Auch hier kommt es zu einer Iteration-Bedingung: Konnten die Risiken entschärft werden?

Any developer can answer the question, “Which features are you working on?” but many have trouble with the question, “What are your primary failure risks and corresponding engineering techniques?” If risks were indeed primary then they would find it an easy question to answer [4]

Architekturen planen und analysieren

Um mit komplexen Architekturen arbeiten zu können, empfiehlt es sich mit Modellen zu arbeiten.

To create a useful model, you must choose to include the right details while sweeping others under the rug. Including irrelevant details adds clutter, making the model harder for you to reason about. [4]

Fairbanks [4] nutzt eine Modell-Hierachie:

Fairbanks

The domain model describes enduring truths about the domain; the design model describes the system you will build; and the code model describes the system source code.

  • Das Domain-Model spiegelt die Wahrheit über die Domäne wieder. Das Domain-Model drückt Details aus, welche nicht unmittelbar mit der konkreten Systemimplementierung etwas zu tun haben müssen.

The designation relationship enables you to say that similar things in different models should correspond.

Man sieht, dass sich im Design Model durchaus (ähnliche) Elemente des Domain-Model wiederfinden können. Trotzdem finde ich die Unterscheidung, die hier gewählt wurde, sehr gut: Ein Modell um die reale Welt zu verstehen, analysieren und dokumentieren zu können, und ein Modell, um eine Lösung für ein konkretes Problem in dieser Welt zu finden. Wichtig ist auch, dass das Domain-Model keinen Einfluss auf die Architektur hat.

Separating the domain from the design has several benefits. Many questions arise that are unrelated to the design, for example, whether current employees of a company should receive a company’s job ads. [4]

  • Das Boundary-Model spiegelt das wieder, was von außen gesehen werden kann (e.g. Behavior, Interchange Data und Quality Attributes). Das ist wichtig, da es nur jene Details zeigt, welche zum Zugriff auf das System benötigt werden, aber Interna nicht Preis gibt. Es ist ein View des Design-Modells.
  • Das Internals-Model ist ein weiterer View des Design-Models, welche aber im Kontrast zum Boundary-Model sämtliche Details enthält.

Ein Modell erzeugen und dann entwickeln - so einfach geht es aber nicht. Eines der größten Herausforderungen ist die Wahrung der Konsistenz zwischen Modell und Implementierung. Hier hat Fairbanks [4] folgende Ausprägungen analysiert:

  • Abweichungen ignorieren: Das ist die einfachste Form und bedarf keinen Aufwands. Modelle sind teilweise noch verwendbar, wenn das Wissen bzgl. der Abweichungen vorhanden ist.
  • Ad-Hoc Modeling: Modelle werden dann erzeugt, wenn gebraucht – eventuell auch auf Whiteboards. Die Architektur ist (teilweise) in den Köpfen der Team-Mitglieder.
  • Nur High-Level-Modelle: High-Level-Modelle weisen oft wenig Abweichungen mit dem Code auf (e.g. Server-Client ändert sich sicher nicht so schnell). Details können dann mit Ad-Hoc Modeling erstellt werden.
  • Aktiv abgleichen: entweder bei einem Milestone, bei einer Kriese oder immer / konstant. Tools wie Visual-Studio und Enterprise-Architekt bietet hier gewisse Unterstützungen an.

Welche Elemente hat nun ein Architektur Modell?

Hier findet man in der Literatur immer ähnliche Aufzählungen. Auch Architecture-Description-Languages (ADLs) bilden sehr oft die selben Elemente ab – siehe dieses Paper.

  • Allocation elements: Die Hardware, auf der die Software läuft, muss irgendwie bereitgestellt werden. Analyse von Diagrammen mit Allokation vom Komponenten kann u.a. helfen zu verstehen, wie die Verfügbarkeit und Sicherheit gewährleistet wird.
  • Component: Software, welche über ein Interface Service-Funktionalitäten anbietet. E.g. Module, Prozesse. Hier werden Daten gespeichert und verarbeitet. Components kommunizieren ausschließlich über Connectors miteinander. Fairbanks [4] unterscheidet auch zwischen Component-Type und Component-Instance (selber Gedankengang wie bei Klassen und Objekten). Oft ist es aber so, dass eine Komponenten nur einmal instanziiert wird. Zu beachten ist auch die Unterscheidung hinsichtlich Module. Module werden nicht zur Laufzeit instanziiert, sondern bilden einen logischen Verbund von Klassen, Interfaces, XML Files, Config-Files usw.

Modules can group together related code, revealing an interface but hiding the implementation. … In short, a module suggests implementation units and artifacts, with less emphasis on the delivery medium and what goes on at runtime. A component is about units of software active at runtime with no visibility into the implementation structure. [1]

  • Interface: Ein wohldefinierter Berührungspunkt für die Kommunikation mit anderen Komponenten oder der Umgebung.
  • Connector: Verbindung zwischen Interfaces / Ports und Components. Connectors leisten richtiger Arbeit:

Real work can be done in connectors. Connectors can convert, transform, or translate datatypes between components. They can adapt protocols and mediate between a collection of components. They can broadcast events, possibly cleaning up duplicate events or prioritizing important ones. Significantly, they can do the work that enables quality attributes, such as encryption, compression, synchronization / replication, and thread-safe communication.

In der akademischen Idealwelt würde man Connectors (wie auch Components) austauschen können, da deren Benutzung nur über Interfaces passiert. In der Praxis ist das aber selten der Fall, da der Style der Kommunikation sind auch oft in der konsumierenden Komponenten wiederfindet (obwohl man mit async / await auch RPC bzw. Response per Event umsetzen kann - und das performant und sauber).

  • Port Types: Komponenten kommunizieren nicht direkt miteinander, sondern nutzen Ports. Das Port gibt alles öffentlichen Methoden bekannt und die Events, welche verarbeitet werden.

A port represents a logical communication channel between a component and one or more components that it is connected to. [7]

Ports können auch ein Protokoll implementieren – sie sind somit stateful. Des Weiteren kann man Ports in Requireed und Provided Ports untergliedern. Eine State-Machine zeigt die Operationen, welche in einem Stateful-Port in welcher Reihenfolge und unter welchen Bedingungen aufgerufen werden können (e.g. muss zuerst open, dann write() und dann close() aufgerufen werden).

Abschließend noch ein Kommentar von Paul Clements et al [1]:

Components have interfaces, which are called ports. Connectors have interfaces, which are called roles. … If a component’s primary purpose is to mediate interaction between a set of components, consider representing it as a connector instead.

Mit diesen Elementen lassen sich Architekturen gut beschreiben. Im UML Buch von Oreilly sieht man sehr schön, welche Diagramme in das Konzept des 4+1 Kruchten View Model passen. Auch sind die referenzierte Bücher sehr zu empfehlen – man wird immer ähnliche Konzepte wieder finden. Manche Autoren tendieren zu Variante und Ausdrucksweise A, andere zu B. Aber ich glaube nicht, dass man deswegen ein Projekt scheitern wird. Eher wird es scheitern, weil man die Sachen falsch oder gar nicht anwendet.

Ein Architekturdokument sollte daher folgende Elemente enthalten:

  • Die Ziele und Philosophie des Systems: Wie lautet der Anwendungsbereich, Wer benutzt die Software, Welche Ziele werden verfolgt, …
  • Für die Architektur signifikante Requirements welche die einzelnen Entscheidungen untermauern
  • Die Annahmen welche über die Umgebung gemacht wurden und die Abhängigkeiten zu anderen Systemen
  • Die Architektur zeigt wie die Komponenten und Subsysteme miteinander interagieren bzw. verteilt werden müssen
  • Es werden kritische und wichtige Elemente bzw. Designentscheidungen hervorgehoben und erklärt
  • Szenarien welche das (kritische) Verhalten zeigen

Twin Peaks [8] [9]

Das Twin-Peaks Modell drückt die Abhängigkeiten zwischen Anforderungen (Requirements) und der Architektur aus. D.h., dass Requirements und die Architektur parallel behandelt werden. Das Wasserfallmodell geht von “Frozen-Requirements” aus – man weiß initial was der Kunde will und geht dann in die Planung über. Die Realität ist meist anders. Durch einen inkrementellen Ansatz versucht das Spiral-Life-Cycle-Model dieses Problem zu lösen. In einem iterativen Verfahren werden ständig die sich ändernden Projektrisiken evaluiert um u.a. instabilen Requirements entgegen zu wirken.

IEEE

Ebenfalls gibt es das Three-Peaks-Model welches zeigt, dass die Architektur zwischen Anforderungen und Umsetzung “sitzt” und alle 3 Tätigkeiten stets interagieren müssen. [10]

Oreilly

Pattern vs. Style

Ein Style beschreibt einen generischen Design-Ansatz. Beispiele aus meiner Sicht sind Satteldachhaus, Pultdachhaus oder Flachdachhaus. Es werden die Elemente, deren Relation und die Einschränkungen beschrieben. Im Kontrast: ein essentieller Teil von Patterns sind ein Problem-Statement und ein Context. Ein Zimmerman hat Patterns zum Verbinden von Hölzern: Zapfenstoß oder Hakenblatt. Er hat ein Problem und einen Context und wird nicht jedes Mal was Neues erfinden wollen.

Architecture styles represent observed architecture approaches. A style description does not generally include detailed problem/context information. Architecture patterns do. [1]

Clements [1] et al. hat Styles in 3 Kategorien eingeteilt:

  • Module Styles: A module is an implementation unit of software that provides a coherent set of responsibilities.
    • Decomposition Style: Vom Größeren ins Kleinere: Aus welchen Teilen besteht mein System? Darstellung mit e.g. Paketdiagramm
    • User-Style: Zeigt die Abhängigkeit zwischen Modulen. Auch hier bietet sich das Paketdiagramm an
    • Generalization Style: Das klassische “Is-A” – es werden Gemeinsamkeiten und Erweiterungen dargestellt.
    • Layering Style: Darstellung einer hierarchischen Abhängigkeit
  • Component-and-Connector Styles: A C&C view shows elements that have some runtime presence, such as processes, objects, clients, servers, and data stores..
    • Data flow styles: e.g. Pipe-and-Filter
    • Event-based styles und Call-return styles: Synchron vs. asynchrony
    • Repository styles: In Repositories befinden sich meist eine große Menge an Datem. E.g. Shared-Data Style
  • Allocation Styles: Zeigen das Mapping von Software in die Umgebung, in der sie ausgeführt werden.

Für Architektur Patterns sollte man sich die POSA Bücher anschauen – ich selbst hab nur 3 davon. Bekannte Beispiele sind: Microkernel, Layers, Pipes & Filters, Blackboard, Reactor, Proactor uvm.

Ports & Adapters (Hexagonal Architecture) [11]

Auch interessante Aspekte hab ich in der Ports & Adapters Architektur gefunden:

Allow an application to equally be driven by users, programs, automated test or batch scripts, and to be developed and tested in isolation from its eventual run-time devices and databases. [11]

Ich glaube man kann festhalten: einer der wichtigsten Eigenschaften von gut wartbarer Software. Cockburn nutzt Ports als Schnittstelle zur Außenwelt – Adaptoren wandeln das Event in eine einfach nutzbarere Nachricht um. Der Applikation ist es egal, von welchem Input das Event kam. Cockborn kritisiert in einem Artikel, dass Business-Logik oft in den falschen Bereichen der Software zu finden sind (e.g. UI). Ähnliche Konzepte findet man auch in anderen Styles wieder.

MicroServices

Grob gesagt helfen Microservices bei großen Systemen. Die wichtigsten Eigenschaften sind [12]:

  • Die Services sind klein gehalten
  • Sie können unabhängig voneinander entwickelt werden
  • Sie können unabhängig voneinander deployed werden

Innerhalb der Services können Teams eigene Entscheidungen treffen, welche für das Lösen des Service-Problems am besten sind. Ein weiterer Vorteil ist, dass nicht funktionale Eigenschaften je nach Service umgesetzt werden können (Availability vs. High-Volume).

In a microservice architecture, the services tend to get simpler, but the architecture tends to get more complex. That complexity is often managed with tooling, automation, and process. [12]

Das Ziel von Microservices sollte sein, dass man ein System erhält, welches ständig angepasst und geändert werden kann, ohne eine einzelne riesige Applikation mit Kopfweh zu deployen. Idealerweise passiert das alles automatisiert – vom Testen, über das Bauen bis zum Deployment. Durch den “Micro”-Approach kann man auch experimentierfreudiger sein, weil es einfacher ist, kleine Service wieder auszutauschen. Auch die Wiederverwendbarkeit von Services ist groß.

Was ist jetzt der Unterschied zu SOA? Es gibt ein Buch [13] dazu – zusammengefasst:

  • Service Taxonomy: Klassifikation der Services in der Architektur. Hier geht es e.g. darum, ob das Service Business-Relevante Dinge implementiert oder nicht. Microservices haben zwei Service-Types: Functional-Services und Infrastructure-Services (e.g. Logging, Monitoring, Authorisation, …). Infrastructure-Services sind von außen nicht zugreifbar und werden nur intern genutzt. SOA hingegen unterscheidet zwischen vier Haupttypen: Business-Services, Enterprise-Services, Application-Services und Infrastructure-Services.
  • Service Owner: hier besteht auch ein großer Unterschied: bei Microservices kann das gleiche Team ein Infrastructure- und Functional-Services implementieren. Bei SOA sind es meist dedizierte Teams.
  • Service Granularity: Microservices sind fein granularer als SOA. Die richtige Granularität zu finden ist aber eine große Challenge.

Man findet auch noch genug Artikel zu dem Thema. Technologisch hat sich im Microservice Sektor auch viel getan. Angefangen von Container-Technologien bis hin zu Monitoring – damit könnte man Seiten füllen.

Event-Driven Architecture [14]

The event-driven architecture pattern is a popular distributed asynchronous architecture pattern used to produce highly scalable applications. It is also highly adaptable and can be used for small applications and as well as large, complex ones. The event-driven architecture is made up of highly decoupled, single-purpose event processing components that asynchronously receive and process events.

Auch hier wieder ein ähnlicher Ansatz: hohe Entkopplung. Es gibt zwei topologische Ausprägungen: Mediator und Broker. Da auch hier Komponenten verteilt sein können, gibt es auch hier natürlich alle Schwierigkeiten eines Verteilten-Systems (e.g. unzuverlässiges Transportmedium, Transaktionen, …). Der Unterschied bei EDA ist, dass Events zur Verfügung gestellt werden, wenn etwas geschehen ist (im Kontrast zu Commands). Diese können von Interessenten konsumiert und verarbeitet werden. Diese Technik lässt sich natürlich auch mit Microservices umsetzen. Sehr interessant sind in diesem Bereich auch moderne Technologien zum Abarbeiten und Analysieren von Event Streams.

Space Based vs Micro Services

Space Based Architecture versucht die Persistenz Einheit so nah an die verarbeitende Einheit wie nur möglich zu bekommen, um eine hohe Skalierbarkeit zu erreichen und keinen limitierende Komponenten zu haben. Die Daten werden in einem In-Memory Grid repliziert (Distributed Shared Memory). In einer sogenannten Processing Unit befinden sich Service-Beans (zur Datenverarbeitung) und e.g. ein Teil der Space Daten, welche meist repliziert werden.

Fazit

Software-Architekturen in Projekten mit entsprechende Eigenschaften (siehe oben) zu ignorieren, halte ich für fatal. Durch schlechte Entscheidungen (welche meist ohne Überlegung getroffen werden), erhält man schlechte Architekturen, die einem in Zukunft das Leben schwermachen werden. Im Netz findet man inzwischen viele Architekturen großer Internet-Dienstleistungsanbieter (siehe highscalability.com). Man sollte diese ständig studieren, Ideen extrahieren und hinterfragen, wie man sie in der eigenen Domäne einsetzen kann. Einfach Copy & Paste wäre fatal. Die Ideen (e.g. wie Event-Streams) zu ignorieren, allerdings auch.


[1] Clements, P., Garlan, D., Bass, L., Stafford, J., Nord, R., Ivers, J., & Little, R. (2002). Documenting software architectures: views and beyond. Pearson Education.
[2] Taylor, R. N., Medvidovic, N., & Dashofy, E. M. (2009). Software architecture: foundations, theory, and practice. Wiley Publishing.
[3] Fowler, M. (2002). Patterns of enterprise application architecture. Addison-Wesley Longman Publishing Co., Inc..
[4] Fairbanks, G. (2010). Just enough software architecture: a risk-driven approach. Marshall & Brainerd.
[5] Bass, L., Clements, P. & Kazman, R. (2013). Software architecture in practice. Upper Saddle River, N.J: Addison-Wesley.
[6] Cervantes, H. & Kazman, R. (2016). Designing software architectures : a practical approach. Boston: Addison-Wesley.
[7] Aldrich, J., Chambers, C., & Notkin, D. (2002, May). ArchJava: connecting software architecture to implementation. In Software Engineering, 2002. ICSE 2002. Proceedings of the 24rd International Conference on (pp. 187-197). IEEE.
[8] Cleland-Huang, J., Hanmer, R. S., Supakkul, S., & Mirakhorli, M. (2013). The twin peaks of requirements and architecture. IEEE Software, 30(2), 24-29.
[9] Nuseibeh, B. (2001). Weaving together requirements and architectures. Computer, 34(3), 115-119.
[10] Rozanski, N., & Woods, E. (2012). Software systems architecture: working with stakeholders using viewpoints and perspectives. Addison-Wesley.
[11] http://alistair.cockburn.us/Hexagonal+architecture
[12] Nadareishvili, I., Mitra, R., McLarty, M., & Amundsen, M. (2016). Microservice Architecture: Aligning Principles, Practices, and Culture. “ O’Reilly Media, Inc.”.
[13] http://www.oreilly.com/programming/free/microservices-vs-service-oriented-architecture.csp
[14] Richards, M. (2015). Software architecture patterns : understanding common architecture patterns and when to use them. Sebastopol, CA: O’Reilly Media.