ArchitekturprinzipienArchitectural principles

„Wenn Architekten Gebäude so bauen würden, wie Programmierer Programme erstellen, würde der erste Specht, der auftauchen würde, die Zivilisation zerstören.“"If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization."
- Gerald Weinberg- Gerald Weinberg

Sie sollten Softwarelösungen mit der Verwaltbarkeit im Hinterkopf entwickeln und entwerfen.You should architect and design software solutions with maintainability in mind. Die Prinzipien, die in diesem Artikel erläutert werden, können Ihnen bei Entscheidungen bezüglich der Architektur helfen, wodurch Sie ordentliche und verwaltbare Anwendungen erstellen können.The principles outlined in this section can help guide you toward architectural decisions that will result in clean, maintainable applications. Im Allgemeinen begleiten Sie diese Prinzipien in Richtung der Erstellung von Anwendungen aus einzelnen Komponenten, die nicht eng an andere Teile Ihrer Anwendung gebunden sind, sondern die eher über explizite Schnittstellen oder Nachrichtensysteme kommunizieren.Generally, these principles will guide you toward building applications out of discrete components that are not tightly coupled to other parts of your application, but rather communicate through explicit interfaces or messaging systems.

Allgemeine EntwurfsprinzipienCommon design principles

Separation of ConcernsSeparation of concerns

Ein Leitprinzip beim Entwickeln ist das Separation of Concerns.A guiding principle when developing is Separation of Concerns. Dieses Prinzip macht geltend, dass Software basierend auf der Arbeit, die von dieser ausgeführt wird, getrennt werden soll.This principle asserts that software should be separated based on the kinds of work it performs. Ein Beispiel hierfür ist eine Anwendung, die Logik zur Identifizierung von wichtigen Elementen enthält, die dem Benutzer angezeigt werden sollen, und die diese Elemente in einer Art und Weise formatiert, sodass diese auffälliger werden.For instance, consider an application that includes logic for identifying noteworthy items to display to the user, and which formats such items in a particular way to make them more noticeable. Das Verhalten, das dafür verantwortlich ist, welche Elemente formatiert werden, sollte von dem Verhalten getrennt werden, das für das Formatieren der Elemente verantwortlich ist, da diese Verhaltensweisen separate Aspekte sind, die nur zufällig miteinander in Verbindung stehen.The behavior responsible for choosing which items to format should be kept separate from the behavior responsible for formatting the items, since these behaviors are separate concerns that are only coincidentally related to one another.

Anwendungen können – architektonisch gesehen – logisch erstellt werden, um diesen Prinzipien zu folgen, indem das grundlegende Geschäftsverhalten von der Infrastruktur und der Logik der Benutzeroberfläche getrennt wird.Architecturally, applications can be logically built to follow this principle by separating core business behavior from infrastructure and user-interface logic. Im Idealfall sollten sich Geschäftsregeln und Logik in einem separaten Projekt befinden, das nicht von anderen Projekten in der Anwendung abhängig sein darf.Ideally, business rules and logic should reside in a separate project, which should not depend on other projects in the application. Diese Trennung stellt sicher, dass das Geschäftsmodell einfach zu testen ist und sich entwickeln kann, ohne eng an Details der untergeordneten Implementierung geknüpft zu sein.This separation helps ensure that the business model is easy to test and can evolve without being tightly coupled to low-level implementation details. Die Separation of Concerns spielt im Hinblick auf die Verwendung von Schichten in Anwendungsarchitekturen eine wichtige Rolle.Separation of concerns is a key consideration behind the use of layers in application architectures.

KapselungEncapsulation

Unterschiedliche Teile einer Anwendung müssen die Kapselung verwenden, um sie von anderen Teile der Anwendung zu isolieren.Different parts of an application should use encapsulation to insulate them from other parts of the application. Anwendungskomponenten und -schichten sollten ihre interne Implementierung anpassen können, ohne dass Fehler bei ihren Komponenten verursacht werden, solange nicht gegen externe Verträge verstoßen wird.Application components and layers should be able to adjust their internal implementation without breaking their collaborators as long as external contracts are not violated. Durch die ordnungsgemäße Verwendung der Kapselung kann die lose Kopplung und Modularität in Anwendungsdesigns erreicht werden, da Objekte und Pakete durch alternative Implementierung ersetzt werden können, solange dieselbe Schnittstelle beibehalten wird.Proper use of encapsulation helps achieve loose coupling and modularity in application designs, since objects and packages can be replaced with alternative implementations so long as the same interface is maintained.

In Klassen erfolgt die Kapselung durch Verringern des Zugriffs auf den internen Zustand der Klasse von außerhalb.In classes, encapsulation is achieved by limiting outside access to the class's internal state. Wenn ein Akteur von außerhalb den Zustand des Objekts manipulieren will, sollte dies durch eine klar definierte Funktion (oder einen Eigenschaftensetter) erfolgen und nicht über den Direktzugriff auf den privaten Zustand des Objekts.If an outside actor wants to manipulate the state of the object, it should do so through a well-defined function (or property setter), rather than having direct access to the private state of the object. Anwendungskomponenten und Anwendungen selbst müssen ebenso klar definierte Schnittstellen für die Verwendung durch ihre Komponenten vorweisen und nicht zulassen, dass ihr Zustand direkt geändert werden kann.Likewise, application components and applications themselves should expose well-defined interfaces for their collaborators to use, rather than allowing their state to be modified directly. Dadurch kann das interne Design der Anwendung über einen Zeitraum weiterentwickelt werden, ohne dass die Sorge besteht, dass durch diese Aktion Fehler bei Komponenten auftritt, solange die öffentlichen Verträge bestehen.This frees the application's internal design to evolve over time without worrying that doing so will break collaborators, so long as the public contracts are maintained.

AbhängigkeitsumkehrDependency inversion

Die Abhängigkeitsrichtung innerhalb der Anwendung sollte sich in Richtung der Abstraktion bewegen, nicht in Richtung Implementierungsdetails.The direction of dependency within the application should be in the direction of abstraction, not implementation details. Die meisten Anwendungen werden so geschrieben, dass die Kompilierzeitabhängigkeit in Richtung der Runtimeausführung geht und ein Diagramm der direkten Abhängigkeit produziert.Most applications are written such that compile-time dependency flows in the direction of runtime execution, producing a direct dependency graph. Das heißt, wenn Modul A eine Funktion in Modul B aufruft, die eine Funktion in Modul C aufruft, hängt A zur Kompilierzeit von B ab, das von C abhängt, wie in Abbildung 4-1 gezeigt.That is, if module A calls a function in module B, which calls a function in module C, then at compile time A will depend on B, which will depend on C, as shown in Figure 4-1.

Diagramm der direkten Abhängigkeit

Abbildung 4-1.Figure 4-1. Diagramm der direkten AbhängigkeitDirect dependency graph.

Durch die Anwendung des Prinzips der Abhängigkeitsumkehr kann A Methoden auf einer Abstraktion abrufen, die von B implementiert wird. So kann B von A zur Laufzeit aufgerufen werden, jedoch kann B von einer Schnittstelle abhängig sein, die von A zur Kompilierzeit kontrolliert wird (das bedeutet, dass die typische Kompilierzeitabhängigkeit umgekehrt wird).Applying the dependency inversion principle allows A to call methods on an abstraction that B implements, making it possible for A to call B at runtime, but for B to depend on an interface controlled by A at compile time (thus, inverting the typical compile-time dependency). Der Ablauf der Programmausführung bleibt zur Laufzeit unverändert, jedoch bedeutet die Einführung von Schnittstellen, dass unterschiedliche Implementierungen dieser Schnittstellen einfach mit eingeschlossen werden können.At run time, the flow of program execution remains unchanged, but the introduction of interfaces means that different implementations of these interfaces can easily be plugged in.

Diagramm der umgekehrten Abhängigkeit

Abbildung 4-2.Figure 4-2. Diagramm der umgekehrten AbhängigkeitInverted dependency graph.

Die Abhängigkeitsumkehrung ist ein wichtiger Bestandteil beim Erstellen von lose gekoppelten Anwendungen, da die Implementierungsdetails so geschrieben werden können, dass sie von übergeordneten Abstraktionen abhängig sind und diese implementieren, anstatt andersherum.Dependency inversion is a key part of building loosely coupled applications, since implementation details can be written to depend on and implement higher-level abstractions, rather than the other way around. Die sich daraus ergebenden Anwendungen können besser getestet werden, sind modular und deshalb auch besser verwaltbar.The resulting applications are more testable, modular, and maintainable as a result. Die Methode der Abhängigkeitsinjektion wird durch das nachfolgende Prinzip der Abhängigkeitsumkehrung ermöglicht.The practice of dependency injection is made possible by following the dependency inversion principle.

Explizite AbhängigkeitenExplicit dependencies

Methoden und Klassen sollten explizit alle benötigten zusammenarbeitenden Objekte erfordern, um ordnungsgemäß zu funktionieren.Methods and classes should explicitly require any collaborating objects they need in order to function correctly. Damit Klassen sich in einem gültigen Zustand befinden bzw. ordnungsgemäß funktionieren können, bieten Klassenkonstruktoren die Möglichkeit, dass Klassen die dafür benötigen Elemente identifizieren können.Class constructors provide an opportunity for classes to identify the things they need in order to be in a valid state and to function properly. Wenn Sie Klassen identifizieren, die konstruiert und aufgerufen werden können, die jedoch nur ordnungsgemäß funktionieren, wenn bestimmte globale Komponenten bzw. Komponenten der Infrastruktur vorhanden sind, sind diese Klassen Ihren Kunden gegenüber unehrlich.If you define classes that can be constructed and called, but that will only function properly if certain global or infrastructure components are in place, these classes are being dishonest with their clients. Der Konstruktorvertrag sagt aus, dass der Kunde nur die angegebenen Elemente benötigt (wenn möglich auch nichts, wenn die Klasse nur einen parameterlosen Konstruktor verwendet), aber zur Laufzeit wird angegeben, dass das Objekt etwas anderes benötigt.The constructor contract is telling the client that it only needs the things specified (possibly nothing if the class is just using a parameterless constructor), but then at runtime it turns out the object really did need something else.

Durch Befolgen des expliziten Abhängigkeitsprinzips sind Ihre Klassen und Methoden gegenüber den Kunden ehrlich, wenn es um die Elemente geht, die sie benötigen, um ordnungsgemäß zu arbeiten.By following the explicit dependencies principle, your classes and methods are being honest with their clients about what they need in order to function. Bei Befolgen dieses Prinzips wird Ihr Code selbstdokumentierender und Ihr Codierungsvertrag benutzerfreundlicher, da Benutzer darauf vertrauen werden, dass die Objekte, mit denen sie arbeiten, sich zur Runtime ordnungsgemäß verhalten, solange sie die erforderlichen Methoden oder Konstruktorparameter bereitstellen.Following the principle makes your code more self-documenting and your coding contracts more user-friendly, since users will come to trust that as long as they provide what's required in the form of method or constructor parameters, the objects they're working with will behave correctly at run time.

Prinzip der einzigen Verantwortung (Single Responsibility)Single responsibility

Das Prinzip der einzigen Verantwortung gilt für ein objektorientiertes Design, kann aber auch als Architekturprinzip ähnlich der Separation of Concerns angesehen werden.The single responsibility principle applies to object-oriented design, but can also be considered as an architectural principle similar to separation of concerns. Es besagt, dass Objekte nur eine Verantwortung haben dürfen und dass sie nur einen Grund für eine Änderung haben dürfen.It states that objects should have only one responsibility and that they should have only one reason to change. Dies bedeutet, dass das Objekt nur dann geändert werden muss, wenn die Art und Weise, wie es seine einzige Aufgabe durchführt, aktualisiert werden muss.Specifically, the only situation in which the object should change is if the manner in which it performs its one responsibility must be updated. Wenn Sie dieses Prinzip befolgen, können Sie mehr lose gekoppelte und modulare Systeme erstellen, da viele Teile des neuen Verhalten als neue Klassen implementiert werden können, und so wird vorhandenen Klassen keine zusätzliche Verantwortung hinzugefügt.Following this principle helps to produce more loosely coupled and modular systems, since many kinds of new behavior can be implemented as new classes, rather than by adding additional responsibility to existing classes. Das Hinzufügen neuer Klassen ist immer sicherer als das Ändern vorhandener Klassen, da noch kein Code von den neuen Klassen abhängig ist.Adding new classes is always safer than changing existing classes, since no code yet depends on the new classes.

In einer monolithischen Anwendung können wir das Prinzip der einzigen Verantwortung allgemein auf die Schichten in der Anwendung anwenden.In a monolithic application, we can apply the single responsibility principle at a high level to the layers in the application. Die Präsentationsverantwortung muss im Benutzeroberflächenprojekt verbleiben, während die Datenzugriffsverantwortung innerhalb eine Infrastrukturprojekts beibehalten werden sollte.Presentation responsibility should remain in the UI project, while data access responsibility should be kept within an infrastructure project. Geschäftslogik sollte im Anwendungskernprojekt verbleiben, wo sie einfach getestet werden kann und sich unabhängig von anderen Verantwortungen entwickeln kann.Business logic should be kept in the application core project, where it can be easily tested and can evolve independently from other responsibilities.

Wenn dieses Prinzip auf die Anwendungsarchitektur angewendet wird und bis zu ihrem logischen Endpunkt reicht, erhalten Sie Microservices.When this principle is applied to application architecture and taken to its logical endpoint, you get microservices. Ein bestimmter Microservice muss über eine einzige Verantwortung verfügen.A given microservice should have a single responsibility. Wenn Sie das Verhalten eines Systems erweitern müssen, ist es in der Regel am besten, dies durch Hinzufügen von zusätzlichen Microservices zu tun, anstatt Verantwortung zu einem vorhandenen Verhalten hinzuzufügen.If you need to extend the behavior of a system, it's usually better to do it by adding additional microservices, rather than by adding responsibility to an existing one.

Weitere Informationen zur MicroservicearchitekturLearn more about microservices architecture

Don't Repeat Yourself (DRY)Don't repeat yourself (DRY)

Die Anwendung sollte kein Verhalten angeben, das mit einem bestimmten Konzept in mehreren Bereichen im Zusammenhang steht, da diese Methode eine bekannte Fehlerquelle ist.The application should avoid specifying behavior related to a particular concept in multiple places as this practice is a frequent source of errors. Zu einem späteren Zeitpunkt können geänderte Anforderungen dazu führen, dass dieses Verhalten geändert werden muss.At some point, a change in requirements will require changing this behavior. Es ist wahrscheinlich, dass mindestens eine Instanz des Verhaltens nicht aktualisiert werden kann, und das System wird sich inkonsistent verhalten.It's likely that at least one instance of the behavior will fail to be updated, and the system will behave inconsistently.

Kapseln Sie die Logik in einem Programmierungskonstrukt anstatt sie zu duplizieren.Rather than duplicating logic, encapsulate it in a programming construct. Machen Sie dieses Konstrukt zur einzelnen Autorität über dieses Verhalten. Ein anderer Teil der Anwendung, die dieses Verhalten erfordert, verwendet dann dieses neue Konstrukt.Make this construct the single authority over this behavior, and have any other part of the application that requires this behavior use the new construct.

Hinweis

Verknüpfen Sie keine Verhaltensmuster, die sich nur durch Zufall wiederholen.Avoid binding together behavior that is only coincidentally repetitive. Auch wenn zwei unterschiedliche Konstanten über den gleichen Wert verfügen, bedeutet das nicht, dass Sie nur eine Konstante besitzen dürfen, wenn diese sich konzeptuell gesehen auf unterschiedliche Dinge beziehen.For example, just because two different constants both have the same value, that doesn't mean you should have only one constant, if conceptually they're referring to different things.

Ignorieren der PersistenzPersistence ignorance

Das Ignorieren der Persistenz (Persistence Ignorance, PI) bezieht sich auf Typen, die beibehalten werden müssen, deren Code jedoch von der Wahl der Persistenztechnologie nicht beeinflusst wird.Persistence ignorance (PI) refers to types that need to be persisted, but whose code is unaffected by the choice of persistence technology. Solche Typen werden in .NET häufig als „Plain Old CLR Objects“ (POCOs) bezeichnet, da sie nicht von einer bestimmten Basisklasse erben oder eine bestimmte Schnittstelle implementieren müssen.Such types in .NET are sometimes referred to as Plain Old CLR Objects (POCOs), because they do not need to inherit from a particular base class or implement a particular interface. Das Ignorieren der Persistenz ist wertvoll, weil das Geschäftsmodell so auf unterschiedliche Weise beibehalten werden kann, wodurch zusätzliche Flexibilität für die Anwendung garantiert werden kann.Persistence ignorance is valuable because it allows the same business model to be persisted in multiple ways, offering additional flexibility to the application. Die Wahl der Persistenz kann sich mit der Zeit von einer Datenbanktechnologie zur anderen ändern, oder es sind möglicherweise zusätzliche Persistenzformen entsprechend der Komponente erforderlich, mit der die Anwendung gestartet wurde (z. B. mithilfe eines Redis-Caches oder mit Azure Cosmos DB zusätzlich zu einer relationalen Datenbank).Persistence choices might change over time, from one database technology to another, or additional forms of persistence might be required in addition to whatever the application started with (for example, using a Redis cache or Azure Cosmos DB in addition to a relational database).

Einige Beispiele für Verstöße gegen dieses Prinzip:Some examples of violations of this principle include:

  • Eine erforderliche BasisklasseA required base class.

  • Eine erforderliche SchnittstellenimplementierungA required interface implementation.

  • Klassen, die für die Speicherung von sich selbst verantwortlich sind (z. B. das Muster „Aktiver Datensatz“)Classes responsible for saving themselves (such as the Active Record pattern).

  • Erforderlicher parameterloser KonstruktorRequired parameterless constructor.

  • Eigenschaften, die ein virtuelles Schlüsselwort erfordernProperties requiring virtual keyword.

  • Eigens für die Persistenz erforderliche AttributePersistence-specific required attributes.

Die Anforderung, dass Klassen über eines der oben genannten Features oder Verhalten verfügen müssen hat zur Folge, dass die Kopplung zwischen Typen beibehalten werden muss, sowie die Wahl der Persistenztechnologie. So wird es schwieriger, zukünftig neue Strategien für den Datenzugriff zu realisieren.The requirement that classes have any of the above features or behaviors adds coupling between the types to be persisted and the choice of persistence technology, making it more difficult to adopt new data access strategies in the future.

KontextgrenzenBounded contexts

Kontextgrenzen stellen ein zentrales Muster im domänengesteuerten Design dar.Bounded contexts are a central pattern in Domain-Driven Design. Sie bieten die Möglichkeit, mit der Komplexität in großen Anwendungen und Organisation umzugehen, indem eine Aufteilung in einzelne konzeptuelle Module erfolgt.They provide a way of tackling complexity in large applications or organizations by breaking it up into separate conceptual modules. Jedes konzeptuelle Modul stellt einen Kontext dar, der von anderen Kontexten getrennt (also gebunden) ist und sich unabhängig entwickeln kann.Each conceptual module then represents a context that is separated from other contexts (hence, bounded), and can evolve independently. Jede Kontextgrenze sollte idealerweise ihre eigenen Namen für interne Konzepte auswählen und über exklusiven Zugriff auf den eigenen persistenten Speicher verfügen können.Each bounded context should ideally be free to choose its own names for concepts within it, and should have exclusive access to its own persistence store.

Anstatt eine Datenbank mit anderen Anwendungen zu teilen, sollten einzelne Webanwendungen darin bestrebt sein, mindestens die eigene Kontextgrenze darzustellen, mit eigenem persistenten Speicher für ihr Geschäftsmodell.At a minimum, individual web applications should strive to be their own bounded context, with their own persistence store for their business model, rather than sharing a database with other applications. Die Kommunikation zwischen Kontextgrenzen erfolgt über Programmschnittstellen und nicht über eine freigegebene Datenbank. So können Geschäftslogik und Ereignisse als Reaktion auf auftretende Änderungen erfolgen.Communication between bounded contexts occurs through programmatic interfaces, rather than through a shared database, which allows for business logic and events to take place in response to changes that take place. Kontextgrenzen sind Microservices eng zugeordnet. Diese sind ebenso ideal als ihre eigenen individuellen Kontextgrenzen implementiert.Bounded contexts map closely to microservices, which also are ideally implemented as their own individual bounded contexts.

Zusätzliche RessourcenAdditional resources