Wann entwickelt man einen Monolith und wann getrennte Systeme?
Ich bin immer ein bisschen dabei ein bisschen programmieren zu lernen.
Bisher habe ich glaube ich die "klassische" Art gelernt, wo man eine Webseite quasi aus einem Guss also als Monolith baut. Es gibt zwar ne Trennung mit nem Template-System aber intern arbeitet ja alles irgendwie zusammen.
Jetzt habe ich aber gelernt, es geht auch anders: Man kann auch z.B eine Webseite mit Angular und React bauen und die Daten holt man sich über eine API und beide Systeme sind aber im Grunde komplett unabhängig voneinander.
Aber ich frage mich nun: Was sind die Vor- und Nachteile davon? Und wie entscheidet man ob man jetzt das eine oder das andere nutzt?
3 Antworten
Man kann auch z.B eine Webseite mit Angular und React bauen und die Daten holt man sich über eine API und beide Systeme sind aber im Grunde komplett unabhängig voneinander.
Ja und nein - prinzipiell ist dein Verständnis korrekt, aber es gibt auch solche Systeme, die trotzdem als Monolith zählen würden.
Wir arbeiten z.B. fast nur mit Blazor WebAssembly, dabei ist das Frontend in Blazor entwickelt und läuft im Browser des Nutzers, während das Backend eine Web-API anbietet und auf diesem Weg genutzt wird. Deiner Beschreibung nach wären das getrennte Systeme, im Code sind sie das aber nicht.
Du musst es dir eher so betrachten, ob man die Bestandteile auch unabhängig voneinander deployen kann und ob der Code so aufgebaut ist, dass es auch sinnvoll machbar ist. Das wäre in unserem Fall vermutlich möglich, aber nicht sinnvoll, da praktisch jede Änderung immer beide Seiten betrifft. Ein getrenntes Deployment wäre technisch machbar, aber dann gibt es z.B. ein aktualisiertes Frontend, aber kein aktualisiertes Backend und das ganze funktioniert nicht.
Du kannst es aber auch so aufbauen, dass das Backend eine allgemeiner aufgebaute Schnittstelle hat, die alle Zugriffe ermöglicht, während das Frontend die Logik, die wir im Backend haben (weil es einfacher ist), im Frontend löst und zum Schluss dann die Daten mit dem Backend synchronisiert. Mit diesem Aufbau bräuchte das Fronend nur dann eine aktualisierte Backend-Version, wenn sich auch tatsächlich die Datenstruktur ändert, was eher selten der Fall ist.
Was sind die Vor- und Nachteile davon?
Dieser Aufbau ist allerdings auch sehr viel komplizierter. Das Backend klingt zwar auf den ersten Blick einfacher, allerdings kannst Du dann die Zugriffe nicht so gezielt steuern und optimieren, Rechteprüfungen für Daten werden aufwändiger, die Synchronisation zwischen Frontend und Backend würde extrem kompliziert werden. etc.
Vorteile sieht man vor allem dann, wenn man sich einmal vom Frontend vs. Backend weg bewegt, sondern z.B. Microservices anschaut. Generell nennt man das, wonach Du fragst "Service-Oriented Architecture" (bzw. so hieß es früher, ist aber im Grunde das gleiche), Microservices sind im Grunde eine Service-Oriented Architecture auf Steroiden - ideal zum Erklären, weil dabei die Vor- und Nachteile besonders deutlich werden.
Eine gut umgesetzte Microservices-Architektur setzt darauf, dass die einzelnen Services 100% unabhängig sind, die API ist unabhängig, die Release-Zyklen sind unabhängig, die Datenbanken sind unabhängig und sogar die Struktur des Netzwerks ist unabhängig, etc.
Eine Microservices-Architektur punktet dann z.B. in der Skallierbarkeit, so kann ein Services 10 mal nebeneinander laufen, auf 10 getrennten Servern, als 10fache Rechenleistung. Dafür brauchst Du allerdings auch ein System, was die Zugriffe auf diesen "einen" (die anderen Services wissen ja nicht, dass es 10 sind) verteilen und die Antworten zurück leiten. Und dann musst Du auch die getrennten Datenbanken irgendwie unter einen Hut bringen.
Ein anderer Vorteil ist, dass mehrere Entwicklerteams komplett unabhängig daran arbeiten können, allerdings ist wird die Abstimmung untereinander dadurch deutlich aufwändig.
Oder wenn einer der 10 Server abstürzt, fällt nichts auf, die verbleibenden 9 Server haben halt etwas mehr Last, aber passt schon. Oder wenn es nur ein Server ist, dann funktioniert die Funktion nicht, die dieser eine Service übernimmt, aber alle anderen Funktionen laufen ohne Probleme weiter.
Die Nachteile kannst Du dir vielleicht schon denken: Extrem kompliziert, aufwändig und fehleranfällig. Generell ist das nichts, woran unerfahrene Entwickler gut arbeiten können, im Gegenteil: Alle Microservices-Architekturen, die ich bisher gesehen habe, waren eigentlich keine Microservices-Architektur, sondern ein ziemlich zerstückelter Monolith mit allen Nachteilen für keine Vorteile - also genau, wie man es nicht machen sollte - aber gebaut von "erfahrenen" Entwicklern.
Und durch mehrere getrennte Services debuggen ist kein Spaß, das kann ich dir versichern ;)
Ach und hast Du schon Mal eine Authentifizierung über viele getrennte Systeme verwaltet? Der Nutzer will sich ja nicht 100 Mal anmelden, sondern nur einmal. Je nach Ausbaustufe kann ich dir sagen: Diese Authentication-Frameworks gehören mit zum den kompliziertesten Dingen, die ich kenne.
Das gleiche gilt aber auch für kleinere Ausprägungen von nur wenigen Services, denn man hat immer noch die zusätzliche Komplexität der Kommunikation zwischen den Services und wenn man die wesentlichen Vorteile (Skallierbarkeit, Ausfallsicherheit, etc.) nutzen will, dann braucht man immer einiges an zusätzlicher Komplexität zwischen den Services.
Man kann zwar auch Misch-Varianten aufbauen (z.B. gemeinsam genutzte Datenbank), allerdings verschenkt man damit die Vorteile und holt sich weitere große Nachteile mit ins Boot, sowas sollte man wirklich nur im absoluten Ausnahmefall machen und selbst dann ist es vermutlich eine blöde Idee.
Und wie entscheidet man ob man jetzt das eine oder das andere nutzt?
In den allermeisten Fällen braucht man aber keine Service-Oriented Architecture, egal in welcher Ausprägung. Eine Firma wie Netflix braucht sie vielleicht, aber solange Du bei so Stichpunkten wie "Skallierbarkeit" und "Ausfallsicherheit" nicht sofort über glücklich in Tränen ausbrichst, dann brauchst Du vermutlich keine Microservices-Architektur - bildlich gesprochen ^^
Oder anders formuliert:
Überlege dir, ob diese Vorteile die enormen Nachteile wert sind.
Wenn Du dir unsicher bist, dann ist die Antwort vermutlich: Nein.
Es kann aber durchaus sinnvoll sein, eine modulare Architektur zu wählen, das wäre so ganz grob der Mittelweg. Also ein Monolith, der aber in mehrere Projekte aufgeteilt sind, die vom Aufbau größtenteils abgeschlossen sind, aber im selben Prozess arbeiten, selbes Depolyment, selbe Datenbank, etc.
Netflix dagegen hat über die ganze Welt > 300 Millionen Nutzer, wenn davon nur 1% (immer noch 3 Millionen) gleichzeitig streamen wollen, würde ein einzelner Server sofort in die Knie gehen, ganz zu schweigen von der Latenz um die ganze Welt, weil der Server irgendwo stehen muss. Und was meinst Du passiert, wenn dieser eine Server ausfällt? Vermutlich wäre Netflix dann pleite. Die brauchen also ein System, was weltweit auf vielen gleichmäßig verteilten Servern aufbauen kann und bei dem ein einzelner Servausfall nur einen kleinen Teil der Nutzer stört. Perfektes Szenario für Microservices.
Ein gutes eigenes Beispiel wäre eine Website mit einer Web-API im Hintergrund und Mobile-/Desktop-Apps ganz woanders, aber auch die würde ich möglichst monolithisch aufbauen, es ist so viel einfacher. Aus System-Architektur-Sicht (also konkrete Hardware, Netzwerk, etc.) wäre das dann zwar getrennte Systeme (worauf Du ja hinaus willst), aus Projekt-Architektur-Sicht (also Trennung im Code) wäre das aber sehr viel näher an einem Monolithen und kann dank moderner IDEs auch viel leichter gepflegt werden - mit dem Nachteil, dass man nicht Mal eben so einen zweiten oder fünften Server hin stellen und so die Last verteilen kann. Aber wie gesagt: Die meisten brauchen das nicht, in den allermeisten Fällen reicht es, wenn man die Performance generell im Blick behält und die optimiert, dann verursacht das Projekt gar nicht so viel Last auf dem einen Server.
Ich bin immer ein bisschen dabei ein bisschen programmieren zu lernen
Du bist also noch am Anfang?
Dann mein Rat: Schieb das Thema ein oder zwei Jahre in die Zukunft ;)
Es ist gut, dass Du dir Gedanken dazu machst, das tun leider nicht alle, aber Du solltest dich mehr auf eine modular aufgebaute, aber immer noch monolithische Architektur konzentrieren, das ist schwer genug, in den meisten Fällen aber viel einfacher und viel sinnvoller in echten Projekten. Außerdem ist das die Vorarbeit, wenn Du dich dann mit einer Service-Oriented Architecture befassen willst.
Außerdem tut eine unpassend ausgewählte monolithische Architektur weit weniger weh, Du hast zwar Nachteile, aber z.B. Microservices können das Gesamt-Projekt ganz schnell töten (und häufig die Firma gleich mit), wenn man nicht aufpasst.
Überraschend gute Antwort für diese Plattform. Vollkommen korrekt, da kann man fast nichts mehr besser machen. Vor allem auch Anfängergerecht erklärt.
Berufserfahrung – C#.NET Senior Softwareentwickler
Das merkt man in der Antwort sofort. Jeder Junior kann froh sein, wenn er an jemand wie dich gerät.
Komplizierter ist es auch, das ist normal.
Dafür hast Du aber auch den Vorteil, dass die Module in der Regel klein und übersichtlich bleiben, als wenn alles "verzahnt" ist.
Außerdem fördert es UnitTests, die willst Du in der Regel haben, sie sind aber nicht unbedingt notwendig.
Eine modulare Architektur ist ein Balanceakt, wie viel modular ist zu viel modular und wie viel ist zu wenig? Entscheidend ist, dass Du dich leicht in deinem Projekt zurechtfinden kannst, ohne ständig andere Module im Blick behalten zu müssen, wie konkret das aussieht, hängt dann von deinem Projekt ab. Deutlicher wird es, wenn eine andere Person (Du solltest es ja gut kennen) sich in dein Projekt hinein finden muss.
Und am besten kannst Du auch eine umfangreiche UnitTest-Abdeckung aufbauen. Es sollten aber "echte" UnitTests sein, die Tests sollten wirklich nur von der einen Unit (Klasse, Methode, etc. - ein abgeschlossener kleiner Funktionsabschnitt) oder sehr wenig anderen Units abhängig sein. Du möchtest nicht mit einem Test das halbe Programm testen, sodass am Ende mit einer kleinen Änderung 90% der Tests plötzlich fehlschlagen.
Diese UnitTests (wenn Du sie automatisch ausführen lässt) sind dann auch ein gutes "Rettungsnetz", weil Du mitbekommst, wenn eine Funktion kaputt gegangen ist. Und wenn Du einen Bug findest, kannst Du automatisch prüfen lassen, ob der Bug auch in Zukunft gefixt bleibt.
Eine gute UnitTest-Abdeckung (muss nicht 100% sein, aber hoch) setzt außerdem eine gute Architektur voraus, wenn dir das also nicht gelingt, dann musst Du noch nacharbeiten ;)
Bin kein professioneller Entwickler, aber ich könnte mir gut vorstellen, dass eine Trennung in Frontend und Backend vor allem gut geeignet ist, wenn auf die Datenbasis noch andere Applikationen zugreifen wie z.B. eine Handy oder Desktop-App.
Architekturentscheidungen sind erstens komplex und zweitens können sie noch so gut überlegt und richtig sein, oft ändern sich die Anforderungen, und dann musst du eh umbauen oder damit leben ("technische Schulden").
Vorteile und Nachteile: Alles aus einem Guss vermeidet idealerweise Redundanz durch Wiederverwendung gemeinsamer Komponenten und lässt sich besser testen und optimieren. Aber es kann durch seine Größe auch unübersichtlich werden oder zu viele unterschiedliche Elemente vereinen wollen, die nicht zusammengehören.
Viele kleine Systeme (Micro-Frontends) bzw. schlanke Frontends die ihre Daten vom Backend holen, lassen sich leichter überblicken, und es muss vom Endkunden idealerweise nur die Datenmenge geladen werden, die auch tatsächlich nötig ist.
Ok aber gibt es da irgendwie ne Art Faustregel an der man sich erstmal grob orientieren kann?
Einfach anfangen und nicht zu kompliziert starten, besonders wenn du es als Projekt zum Lernen machst. Vermeide Overthinking, und mach erstmal überhaupt etwas, um damit Erfahrung zu sammeln.
Ui, vielen Dank für die Mühe und die vielen Erklärungen. :)
Dass das so viel ist und so kompliziert hatte ich gar nicht erwartet. Ich dachte jetzt da geht's nur darum, dass man die Software auf dem Server besser vom Client trennen kann.
Das mache ich schon. Ich hab z.B schon ein Forum programmiert (also natürlich nicht so krass wie die großen Foren, aber so mit den wichtigsten Funktionen).
Und da hab ich auch schon viel versucht modular zu bauen, da kam mir das teilweise aber echt kompliziert vor bzw. viel aufwendiger als wenn man es nicht so streng macht.