Software-Architektur (Monolith / Death Start / Tier etc.)

Ghost_Rider_R schrieb:
1. Klassen dürfen grundsätzlich fast immer und überall bekannt sein und müssen dies auch, sonst kann man damit ja nicht arbeiten. Diese sollten beim Schichtenmodell so also nicht direkt betrachtet werden, die Klasse String oder DateTime verwende ich ja auch ständig, ich denke so eine Abhängigkeit ist nicht mit dem Schichtenmodell gemeint.

Nahezu alles sind Klassen. Wenn du aber allgemeine Objekte ohne große Businesslogik meinst, dann liegen diese in einem extra Projekt (Im Beispiel unter Dependency.Common) und können von jedem anderen Projekt beliebig referenziert werden. Das sind quasi die komplexeren Varianten von Datetime/String und sie werden manchmal auch POCO genannt.

Ghost_Rider_R schrieb:
2. ... Sollte zwei Klassen in einer darunterliegenden Schicht das selbe Objekt benötigen z.B. eine DB-Verbindung, so kann das selbe Objekt auch an mehrere Zweige durchgereicht werden, sodass zwei Klassen das selbe Objekt verwenden können.

Ob es wirklich das gleiche Objekt oder aber eine neue Instanz ist, wird beim Registrieren der Klasse in der DI festgelegt (Stichwort: Transistent, Singleton, Scoped). Meine Empfehlung ist, konsequent Constructor-Injection zu nutzen.

Ghost_Rider_R schrieb:
3. Verwende wenn möglich immer Interfaces, sodass die dahinterliegende Implementierung austauschbar bleibt.

Kein Muss. Wenn die Implementierung nie ausgetauscht wird, erhöht es nur sinnlos die Komplexität.

Ghost_Rider_R schrieb:
4. Das Schichtenmodell bezieht ...

Siehe 1.

Ghost_Rider_R schrieb:
5. ... ich möchte für jede zusammenhängende Funktion eine eigene Bibliothek erstellen, welche ich dann bei diversen Anwendungen wiederverwenden kann. So z.B. eine Bibliothek für DB-Zugriffe, eine für REST-API zugriffe, eine zum einlesen von Excel-Daten, eine Klasse ,,Konvertierung", welche bei mir häufig verwendete Konvertierungsfunktionen bereitstellt etc.

Das ist üblich (siehe NuGet) und läuft dann als Third-Party-Library, die von deiner Businesslogik verwendet wird.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Ghost_Rider_R
Mextli schrieb:
Microservices die über ein (lahmes) REST Api miteinander kommunizieren fängt man eigentlich erst ab einer gewissen Skalierung an zu bauen.
Und da liegt schon der Fehler. Wenn die Microservices so geschnitten sind, dass sie viel untereinander kommunizieren muessen, dann ist schon was falsch gelaufen!
Man sollte eine vernuenftige Choreographie immer einer Orchestrierung vorziehen. Idealerweise ist eine Microservice-Architektur sternfoermig mit einem Eventbus in der Mitte.

orchestration-vs-choreography-097566bf059109c51c8a95faaf3ea77092a626c2a63bc5f06ae0a7ade4a31378.png



Man sollte NIEMALS Microservices so schneiden, dass sie ihre Aufgabe nicht erfuellen koennen, ohne zig andere Microservices aufzurufen. Ausnahme bilden einzig Crosscutting Concerns wie Authentication.
Ansonsten werden die Dependencies zwischen den Services schnell zum limitierenden Faktor.
 
  • Gefällt mir
Reaktionen: BeBur, Madman1209 und Ghost_Rider_R
efcoyote schrieb:
C#:
public A(Lazy<B> b) { }

public B(Lazy<A> a) { }
;)

Autofac kann es Out-of-the-Box und bei MS muss man es gesondert registrieren.
Und du bist dir wirklich sicher, dass das per Constructor Injection funktioniert? Teste das mal lieber aus ;-D
 
Funktioniert tadellos. Wie geschrieben kann Autofac es ohne zusätzliche Registrierungen. Bei der DI von Microsoft wird hingegen eine benötigt:
C#:
services.AddTransient<Lazy<A>>(provider => new Lazy<A>(provider.GetService<A>));
services.AddTransient<Lazy<B>>(provider => new Lazy<B>(provider.GetService<B>));
Damit hängt A dann nicht mehr direkt von B ab, lässt sich allerdings in A nutzen durch die späte Auflösung der Expression.
 
Ich glaub in dem Codebeispiel oben ist dir ein Fehler unterlaufen.

Aber selbst die Autofac Doku schreibt:

Constructor/Constructor Dependencies​

Two types with circular constructor dependencies are not supported. You will get an exception when you try to resolve types registered in this manner.

You may be able to work around this using the DynamicProxy2 extension and some creative coding.
Quelle: https://autofac.readthedocs.io/en/latest/advanced/circular-dependencies.html

Vermutlich wird der Service durch das Lazy Konstrukt erst bei der Verwendung resolved, weswegen es im Konstruktor nicht fliegt, halte aber nichts davon, weil es schlechten Programmierstil unterstützt.
 
Das ist richtig, dass Zirkelreferenzen nicht unterstützt werden. Der Code ist korrekt und geprüft. Und Autofac ist in der Lage Lazy<A> fehlerfrei aufzulösen, wenn nur A registriert wurde. Ich habe nicht behauptet, dass Autofac Zirkelreferenzen unterstützt.
Wenn 2 Klassen (z.B. im Business-Layer) gegenseitig Methoden voneinander nutzen, dann kann man es entweder mit später Auflösung (Lazy) realisieren, Property Injection nutzen oder aber die Methoden in eine 3. Klasse auslagern. Was davon besser ist, liegt wie so oft im Auge des Betrachters bzw. ist abhängig vom konkreten Code. Richtig ist aber auch, dass man Zirkelreferenzen vermeiden sollte, wo immer es geht.
 
  • Gefällt mir
Reaktionen: VD90
@SheepShaver sowas geht nur, wenn du die Microservices auf einen Anwendungsfall zuschneidest oder alles gerade am neu entwickeln bist und man ettliche Programmierer, Architekten, Projektleiter etc hat, die das große Ganze im Auge haben.

Ansonsten hast du immer eine Orchestrierung über eine Middleware dazwischen. Irgendwann kommt die Anforderung, dass der JSON Response eines Events in SAP übergeben werden muss und bspw. der SAP Funktionsbaustein unterstützt auf einmal kein JSON sondern nur XML in einer bestimmten Struktur. Und es macht keinen Sinn (ROI Kosten/Nutzenfaktor), einen erneuten Microservice an dieser Stelle zu entwickeln, der nur die Altlast des SAP FB löst.
 
Zurück
Oben