A QUICK SUMMARY – FOR THE BUSY ONES
TABLE OF CONTENTS
Ein neues Projekt zu starten ist immer aufregend und vielversprechend. Es birgt jedoch auch viele Herausforderungen, da es eine gründliche Navigation durch zahlreiche Entscheidungen erfordert, um einen Kurs festzulegen, der die zukünftige Entwicklung des Systems optimal sichert.
Dieser Artikel befasst sich mit der Entscheidungsfindung, Strategien und Entscheidungen in Bezug auf ein neues Projekt zielt darauf ab schrittweises Ersetzen eines bestehenden großen Systems durch eine neuartige Plattform.
Die Architektur, die wir unten vorstellen, bietet uns Einfachheit zu Beginn des Projekts, wenn wir viel brauchen Flexibilität aufgrund plötzlicher Änderungen der Anforderungen, ohne jedoch die Sicherheit der Lösung sowie Qualität und Beobachtbarkeit.
Trotz der Umstände des beschriebenen Projekts sind wir der Ansicht, dass diese Konzepte auch für alle anderen Szenarien in Betracht gezogen werden könnten, da sie eine Reihe universeller Techniken und Muster bilden, die für verschiedene Projekte generisch sein können und eine hohe Skalierbarkeit und Widerstandsfähigkeit gegenüber anspruchsvollen Änderungen bieten.
Im Bereich der Architektur sind viele Praktiken und Prinzipien maßgeblich an der Gestaltung des Projektverlaufs beteiligt. In Anerkennung ihrer Bedeutung haben wir einen detaillierten Leitfaden zusammengestellt, um herauszufinden, warum sie wichtig sind und wie sie dazu beitragen, dass Projekte reibungslos wachsen und sich anpassen.
In diesem Abschnitt werden wir uns ausführlich auf architektonische Überlegungen konzentrieren. Wir möchten erklären, warum wir sie für so wertvoll halten und warum sie dazu beitragen, das System nahtlos zu erweitern und zu modifizieren.
Lassen Sie uns das jetzt genauer untersuchen.
Wenn Sie ein Projekt mit Erweiterungs- und Entwicklungspotenzial in Angriff nehmen, legt die Wahl des richtigen architektonischen Ansatzes die Grundlage für den zukünftigen Erfolg. Ein solcher Ansatz, der zunehmend an Bedeutung gewinnt, ist der Modular Monolith, eine Designphilosophie, die eine pragmatische Lösung für Skalierbarkeit ohne die unmittelbare Komplexität einer Microservices-Architektur bietet.
Im Kern umfasst der Modular Monolith das Konzept von Modulen, die bestimmte Geschäftsbereiche oder Funktionen umfassen und eine unabhängige Entwicklung und Bereitstellung ermöglichen. Dieses modulare Design fördert nicht nur eine klare Trennung der Belange, sondern erleichtert auch die schrittweise Erweiterung, da neue Module nahtlos in die bestehende Struktur integriert werden können.
Im Mittelpunkt der modularen Monolith-Architektur steht die Verpflichtung, die Kopplung zwischen Systemkomponenten zu minimieren. Dies ist ein grundlegendes Prinzip, um Flexibilität, Wartbarkeit und Skalierbarkeit zu gewährleisten. Eine Kopplung, bei der Komponenten zu stark voneinander abhängig sind, kann zu spröden Systemen führen, die schwer zu modifizieren sind und zu kaskadierenden Ausfällen neigen. Beispielsweise kann es bei eng gekoppelten Systemen zu Welleneffekten kommen, wenn eine einzelne Komponente aktualisiert wird, was zu unbeabsichtigten Folgen für das gesamte System führen kann.
Ein Ansatz besteht darin, dass Module rufen sich gegenseitig über klar definierte APIs auf und rufen Abfragen für Daten auf, die für die Verarbeitung benötigt werden, obwohl verschachtelte Abfragen unhandlich werden, die Interdependenz erhöhen und in einigen Szenarien zu Leistungsproblemen führen können.
Ein weiterer, lockerer gekoppelter, ereignisgesteuerter Ansatz fördert Entkopplung der Eventproduzenten von den Verbrauchern, ermöglicht ein flexibles Systemdesign und ermöglicht asynchrone Kommunikation. Ereignisse dienen als präzise Beschreibungen von Ereignissen innerhalb des Systems, die von einer einzigen Quelle ausgesendet und von mehreren Handlern verarbeitet werden können, die jeweils über ihre eigene Verarbeitungslogik verfügen.
Im Mittelpunkt dieses Paradigmas stehen Domänenereignisse, die eng mit dem Domänenmodell verknüpft sind und unter Verwendung einer gemeinsamen, allgegenwärtigen Sprache konstruiert werden. Indem Entwickler Domänenereignisse berücksichtigen, kodieren sie wichtige Änderungen innerhalb des Systems, um ein tieferes Verständnis seines Verhaltens zu fördern und präzise, kontextsensitive Reaktionen zu ermöglichen.
Die Entwicklung von Systemen rund um Veranstaltungen bietet inhärente Flexibilität und ermöglicht das Hinzufügen neuer Anwendungsfälle mit minimalen Auswirkungen auf bestehende Komponenten. Das Eine geringe Kopplung zwischen Veranstaltern und Verbrauchern fördert nicht nur die Modularität, sondern verbessert auch die Widerstandsfähigkeit und Skalierbarkeit des Systems, da Module weitgehend unabhängig voneinander bleiben.
Darüber hinaus können Ereignisse als leistungsstarkes Tool zur Erfassung des Systemzustands und zur Bereitstellung eines umfassenden Aktualisierungsverlaufs dienen. Von Durch anhaltende Ereignisse können wir Einblicke in die Entwicklung der Domain-Anwendungsfälle im Laufe der Zeit gewinnen, das Debugging-, Audit- und Analyseaufgaben erleichtert.
Was in unserem Kontext ebenfalls sehr wichtig ist, ist, dass Ereignisse sich auch bei der Integration in ältere Systeme als leistungsstarke Tools erweisen. Von Durch die Nutzung von Ereignissen können Unternehmen die Lücke zwischen modernen Architekturen und Altsystemen schließen, was eine reibungslose Kommunikation und schrittweise Migrationsstrategien ermöglicht. Wir werden uns später in diesem Artikel ausführlich damit befassen.
Per Definition sollte jedes Modul entkoppelt und unabhängig vom anderen sein. Um einen Kommunikationsmechanismus bereitzustellen, haben wir Integrationsereignisse implementiert.
Integrationsereignisse sind entscheidende Mechanismen, um die asynchrone Kommunikation und Koordination zwischen Modulen oder verteilten Systemen zu ermöglichen. Durch die Nutzung von Integrationsereignissen können wir Domänenereignisse effektiv von externen Einflüssen entkoppeln und so das Risiko verringern, dass versehentlich andere Module an unsere Domain-Ereignisse gekoppelt werden, wenn sie in die Welt übertragen werden.
Einer der Hauptvorteile des Modular Monolith liegt in seiner inhärenten Bereitschaft zur zukünftigen Segmentierung. Obwohl die Architektur ursprünglich als eine zusammenhängende Einheit strukturiert war, ist sie so konzipiert, dass sie im Zuge der Skalierung des Projekts einer möglichen Aufteilung in unabhängig voneinander einsetzbare Einheiten Rechnung trägt. Diese Flexibilität mindert das Risiko architektonischer Engpässe und minimiert die Störungen, die typischerweise mit dem Übergang zu einer Microservices-Architektur einhergehen.
Durch die Einführung eines modularen Monolith-Ansatzes können Teams ein Gleichgewicht zwischen der Agilität, die für eine iterative Entwicklung erforderlich ist, und der Stabilität, die für eine langfristige Skalierbarkeit erforderlich ist, finden. Dieser pragmatische Ansatz rationalisiert nicht nur die anfänglichen Entwicklungsbemühungen, sondern schafft auch die Voraussetzungen für zukünftiges Wachstum und ermöglicht es Unternehmen, sich an sich ändernde Geschäftsanforderungen anzupassen, ohne Abstriche bei Stabilität oder Skalierbarkeit machen zu müssen.
Da eine modulare Struktur auf hohem Niveau definiert ist, wird die Wahl der Anwendungsarchitektur für die internen Komponenten der einzelnen Module von größter Bedeutung, zumal dies der Bereich ist, in dem wir als Softwareingenieure die meiste Zeit während des Projektlebenszyklus verbringen werden.
Ohne eine solche Voraussicht kann die zunehmende Kopplung innerhalb der Codebasis sowohl die Geschwindigkeit als auch die Sicherheit von Änderungen beeinträchtigen und im Laufe der Zeit sowohl das Risiko als auch die Kosten erhöhen.
Die Schaffung einer soliden architektonischen Grundlage ist eine entscheidende Investition für die zukünftige Entwicklung, bringt aber auch einige wichtige Überlegungen mit sich:
Die Einhaltung architektonischer Konventionen kann zwar, wenn sie auf die Spitze getrieben werden, den Code im Kern übermäßig komplizieren, Saubere und sechseckige Architekturen (letzteres ist eine Spezialisierung des ersteren) bieten lesbare und leicht durchsetzbare Optionen, die von Softwareingenieuren allgemein verstanden werden und als Lingua Franca für substanzielle Lösungen dienen.
Clean Architecture ist ein strukturierter Ansatz, der die Trennung von Belangen betont und eine klare Abgrenzung zwischen Geschäftslogik und technischer Implementierung ermöglicht, wobei der Schwerpunkt auf der Definition von Anwendungsfällen zur Steuerung des Anwendungsverhaltens liegt.
Für das beschriebene Projekt wurde beschlossen, jede Geschäftskomponente in Module mit strengen Grenzen aufzuteilen, was zu lose gekoppelten Modulen mit jeweils hoher Kohäsion führt. Dadurch erhielten wir kleine, leicht verständliche Arbeitseinheiten, die später bei Bedarf erweitert werden konnten.
In unserem Fall war die Entscheidung, jedes Modul innerhalb des Projekts physisch zu strukturieren, wie folgt:
Wir glauben, dass ein funktionsorientierter Ansatz bei der Softwareentwicklung die nahtlose Umsetzung von Geschäftsanforderungen in Anwendungsfunktionalitäten ermöglicht und so den Prozess der Erfüllung der Kundenanforderungen vereinfacht. Durch Workshops, Entdeckungsprozesse (unter Verwendung von Techniken wie Event Storming) und sorgfältiges Design können wir Geschäftsfälle effektiv dem Code zuordnen und so ein klares und geschäftsorientiertes Design der Anwendung ermöglichen.
Dieser Ansatz ermöglicht es uns, den Anwendungskern als eine Sammlung von Funktionen aufzubauen, die auf die wesentlichen Geschäftsaktivitäten abgestimmt sind und klar definierte und getestete Abläufe bieten. Durch die Nutzung gut verstandener Abstraktionen und Verhaltensweisen können wir Funktionen zusammenstellen, sequenzieren und aufrufen und so die Integrität der Abläufe und der zugehörigen Daten sicherstellen und gleichzeitig die Kerngeschäftslogik in allen Szenarien konsistent durchsetzen.
Darüber hinaus ermöglicht es das Auslösen von Anwendungsfällen Nebenwirkungen Nutzung der zuvor beschriebenen Ereignisse, wodurch Belange wie die Logik einer Buchung effektiv von der Notwendigkeit getrennt werden, eine Bestätigungs-E-Mail an den Nutzer zu senden, wodurch die Übertragung von Verantwortlichkeiten zwischen Funktionen im Laufe der Zeit ermöglicht wird.
Diese Methode ermöglicht es uns, User Stories zu implementieren, Anwendungsfunktionen bereitzustellen und mehrere Funktionen gleichzeitig zu entwickeln, wodurch die Zeit bis zur Produktion erheblich reduziert wird, ohne andere Bereiche negativ zu beeinflussen. In diesem Fall liegt der Fokus weiterhin auf der Funktionalität und nicht auf der technischen Umsetzung.
Beobachtbarkeit ist in der Systemarchitektur besonders wichtig, insbesondere beim Übergang von Altsystemen zu neuen Systemen. Durch die Nutzung bewährter Standards wie OpenTelemetry wollen wir eine umfassende Beobachtbarkeit des gesamten Systems sicherstellen. Dazu gehört es, das Verhalten des Systems zu verstehen, potenzielle Probleme zu identifizieren und sie letztendlich effizient zu lösen. Mit einem vollständig beobachtbaren System gewinnen wir Einblicke in seine Funktionsweise und sind in der Lage, alle auftretenden Herausforderungen effektiv anzugehen.
Wir waren sehr daran interessiert, dass Observability eine zentrale Rolle in unserer Systemarchitektur spielt, insbesondere bei der Migration von Altsystemen auf moderne Systeme.
Wir haben uns aufgrund seiner Robustheit und der breiten Akzeptanz in der Branche für OpenTelemetry entschieden. Telemetrie öffnen ist ein Open-Source-Projekt, das einen einheitlichen Ansatz für die Erfassung von Observability-Daten wie Metriken, Logs und Traces aus verschiedenen Komponenten unseres Systems bietet. Diese Standardisierung ermöglicht eine nahtlose Integration in bestehende Tools und Plattformen und erleichtert so die Überwachung und Fehlerbehebung in verschiedenen Umgebungen.
Durch die Implementierung von OpenTelemetry stellen wir sicher, dass unser System vollständig beobachtbar ist, sodass wir tiefe Einblicke in sein Verhalten gewinnen, Leistungsengpässe erkennen und etwaige Probleme umgehend beheben können. Dies verbessert nicht nur unsere Fähigkeit, das System effektiv zu warten und zu betreiben, sondern verbessert auch die allgemeine Zuverlässigkeit und Leistung des Systems.
Bei unserem Projekt wurde viel Wert darauf gelegt, dass der Code schnell und einfach produziert werden kann, wobei mehrere Ingenieure gleichzeitig beitragen konnten, was großartige Entwicklererfahrung und Erfüllung der Geschäftsanforderungen. Bei einer solchen Lösung können Änderungen aufgrund der Projektstruktur selbst sowie der robusten Beobachtbarkeit schnell, einfach und zuverlässig umgesetzt werden.
In den späteren Phasen ist diese Architektur nicht für Erweiterungen und Weiterentwicklungen verschlossen, d. h. für Microservices, wenn das Entwicklungsteam erweitert wird oder plötzlich Skalierungsbedarf entsteht. Insgesamt ist dieses Setup etwas, von dem viele .NET-Projekte in der Anfangsphase profitieren könnten.
Lesen Sie auch unseren Artikel über Nutzung von.Net für skalierbare und wartbare Lösungen.
Our promise
Every year, Brainhub helps 750,000+ founders, leaders and software engineers make smart tech decisions. We earn that trust by openly sharing our insights based on practical software engineering experience.
Authors
Read next
Popular this month