commit 192194b0ece264eba290009484b5ec97da9cc51b Author: Benedikt Hunger Date: Tue Feb 13 15:51:50 2024 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7585238 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +book diff --git a/README.md b/README.md new file mode 100644 index 0000000..05f0756 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# iSAQB CPSA-F book + +These are the learning materials for the Scandio CPSA-F course. + +## Preliminaries + +The book is built using [mdBook](https://rust-lang.github.io/mdBook/), so you should install it first: `cargo install mdbook`. + +The book uses the `mdbook-graphviz` preprocessor and the GraphViz `dot` binary for rendering diagrams. See [the GraphViz page](https://graphviz.org/download/) and the [mdbook-graphviz GitHub](https://github.com/dylanowen/mdbook-graphviz) for installation instructions. + +## Serving the book + +```shell +mdbook serve --open +``` + +## Further information + +See [the mdBook documentation](https://rust-lang.github.io/mdBook/). + diff --git a/book.toml b/book.toml new file mode 100644 index 0000000..16a226b --- /dev/null +++ b/book.toml @@ -0,0 +1,14 @@ +[book] +authors = ["Benedikt Hunger"] +language = "de" +multilingual = false +src = "src" +title = "Grundlagen der Softwarearchitektur" + +[output.html] +curly-quotes = true +additional-css = ["theme/css/custom.css"] +preferred-dark-theme = "coal" + +[preprocessor.graphviz] + diff --git a/src/SUMMARY.md b/src/SUMMARY.md new file mode 100644 index 0000000..05b5d57 --- /dev/null +++ b/src/SUMMARY.md @@ -0,0 +1,51 @@ +# Summary + +# LZ 1: Grundbegriffe + +- [LZ 1-1: Definitionen von Softwarearchitektur diskutieren](./lz1/1_01.md) +- [LZ 1-2: Nutzen und Ziele von Softwarearchitektur verstehen und erläutern](./lz1/1_02.md) +- [LZ 1-3: Softwarearchitektur in Software-Lebenszyklus einordnen](./lz1/1_03.md) +- [LZ 1-4: Aufgaben und Verantwortung von Softwarearchitekt:innen verstehen](./lz1/1_04.md) +- [LZ 1-5: Rolle von Softwarearchitekt:innen in Beziehung zu anderen Stakeholdern setzen](./lz1/1_05.md) +- [LZ 1-6: Zusammenhang zwischen Entwicklungsvorgehen und Softwarearchitektur erläutern können](./lz1/1_06.md) +- [LZ 1-7: Kurz- und langfristige Ziele differenzieren](./lz1/1_07.md) +- [LZ 1-8: Explizite Aussagen von impliziten Annahmen unterscheiden](./lz1/1_08.md) +- [LZ 1-9: Zuständigkeit von Softwarearchitekt:innen in organisatorischen Kontext einordnen](./lz1/1_09.md) +- [LZ 1-10: Typen von IT-Systemen unterscheiden](./lz1/1_10.md) +- [LZ 1-11: Herausforderungen verteilter Systeme](./lz1/1_11.md) +- [Aufgaben zu LZ 1](./lz1/aufgaben.md) + +# LZ 2: Entwurf und Entwicklung von Softwarearchitekturen + +- [LZ 2-1: Vorgehen und Heuristiken zur Architekturentwicklung auswählen und anwenden können](./lz2/2_01.md) +- [LZ 2-2: Softwarearchitekturen entwerfen](./lz2/2_02.md) +- [LZ 2-3: Anforderungen klären und berücksichtigen können](./lz2/2_03.md) +- [LZ 2-4: Querschnittskonzepte entwerfen und umsetzen](./lz2/2_04.md) +- [LZ 2-5: Wichtige Lösungsmuster beschreiben, erklären und angemessen anwenden](./lz2/2_05.md) +- [LZ 2-6: Entwurfsprinzipien erläutern und anwenden](./lz2/2_06.md) +- [LZ 2-7: Abhängigkeiten von Bausteinen managen](./lz2/2_07.md) +- [LZ 2-8: Qualitätsanforderungen mit passenden Ansätzen und Techniken erreichen](./lz2/2_08.md) +- [LZ 2-9: Schnittstellen entwerfen und festlegen](./lz2/2_09.md) +- [LZ 2-10: Grundlegende Prinzipien von Software-Deployments kennen](./lz2/2_10.md) +- [Aufgaben zu LZ 2](./lz2/aufgaben.md) + +# LZ 3: Beschreibung und Kommunikation von Softwarearchitekturen + +- [LZ 3-1: Anforderungen an technische Dokumentation](./lz3/3_01.md) +- [LZ 3-2: Softwarearchitekturen beschreiben und kommunizieren](./lz3/3_02.md) +- [LZ 3-3: Notations- und Modellierungsmittel](./lz3/3_03.md) +- [LZ 3-4/3-5: Architektursichten und Kontextabgrenzung](./lz3/3_04+05.md) +- [LZ 3-6: Querschnittskonzepte](./lz3/3_06.md) +- [LZ 3-7: Schnittstellen](./lz3/3_07.md) +- [LZ 3-8: Architekturentscheidungen](./lz3/3_08.md) +- [LZ 3-9: Weitere Hilfsmittel](./lz3/3_09.md) +- [Aufgaben zu LZ 3](./lz3/aufgaben.md) + +# LZ 4: Softwarearchitektur und Qualität + +- [LZ 4-1: Qualitätsmodelle und Qualitätsmerkmale](./lz4/4_01.md) +- [LZ 4-2: Qualitätsanforderungen](./lz4/4_02.md) +- [LZ 4-3: Qualitätive Analyse](./lz4/4_03.md) +- [LZ 4-4: Quantitative Bewertung](./lz4/4_04.md) +- [Aufgaben zu LZ 4](./lz4/aufgaben.md) + diff --git a/src/lz1/1_01.md b/src/lz1/1_01.md new file mode 100644 index 0000000..60e2010 --- /dev/null +++ b/src/lz1/1_01.md @@ -0,0 +1,88 @@ +# LZ 1-1: Definitionen von Softwarearchitektur diskutieren + +## Einige Definitonen von Softwarearchitektur + +### ISO/IEC/IEEE 42010:2022 + +> fundamental concepts or properties of an entity in its environment (3.13) and governing principles for the realization and +> evolution of this entity and its related life cycle processes + +(Quelle: [ISO Online Browsing Platform](https://www.iso.org/obp/ui/en/#iso:std:iso-iec-ieee:42010:ed-2:v1:en)) + +### IEEE 1471 + +> The fundamental organization of a system embodied in its components, their relationships to each other, and to the +> environment, and the principles guiding its design and evolution + +(Quelle: [Wikipedia](https://en.wikipedia.org/wiki/IEEE_1471)) + +### Clements et al. (2010) + +> The set of structures needed to reason about the system, which comprises software elements, relations among them, and +> properties of both + +(Quelle: [Software Engineering Institute (SEI)][1]) + +### Bass, Clements, Kazman (2003) + +> The software architecture of a program or computing system is the structure or structures of the system, which comprise +> software elements, the externally visible properties of those elements, and the relationships among them + +(Quelle: [Software Engineering Institute (SEI)][1]) + +### Kruchten (2004) + +> Architecture encompasses significant decisions about the following: +> * The organization of a software system +> * The selection of structural elements and their interfaces by which the system is composed, together with their behavior as +> specified in the collaboration among those elements +> * The composition of these elements into progressively larger subsystems +> * The architectural style that guides this organization, these elements and their interfaces, their collaboration, and their +> composition +> +> Software architecture is concerned with not only structure and behavior but also context: usage, functionality, performance, +> resilience, reuse, comprehensibility, economic and technological constraints and trade-offs, and aesthetics + +(Quelle: [Google Books](https://books.google.de/books?id=RYCMx6o47pMC)) + +### Garlan & Shaw (1994) + +> As the size and complexity of software systems increases, the design problem goes beyond the algorithms and data structures of +> the computation: designing and specifying the overall system structure emerges as a new kind of problem. Structural issues +> include gross organization and global control structure; protocols for communication, synchronization, and data access; +> assignment of functionality to design elements; physical distribution; composition of design elements; scaling and +> performance; and selection among design alternatives. +> +> This is the software architecture level of design. + +(Quelle: [Carnegie Mellon University](https://www.cs.cmu.edu/afs/cs/project/able/ftp/intro_softarch/intro_softarch.pdf)) + +### Hayes-Roth (1995) + +> The architecture of a complex software system is its “style and method of design and construction”. + +(Quelle: [Software Engineering Institute (SEI)][1]) + +[1]: https://resources.sei.cmu.edu/asset_files/FactSheet/2010_010_001_513810.pdf + +## Gemeinsame Begrifflichkeiten + +### Komponenten + +Diese werden auch *Bausteine*, *Elemente* oder ähnlich genannt und bezeichnen Teile des Gesamtsystems. Beispiele für Komponenten +sind Module, Klassen, Funktionen, Microservices, Datenbanken etc. + +### Beziehungen + +Die Komponenten stehen über *Beziehungen* (oder auch *Abhängigkeiten*) miteinander in Verbindung, mit denen sie interagieren. + +### Prinzipien + +Diese werden auch *(Querschnitts-)Konzepte* genannt und bezeichnen diejenigen Eigenschaften oder Regeln, die für mehrere +Komponenten des Systems relevant sein können. + +### Entscheidungen + +Entscheidungen über die Softwarearchitektur eines Systems sind in jeder Entwicklungsphase des Systems relevant, nicht nur bei +der initialen Planung. + diff --git a/src/lz1/1_02.md b/src/lz1/1_02.md new file mode 100644 index 0000000..09aac3d --- /dev/null +++ b/src/lz1/1_02.md @@ -0,0 +1,32 @@ +# LZ 1-2: Nutzen und Ziele von Softwarearchitektur verstehen und erläutern + +Die folgenden Ziele sollen durch Softwarearchitektur erreicht werden: + +## Entwurf, Implementierung, Pflege und Betrieb von Systemen + +Die Entwicklung und Wartung eines Softwaresystems sollte durch seine Architektur erleichtert werden. Insbesondere sollten +Entscheidungen so getroffen werden, dass das entstehende System strukturiert und nicht chaotisch wird. Auf der anderen Seite +sollten die Entwickler:innen aber ausreichend Freiraum haben, um kreativ Probleme zu lösen. Das Maß an Detailgrad, das durch die +Architektur vorgeschrieben werden sollte, hängt somit sowohl von der Komplexität des zu lösenden Problems als auch von der +Expertise der Entwickler:innen ab. + +## funktionale Anforderungen + +Natürlich muss ein System gewisse fachliche Anforderungen erfüllen. Das Ziel der Softwarearchitektur in diesem Zusammenhang ist +es sicherzustellen, dass die Anforderungen im Rahmen der gegebenen Einschränkungen erfüllbar sind und bleiben. + +## Qualitätsanforderungen + +Zu diesen Qualitätsanforderungen zählen Zuverlässigkeit, Wartbarkeit, Änderbarkeit, Sicherheit, Energieeffizienz des +Softwaresystems. + +## Vermittlung von Verständnis für Strukturen und Konzepte des Systems + +Dieser Bereich schließt die Dokumentation und Kommunikation der Architektur an alle relevanten Stakeholder des Systems mit ein. +Die Dokumentation und Kommunikation muss an die jeweiligen Stakeholder und ihre Bedürfnisse angepasst sein. + +## Reduktion von Komplexität + +Softwaresysteme sind oft komplexe Gebilde. Softwarearchitektur sollte dazu beitragen, dass diese Komplexität nicht über die +Maßen wächst und gegebenenfalls sogar wieder reduziert werden kann. + diff --git a/src/lz1/1_03.md b/src/lz1/1_03.md new file mode 100644 index 0000000..7cc0f24 --- /dev/null +++ b/src/lz1/1_03.md @@ -0,0 +1,92 @@ +# LZ 1-3: Softwarearchitektur in Software-Lebenszyklus einordnen + +Viele denken fälschlicherweise, das Softwarearchitektur hauptsächlich in der Planungs-Phase relevant ist. Tatsächlich ist +Softwarearchitektur (genau wie die Software-Entwicklung) ein iterativer Prozess und somit in allen Phasen der +Softwareentwicklung vertreten und relevant. + +Die Anforderungen an das System unterliegen einem stetigen Wandel, und so muss die Architektur des Systems stetig neu evaluiert +und angepasst werden. + +## Der Software-Lebenszyklus + +Das folgende Modell von [Rajlich & Bennet (2000)](http://www.dsc.ufcg.edu.br/~garcia/cursos/dglobal_software/artigos/staged_modelsw.pdf) +zeigt die Phasen im Lebenszyklus einer Software auf: + +
+ +```dot process +digraph { + rankdir=LR + node [ + fontname="Roboto, sans-serif" + style=filled + fillcolor="#42d4fb" + shape=box + ] + { + rank = same + "Initial\ndevelopment" -> "Evolution,\nversion 1" + "Evolution,\nversion 1" -> "Evolution,\nversion 1" + "Evolution,\nversion 1" -> "Servicing,\nversion 1" + "Servicing,\nversion 1" -> "Servicing,\nversion 1" + "Servicing,\nversion 1" -> "Phaseout,\nversion 1" + "Phaseout,\nversion 1" -> "Closedown,\nversion 1" + } + + "Evolution,\nversion 1" -> "Evolution,\nversion 2" + + { + rank=same + "Evolution,\nversion 2" -> "Evolution,\nversion 2" + "Evolution,\nversion 2" -> "Servicing,\nversion 2" + "Servicing,\nversion 2" -> "Servicing,\nversion 2" + "Servicing,\nversion 2" -> "Phaseout,\nversion 2" + "Phaseout,\nversion 2" -> "Closedown,\nversion 2" + } + + "Evolution,\nversion 2" -> "Evolution,\nversion ..." +} +``` + +
+ +### Initiale Entwicklung + +In dieer Phase werden die initialen Anforderungen an die Software implementiert. Somit wird auch die Grundlage für die +Softwarearchitektur des Systems in dieser Phase gelegt. Da Architekturentscheidungen mit fortlaufender Evolution des Systems +immer schwerer zu ändern sind, ist es in dieser Phase wichtig, Architekturentscheidungen so zu treffen, dass das System auch in +der Zukunft leicht anzupassen, zu ändern und zu warten ist. Diese Ziele stehen in der initialen Entwicklungsphase typischerweise +im Konflikt mit Managementzielen wie schneller Markteinführung, um möglichst bald Umsatz generieren zu können. Hier ist eine +feine Abstimmung dieser gegensätzlichen Ziele notwendig. + +### Evolution + +In der Evolutionsphase wird die Funktionalität des Systems schrittweise weiterentwickelt. Hier ist die Aufgabe der +Softwarearchitektur, dafür zu sorgen, dass diese Weiterentwicklung weiterhin möglich bleibt und das System möglichst spät in die +Servicing-Phase gelangt. + +### Servicing + +In dieser Phase sind Änderungen an der Software durch mangelhafte Architektur oder ein fehlendes Entwicklerteam schwierig und +somit kostspielig geworden. Durch Patches, die in dieser Phase weiter entwickelt werden, kann die Architektur nochmals +verschlechtert werden. Daher sollten auch in dieser Phase Architekturentscheidungen getroffen werden, die diesen Prozess +möglichst verlangsamen. + +### Phaseout + +In dieser Phase werden keine Änderungen an der Software mehr vorgenommen. Die Softwarearchitektur in dieser Phase wird +entsprechend auch nicht mehr angepasst und keine Architekturentscheidungen müssen getroffen werden. Allerdings sollten frühere +Architekturentscheidungen auch Konsequenzen für diese Phase berücksichtigen, insbesondere in Hinblick auf Sicherheit und +Migration auf Ersatzsysteme. + +### Closedown + +Die Software wird abgeschaltet. Falls eine spätere Version oder ein Ersatz für das System besteht, müssen Bestandsnutzer bei der +Migration auf diese neue Version unterstützt werden. Die Softwarearchitektur kann helfen, diesen Prozess zu erleichtern. + +### Versionierung + +Oft wird Software versioniert entwickelt, sodass bei der Entwicklung einer neuen Softwareversion die alte Version in die +Servicing-Phase übergeht, während die neue Version evolviert. Für diesen Prozess ist die Softwarearchitektur verantwortlich für +die Kompatibilität zwischen den Versionen. + diff --git a/src/lz1/1_04.md b/src/lz1/1_04.md new file mode 100644 index 0000000..d40b53b --- /dev/null +++ b/src/lz1/1_04.md @@ -0,0 +1,21 @@ +# LZ 1-4: Aufgaben und Verantwortung von Softwarearchitekt:innen verstehen + +Softwarearchitekt:innen haben eine Reihe von Aufgaben. Vor allem sind sie verantwortlich für die Erreichung von fachlichen und +nichtfachlichen Anforderungen und die Entwicklung der Architektur der Softwarelösung. Etwas spezifischer umfasst das +Aufgabenfeld von Softwarearchitekt:innen die folgenden Themen: + +* *Anforderungen und Randbedingungen* klären, hinterfragen und bei Bedarf verfeinern: hierbei ist es insbesondere entscheidend, + sowohl Anforderungen als auch Einschränkungen zu priorisieren und die unbedingt notwendigen Anforderungen + herauszukristallisieren, um gegebenenfalls Kompromisse vorzuschlagen. +* *Strukturentscheidungen hinsichtlich Systemzerlegung und Bausteinstruktur* treffen. Das schließt in jedem Fall die Zerlegung + des Gesamtsystems auf einer groben Ebene ein. Wie fein die Bausteinzerlegung des Systems durch die Architekt:innen festgelegt + werden sollten, hängt von der konkreten Situation im Projekt ab. Nicht nur die Zerlegung des Systems in Bausteine, sondern + auch die Spezifikation von Abhängigkeiten zwischen den Bausteinen muss festgelegt werden. +* *Querschnittskonzepte* (also übergreifende Konzepte, die für mehrere Bausteine relevant sein können) entscheiden und bei + Bedarf umsetzen +* *Dokumentation und Kommunikation* der Architektur des Softwaresystems +* *Umsetzung und Implementierung der Architektur begleiten*. Das schließt zum einen das Einholen und Einarbeiten von Feedback + der relevanten Stakeholder, zum anderen die Sicherstellung der Konsistenz von Quellcode und Softwarearchitektur ein. +* *Softwarearchitektur analysieren und bewerten*, insbesondere hinsichtlich Risiken bezüglich der Erreichung von Anforderungen. +* *Architekturentscheidungen* auf Basis der erwarteten Konsequenzen informiert treffen und gegenüber Stakeholdern argumentieren + diff --git a/src/lz1/1_05.md b/src/lz1/1_05.md new file mode 100644 index 0000000..14b9548 --- /dev/null +++ b/src/lz1/1_05.md @@ -0,0 +1,29 @@ +# LZ 1-5: Rolle von Softwarearchitekt:innen in Beziehung zu anderen Stakeholdern setzen + +Ein:e Softwarearchitekt:in muss typischerweise mit einigen *Stakeholdern* zusammenarbeiten. Dabei bezeichnen Stakeholder +diejenigen Personen, Rollen, oder Gruppen, die in irgendeiner Form ein Interesse an der Architektur des Systems haben, sei es +hinsichtlich fachlichen Anforderungen, Qualitätsanforderungen, oder Compliance-Regeln. Konsequenterweise müssen +Softwarearchitekt:innen bei ihrer Arbeit mit diesen Stakeholdern kommunizieren und interagieren. Insbesondere gehören zu den +Stakeholdern eines Systems potenziell folgende: + +* Produktmanagement, Product Owner +* Projektleitung und -management +* Anforderungsanalytiker:innen (System-/Businessanalyse, Anforderungsmanagement, Fachbereich) +* Entwicklung +* Qualitätssicherung und Test +* IT-Betrieb (Produktion, Rechenzentren), zutreffend primär für Informationssysteme +* Hardwareentwicklung +* Unternehmensarchitektur, Architekturboard + +Je nach Stakeholder kann die Zusammenarbeit sehr unterschiedlich ausfallen: +* Mit Product Owner und Businessanalyst:innen werden typischerweise Anforderungen geklärt, diskutiert und auf ihre Machbarkeit + und Komplexität hin analysiert. Dabei geht es sowohl um die fachlichen als auch die nichtfachlichen Anforderungen, aber + typischerweise nicht um technische Details der Umsetzung. +* Mit Management-Stakeholdern wie Projektmanagement müssen organisatorische Rahmenbedingungen, Ressourcen und + Entwicklungskapazität und Zeitpläne abgestimmt werden. Auch hier sind technische Details üblicherweise in der Kommunikation + nicht relevant. +* Gegenüber Entwickler:innen, IT-Betrieb, Hardwareentwicklung und anderen Architekt:innen müssen Softwarearchitekt:innen auf + technischer Ebene kommunizieren, um beispielsweise Schnittstellen genau spezifizieren zu können. +* Für andere Stakeholder wie Qualitätssicherung oder Security- oder Compliance-Verantwortliche ist nur ein spezifisches + Qualitätsmerkmal der Software relevant. Hier müssen Trade-Offs gegenüber anderen Anforderungen klar kommuniziert und in + Zusammenarbeit mit fachlichen Stakeholdern priorisiert werden. diff --git a/src/lz1/1_06.md b/src/lz1/1_06.md new file mode 100644 index 0000000..0204e34 --- /dev/null +++ b/src/lz1/1_06.md @@ -0,0 +1,7 @@ +# LZ 1-6: Zusammenhang zwischen Entwicklungsvorgehen und Softwarearchitektur erläutern können + +Software wird häufig in iterativen Zyklen entwickelt. Der Vorteil bei diesem Vorgehen ist, dass Probleme schneller erkannt und +beseitigt werden können und man leichter auf geänderte Herausforderungen reagieren kann. Da konsequenterweise auch die +Softwarearchitektur häufigen Änderungen unterworfen ist, ist es notwendig, regelmäßig Stakeholder-Feedback einzuholen und mit +relevanten Stakeholdern über Architekturentscheidungen und ihre Konsequenzen zu kommunizieren. + diff --git a/src/lz1/1_07.md b/src/lz1/1_07.md new file mode 100644 index 0000000..53d3205 --- /dev/null +++ b/src/lz1/1_07.md @@ -0,0 +1,25 @@ +# LZ 1-7: Kurz- und langfristige Ziele differenzieren + +## Projekt + +Ein Projekt ist durch folgende Eigenschaften gekennzeichnet: + +* mehrere Personen arbeiten zusammen +* es gibt ein klar definiertes Ziel +* Zeit und finanzielles Budget sind begrenzt + +In diesem Sinne ist in einem durch Scrum organisierten Entwicklungsprojekt ein Projekt gleichzusetzen mit einem einzelnen Sprint. + +## System + +Die Anwendung/Software/..., an der das Entwicklerteam arbeitet. Typischerweise ist das System das Ergebnis mehrerer Projekte. + +Typischerweise ist die Lebenszeit des Systems länger als die Gesamtzeit der für die Entwicklung benötigten Projekte. + +## Kurzfristige und langfristige Ziele + +* Projektziele sind (oft) kurzfristig +* auf der anderen Seite sind Systemziele oder architektonische Ziele (oft) langfristig +* Systemziele können bei der Erreichung der Projektziele unterstützen, aber Systemziele und Projektziele können auch miteinander in Konflikt stehen. +* Es ist Aufgabe des Softwarearchitekten, die Systemziele im Auge zu behalten und auf ihrer Verfolgung zu bestehen. + diff --git a/src/lz1/1_08.md b/src/lz1/1_08.md new file mode 100644 index 0000000..fb251c9 --- /dev/null +++ b/src/lz1/1_08.md @@ -0,0 +1,13 @@ +# LZ 1-8: Explizite Aussagen von impliziten Annahmen unterscheiden + +Aussagen und Entscheidungen werden oft implizit angenommen. Ein typisches Beispiel ist die Anforderungen, qualitativ hochwertige +Software zu entwickeln: die Kriterien, wann Software als qualitativ hochwertig gilt, entscheidet sich wesentlich je nachdem, wer +mit welchem Interesse die Software beurteilt. Doch auch konkreter sind Anforderungen wie "es soll wenige Verbindungsabbrüche +geben" problematisch: Wie wenige Verbindungsabbrüche sind wenige? In welchem Zeitraum? + +Eine der wichtigsten Aufgaben eine:r Softwarearchitekt:in ist daher, implizite Annahmen zu erkennen und durch Kommunikation mit +den relevanten Stakeholdern explizit zu machen. Genauso sollten Architekturentscheidungen immer explizit dokumentiert werden, um +nachvollziehbar zu sein. + +In manchen Fällen sind implizite Aussagen trotzdem vertretbar, nämlich wenn die expliziten Details für die Softwarearchitektur +irrelevant sind. diff --git a/src/lz1/1_09.md b/src/lz1/1_09.md new file mode 100644 index 0000000..86b8614 --- /dev/null +++ b/src/lz1/1_09.md @@ -0,0 +1,16 @@ +# LZ 1-9: Zuständigkeit von Softwarearchitekt:innen in organisatorischen Kontext einordnen + +Neben Softwarearchitekt:innen, die mit der Struktur und Entscheidungen bezogen auf einzelne Systeme betraut sind, gibt es noch +andere Typen von Architekt:innen, die in einem organisatorischen Kontext relevant sind. Es ist wichtig, diese Rollen voneinander +abgrenzen zu können, um die Rolle der Softwarearchitekt:innen gegenüber Stakeholdern erklären zu können: + +* Die *Unternehmens-IT-Architektur* beschäftigt sich mit der Struktur und Interaktion mehrerer IT-Systeme und kann somit als + Architektur auf einer weiter außen liegenden Ebene beschrieben werden. +* Die *Geschäfts-/Prozessarchitektur* ist zuständig dafür, Geschäftsprozesse zu strukturieren und Entscheidungen diesbezüglich + zu treffen. Hier werden grundsätzliche Entscheidungen bezogen auf fachliche Anforderungen gefällt. +* Die *Informationsarchitektur* beschäftigt sich damit, wie Information und Daten systemübergreifend strukturiert sind. +* Die *Infrastruktur-/Technologiearchitektur* ist für die Struktur und Entscheidungen bezüglich der technischen Infrastruktur + verantwortlich. Hier werden Entscheidungen getroffen, die gegebenenfalls Grundlage und Einschränkungen für die Architektur + einzelner Systeme auf einer technischen Ebene darstellen. +* Die *Hardware-/Prozessorarchitektur* entwickelt und trifft Entscheidungen über die Struktur der Hardwaresysteme, von denen die + Softwaresysteme der Organisation abhängen. diff --git a/src/lz1/1_10.md b/src/lz1/1_10.md new file mode 100644 index 0000000..6bfe479 --- /dev/null +++ b/src/lz1/1_10.md @@ -0,0 +1,13 @@ +# LZ 1-10: Typen von IT-Systemen unterscheiden + +Es gibt verschiedene Typen von IT-Systemen, für die sich die Anforderungen an die Softwarearchitektur häufig deutlich +unterscheiden, unter anderem: + +* Bei *mobilen Systemen* gibt es deutliche Unterschiede bei den genutzten Betriebssystemen und Bildschirmgrößen. Es muss klar + sein, welche Geräte unterstützt werden, und UX (User Experience) spielt oft eine große Rolle. Zusätzlich sind die begrenzten + Ressourcen auf mobilen Geräten sowie die potenziell schlechte Konnektivität Herausforderungen, die beachtet werden müssen. +* *KI-basierte Systeme* erfordern eine ganz eigene Art von Test- und Deploymentstrategien, um verlässliche Systeme zu + entwickeln. Hierbei können Best Practices im Bereich MLOps hilfreich sein. +* *Cloud-Native-Systeme* basieren oft auf Kubernetes und können aufgrund des dort gegebenen Abstraktionslevels oft sehr flexibel + gestaltet werden, was sich auch in einer flexiblen Architektur wiederspiegelt. + diff --git a/src/lz1/1_11.md b/src/lz1/1_11.md new file mode 100644 index 0000000..b9dd55c --- /dev/null +++ b/src/lz1/1_11.md @@ -0,0 +1,16 @@ +# LZ 1-11: Herausforderungen verteilter Systeme + +Verteilte Systeme ermöglichen im Gegensatz zu monolithischen Systemen oft eine schnellere Entwicklung und Time-to-Market des +Systems, wenn die Verteilung durch kleine Services (Microservices) zustande kommt. Außerdem können die Teile verteilter Systeme +durch einzelne Teams leichter getrennt voneinander entwickelt werden, was Kommunikations-Overheads reduzieren kann. + +Auf der anderen Seite müssen bei verteilten Systemen die Schnittstellen zwischen den Systemen klar spezifiziert werden, und es +gibt einige Herausforderungen von verteilten Systemen, die architektonisch herausfordernd sein können: + +* Durch die Latenz von Netzwerkverbindungen kann man nicht davon ausgehen, zu jedem Zeitpunkt einen global konsistenten Zustand + des Systems zu erreichen. Das Ziel ist vielmehr ein *schließlich konsistenter* ("eventually consistent") Zustand, bei dem die + Datenkonsistenz nach einer kurzen Zeit erreicht wird. +* Zeitliche Ordnung von Prozessen ist oft nicht strikt möglich. +* Kommunikation zwischen den einzelnen Teilen eines verteilten Systems kann fehlschlagen, sodass Resilienz und Fehlerbehandlung + bei der Kommunikation mitbehandelt werden muss. + diff --git a/src/lz1/aufgaben.md b/src/lz1/aufgaben.md new file mode 100644 index 0000000..3cbd612 --- /dev/null +++ b/src/lz1/aufgaben.md @@ -0,0 +1,87 @@ +# Aufgaben zu LZ 1 + +**Welche drei der folgenden Aussagen über Definitionen von Softwarearchitektur treffen am ehesten zu?** + +1. Es gibt eine einzige Definition von Softwarearchitektur für jede Kategorie von IT-Systemen. +2. Softwarearchitektur befasst sich mit Beziehungen zwischen verschiedenen Bausteinen eines Systems. +3. Die Spezifikation eines relationalen Datenbankschemas ist ein typisches Beispiel für architektonische Arbeit. +4. Neben einzelnen Komponenten behandelt die Softwarearchitektur auch Querschnittskonzepte, die für mehrere Komponenten relevant sind. +5. Softwarearchitektur umfasst die Entwicklung von Hardware für die optimale Lösung eines gegebenen Problems. +6. Es gibt mehr als ein Dutzend verschiedene Definitionen von Softwarearchitektur. + +
+
+ 2, 4, 6 +
+
+ +**Was sind Hauptziele der Softwarearchitektur? Wähle die vier passendsten Antworten aus.** + +1. Qualitätsanforderungen wie Wartbarkeit oder Energieeffizienz zu erreichen +2. Sicherstellung einer ausreichenden Testabdeckung des Systems durch Unit- und Integrations-Tests +3. Unterstützung bei Entwurf, Implementierung, Pflege und Betrieb von Softwaresystemen +4. Vermittlung von Strukturen und Konzepten eines Softwaresystems an relevante Stakeholder +5. Erarbeitung und Spezifikation der Businesslogik eines Systems + +
+
+ 1, 3, 4, 5 +
+
+ +**Welche fünf dieser Aufgaben passen am ehesten in den Aufgabenbereich von Softwarearchitekt:innen?** + +1. Anforderungen in Zusammenarbeit mit Stakeholdern des Systems klären +2. Entscheidungen bezüglich der Ausgestaltung von Querschnittskonzepten treffen +3. Management bei technischen Fragen beraten +4. Hardware für Systeme entwickeln +5. Neue Business-Anforderungen an das System entwickeln +6. Integrationstests durchführen +7. Softwarearchitektur analysieren und bewerten +8. Die Konsequenzen von Architekturentscheidungen erkennen und gegenüber Stakeholdern transparent kommunizieren + +
+
+ 1, 2, 3, 7, 8 +
+
+ +**Inwiefern kann ein iterativer Ansatz bei der Softwarearchitektur helfen? (wähle die 2 passendsten aus)** + +1. Iterationen können dabei helfen, konkrete Businessanforderungen an das System schneller zu erreichen. +2. Probleme mit der Softwarearchitektur tauchen bei einem iterativem Vorgehen schneller auf und können somit leichter behoben werden. +3. Durch die iterative Arbeit entsteht eine organischere Struktur des Projekts, sodass viele Architekturentscheidungen nicht mehr wichtig werden. +4. Unsicherheit in Bezug auf zukünftige Anforderungen erfordert häufig einen iterativen Ansatz bei der Entwicklung von Softwarearchitekturen. + +
+
+ 2, 4 +
+
+ +**Welche Aussagen bezüglich Projektzielen und architektonischen Zielen sind wahr und welche sind falsch?** + +1. Architektonische Ziele und Projektziele müssen identisch sein. +2. In den meisten Fällen sind architektonische Ziele längerfristigerer Natur als Projektziele. +3. Architektonische Ziele und Projektziele müssen zwischen den beteiligten Parteien verhandelt werden. +4. Architektonische Ziele sind eine Untermenge von Projektzielen. + +
+
+ wahr: 2, 3 +
+
+ +**Ihr entwickelt ein Backendsystem, das Firmwareupdates von IoT-Geräten verwaltet. Welche der folgenden Aussagen sollten durch die Softwarearchitekt:in explizit gemacht werden, und bei welcher ist eine implizite Aussage angemessen?** + +1. Trade-Offs zwischen Qualitätsanforderungen +2. Die Gründe für wichtige architektonische Entscheidungen, die das gesamte System betreffen +3. Details zur inneren Funktionsweise des verwendeten Frameworks +4. Die Beschreibung der Behandlung von Fehlern bei der Netzwerkkommunikation + +
+
+ explizit: 1, 2, 4 +
+
+ diff --git a/src/lz2/2_01.md b/src/lz2/2_01.md new file mode 100644 index 0000000..29eeeb0 --- /dev/null +++ b/src/lz2/2_01.md @@ -0,0 +1,46 @@ +# LZ 2-1: Vorgehen und Heuristiken zur Architekturentwicklung auswählen und anwenden können + +Es gibt verschiedene Ansätze zur Entwicklung von Softwarearchitekturen, die sich gegenseitig ergänzen können. + +## Top-Down + +* mit einer abstrakten, allgemeinen Perspektive starten und dann in Details gehen +* Details, die noch nicht benötigt werden wegabstrahieren +* Überblick über mehrere Komponenten und Sub-Systeme behalten + +## Bottom-Up + +* mit Details starten und diese später wegabstrahieren +* zuerst funktionierendes Proof of Concept bauen +* Wissen und Erfahrung in speziellen, wichtigen Bereichen sammeln +* Risiken reduzieren + +Top-Down und Bottom-Up Herangehensweisen können oft auch gut kombiniert werden. + +## View-based Architecture + +* verschiedene Sichten, die sich auf spezielle Bereiche, Teile oder Aspekte eines Systems fokusieren +* verschiedene Aspekte können getrennt voneinander betrachtet und evaluiert werden + +## Iteratives und inkrementelles Design + +* Iterativ: Das System wird in iterativen, sich wiederholenden Zyklen entwickelt und gebaut +* Inkrementell: Die Arbeit wird aufgeteilt und in aufeinander aufbauenden Stücken bearbeitet + +Mit dieser Herangehensweise können Probleme sehr früh erkannt werden. Durch die sich wiederholenden Zyklen stellt sich eine +Routine ein, was weniger Fehler zur Folge hat. Architektur, die inkrementell und iterativ entwickelt wird, ist außerdem sehr +flexibel; mit Änderungen an den Anforderungen kann daher relativ einfach umgegangen werden. Risiken und Unsicherheiten werden +durch die Aufteilung in kleine Stücke minimiert. + +## Domain-driven Design + +* Herangehensweise zur Modellierung komplexer Systeme basierend auf Input von Domänenexperten +* gemeinsame, eindeutige Sprache zur Beschreibung des Systems entwickeln +* strategic design - System in Sub-Domänen ("bounded contexts") unterteilen → top-down +* tactical design - zuerst Service, Events, Entities und Daten identifizieren → bottom-up +* gut kombinierbar mit Microservice-Architekturen + +## Evolutionary Architecture + +Inkrementelle Änderungen auf Basis sogenannter "fitness functions", die messen, inwieweit die Anforderungen an das System +erfüllt werden. Diese Messungen können entweder manuell durchgeführt werden, oder im Rahmen von automatischen Tests geschehen. diff --git a/src/lz2/2_02.md b/src/lz2/2_02.md new file mode 100644 index 0000000..7a2a1b4 --- /dev/null +++ b/src/lz2/2_02.md @@ -0,0 +1,74 @@ +# LZ 2-2: Softwarearchitekturen entwerfen + +## Blackboxes und Whiteboxes + +Bausteine eines Systems können als Blackbox oder als Whitebox beschrieben werden: +* Blackboxes verstecken die innere Strukture eines Bausteins: + * Name + * Verantwortlichkeit/Funktion + * Bereitgestellte und benötigte Schnittstellen + * ggf. Qualitätseigenschaften, Einschränkungen, Risiken, Probleme +* Whiteboxes erweitern die Blackboxdarstellung um die innere Struktur + * Überblick (Diagramm) der internen Struktur + * Gründe für das innere Design + * enthaltene Blackboxes + +Das folgende Diagramm zeigt, wie eine Blackbox schrittweise in Whiteboxes zerlegt werden kann: + +
+ +```dot process +graph G { + compound=true; + node [ + fontname="Roboto, sans-serif" + style=filled + fillcolor="#42d4fb" + shape=box + ] + graph [ + fontname="Roboto, sans-serif" + ] + Sys + subgraph clusterSys { + label = "Sys" + { + rank = same + White + Black + } + White -- Black; + } + subgraph clusterWhite { + label = "White" + a -- b; + a -- c; + } + Sys -- White [lhead=clusterSys label=" " style="dashed"] + White -- a [lhead=clusterWhite label=" " style="dashed"] +} +``` + +
+ +## Abhängigkeiten, Trade-Offs und Risiken + +Entscheidungen bezüglich der Architektur haben immer Konsequenzen und schließen Trade-Offs mit ein: +[TANSTAAFL](https://de.wikipedia.org/wiki/TANSTAAFL) (There ain't no such thing as a free lunch). Konkret stehen verschiedene +Qualitätsattribute oft miteinander in Konflikt. Deshalb sollten Architektureintscheidungen explizit getroffen und dokumentiert +werden. + +Beispiele für typische Trade-Offs: + +* gute runtime Performance (gut) wird erreicht durch Caching, parallele Prozesse, komplexe Strategien, was zu mehr Code und Komplexität führt (schlecht) +* gute Benutzerfreundlichkeit (gut) erfordert mehr Aufwand beim UI- und UX-Design, was wiederum mehr Kostet (schlecht) +* besserer Schutz der Privatsphäre (gut) benötigt mehr Auswahlmöglichkteiten, was das System komplizierter zu Benutzten macht (schlecht) + +Beispiele für typische Risiken + +* innovativer, schlecht getesteter Ansatz +* fehlende Erfahrung im Implementierungsteam +* fehlende Tests eine Kombination von Technologien +* die Lösung ist suboptimal, aber es gibt keine bessere Alternative +* die Lösung wurde von oben vorgegeben und ist bekannt dafür, Probleme zu verursachen + diff --git a/src/lz2/2_03.md b/src/lz2/2_03.md new file mode 100644 index 0000000..6a020af --- /dev/null +++ b/src/lz2/2_03.md @@ -0,0 +1,30 @@ +# LZ 2-3: Anforderungen klären und berücksichtigen können + +Bei der Gestaltung der Softwarearchitektur eines Systems sind immer bestimmte Rahmenbedingungen zu beachten, die die möglichen +Ausprägungen der gestalteten Architektur einschränken können. + +Insbesondere können nichtfachliche Qualitätsanforderungen oft einen größeren Einfluss auf die Architektur haben als die +fachlichen Anforderungen. + +## Kategorien von Anforderungen + +Es gibt verschiedene Arten von Anforderungen, die sich grob in die folgenden Kategorien einordnen lassen: + +* produktbezogenen Anforderungen +* Technologische Randbedingungen +* Organisatorischen Randbedingungen +* Regulatorischen Randbedingungen +* Trends + +## Conway's Law + +Conway's Law besagt: + +> Jede Organisation die ein System entwirft, wird zwangsweise einen Entwurf erstellen, der eine Kopie ihrer +> Kommunikationsstruktur ist. + +* oft keine bewusste Entscheidung - "es ist einfach so passiert/gewachsen" +* kann gewünschte Attribute schwächen +* z.B. Struktur der entworfenen Microservices spiegeln bereits existierende Abteilungsstrukturen der Firma wieder +* Inverse Cinway Maneuver - Teams anhand von Architektur (neu) strukturieren + diff --git a/src/lz2/2_04.md b/src/lz2/2_04.md new file mode 100644 index 0000000..e9033b0 --- /dev/null +++ b/src/lz2/2_04.md @@ -0,0 +1,11 @@ +# LZ 2-4: Querschnittskonzepte entwerfen und umsetzen + +Einige Entscheidungen können für viele Bereiche oder sogar alle Elemente einer Architekur relevant sein und beeinflussen - s.g. "Cross-cutting concepts". Diese werden genutzt, um wiederkehrende Probleme ("cross-cutting concerns") zu lösen. Sie gewärleisten außerdem Konsistenz, da sie immer auf die gleiche Art und Weise umgesetzt werden. + +Beispiele: + +* fundamentale Technologieentscheidungen +* Logging +* Frameworks +* Interfacerichtlinien + diff --git a/src/lz2/2_05.md b/src/lz2/2_05.md new file mode 100644 index 0000000..21ff93d --- /dev/null +++ b/src/lz2/2_05.md @@ -0,0 +1,232 @@ +# LZ 2-5: Wichtige Lösungsmuster beschreiben, erklären und angemessen anwenden + +Architekturmuster sind Lösungen für häufig wiederkehrende Probleme. Es ist hilfreich, viele Architekturmuster zu kennen, um das +Rad bei einem bestehenden Problem nicht neu erfinden zu müssen, sondern auf existierende Lösungen zurückgreifen zu können. + +## Layers + +* untere Ebenen verbergen Details vor den darüberliegenden Ebenen. +* obere Ebenen greifen auf darunterliegende Ebenen nur über klar definierte Schnittstellen zu. +* bei "strict Layering" dürfen Ebenen nur auf die direkt darunterliegende Ebene zugreifen, während bei "loose Layering" Ebenen + übersprungen werden dürfen. + +
+
+ +**strict layering** + +```dot process +digraph { + node [ + fontname="Roboto, sans-serif" + style=filled + fillcolor="#42d4fb" + shape=box + ] + "Top" -> "Medium" -> "Lower" -> "Lowest" +} +``` + +
+
+ +**loose layering** + +```dot process +digraph { + rankdir=LR + node [ + fontname="Roboto, sans-serif" + style=filled + fillcolor="#42d4fb" + shape=box + ] + { + rank = same + "Top" + "Medium" + "Lower" + "Lowest" + } + "Top" -> "Medium" -> "Lower" -> "Lowest" + "Top" -> "Lower" + "Top" -> "Lowest" +} +``` + +
+ +
+ +### Pros + +* Abhängigkeiten nur in eine Richtung +* Einfache Struktur, einfach zu verstehen + +### Cons + +* geringere Effizienz wenn eine Anfrage durch mehrere Ebenen muss, um eigendliches "Ziel" zu erreichen +* mögliche Kaskade von Änderungen nötig, wenn sich das Verhalten einer Ebene ändert + +## Pipes and Filters + +
+ +```dot process +digraph { + rankdir=LR + node [ + fontname="Roboto, sans-serif" + style=filled + fillcolor="#42d4fb" + shape=box + ] + edge [ fontname="Roboto, sans-serif" ] + "Filter 1" -> "Filter 2" [label = "Pipe 1"] + "Filter 2" -> "Filter 3" [label = "Pipe 2"] + "Filter 3" -> "Filter 4" [label = "Pipe 3"] +} +``` + +
+ +Beim Verarbeiten von z.B. Datenstreams können größere Aufgaben in eine Reihe kleinere, voneinander unabhängige Schritte ("Filter") getrennt werden, die mit "Pipes" verbunden sind. + +* Filter - transformiert, aggregiert, manipuliert Daten. Erhält Daten über eine/mehrere Input-Pipe(s) und gibt Ergebnis an + eine/mehrere Output-Pipe(s) weiter. +* Pipe - transportiert Daten zwischen Filtern ohne sie zu verändern. Kann Daten auch puffern bis der Emfänger sie verarbeiten + kann. + +### Pros + +* einfache, lineare Abhängkeiten +* flexibel bzgl. der teilnehmenden Schritte/Filter +* wenn das Format des Datenstreams fest definiert oder standartisiert ist, können Filter unabhängig eintwickelt werden (z.B. + siehe Unix) + +### Cons + +* wenn ein Filter auf den gesamten Datenstream warten muss (z.B. zum Sortieren), kann ein Buffer der Input-Pipe überlaufen +* Fehler können möglicherweise schwieriger nachzuverfolgen sein +* möglicherweise schwieriger, globale Daten zu teilen + + +## Microservices + +* *Absicht:* hoch-flexible Systeme bauen, die sich schnell an ändernde Anforderungen anpassen können. +* *Problem:* Monolitische Anwendungen haben oft lange Entwicklungs- und Release-Zyklen, da das Gesamtsystem kompiliert, getestet + und deployed werden muss. +* *Lösung:* Große Systeme in kleine, unabhängig entwickelbare, deploy-bare und lauffähige Einheiten aufteilen, die über das + Netzwerk miteinander kommunizieren. + +### Pros + +* flexiblere Systeme +* kürzere "Time-to-Market", da neue Funktionen und Fixes schneller ausgerollt werden können +* mehr Platz für Innovation und spezifische Technologie-Entscheidungen, da jeder Service technologisch unabhängig ist + +### Cons + +* Fallacies of distributed computing + * "Das Netzwerk ist ausfallsicher." + * "Die Latenzzeit ist gleich 'null'." + * "Der Datendurchsatz ist unbegrentzt." +* zusätzliche Maßnahmen zur Fehlerbehandlung nötig +* Eventual Consistency durch verteilte Systeme und Daten +* Komplexität verschiebt sich von Entwicklung hin zum Deployment und Betrieb +* Testen komplizierter und benötigt meist eigene Infrastruktur/Werkzeuge + +## Dependency Injection + +* *Absicht:* Abhängigkeiten sind abstrakt; konkrete Details können zur Compilezeit oder Laufzeit substituiert werden. +* *Problem:* Eine Komponente hängt von einem Service ab, aber die konkrete Instanz des Services ist zur Entwicklungszeit + entweder unbekannt, variabel oder kann sich in der Zukunft potenziell ändern. +* *Lösung:* Die Auflösung der Abhängigkeit wird auf die Laufzeit oder (seltener) Compilezeit verschoben. Eine eigene Komponente, + der Dependency Injector, kümmert sich darum, geeignete Services zu Laufzeit zu erstellen und in die Komponenten zu injizieren. + +### Pros + +* Das System wird flexibler. +* Komplexität in Bezug auf Entscheidungslogik wird in den Dependency Injector verlagert, der üblicherweise durch ein Framework + bereitgestellt wird. +* Tests können leicht mit Mock-Instanzen des Services durchgeführt werden. + +### Cons + +* Durch die verwendete Indirektion ist der Code potenziell schwerer verständlich +* Fehlkonfiguration kann zu Laufzeitfehlern führen, die in Tests nicht auffallen + +## Blackboard + +Ziel: Integration verschiedenartiger Komponenten mit komplexen, nichtdeterministischen Kontrollstrategien. + +* Lösungsraum und Wissensquellen werden identifiziert. +* Auf der Blackboard-Komponente werden Informationen gesammelt und die anderen Prozesse über die abgelegten Daten + benachrichtigt. +* Eine Kontrollkomponente ruft die einzelnen Wissensquellen auf. + +## Broker + +* Einzelne Komponenten werden voneinander entkoppelt. +* Eine zentrale Komponente, der Broker, verwaltet die gesamte Kommunikation zwischen den Komponenten anhand einer + Routing-Tabelle und einer Filtertabelle. +* Die Kommunikation findet mit Hilfe von Nachrichten statt, die über den Broker versendet werden. + +### Pros + +* konsumierende Komponenten können leicht angepasst werden +* Komponenten sind lose gekoppelt + +### Cons + +* die Broker-Komponente muss äußerst robust und effizient sein, da die anderen Komponenten in ihrer Funktionalität vom Broker + abhängen. +* strikte Datenkonsistenz ist typischerweise nicht gegeben. + +## Interpreter + +Ziel: Abstrakter Syntaxbaum wird im Rahmen eines Kontexts interpretiert. + +### Pros + +* Die Sprache ist leicht erweiterbar. + +### Cons + +* Bei komplexen Syntaxbäumen ist das Interpreter-Pattern schnell sehr ineffizient. + +## Observer + +Eine Komponente (Subjekt) hat eine Liste der Abhängigkeiten (Observers). Bei jeder Zustandsänderung werden alle Observer vom +Subjekt über die Änderung informiert. + +### Pros + +* Abhängigkeiten werden umgekehrt: Das Subjekt muss nicht wissen, welche Observer von ihm abhängen + +### Cons + +* die Struktur wird durch die Indirektion weniger verständlich. +* Observer müssens sich deregistrieren, was ggf. zu Memory Leaks führen kann, wenn die Deregistrierung bei der Implementierung + vergessen wird. + +## Adapter/Fassade/Proxy + +Vereinfachung der Integration von Subsystemen: + +* *Adapter:* Entkopplung von Konsument und Provider - wenn die Schnittstelle des Providers nicht genau mit der des Konsumenten + übereinstimmt. +* *Fassade:* vereinfacht die Verwendung eines Providers für den/die Consumer durch vereinfachten Zugriff. +* *Proxy:* Ein Vermittler/Stellvertreter zwischen Consumer und Provider, der beispielsweise die zeitliche Entkopplung, das + Caching von Ergebnissen oder die Zugriffskontrolle auf den Provider ermöglicht + +## Hexagonale Architektur + +* konsistente Anwendung des Dependency Inversion Principle: Abhängigkeiten sollten immer von Abstrakt zu konkret gehen + +## SOA + +* Abstrakte Services +* schwächere Kopplung durch Abstraktion und Kapselung +* Wiederverwendbarkeit wird gefördert + diff --git a/src/lz2/2_06.md b/src/lz2/2_06.md new file mode 100644 index 0000000..75df2b9 --- /dev/null +++ b/src/lz2/2_06.md @@ -0,0 +1,256 @@ +# LZ 2-6: Entwurfsprinzipien erläutern und anwenden + +Wenn *Entwurfsmuster* Rezepte sind, mit denen wiederkehrende Probleme gelöst werden sollen, setzen *Entwurfsprinzipien* auf +einer höheren Abstraktionsebene an: sie beschreiben nämlich die grundlegenden Prinzipien, die bei der Suche nach konkreten +Architekturlösungen beachtet werden können. Besonders wenn kein Entwurfsmuster auf das gegebene Problem passt, bieten +Entwurfsprinzipien die Gestaltungs- und Bewertungsgrundlage für eine Lösung des Problems. + +## Abstraktion + +* Gemeinsamkeiten mehrerer Komponenten werden in eine gemeinsame Abstraktion dieser Komponenten ausgelagert. +* Details, die außerhalb der Komponenten irrelevant sind, werden in der Abstraktion weggelassen. + +### Ziele + +* Komplexität wird reduziert, indem unwichtige Details weggelassen werden. +* Komponenten können leicht durch andere Komponenten mit der gleichen Abstraktion ersetzt werden. +* Wiederholungen werden vermieden (DRY: Don't Repeat Yourself), was zu besserer Konsistenz, Wartbarkeit, und Verständlichkeit + führt. + +### Risiken + +Das Gesamtsystem wird durch die Einführung von Abstraktionen komplexer. + +### Wann ist dieses Prinzip angebracht? + +Abstraktion ist sinnvoll, wenn ... + +* mindestens zwei Komponenten eine Gemeinsamkeit aufweisen, +* diese Gemeinsamkeit für andere Komponenten relevant sind und +* durch die Verwendung der Abstraktion in anderen Komponenten die Komplexität nicht erhöht wird. + +Eine Abstraktion, die nur an einer Stelle benutzt wird, erhöht typischerweise nur die Komplexität und ist daher nur sinnvoll, +wenn dadurch ein anderes Gestaltungsprinzip verfolgt wird. + +### Das Liskovsche Substitutionsprinzip + +Dieses aus der objektorientierten Programmierung stammende Prinzip besagt, dass eine Spezialisierung ohne Modifikation als +Ersatz für ihre Abstraktionen verwendet werden können soll. Dadurch wird gewährleistet, dass verschiedene konkrete +Implementierungen einer Abstraktion ohne weitere Änderungen durcheinander ersetzt werden können. + +### Beispiele + +* **Schnittstellen** stellen den Teil einer Komponente dar, mit der sie mit ihrer Umgebung in Kontakt tritt. Dadurch können + interne Strukturen und Implementierungsdetails weggelassen werden und verschiedene Implementierungen der gleichen + Schnittstelle leichter durcheinander ersetzt werden. +* Bei **Datenabstraktionen** werden nur abstrakte Eigenschaften eines Datentyps festgelegt, wenn Implementierungsdetails + entweder nicht wichtig sind oder verschiedene Datentypen eine gemeinsame Funktionalität teilen. +* **Programmiersprachen** bieten eine Abstraktion von Maschinencode. **Domänenspezifische Sprachen (DSL)** erlauben eine bessere + Lesbarkeit, Verständlichkeit und Erlernbarkeit von präzisen Spezifikationen (Beispiele: SQL, reguläre Ausdrücke). +* **Softwarearchitektur** selbst ist eine Abstraktion, da Details über Interna von Komponenten weggelassen werden, um eine + verständliche Sicht auf das Gesamtsystem zu erhalten. + +## Modularisierung + +* Ein Gesamtsystem wird in kleinere Komponenten aufgeteilt. +* Jede der Komponenten hat klar spezifizierte und voneinander getrennte Verantwortlichkeiten (Trennung von Verantwortlichkeiten + — Separation of Concerns). +* Interne Details werden nach außen weggekapselt (Geheimnisprinzip — Information Hiding) +* Komponenten treten über wohldefinierte Schnittstellen miteinander in Kontakt +* Die Kopplung zwischen verschiedenen Komponenten ist möglichst lose + +### Ziele + +* Die Komplexität des Gesamtsystems wird reduziert, indem einzelne Komponenten auf Black-Box-Darstellungen reduziert werden + können. +* Einzelne Komponenten können unabhängig voneinander entwickelt und gewartet werden. +* Komponenten können durch andere Komponenten mit äquivalenten Schnittstellen ersetzt werden. + +### Risiken + +* Die Komplexität des Systems kann sich bei unnötiger Modularisierung erhöhen +* Durch Modularisierung kann sich der Resourcenaufwand des Gesamtsystems sowie die Komplexität bei der Entwicklung erhöhen. +* Modularisierung führt grundsätzlich zu einer erhöhten Kopplung zwischen verschiedenen Komponenten. + +### Wann ist dieses Prinzip angebracht? + +Es gibt einige Prinzipien, die dabei helfen können zu entscheiden, ob Modularisierung angebracht ist. + +* Das **Geheimnisprinzip** (Information hiding principle) besagt, dass diejenigen Entscheidungen, die sich am wahrscheinlichsten + ändern werden, möglichst abgekapselt werden. Durch diese Kapselung entstehen Komponenten, die als Black Boxes mit klar + definierten und möglichst stabilen Schnittstellen verwendet werden können, während die interne Implementierung der + Schnittstellen unkompliziert an geänderte Bedürfnisse angepasst werden kann. In diesem Sinne bedeutet die Anwendung des + Geheimnisprinzips eine Instanz des Prinzips der Abstraktion, die grundsätzlich wünschenswert ist. +* Unterschiedliche Aufgaben sollten von unterschiedliche Komponenten ausgeführt werden. Das **Single Responsibility Principle** + (SRP) und das Prinzip der **Trennung von Verantwortlichkeiten** (SoC — Separation of Concerns) sind zwei verschiedene + Perspektiven auf das gleiche Ziel: bei SRP wird von einer Komponente ausgegangen, die nur für eine Aufgabe verantwortlich sein + soll, während bei SoC die Aufteilung eines Systems in verschiedene Komponenten im Vordergrund steht, sodass sich die Aufgaben + der einzelnen Komponenten möglichst wenig überschneiden. Einzelne Komponenten sollten... + * für genau eine Funktionalität des Systems verantwortlich sein; als gute Richtlinie hierbei gilt, dass man die + Verantwortlichkeiten einer Komponente in einem kurzen und präzisen Satz zusammenfassen können sollte. + * nur Funktionen und Unterkomponenten beinhalten, die direkt zu dieser Funktionalität beitragen. + * die Funktionalität abkapseln und durch eine spezifische Schnittstelle bereitstellen. + * nur einen Grund haben sich zu ändern ("one reason to change"). + Durch die Trennung von Verantwortlichkeiten wird eine erhöhte Kopplung zwischen den Komponenten entstehen, die voneinander + getrennt wurden. Das ist prinzipiell akzeptabel, da dadurch Abhängigkeiten und Zusammenhänge zwischen einzelnen Aufgaben + klarer zu Tage treten. +* Die **Kohäsion** einer Komponente beschreibt, wie eng die inneren Elemente der Komponente miteinander in Verbindung stehen. + Typischerweise bedeutet eine niedrige Kohäsion, dass die Komponente verschiedene unabhängige Aufgaben erfüllt und in + verschiedene Komponenten aufgeteilt werden kann, während eine hohe Kohäsion typischerweise mit der Anwendung des Prinzips der + Trennung von Verantwortlichkeiten einhergeht. +* Die **Kopplung** zwischen Komponenten beschreibt die Abhängigkeiten zwischen verschiedenen Komponenten. Es ist nicht möglich, + Kopplung zwischen Komponenten vollständig zu reduzieren, da die Komponenten ja miteinander interagieren sollen. Allerdings + sollte die Kopplung so lose wie möglich ausfallen, in dem Sinne, dass Komponenten möglichst wenig von Implementationsdetails + andere Komponenten abhängen sollten. Eine zu starke Kopplung kann ein Indiz dafür sein, dass eine eigentlich zusammengehörige + Komponente falsch getrennt wurde, aber auch, dass die Schnittstellen zwischen Komponenten detaillierter und spezifischer sind + als nötig. +* Das **offen/geschlossen-Prinzip** besagt, dass Komponenten offen für Erweiterung, aber geschlossen für Veränderung sein + sollten. Das heißt, die Funktionalität einer Komponente soll erweitert werden können, ohne die Komponente selbst verändern zu + müssen. +* Das **Schnittstellentrennungsprinzip** (ISP — Interface Segregation Principle) besagt, dass Schnittstellen möglichst klein und + auf die Bedürfnisse der sie nutzenden Komponenten zugeschnitten sein sollten. Universelle Schnittstellen führen üblicherweise + zu größeren Abhängigkeiten zu anderen Komponenten, während die Trennung von Schnittstellen ein erster Schritt hin zur + Aufteilung einer Komponente gemäß des SoC-Prinzips sein kann. Für die Definition von Schnittstellen siehe auch Schnittstellen. +* **Dependency Inversion:** Komponenten sollten möglichst nicht von Details der Komponenten abhängen, die sie benutzen. Daher + ist es sinnvoll, wenn Komponenten, die eine Funktionalität benötigen, die Schnittstelle zu dieser Funktionalität in einer SPI + (Service Programming Interface) spezifizieren. Die konkrete Implementierung dieser Schnittstelle kann dann einfach durch + andere Implementierungen ersetzt werden, die andere Komponenten benutzen. Dieses Prinzip lässt sich folgendermaßen + zusammenfassen: + * Komponenten auf einer hohen Ebene sollten nicht von Komponenten einer niedrigen Ebene abhängen, sondern beide sollten von Schnittstellen abhängen. + * Abstraktionen sollten nicht auf Implementierungsdetails angewiesen sein. + * Spezialisierungen sollten von Abstraktionen abhängen. + +### Beispiele + +* Die meisten höheren Programmiersprachen haben **Zugriffsmodifikatoren** (protected, private etc.), mit denen der Zugriff auf + Interna eines Objekts oder Moduls beschränkt werden kann. So können die Interna der entsprechenden Komponenten auf Sprachebene + von der Umgebung abgekapselt werden. +* **Webservices** stellen Schnittstellen bereit, über die die gesamte Kommunikation mit dem Service abläuft. Die Interna des + Webservice sind dadurch automatisch von der Umgebung abgekapselt, da es keine Möglichkeit gibt, darauf zuzugreifen. Wird auf + dieser Ebene das Prinzip der Trennung von Verantwortlichkeiten konsequent eingesetzt, kommt man zu **Microservices,** die als + einzelne Webservices nur eine genau beschränkte Verantwortung haben. Weiterhin ist die Kohäsion in einem Microservice + typischerweise deutlich höher als in einem Monolithen, der viele verschiedene Aufgaben wahrnehmen muss. +* **Trennung von Businesslogik und technischen Details:** Ein Beispiel für die Trennung von Verantwortlichen ist, dass die + Businesslogik (oder Anwendungs- bzw. Geschäftslogik) von der benötigten technischen Infrastruktur getrennt werden sollte. + Hierbei bedeutet Businesslogik die dem Problem inhärente Logik, während technische Details wie etwa die konkrete Wahl einer + Datenbank und der Tabellennamen oder eine konkret aufzurufende REST-Schnittstelle eines Webservices beinhaltet. +* **Pipes und Filter** ist ein Beispiel für die Trennung von Verantwortlichkeiten, indem der Informationsfluss (Pipes) von der + Informationsverarbeitung und -manipulation (Filter) getrennt behandelt wird. +* Aus der objektorientierten Programmierung stammen die sogenannten **SOLID-Prinzipien,** die einige der oben genannten + Prinzipien zusammenfassen: + * Single Responsibility Principle + * Open-Closed Principle + * Liskov Substitution Principle + * Interface Segregation Principle + * Dependency Inversion Principle +* Das offen/geschlossen-Prinzip kann durch **Vererbung** in objektorientierten Sprachen implementiert werden. So kann eine + (abstrakte) Basisklasse erweitert werden, ohne selbst geändert werden zu müssen. +* Durch die Nutzung von Frameworks zur **Dependency Injection** kann das Prinzip der Dependency Inversion leicht umgesetzt + werden, indem Service Programming Interfaces (SPI) zur Laufzeit oder zur Compilezeit durch konkrete Implementierungen ersetzt + werden. Dadurch wird erreicht, dass die konkreten Implementierungen von dem implementierten SPI und somit von der abstrakteren + Schicht abhängen anstatt umgekehrt. Ebenfalls wird so offen/geschlossen-Prinzip begünstigt, da die Funktionalität durch die + Bereitstellung anderer konkreter Implementierungen erweitert werden kann, ohne dass die innere (abstrakte) Schicht modifiziert + werden muss. Für die Unterscheidung von APIs und SPIs siehe auch Schnittstellen. + +## Konzeptionelle Integrität + +* Die Gestaltung des Gesamtsystems sollte einem konsistenten Grundgedanken folgen. +* Ähnliche Aufgaben sollten auf ähnliche Weise erledigt werden + +### Ziele + +* Das Verständnis einer Komponente kann auf andere Komponenten übertragen werden. +* Dadurch wird das Gesamtsystem verständlicher und die Weiterentwicklung des Systems wird vereinfacht. +* Gedankliche Kapazität wird auf tatsächlich neue Probleme reduziert + +### Risiken + +Das strikte Befolgen eines Prinzips kann in Einzelfällen zu komplizierteren und weniger verständlichen Lösungen führen, da es zu Einschränkungen beim Design der Architektur führt. + +### Wann ist dieses Prinzip angebracht? + +Grundsätzlich ist konzeptionelle Integrität immer sinnvoll. Allerdings kann es passieren, dass Innovation durch das Beharren auf +konzeptioneller Integrität blockiert wird, da neue Technologien eventuell nicht den bisherigen Konzepten folgen. + +### Beispiele + +* **Das Prinzip der kleinsten Überraschung:** Bei der Gestaltung einer neuen Komponente sollte darauf geachtet werden, dass sie + so strukturiert ist, wie man es am ehesten erwarten würde. +* In **Unix** gilt "everything is a file" als Grundprinzip. Diesem Prinzip folgend, können in Unix-Systemen Byteströme genutzt + werden, um neben der Verarbeitung von Dateien auch etwa Tastaturen, Drucker, Interprozessverbindungen oder + Netzwerkverbindungen zu benutzen. +* Die gesamte Konfiguration von Tabellen wie etwa Indexe wird in **SQL-Datenbanken** üblicherweise wieder in Tabellen abgelegt, + sodass gilt: "alles liegt in einer Tabelle". +* Verschiedene Teile eines Gesamtsystems können im Quellcode die gleiche **Paketstruktur** aufweisen, etwa bestehend aus Paketen + für Controller, Clients, Datenbankzugriff und Servicelogik. +* **Namenskonventionen** wie etwa "REST-Modelle enden immer auf -Rest" können helfen, den Zweck von Komponenten auf einen Blick + zu erfassen. +* **Konsistente Verwendung von Frameworks:** Ein Beispiel für konzeptionelle Integrität in einem System wäre: "Alle Frontends + werden mit React und TypeScript entwickelt, alle Backends mit Micronaut und Kotlin". Dadurch wird erreicht, dass Entwickler + nur wenige Frameworks vertieft verstehen müssen. + +## Einfachheit + +Systeme sollten so einfach wie möglich gehalten werden, um die aktuell geforderten Aufgaben zu erfüllen. + +### Ziele + +Unnötige Komplexität wird vermieden. + +### Risiken + +Viele der anderen Entwurfsprinzipien können dem Prinzip der Einfachheit entgegenwirken. Hier ist es wichtig, ein gutes Mittelmaß +zu finden. + +### Wann ist dieses Prinzip angebracht? + +Bei jeder architektonischen Entscheidung sollte überprüft werden, ob eine einfachere Lösung nicht genauso gut ist. Komplexere +Lösungen müssen nicht grundsätzlich vermieden werden, sollten aber gerechtfertigt werden können. + +### Beispiele + +* Es gibt den Satz von Donald E. Knuth: **"Premature optimization is the root of all evil".** Insbesondere sollte man... +* komplizierte Technologie vermeiden, wenn eine einfache Lösung möglich ist. +* Abstraktionen vermeiden, wenn nur eine konkrete Implementierung existiert und die Abstraktion an nur einer Stelle verwendet + wird. +* Funktionalität erst hinzugefügt werden, wenn sie auch benötigt wird. +* darauf vertrauen, dass zukünftige Entwickler das System sinnvoll weiterentwickeln können. +* den Erfolg von Optimierungen messen und nur erfolgreiche und notwendige Optimierungen im System behalten. + +## Fehler erwarten + +* An jeder Stelle sollte überlegt werden, ... + * was für Fehler entstehen können. + * welche Punkte missverstanden, vergessen oder ignoriert werden könnten. + * was die Folgen für Fehler in Teilen des Systems sind. +* Das **Robustheitsprinzip** (Postels Gesetz) sollte befolgt werden: "Sei konservativ in deinen Handlungen, sei liberal darin, + was von Anderen akzeptiert wird." + * Andere Komponenten sollten so korrekt wie möglich und entsprechend der Spezifikationen benutzt werden. + * Die eigenen Komponenten sollten so weit wie möglich auch funktionieren, wenn sie nicht korrekt benutzt werden. + +### Ziele + +* Durch eine extensive Fehlerbehandlung soll die Resilienz und Fehlertoleranz des Systems erhöht werden. +* Funktionalität des Systems soll erhalten werden, auch wenn Teile des Systems versagen. + +### Risiken + +* Durch die Fehlerbehandlung wird die Komplexität erhöht und gegebenenfalls können sekundäre Fehler entstehen. +* Konsistenz und Integrität des Systems wird verringert, wenn konsumierende Systeme die liberalen Schnittstellen ausnutzen. +* Datenkorrektheit kann reduziert werden, wenn Teile der Daten nicht mitgeliefert, aber auch nicht validiert werden. + +### Wann ist dieses Prinzip angebracht? + +Dieses Prinzip wird immer relevanter, je kritischer die Funktionalität des Systems ist. Das heißt, für missionskritische +Backendsysteme sollte ein größerer Fokus auf Fehlertoleranz gelegt werden als für Frontends mit geringerer Kritikalität für +umliegende Systeme. + +### Beispiele + +* In der funktionalen Programmierung ist es üblich, **Result-Typen** als Rückgabewert zu haben, die entweder aus einem + erfolgreichen Resultat oder einem Fehler bestehen. Das erzwingt Fehlerbehandlung auf der Ebene der Programmiersprache. +* Bei HTTP-Schnittstellen sollten **Fehlercodes** konsistent verwendet werden. Insbesondere sollte + * ein 4xx-Fehlercode bedeuten, dass der Fehler auf der aufrufenden Seite verursacht wurde, und + * ein 5xx-Fehlercode bedeuten, dass der Fehler auf der Serverseite verursacht wurde. +* In Sprachen mit **Exceptions** sollten die erwarteten Exceptions in der Schnittstellendokumentation aufgeführt und beim Aufruf + behandelt oder bewusst weiterpropagiert (und dann wieder entsprechend dokumentiert) werden. diff --git a/src/lz2/2_07.md b/src/lz2/2_07.md new file mode 100644 index 0000000..bfb99b3 --- /dev/null +++ b/src/lz2/2_07.md @@ -0,0 +1,124 @@ +# LZ 2-7: Abhängigkeiten von Bausteinen managen + +Eine Komponente hängt von einer anderen Komponente ab, wenn sie sie auf irgendeine Weise benötigt, etwa um kompiliert, +installiert, getested, gestartet zu werden oder um richtig zu laufen und zu funktionieren. In diesem Abschnitt werden +verschiedene Typen von Abhängigkeiten genauer beschrieben. Abhängigkeiten können üblicherweise nicht vollständig vermieden +werden. + +Risiken und Probleme von Abhängigkeiten sind: +* Änderungen in einer Komponente könnte Änderungen in abhängigen Komponenten nach sich ziehen. +* Kompilierung und Testen von Komponenten wird aufwändiger, da die Abhängigkeiten mit berücksichtigt werden müssen. +* Komponenten sind schwerer wiederzuverwenden, da auch Abhängigkeiten mit eingeschlossen werden müssen. +* Verständnis von Komponenten wird schwieriger, wenn die Abhängigkeiten auch verstanden werden müssen. + +## Daten + +Wenn mehrere Komponenten auf dieselben Daten zurückgreifen, sind sie dadurch voneinander abhängig. + +### Best Practices + +* Komponenten sollten nach Möglichkeit nur sehr explizit gemeinsam genutzte Daten verwenden. +* Da diese Art von Kopplung sehr implizit ist, ist eine gute Dokumentation erforderlich. + +### Abhängigkeit reduzieren + +Die Abhängigkeit kann reduziert werden, indem jede Komponente eigene Daten besitzt, die mit keiner anderen Komponente geteilt +werden. Hierbei spielt das Entwurfsprinzip der Einfachheit gegen das der Modularisierung. + +## Datentypen + +Alle Komponenten, die den gleichen Datentyp verwenden, sind über den Datentyp miteinander gekoppelt. Der Grund hierfür ist: wenn +eine Komponente eine Veränderung im Datentyp benötigt, dann müssen eventuell auch alle anderen Komponenten, die den gleichen +Datentyp benutzen, angepasst werden. + +### Best Practices + +* Gemeinsame Datentypen sollten möglichst dort verwendet werden, wo kaum Änderungen zu erwarten sind. +* Insbesondere kann Dependency Inversion dafür genutzt werden, dass immer konkretere Komponenten von abstrakteren abhängen und so möglichst selten Änderungen am geteilten Datentyp notwendig werden. +* Falls der gemeinsame Datentyp doch angepasst werden muss, ist diese Änderung gegebenenfalls abwärtskompatibel möglich. + +### Abhängigkeit reduzieren + +Diese Art von Abhängigkeit kann reduziert werden, indem Komponenten ihre eigenen Datentypen definieren. Allerdings erhöht sich +so die Komplexität. + +## Delegation + +Eine Delegation ist ein Aufruf einer Funktion in einer Komponente durch eine andere Komponente. + +### Best Practices + +* So ein Aufruf sollte über eine spezifizierte öffentliche Schnittstelle stattfinden. +* Auf gar keinen Fall sollten interne Details der aufzurufenden Komponente verwendet werden. Auf Programmiersprachenebene kann + das oft durch Sichtbarkeits-Modifikationen vermieden werden. +* Die Kopplung wird loser, indem für den Aufruf eine Interface-Methode benutzt wird. Außerdem können die Konsequenzen der + Abhängigkeit durch Dependency Inversion reduziert werden. + +### Abhängigkeit reduzieren + +* Gegebenenfalls kann eine Delegations-Abhängigkeit reduziert werden, indem die aufgerufene Methode in die aufrufende Komponente + verschoben wird. +* Gegebenenfalls kann ein direkter (synchroner) Aufruf durch Nachrichten und Events ersetzt werden, wodurch die Kopplung loser + wird. +* Eine direkte Kopplung zwischen Komponenten via Delegation kann durch Entwurfsmuster wie Broker oder Registrys in eine + indirekte und losere Kopplung umgewandelt werden. + +## Erzeugung + +Wenn eine Komponente eine andere Komponente (Factory) benötigt, um instanziiert zu werden, dann ist die Komponente von der +Factory abhängig. + +### Best Practices + +Um die Konzeptionelle Integrität zu erhöhen, sollte auf Erzeugungsmuster wie abstrakte +[Factories](https://en.wikipedia.org/wiki/Creational_pattern) zurückgegriffen werden. + +## Hardware + +Komponenten können voneinander abhängen, wenn sie die gleiche Hardware benutzen oder wenn eine der Komponenten zur Voraussetzung +hat, dass sich die andere Komponente auf derselben Hardware befindet. Ein Beispiel hierfür wäre eine verschlüsselte Komponente, +die zum Laufen einen Schlüssel benötigt, der in eine bestimmte Hardware eingebettet ist. + +## Komposition + +Wenn eine Komponente in einer anderen Komponente enthalten ist, ist die enthaltende Komponente abhängig von den Komponenten, die +sie enthält. Teilweise können auch enthaltene Komponenten von der sie umgebenden Komponente abhängen, wenn sie nicht isoliert +existieren können. + +## Nachrichten und Events + +In beiden Fällen wird eine Information asynchron von einer Komponente an eine andere übertragen. So entsteht eine (relativ lose) +Abhängigkeit zwischen Sender und Empfänger der Information. Die beiden Begriffe sind nicht vollständig klar definiert und +voneinander abgegrenzt, aber die Grundidee ist folgende: + +* Bei einer *Nachricht* (Message) wird von der Sender-Komponente eine Aktion angefragt. Üblicherweise erwartet die + Senderkomponente, dass die Nachricht irgendwie bearbeitet wird, aber eine Antwort wird nicht erwartet. +* Bei einem *Event* informiert ein Sender beliebig viele Empfänger über etwas, das passiert ist. Typischerweise ist dem + Produzent des Events nicht klar, ob und wie viele Empfänger das Event hat. + +## Vererbung + +Eine Unterklasse ist abhängig von der Oberklasse, dem Interface, oder dem Objekt, von dem sie erbt. Diese Kopplung ist sehr eng, +da der Ballast der Eltern sich vollständig auf die Kinder überträgt. + +### Best Practices + +Die Kopplung bei der Vererbung von Interfaces ist im Allgemeinen loser als bei der Vererbung von Klassen, wenn keine konkreten +Implementierungen mitvererbt werden. + +## Zeitliche Kopplung + +Eine zeitliche Kopplung liegt dann vor, wenn eine Komponente eine Aufgabe nur dann ausführen kann, wenn zuvor eine andere +Komponente eine andere Aktion ausgeführt hat. Die erste Komponente hängt dann von der zweiten ab, selbst wenn keine direkte +Abhängigkeit in irgendeiner Form vorhanden ist. + +### Best Practices + +Da zeitliche Kopplungen sehr implizite Abhängigkeiten sind, sollten sie besonders gut dokumentiert sein. + +### Abhängigkeit reduzieren + +* Durch asynchrone Kommunikation mittels Nachrichten und Events kann eine zeitliche Kopplung gegebenenfalls aufgehoben werden. +* Typischerweise sind zeitliche Abhängigkeiten mit einem globalen oder geteilten Zustand verbunden. Wenn dieser vermieden werden + kann, kann gegebenenfalls auch die zeitliche Abhängigkeit vermieden werden. + diff --git a/src/lz2/2_08.md b/src/lz2/2_08.md new file mode 100644 index 0000000..76f55b7 --- /dev/null +++ b/src/lz2/2_08.md @@ -0,0 +1,53 @@ +# LZ 2-8: Qualitätsanforderungen mit passenden Ansätzen und Techniken erreichen + +Später wird das Thema *Qualität* noch ausführlicher behandelt. Die Erreichung von Qualitätsanforderungen ist eine der +wichtigsten Aufgaben von Softwarearchitekt:innen. Dabei können die im Folgenden beschriebenen *Architekturtaktiken* helfen. +Diese Taktiken sind wiederkehrende Muster, die dabei helfen können, bestimmte Kategorien von Qualitätsanforderungen systematisch +zu erreichen. + +## Performanztaktiken + +* **Verringerung von Resourcenanforderungen**, indem unnötiger + * unnötiger Overhead vermieden, + * Berechnungszeiten verlängert und + * die Effizienz der verwendeten Algorithmen verbessert wird. +* **Resourcen verbessert nutzen** durch + * eine balancierte Nutzung der Resourcen, etwa durch Load Balancer, + * die Erhöhung der verfügbaren Resourcen, also vertikale oder horizontale Skalierung, und + * die Replikation von Daten. +* **Vermittlung zwischen widersprüchlichen Anforderungen** vermitteln durch: + * Scheduling von Aufgaben sowie + * eine erhöhte Anzahl gleichzeitig ablaufender Prozesse und Synchronisation zwischen diesen + +## Verfügbarkeitstaktiken + +* **Fehlererkennung** durch Konzepte wie + * Pings und Heartbeats, + * Health checks und Selbsttests oder + * Monitoring +* **Resilienz**, also die Fähigkeit, Fehler zu verzeihen und sich von ihnen zu regenerieren, kann erreicht werden durch + * Redundanz, + * Fehlerbehandlung, + * Rollbacks, + * Retries, oder + * das bewusste Ignorieren der Fehler, wenn sie für den Kontrollfluss nicht so wichtig sind. +* **Fehler können vermeiden werden**, indem + * fehlerhafte Komponenten aus dem System entfernt, + * Transaktionen verwendet und + * Exceptions vermieden werden. + +## Wartbarkeitstaktiken + +* **Erwartbare Änderungen sollten möglichst lokal gehalten werden**, damit der Aufwand für diese Änderungen möglichst gering + bleibt. Das kann durch + * eine Verringerung der Größe oder Aufteilung von Modulen, + * Kapselung von Komponenten und + * die Verringerung von Abhängigkeiten und Kopplung erreicht werden. +* **Sichtbarkeit beschränken** durch + * Die Befolgung des Geheimnisprinzips, + * Konstante und abwärtskompatible Schnittstellen, und + * die Trennung von Schnittstellen von ihrer Implementierung. +* **Vermeidung von Nachwirkungen und Kettenreaktionen**, indem + * Abhängigkeitsketten aufgebrochen und + * Kommunikationswege beschränkt werden. + diff --git a/src/lz2/2_09.md b/src/lz2/2_09.md new file mode 100644 index 0000000..7139376 --- /dev/null +++ b/src/lz2/2_09.md @@ -0,0 +1,41 @@ +# LZ 2-9: Schnittstellen entwerfen und festlegen + +Schnittstellen sind die Beschreibung und Definition der Zusammenarbeit verschiedener architektonische Bausteine. Im folgenden +werden die Elemente beschrieben, die eine Schnittstelle ausmachen. + +## Syntax + +Unter der *Syntax* einer Schnittstelle versteht man die formalen Kriterien für den Aufruf der Schnittstelle und die formale +Struktur der Antwort auf diesen Aufruf. Hierunter fallen beispielsweise die Typen der Objekte, die über die Schnittstelle +ausgetauscht werden (also Ein- und Ausgabetypen), die Funktionen/Methoden mit ihren Namen und ihrer Signatur. + +## Semantik + +Die *Semantik* umfasst die Bedeutung der Schnittstelle inklusive der einzelnen Methoden, der verwendeten Objekte und Felder. + +## Protokoll + +Das *Protokoll* beantwortet die folgende Frage: *Welche Interaktionen sind zwischen Konsument und Anbieter der Schnittstelle +nötig?* Das schließt die Reihenfolge der Aufrufe, die Voraussetzungen für die Aufrufe sowie andere Bedingungen oder Erwartungen +im Sinne von Contracts ein, die einerseits an die aufrufende Komponente, andererseits aber auch an das verhalten der +Schnittstelle gestellt werden. Ein Beispiel wäre ein Contract, der aussagt, dass die übergebenen Objekte nicht mutiert werden, +auch wenn diese Eigenschaft nicht formal, etwa durch die verwendete Programmiersprache, garantiert werden kann. + +## Medium + +Das physikalische oder technische *Medium*, über das die Kommunikation stattfindet, kann die Schnittstelle beeinflussen. + +## Qualitätscharakteristiken + +Beispiele für *Qualitätscharakteristiken* von Schnittstellen sind: +* Performanz +* Last +* Verlässlichkeit + +## Versionierung + +Hierbei sollten folgende Fragen beantwortet werden: +* Ist die Schnittstelle versioniert? +* Wie können verschiedene Versionen der Schnittstelle voneinander abgegrenzt angesprochen werden? +* Sind die Versionen der Schnittstelle abwärtskompatibel? + diff --git a/src/lz2/2_10.md b/src/lz2/2_10.md new file mode 100644 index 0000000..8006b89 --- /dev/null +++ b/src/lz2/2_10.md @@ -0,0 +1,35 @@ +# LZ 2-10: Grundlegende Prinzipien von Software-Deployments kennen + +Unter einem **Deployment** wird der Prozess verstanden, unter dem die Software zur tatsächlichen Nutzung bereitgestellt wird. +Solche Deployments können manuell oder automatisiert stattfinden, wobei automatisierte Deployments den Vorteil bieten, dass sie +leichter reproduzierbar und testbar sind. + +Die Praktiken von *Continuous Integration* (CI), *Continuous Delivery* (CD) und *Continuous Deployment* können helfen, die Zeit +zu verringern, die bis zur Bereitstellung der entwickelten Software vergeht. + +## Continuous Integration + +Bei *Continuous Integration* wird Source Code in einem Repository so oft und schnell wie möglich auf den Hauptbranch gemerged. +Dadurch kann die komplexe Merge-Prozedur vermieden werden, die entsteht, wenn Features erst zu einem Release-Datum gemerged +werden. Automatisierte Tests sind im Rahmen von Continuous Integration essenziell, um sicherzugehen, dass die Anwendung zu jeder +Zeit korrekt funktioniert. + +## Continuous Delivery + +Zusätzlich zur Continuous Integration werden bei der *Continuous Delivery* die Änderungen am Source Code automatisiert in eine +Test- oder Produktionsumgebung nach der Build-Stage deployed. Der Kernpunkt hier ist, dass das Deployment automatisiert abläuft +und nur gegebenenfalls manuell für die jeweiligen Stages gestartet wird. + +## Continuous Deployment + +*Continuous Deployment* geht noch einen Schritt weiter als Continuous Delivery, indem hier grundsätzlich auch Deployments +automatisiert ablaufen. Das wird durch extensive Integrationstests des Codes ermöglicht. Der Vorteil hierbei ist, dass neue +Features sehr schnell bereitgestellt werden können und Fehler schneller erkannt werden. Der Nachteil ist, dass durch die +geringere Testzeit auf Pre-Deployment-Stages eventuell weniger Fehler erkannt werden, bevor das System produktiv deployed wird. + +## Rollbacks + +Der Begriff *Rollback* bezeichnet die Bereitstellung einer früheren Version des Systems, beispielsweise wenn festgestellt wurde, +dass die neue Version fehlerhaft läuft. Um das Risiko von Deployments zu verringern, ist es sinnvoll, die Möglichkeit von +Rollbacks mitzuberücksichtigen. Besonders schwierig ist das bei Abhängigkeiten von Datenstrukturen, etwa nach Datenmigrationen. + diff --git a/src/lz2/aufgaben.md b/src/lz2/aufgaben.md new file mode 100644 index 0000000..cb04197 --- /dev/null +++ b/src/lz2/aufgaben.md @@ -0,0 +1,154 @@ +# Aufgaben zu LZ 2 + +**Welche zwei Aussagen bezüglich Top-down- und Bottom-up-Design stimmen am ehesten?** + +1. Top-down- und Bottom-up-Design können in demselben Projekt verwendet werden. +2. Top-down erfordert, dass Details zunächst ignoriert werden. +3. Architekten überlassen das Bottom-up-Design normalerweise den Entwicklern. +4. Im Allgemeinen sollten Architekten top-down arbeiten. +5. Bottom-up-Design bedeutet, vom Abstrakten zum Konkreten vorzugehen. + +
+
+ 1, 2 +
+
+ +**Welche dieser Aussagen zu inkrementeller Entwicklung sind wahr und welche falsch?** + +1. Es ist oft nötig, bei der Planung der Softwarearchitektur iterativ vorzugehen, da nicht alle Anforderungen von Anfang an bekannt sind. +2. Bereits vor der ersten Iteration sollten die wichtigsten Architekturentscheidungen getroffen werden. +3. Inkrementelle Entwicklung kann dabei helfen, Risiken bei der Entwicklung zu verringern. +4. Architekturdokumente sind in einem iterativen Setting nicht nötig, da Architekturentscheidungen dem Entwicklerteam in Daily Standups mitgeteilt werden können. +5. Der Gesamtaufwand für den Entwurf von Softwarearchitekturen ist in einem iterativen Projekt typischerweise deutlich höher als in einem Wasserfall-Projekt. + +
+
+ wahr: 1, 3 +
+
+ +**Welche der Attribute gehören zu Black-Boxen, welche zu White-Boxen und welche zu beiden?** + +1. interne Struktur +2. bereitgestellte Funktionalitäten +3. benutzte Algorithmen +4. bekannte Risiken oder Probleme + +
+
+ Black-Box: 2, 4; White-Box: 1, 2, 3, 4 +
+
+ +**Welche drei dieser Faktoren haben typischerweise den höchsten Einfluss auf den Entwurf von Softwarearchitekturen?** + +1. ethische Faktoren +2. Organisationsstrukturen +3. Datenschutzregulatorien +4. technische Einschränkungen +5. Budget + +
+
+ 2, 3, 4 +
+
+ +**Welche dieser Bedingungen müssen vor dem Entwurf einer Softwarearchitektur erfüllt sein?** + +1. Die Namen der Stakeholder sind bekannt. +2. Die Programmiersprache, in der das System entwickelt werden soll, wurde ausgewählt. +3. Die wichtigsten Qualitätsanforderungen wurden kommuniziert. +4. Compliance-Regeln innerhalb der Organisation sind bekannt. +5. Eine vollständige Liste von Anforderungen an das System wurde bereitgestellt. +6. Das Entwicklerteam hat Hardware für die Entwicklung erhalten. + +
+
+ 3, 4 +
+
+ +**Welche drei dieser Qualitätsanforderungen werden durch eine schichtenbasierte Architektur am ehesten verbessert?** + +1. Zirkuläre Abhängigkeiten werden vermieden. +2. Der Speicherbedarf wird reduziert. +3. Die Verständlichkeit des Systems wird verbessert. +4. Durch das Prinzip "Separation of Concerns" könen einzelne Schichten unabhängig voneinander weiterentwickelt werden. + +
+
+ 1, 3, 4 +
+
+ +**Welche der folgenden Aussagen sind wahr?** + +1. Eine Microservice-Architektur kann Time-to-market für neue Funktionen und Fehlerbehebungen deutlich verbessern. +2. Durch die Nutzung von Pipes-and-Filters können einzelne Verarbeitungsschritte leicht ausgetauscht werden. +3. Die Fehlerbehebung wird sowohl durch Microservices als auch bei Pipes-and-Filters einfacher. +4. Dependency Injection hilft dabei, konkrete Details von Komponenten durch Abstraktion zu kapseln. +5. Integrationstests für ein aus Microservices basiertes System kann im Vergleich zu einem Monolithen deutlich komplexer werden. +6. Dependency Injection kann durch die verwendete Indirektion dazu führen, dass der Code für neue Entwickler:innen schwerer verständlich wird. + +
+
+ wahr: 1, 2, 4, 5, 6 +
+
+ +**Welche Aussage zum Dependency Inversion Principle stimmt?** + +1. Große Komponenten sollten nicht von kleinen Komponenten abhängen. +2. Dependency Injection ist ein geeignetes Mittel, um das Dependency Inversion Principle umzusetzen. +3. Abstrakte Komponenten sollten immer von konkreten abhängen. + +
+
+ 2 +
+
+ +**Ihr seid mit der Entwicklung eines Web-Frontends zu einer API beauftragt. Welche zwei der folgenden Aussagen sind Konsequenzen des Robustheitsprinzips (Postels Gesetz)?** + +1. Das Frontend sollte die API nicht mit unspezifizierten Parametern aufrufen, selbst wenn der Aufruf in Tests funktioniert. +2. Bei der Entwicklung des Frontends ist die API-Dokumentation eine wichtige Quelle von Informationen. +3. Fehler sollten dem Benutzer des Frontends möglichst ungefiltert angezeigt werden. +4. Falls die API eine Zahl als Zeichenkette formatiert, sollte das Ergebnis verworfen und der Benutzer über den Fehler informiert werden. + +
+
+ 1, 2 +
+
+ +**Welche dieser Aussagen treffen zu und welche sind falsch?** + +1. Es ist Ziel einer Architektur, die Kopplung zwischen allen Komponenten vollständig aufzulösen. +2. Starke Kopplung hilft dabei, Qualitätsanforderungen leichter zu überprüfen. +3. Hohe Kohäsion in einer Komponente impliziert, dass die Komponente mit anderen Komponenten nur lose gekoppelt ist. +4. Eine übermäßig genaue Spezifikation von Schnittstellen führt zu starker Kopplung. +5. Niedrige Kohäsion folgt aus der konsequenten Anwendung des Prinzips der Trennung von Verantwortlichkeiten. +6. Grundsätzlich ist eine Softwarearchitektur mit höherer Kohäsion in allen Komponenten erstrebenswerter als eine mit niedriger Kohäsion. + +
+
+ wahr: 4, 6 +
+
+ +**Welche drei dieser Punkte muss man am stärksten beachten, wenn man externe Schnittstellen entwirft?** + +1. Angemessene Verwendung des Broker-Musters +2. Von benachbarten Systemen benötigte Protokolle +3. Erwartete Anzahl paralleler Aufrufe +4. Einfachheit der Implementierung auf Seite des aufrufenden Systems +5. Minimierung von Überraschungen und Seiteneffekten + +
+
+ 2, 4, 5 +
+
+ diff --git a/src/lz3/3_01.md b/src/lz3/3_01.md new file mode 100644 index 0000000..c6ee6f7 --- /dev/null +++ b/src/lz3/3_01.md @@ -0,0 +1,42 @@ +# LZ 3-1: Anforderungen an technische Dokumentation + +## Korrektheit + +* Inkorrekte Dokumentation führt zu inkorrekter Benutzung des Systems. +* Fehler in Teilen der Dokumentation führen dazu, dass Benutzer der übrigen Dokumentation weniger vertrauen. + +## Aktualität + +* Da Korrektheit sich über die Zeit verändert, ist das ein Aspekt von Korrektheit. + +## Nützlichkeit + +* Dokumentation sollte sowohl bei der Entwicklung als auch bei der Benutzung des Systems hilfreich sein. +* Als Faustregel gilt: Der Aufwand mit Dokumentation sollte geringer sein als der Aufwand ohne Dokumentation. +* Informationen, die mittels Dokumentation vermitteln können, schließen folgende Punkte mit ein: + * übergreifende Strukturen des Systems + * architektonische und technologische Entscheidungen sowie Gründe für diese Entscheidungen + * übergreifende Konzepte + +## Wartbarkeit + +* Dokumentation muss leicht änderbar sein, um die Aktualität gewährleisten zu können. + +## Verständlichkeit + +* Dokumentation muss leicht zu verstehen sein. +* Dazu können Reviews und Feedback der Konsumenten der Dokumentation helfen, denn die Verständlichkeit der Dokumentation kann abschließend nur von der Zielgruppe beurteilt werden. + +## Übersichtlichkeit + +* Die Struktur der Dokumentation muss es dem Leser erleichtern, Information in der Dokumentation zu finden. +* Templates wie arc42 und andere Konventionen helfen hierbei. + +## Angemessenheit + +* Die Dokumentation muss für die Anforderungen des Systems angemessen sein. +* Insbesondere ist es möglich, dass verschiedene Stakeholder verschiedene Anforderungen an die Dokumentation stellen. + +# Aufgaben + + diff --git a/src/lz3/3_02.md b/src/lz3/3_02.md new file mode 100644 index 0000000..8a649e5 --- /dev/null +++ b/src/lz3/3_02.md @@ -0,0 +1,37 @@ +# LZ 3-2: Softwarearchitekturen beschreiben und kommunizieren + +## Unzulänglichkeit von Source Code als Dokumentation + +Folgende Aspekte von Software können in Source Code nicht hinreichend beschrieben werden: +* Übergreifende Struktur: Wie ist das System strukturiert? +* Architekturentscheidungen: + * Welche Technologien, Strukturen, Entwurfsmuster, Konventionen etc. werden genutzt? + * Warum ist die Entscheidung so ausgefallen? Welche Alternativen wurden aus welchen Gründen verworfen? +* Querschnittskonzepte: Was beeinflusst mehrere Teile des Systems? + +## Abhängigkeit der Dokumentation vom jeweiligen Stakeholder + +Dokumentation kann beispielsweise für folgende verschiedene Zielgruppen relevant sein: +* Management +* Entwicklungsteams +* QS-Abteilung +* andere Softwarearchitekt:innen +* zusätzliche Stakeholder + +Je nach Zielgruppe können sich Aspekte der Dokumentation entscheiden, wie beispielsweise: +* Format: Wiki, Präsentation, Dokument, mehrere Dokumente, gebundenes Buch etc. +* Stil: Text, Stichpunkte, Diagramm, Mischung +* Struktur: beispielsweise spezifische Vorgaben für ein Template +* Notation: z.B. UML +* Tiefe + +## Vorteile von Templates + +* Verständlichkeit und Lesbarkeit der Dokumentation ist für Personen verbessert, die mit dem Template vertraut sind. Das + ermöglicht eine schnellere Einarbeitung in das System. +* Auffindbarkeit von konkreten Informationen wird für Personen verbessert, die mit dem Template vertraut sind. +* Es ist einfacher, Teile der Dokumentation für andere Systeme wiederzuverwenden, falls die entsprechenden Aspekte der Systeme + übereinstimmen. +* Die Erstellung und Wartung der Dokumentation wird vereinfacht, da klar ist, an welchen Stellen Informationen eingefügt oder + angepasst werden müssen. + diff --git a/src/lz3/3_03.md b/src/lz3/3_03.md new file mode 100644 index 0000000..0833204 --- /dev/null +++ b/src/lz3/3_03.md @@ -0,0 +1,4 @@ +# LZ 3-3: Notations- und Modellierungsmittel + +Für relevante UML-Diagrammtypen siehe +[die UML-Referenz im Scandio-Inside](https://inside.scandio.de/display/COPSOFTWAREARCHITECTURE/UML). diff --git a/src/lz3/3_04+05.md b/src/lz3/3_04+05.md new file mode 100644 index 0000000..0051d83 --- /dev/null +++ b/src/lz3/3_04+05.md @@ -0,0 +1,54 @@ +# LZ 3-4/3-5: Architektursichten und Kontextabgrenzung + +Architektursichten stellen verschiedene Aspekte dar, unter denen die Softwarearchitektur eines Systems im Detail betrachtet +werden kann. + +## Kontextsicht + +Der Kontext eines Systems umfasst diejenigen Teile der Umgebung des Systems, die relevant für das System sind. Das können Nachbarn sein, die direkt mit dem System interagieren, aber auch weitere Komponenten, die indirekte Relevanz für das System besitzen. Um den Begriff des Kontexts zu klären, sind zwei Fragen relevant: + +* Was ist der Umfang des Systems? +* Was sind die externen Schnittstellen des Systems und wie wird mit ihnen interagiert? + +### Fachlicher und technischer Kontext + +* Der fachliche Kontext umfasst externe Abhängigkeiten aus einer fachlichen Perspektive, wobei technische Details als Black Box behandelt werden. Schnittstellen und Teile des Kontexts werden mit ihrer fachlichen Bedeutung ohne technische Begrifflichkeiten beschrieben. +* In manchen Fällen ist auch der technische Kontext früh in der Entwicklung relevant, wie etwa bei eingebetteten Systemen. Der technische Kontext umfasst Details wie Protokoll, Adressen, physikalische Medien etc. + +### Dokumentation + +Eine Möglichkeit, die Kontextsicht zu beschreiben, ist ein Komponentendiagramm zusammen mit einer Tabelle: + +* Das Komponentendiagramm beinhaltet den Überblick über den Kontext des Systems, wobei das System selbst als eine Komponente als Black Box dargestellt wird. +* Die Tabelle wird für Erläuterungen verwendet, was einzelne Schnittstellen oder Teile des Kontexts bedeuten. + +## Bausteinsicht + +Die Bausteinsicht beschreibt die statische Aufteilung des Systems in seine Komponenten und ihre Beziehungen. + +### Dokumentation + +* In der Kontextsicht wird das Gesamtsystem als Blackbox behandelt, das in der Bausteinsicht schrittweise verfeinert wird. +* Dazu sind wie bei der Kontextsicht statische UML-Diagramme verwendet werden. +* Zusätzlich sollten die enthaltenen Black Boxes kurz beschrieben, die Schnittstellen und Abhängigkeiten zwischen den Komponenten erläutert, und die Gestaltung der inneren Struktur der Komponenten begründet werden. + +## Laufzeitsicht + +In der Laufzeitsicht wird das Verhalten, die Interaktionen, und die Laufzeitabhängigkeiten der Komponenten des Systems in allgemeinen oder konkreten Szenarien beschrieben. + +### Dokumentation + +Es gibt viele Möglichkeiten, solche Laufzeitbeschreibungen zu erstellen. Falls nötig, sollten Interaktionen tabellarisch oder in Textform genauer beschrieben werden. Neben Pseudocode zur Beschreibung von Laufzeitverhalten sind alle dynamischen UML-Diagrammtypen nützlich: + +* Sequenzdiagramme +* Aktivitätsdiagramme, gegebenenfalls mit Schwimmbahnen, die die einzelnen beteiligten Bausteine beschreiben +* Zustandsmaschinendiagramme + +## Deploymentsicht + +Die Deploymentsicht (Verteilungssicht) beschreibt, auf welcher technischen Infrastruktur das System und seine Bausteine ausgeführt wird. In dieser Sicht können auch verschiedene Umgebungen (Test-, Staging-, Production-Umgebung) beschrieben werden. + +### Dokumentation + +Hier sind Verteilungsdiagramme sinnvoll, mit Knoten, die die Elemente der Infrastrukture (Hardware, Prozessoren, Server, etc.) beschreiben, und Kanten, die die Knoten miteinander Verbinden. Softwareartefakte sollten entweder in dem Diagramm enthalten sein oder es sollte eine zusätzliche Beschreibung (etwa in Tabellenform) geben, in der die Information über die Verteilung der Artefakte auf die Hardware enthalten ist. + diff --git a/src/lz3/3_06.md b/src/lz3/3_06.md new file mode 100644 index 0000000..ef4d732 --- /dev/null +++ b/src/lz3/3_06.md @@ -0,0 +1 @@ +# LZ 3-6: Querschnittskonzepte diff --git a/src/lz3/3_07.md b/src/lz3/3_07.md new file mode 100644 index 0000000..704d060 --- /dev/null +++ b/src/lz3/3_07.md @@ -0,0 +1 @@ +# LZ 3-7: Schnittstellen diff --git a/src/lz3/3_08.md b/src/lz3/3_08.md new file mode 100644 index 0000000..e7ad825 --- /dev/null +++ b/src/lz3/3_08.md @@ -0,0 +1 @@ +# LZ 3-8: Architekturentscheidungen diff --git a/src/lz3/3_09.md b/src/lz3/3_09.md new file mode 100644 index 0000000..90c02a8 --- /dev/null +++ b/src/lz3/3_09.md @@ -0,0 +1 @@ +# LZ 3-9: Weitere Hilfsmittel diff --git a/src/lz3/aufgaben.md b/src/lz3/aufgaben.md new file mode 100644 index 0000000..c90486e --- /dev/null +++ b/src/lz3/aufgaben.md @@ -0,0 +1,143 @@ +# Aufgaben zu LZ 3 + +**Welche 4 Aussagen treffen am ehesten zu?** + +1. Dokumentation sollte an Stakeholder zur Review gegeben werden. +2. Es ist wichtiger, jeden Aspekt eines Systems zu dokumentieren als zu gewährleisten, dass die Dokumentation leicht aktuell gehalten werden kann. +3. Jede Datei im Quellcode sollte in der Dokumentation referenziert werden. +4. Eine leicht anpassbare Dokumentation hilft, Aktualität und somit Korrektheit der Dokumentation zu gewährleisten. +5. Der Aufwand mit Dokumentation sollte geringer sein als der Aufwand ohne Dokumentation. +6. In der Dokumentation sollten die wichtigsten Qualitätsziele und wesentliche Architekturentscheidungen aufgeführt + +
+
+ 1, 4, 5, 6 +
+
+ +**Welche der folgenden Aussagen sind korrekt?** + +1. Architekturdokumentation kann beim Onboarding neuer Entwickler:innen helfen. +2. Architekturdokumentation sollte möglichst nur vom Chefarchitekten des Systems angefertigt werden. +3. Die gesamte Dokumentation sollte automatisiert aus dem Source Code generiert werden. +4. Es ist möglich, dass die Rechtsabteilung eines Konzerns spezifische Anforderungen an Form oder Inhalt der Architekturdokumentation stellt. +5. Templates können nützlich für die Anfertigung der Dokumentation sein. + +
+
+ 1, 4, 5 +
+
+ +**Welche der folgenden Techniken können zur Darstellung statischer Strukturen dienen, und welche sind für die Darstellung dynamischer Prozesse geeignet?** + +1. Klassendiagramm +2. Verteilungsdiagramm +3. Sequenzdiagramm +4. Paketdiagramm +5. Aktivitätsdiagramm +6. Komponentendiagramm + +
+
+ statisch: 1, 2, 4, 6; dynamisch: 3, 5 +
+
+ +**Welche vier dieser Techniken können bei der Erstellung der Laufzeitsicht eines Systems am ehesten helfen?** + +1. tabellarische Beschreibung von Abläufen +2. Verteilungsdiagramme +3. Pseudo-Code +4. Sequenzdiagramme +5. Aktivitätsdiagramme +6. Venn-Diagramme + +
+
+ 1, 3, 4, 5 +
+
+ +**Welche der folgenden Informationen sollten Teil der Black-Box-Beschreibung einer Komponente sein?** + +1. Schnittstellen +2. innerer Aufbau +3. verwendete Programmiersprache +4. Name +5. Aufgaben + +
+
+ 1, 4, 5 +
+
+ +**Welche dieser Informationen sind Teil der Bausteinsicht und welche Teil der Deploymentsicht?** + +1. Ausführungsumgebungen wie Hardware/Server +2. technische Kommunikationskanäle zwischen Komponenten +3. White-Box-Darstellungen von Komponenten + +
+
+ Bausteinsicht: 3; Deploymentsicht: 1, 2 +
+
+ +**Welche dieser Aussagen sind korrekt?** + +1. Der Businesskontext umfasst die physischen Kanäle, über die das System mit der Umgebung verbunden ist. +2. Der Businesskontext enthält eine Black-Box-Darstellung des Gesamtsystems. +3. Im technischen Kontext wird das konkrete Framework beschrieben, in dem das System implementiert ist. +4. Der technische Kontext enthält alle externen Schnittstellen des Systems. +5. Konkrete Bus-Nummern von Hardware können Teil des technischen Kontexts sein, wenn sie für die Funktionalität des Systems relevant sind. + +
+
+ korrekt: 2, 5 +
+
+ +**Welche drei dieser Aussagen über Querschnittskonzepte sind am angemessensten?** + +1. Querschnittskonzepte sollten mit Hilfe eines Templates beschrieben werden. +2. Querschnittskonzepte sind nach Möglichkeit zu vermeiden, um Abhängigkeiten zwischen Komponenten zu reduzieren. +3. Logging und Monitoring sind typische Beispiele von Querschnittskonzepten. +4. Ein Querschnittskonzept kann die Implementierung mehrerer Bausteine beeinflussen. +5. Da Querschnittskonzepte generell mehr Vorteile als Risiken besitzen, ist eine Dokumentation der Risiken nicht nötig. + +
+
+ 1, 3, 4 +
+
+ +**Welche dieser Informationen können Teil einer Schnittstellenbeschreibung sein?** + +1. Name und Version +2. mögliche Fehler +3. Seiteneffekte +4. Entwurfsentscheidungen +5. Stabilität +6. Einschränkungen/Bedingungen für die Nutzung + +
+
+ 1, 2, 3, 4, 5, 6 +
+
+ +**Welche dieser Aussagen sind korrekt?** + +1. Jede Architekturentscheidung sollte schriftlich festgehalten und begründet werden. +2. ADRs stellen eine Möglichkeit für die systematische Dokumentation von Architekturentscheidungen dar. +3. Architekturentscheidungen können explizit oder implizit in der Bausteinsicht eines Systems aufgeführt werden. +4. Trade-Offs zwischen Qualitätsmerkmalen sollten explizit entschieden und dokumentiert werden. + +
+
+ 2, 3, 4 +
+
+ diff --git a/src/lz4/4_01.md b/src/lz4/4_01.md new file mode 100644 index 0000000..7d5bfdb --- /dev/null +++ b/src/lz4/4_01.md @@ -0,0 +1 @@ +# LZ 4-1: Qualitätsmodelle und Qualitätsmerkmale diff --git a/src/lz4/4_02.md b/src/lz4/4_02.md new file mode 100644 index 0000000..cf3f6f1 --- /dev/null +++ b/src/lz4/4_02.md @@ -0,0 +1 @@ +# LZ 4-2: Qualitätsanforderungen diff --git a/src/lz4/4_03.md b/src/lz4/4_03.md new file mode 100644 index 0000000..59f3753 --- /dev/null +++ b/src/lz4/4_03.md @@ -0,0 +1 @@ +# LZ 4-3: Qualitätive Analyse diff --git a/src/lz4/4_04.md b/src/lz4/4_04.md new file mode 100644 index 0000000..01e08a1 --- /dev/null +++ b/src/lz4/4_04.md @@ -0,0 +1 @@ +# LZ 4-4: Quantitative Bewertung diff --git a/src/lz4/aufgaben.md b/src/lz4/aufgaben.md new file mode 100644 index 0000000..005cfaa --- /dev/null +++ b/src/lz4/aufgaben.md @@ -0,0 +1,58 @@ +# Aufgaben zu LZ 4 + +**Welche der folgenden Qualitätsmerkmale stehen typischerweise miteinander in Konflikt?** + +1. Sicherheit vs. Benutzbarkeit +2. Speicherbedarf vs. Leistungseffizienz +3. Wartbarkeit vs. Verständlichkeit +4. Konfigurierbarkeit vs. Zuverlässigkeit + +
+
+ 1, 2, 4 +
+
+ +**Welche Typen von Qualitätsszenarien gibt es?** + +1. Nutzungsszenarien +2. Änderungsszenarien +3. Analyseszenarien +4. Fehlerszenarien + +
+
+ 1, 2, 4 +
+
+ +**Welche vier dieser Personengruppen können bei der qualitativen Analyse eines Systems am ehesten helfen?** + +1. Product Owner +2. Entwickler:innen +3. Budgetverantwortliche:r +4. Scrum Master +5. Benutzer:innen +6. Mitarbeitende im Support + +
+
+ 1, 2, 5, 6 +
+
+ +**Welche dieser Metriken können für eine quantitative Analyse der Architektur genutzt werden?** + +1. Entwicklersympathie pro Komponente +2. bekannte Bugs pro Komponente +3. Test Coverage +4. Zyklomatische Komplexität +5. Anzahl der Entwickler:innen, die an einer Komponente arbeiten +6. Durchschnittlicher Aufwand für Bug Fixes pro Komponente + +
+
+ 1, 2, 3, 4, 6 +
+
+ diff --git a/theme/css/custom.css b/theme/css/custom.css new file mode 100644 index 0000000..5b8d284 --- /dev/null +++ b/theme/css/custom.css @@ -0,0 +1,57 @@ +/* Base styles and content styles */ + +@import url(https://fonts.googleapis.com/css?family=Raleway:800|Roboto:300); + +:root { + --scandio-red: #d21515; + --scandio-blue: #42d4fb; +} + +.coal { + --quote-bg: hsl(226, 15%, 17%); +} + +.light { + --links: var(--scandio-red); + --quote-bg: var(--scandio-blue); +} + +html { + font-family: "Roboto", sans-serif; +} + +h1,h2,h3 { + font-family: "Raleway", sans-serif; + font-weight: 800; +} + +.solution { + margin: 12px 0; +} + +.solution * { + margin-top: 12px; +} + +.solution:not(.expanded) * { + display: none; +} + +.solution::before { + content: 'Lösung'; + cursor: pointer; + color: var(--links); +} + +.solution:hover::before { + color: var(--scandio-blue); +} + +a:hover { + color: var(--scandio-blue); +} + +.content a:hover { + text-decoration: none; +} + diff --git a/theme/favicon.png b/theme/favicon.png new file mode 100644 index 0000000..32868ec Binary files /dev/null and b/theme/favicon.png differ diff --git a/theme/favicon.svg b/theme/favicon.svg new file mode 100644 index 0000000..6da2ee6 --- /dev/null +++ b/theme/favicon.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + diff --git a/theme/head.hbs b/theme/head.hbs new file mode 100644 index 0000000..37ccf61 --- /dev/null +++ b/theme/head.hbs @@ -0,0 +1,11 @@ +