Transkript

Self-Contained Systems – Teil 1

Eigenschaften und Umsetzung

Self-contained Systems sind ein Mittel zur Modularisierung von Systemen. Sie übernehmen viele gute Ideen des Microservices-Konzepts. In dieser Episode geht darum, was Self-contained Systems eigentlich ausmacht und welche Vorteile dieser Ansatz hat. Außerdem sprechen Eberhard und Stefan über die Dinge, auf die man bei der Umsetzung achten muss.

Zurück zur Episode

Transkript

Eberhard Wolff: Hallo

Stefan Tilkov: Wir können es beide unmöglich über uns bringen, dass einer interviewt, beziehungsweise „die Klappe hält“ und den anderen sprechen lässt, weil wir eines unserer Lieblingthemen rausgesucht haben: Self-contained Systems. Darüber wollen wir heute reden. Eberhard, starte doch vielleicht einfach mal mit der offensichtlich allerersten Frage und sage mal ganz kurz, was sich hinter Self-contained Systems überhaupt verbirgt.

Eberhard Wolff: Self-contained Systems sind meiner Ansicht nach eine Spielart von Microservices und teilen Systeme auf, im Wesentlichen in Webanwendungen. Das hat ein paar Vorteile, insbesondere eine sehr lose Kopplung, eine gute Modellierung von Domänen, eine unabhängige Modellierung von Domänen und es ist vor allem etwas, was wir bei sehr vielen Kunden sehen, was offensichtlich auf eine ganze Menge Probleme passt, die diese typischerweise haben.

Stefan Tilkov: Über den Punkt mit den Microservices werden wir sicher später noch ein bisschen reden, das noch vernünftig abgrenzen. Lass uns doch einfach direkt einsteigen und ein paar Punkte, die aus unserer Sicht relevant sind für die Defintion, in größerer Detailtiefe betrachten. Fang du doch einfach mal mit der ersten an: Du hast es gerade schon gesagt, das sind autonome Webanwendungen. Erzähl doch ein bisschen mehr dazu.

Eberhard Wolff: Das bedeutet aus meiner Sicht, dass ein Self-contained System eben eine Webanwendung ist, so wie wir schon Tausende gebaut haben. Das ist meiner Ansicht nach sozusagen auch die gute Nachricht: Das ist etwas, was wir schon sehr häufig getan haben, und autonom bedeutet eben, dass die Webanwendung unabhängig ist. Das heißt, dass sie erst mal von anderen Self-contained Systems weitgehend unabhängig ist, wobei es eigentlich so ist, dass man ein System aufteilt in Self-contained Systems, sodass diese schon ein Ganzes ergeben müssen, aber eben ansonsten weitgehend unabhängig sind.

Stefan Tilkov: Wenn du sagst, es sind autonome Webanwendungen, legt es ja die Frage nah, ob das nur für Webanwendungen passt und deshalb in mobilen Szenarien völlig abwegig ist und überhaupt nichts damit zu tun hat. Ist das so?

Eberhard Wolff: Ich glaube schon. Denn Self-contained Systems sind eben Webanwendungen und das ist für mich einer der Vorteile dieser Definition. Im Gegensatz zu Microservices, worunter jeder etwas anderes verstehen kann, ist bei Self-contained Systems die Definition wesentlich präziser. Nur durch Webanwendungen sind ein paar Sachen möglich, also zum Beispiel die UI-Integration, die ein wichtiger Teil von Self-contained Systems ist. Auf der anderen Seite, wenn du sagst: Wie ist das mit Mobilanwendungen? Ich würde sagen, dass einige Ideen aus den Self-contained Systems auch mit mobilen Anwendungen umsetzbar sind, also eine starke fachliche Trennung in eher vertikale Schnitte, aber man kann es dann nicht Self-contained Systems nennen. Und normalerweise wird man ja dafür bezahlt, dass man mit der Architektur irgendwelche Probleme löst und nicht unbedingt Self-contained Systems macht, sondern man muss eben Probleme lösen. Und ich glaube, dass man sich für mobile Anwendungen durchaus Inspirationen holen kann von dem, was dort bei Self-contained Systems gesagt wird.

Stefan Tilkov: Ich muss unterschreiben: Ich glaube, es gibt ein paar Punkte, die man eben nur erreichen kann, wie du schon gesagt hast, wenn man sich auf Webanwendungen festlegt, was ja nicht bedeutet, dass man immer Webanwendungen bauen muss, das ist auch ein ganz wichtiger Punkt. Die Definition ist stärker darauf ausgelegt wirklich griffig zu sein, und eben nicht so „wischiwaschi“ wie viele andere das sind und das ist ein höherer Wert, als damit jetzt tausend Sachen erschlagen zu können. Es ist überhaupt nicht schlimm, wenn man diesen Architekturansatz nicht anwendet, aber wenn man ihn einsetzt, dann weiß man zumindest ziemlich genau, was man damit tut.

Vielleicht ein anderer Punkt, den ich auch noch ergänzen würde: Es gibt natürlich auch noch den Ansatz „hybride Anwendungen“ , also Anwendungen, die vielleicht eine native Shell außen herum haben und innen Web Use einbetten. Da gibt es für mich dann so eine Brücke, die ich ganz attraktiv finde, die das auch nicht alles erreicht, was man mit reinen Webanwendungen, die man im Browser anzeigt, erreicht, aber relativ viel davon erreichen kann.

Eberhard Wolff: Es ist eben auch die Frage, ob man eigentlich mobile Anwendungen bauen will. Wenn man sich die Statistiken anschaut, die kann man im Internet recherchieren, dann ist das so, dass ein durchschnittlicher Mobilanwender, sagen wir mal zehn Anwendungen auf dem Telefon hat, und jetzt ist die Frage, ob man es schafft, bei seinem Kunden eine von zehn Anwendungen zu sein. Aber das ist dann noch ein getrenntes Thema, das sagt hier ja eher, ihr wollt gar keine mobile Anwendunng bauen.

Stefan Tilkov: Bei uns würde niemand bestreiten, wir ganz sicher auch nicht, dass mobile Use Cases, also Leute, die mit dem Mobiltelefon ankommen, natürlich wahnsinnig wichtig sind und in vielen Fällen die viel wichtigeren. Das sind die viel wichtigeren Anwendungsfälle, aber das bedeutet eben nicht zwingend, dass man auch eine native mobile Anwendung bauen muss. Das sehe ich ganz genauso.

Eberhard Wolff: Eine weitere Eigenschaft von Self-contained Systems ist, dass jedes Self-contained Systems einem Team gehört.

Stefan Tilkov: Genau. Also es ist nicht so, dass ein Team nur ein Self-contained System bauen kann, aber es ist schon eine Grundidee, dass ein Self-contained System genau von einem Team geowned wird, einem Team gehört. Da heißt, das können wir auch noch diskutieren, je nach Größe hat ein Team vielleicht eins oder zwei oder fünf, eine bestimmte Anzahl solcher Dinger, aber ist immer ḱlar, zu wem ich gehen muss. Und das ist ein ganz wichtiger Punkt, glaube ich, weil der Ansatz enstanden und inspiriert ist von der Erfahrung aus größeren Projekten, das muss man auch klar sagen, nicht aus Projekten, bei denen zwei Leute etwas bauen. Das kann man da auch anwenden, wir haben tatsächlich ein Projekt, in dem genau zwei Kollegen eingesetzt sind. Die machen das da auch, die legen immer sehr viel Wert darauf, dass das da auch geht.

Aber so wie wir den Ansatz definieren, ist er tatsächlich dafür gedacht und maßgeblich dafür ausgelegt, dass man in größeren Teams eben trotzdem schlagkräftig bleibt, dass man nicht ein 100-Personen-Team hat oder 50 Personen Team und das an einer großen monolithischen Anwendung herumschraubt. Sondern dass man Einheiten schafft, die klein genug sind, dass sie handhabbar sind, klein genug, dass sie überschaubar sind, klein genug, dass man eben nicht mehrere Teams braucht, um sie zu pflegen und zu warten, gleichzeitig aber auch groß genug, dass sie eben diese Autonomie wahren.

Das ist ein klassischer Trade-off: Wenn ich die Dinger zu klein mache, da kommen wir wieder später noch bei der Microservices-Diskussion zu, wenn ich die zu klein mache, dann kann eins alleine gar nichts sinnvolles größeres tun. Es kann schon eine Sache tun, aber nicht einen wirklichen fachlichen Endanwender-Use-Case unterstützen. Und die Idee ist aber, dass ich eine Größe habe, die so ist, dass sie gut zu einem Team passt, und dass ich ganz klar diese Verantwortung habe.

Dann kommt die Beschreibung und Beziehung zu Conway’s Law. Damit wirft im Moment jeder um sich, der im Architekturumfeld Vorträge hält, weil das so eine wichtige Erkenntnis ist. Conway hat irgendwann gesagt: Wir haben eine klare Beziehung zwischen Architektur und den Kommunikationsstrukturen in der Organisation, und das ist etwas, was man sich hier aktiv zunutze macht. Man sorgt dafür, dass das Team so ein System besitzt und damit eben auch die Entscheidungshoheit hat, innerhalb dieses Systems Dinge selbst zu machen.

Eberhard Wolff: Genau. Das ist, glaube ich, tatsächlich einer von den wichtigen Punkten, dass man eben sagt, Organisation und Architektur hängen sehr stark zusammen.

Dann geht es um asynchrone Kommunkation. Das ist eine weitere Eigenschaft, dass eben Self-contained Systems primär asynchron miteinander kommunizieren. Gründe sind, glaube ich, offensichtlich. Erst mal sollten wir vielleicht sagen, was genau mit asynchroner Kommunikation hier gemeint ist. Die Definition, die ich dann häufig nenne, ist: Wenn ein Self-contained System einen Request bearbeitet, schickt es nicht selber einen Request raus und wartet auf die Antwort. Es kann einen Request rausschicken, es darf dann nur nicht auf die Antwort warten, und es darf auch einen Request rausschicken und auf die Antwort warten, nur dann darf es das nicht tun, während es selber einen Request bearbeitet. Wenn man ein System so baut, hat das Vorteile, weil beispielsweise Fehlerkaskaden ausgeschlossen sind. Das heißt, ẃenn ein System jetzt irgendwie verrückt spielt und keinen Request mehr bearbeitet und ich nicht auf die Antworten warte, während ich selber einen Request bearbeite, dann hat das eigentlich keine Auswirkungen auf mich. Dann bedeutet das, dass ich weiterhin funktioniere und vielleicht bestimmte Dinge gerade nicht tun kann, aber das ist halt nicht so schlimm, die mache ich dann einfach später. Und das ist dort für mich einer der Hauptgründe, warum das ein wesentliches Ziel ist. Es ist natürlich die Frage: Geht das eigentlich?

Stefan Tilkov: Kann man das überhaupt durchhalten? Die Frage ist: Ist das nicht so, dass meine Systeme so aufgeteilt sind, dass eins alleine gar nicht sinnvolle Arbeit erledigen kann?

Eberhard Wolff: Ja genau. Dazu gibt es, glaube ich, zwei Antworten. Einmal sagen wir genau genommen, dass asynchrone Kommunikation bevorzugt sein soll. Das bedeutet nicht, dass synchrone Kommunikation ausgeschlossen ist. Die andere Sache ist, dass man an vielen Stellen asynchrone Kommunikation ermöglichen kann, indem man beispielsweise Daten repliziert. Das heißt, die Aussage ist, wenn ich einen Request nicht bearbeiten kann, weil mir Daten fehlen, dann hole ich mir die Daten und die Replikation mache ich asynchron. Oder ich komme zu eventgetriebenen Systemen, wo ich jetzt gar nicht Replikationen in den Mittelpunkt stelle, sondern sage, es gibt halt Events, zum Beispiel eine Bestellung ist da und dann wird auf diese Bestellung reagiert: Irgendjemand schreibt eine Rechnung, irgendjemand sorgt dafür, dass sie ausgeliefert wird, und dann haben die jeweils die Daten, die sie dafür benötigen in ihrem eigenen System drin, aber nicht, weil sie Daten replizieren, sondern weil wir ein eventbasiertes System an der Stelle haben.

Stefan Tilkov: Man kann vielleicht sogar eine Hierarchie oder eine Reihenfolge von Dingen, die man gerne hätte, hinschreiben. Am allerbesten wäre es, wenn die Systeme gar nicht miteinander kommunizieren. Das ist der bevorzugte Fall, dann sind sie am losesten gekoppelt. Loser geht nicht, die sprechen nicht.

Zweite Variante ist: Wir machen das Ganze asynchron. Das bedeutet, es gibt eine asynchrone Kommunikation, um im Prinzip eben diese Redundanzen aufzubauen, damit im Normalfall die Kommunikation gar nicht notwendig ist.

Und dann gibt es noch Fälle, in denen die synchrone Kommunikation einfach nicht zu umgehen ist, wo ich das einfach tun muss, selbst, ganz selten, sogar mal in dem Request. Eines meiner Lieblingbeispiele ist immer eine sicherheitsrelevante Authentifizierungsprüfung, bei der ich auch nichts cachen darf und nichts mit kryptographischen Prüfungen lokal machen kann, indem ich mir immer etwas signieren lasse. In bestimmten Situationen muss ich einfach bei diesem anderen System nachfragen, ob der Benutzer wirklich noch angemeldet ist, nicht gesperrt ist, nicht geblacklistet ist. So etwas mache ich dann vielleicht tatsächlich mit einem Request-Response-Aufruf innerhalb meiner eigenen Request-Response-Verarbeitung. Das mache ich dann hoffentlicht abgesichert mit Mitteln wie Circuit Breakern und ähnnlichen Mechanismen, um mehr Stabilität in die Kommunikation hereinzubringen, das wäre meine Wunschhierarchie.

Eberhard Wolff: Das sehe ich genauso. Was du gesagt hast, ist sehr wichtig, dass wir duch asynchrone Kommunikation eine Menge an Technologien einfach gar nicht benötigen.

Vielleicht noch ein Hinweis: Ich würde sagen, noch besser oder noch stärker bevorzugt als asynchrone Kommunikation ist UI-Integration und im Extremfall einfach sehr, sehr schlicht über Links. Da gibt es ein sehr schönes Beispiel, welches ein paar Kollegen von uns gebaut haben für die LVM, wo man sieht, wie weit man eigentlich kommen kann, nur einfach mit Links.

Stefan Tilkov: Das kann man gerne noch mal in die Shownotes reinpacken. Es gibt ja auch noch zwei Podcast-Folgen zum Thema UI-Integration. In der Tat ist das ein Thema, mit dem ich auch immer durch die Gegend renne, und von dem ich immer schwärme. Das finde ich natürlich auch eine sehr, sehr angenehme Sache.

Im Nebensatz hast du gerade eine Sache gesagt, lass mich die noch mal hinterfragen. Du hast gesagt, wenn man asynchron kommuniziert, dann braucht man ganz viel Technologie überhaupt nicht. Was genau meinst du damit, was braucht man da nicht?

Eberhard Wolff: Circuit Break hast du zum Beispiel genannt, um sich abzusichern gegen Ausfälle bei synchroner Kommunikation. Das bedeutet dann eben auch, dass man sich nicht darum kümmern muss, was passiert, wenn die synchrone Kommuniktion ausfällt.

Vielleicht an der Stelle noch ein Thema: Asynchrone Kommunikation, wie ich sie gerade eben definiert habe, ist mit REST machbar. Ich kann jetzt ohne weiteres sagen, da gibt es eine REST-Ressource. Ich gehe zu dieser REST-Ressource und poll außerhalb meines eigenen Request-Zyklus' und hole mir die Daten ab. Ich kann natürlich auch eine messageorientierte Mittelware benutzen. Man kann auf die Idee kommen, dass asynchrone Kommunikation mit REST so ein Hack ist. Ich finde das eigentlich nicht. Ich glaube, dass man mit dieser Art von asynchroner Kommunikation von REST Vorteile erzeugt, weil man eine Infrastruktur benutzt, die relativ schlicht ist, und die man in einem Self-contained System eh hat. Da hat man eh HTTP-Kommunikation, weil man nach draußen HTTP sprechen muss.

Stefan Tilkov: Ich glaube, das ist ein ganz, ganz wichtiger Gedanke, dass tatsächlich dieses „weniger ist mehr“ da sozusagen drin ist. Normalerweise hat man immer das Gefühl, gerade wenn man mit schicken, neuen Akronymen durch die Gegend rennt, man versucht noch viel mehr coole Technologie, an der man sich austoben kann, mit unterzubringen. Hier ist es tatsächlich so, dass es weniger ist: Self-contained Systems brauchen keine Infrastruktur, die man nicht für eine Webanwendung sowieso braucht.

Eberhard Wolff: Ich bin eigentlich ein Fan von message-orientierten Systemen. Aber die schlichte Realität ist, dass die Dinger betrieben werden müssen und das ist auch nicht trivial. Wenn man dann asynchrone Kommunikation macht und das über message-orientierte Systeme macht, dann das Ding nicht vernünftig betreibt und es halt stillsteht, hat man ein massives Problem. Deswegen, finde ich, ist das tatsächlich ein Trade-off.

Stefan Tilkov: Okay. Lass uns weitermachen. Wir haben einen Punkt in der Liste, nämlich das Service-API ist optional. Erzähl doch mal, wie das sein kann.

Eberhard Wolff: Eigentlich ergibt sich das daraus, dass das autonome Webanwendungen sind. Jetzt ist halt die Frage, ich habe eine autonome Webanwendung und die Logik, die da drin ist, will ich anderweitig auch nutzen. Sei es in einem B2B-Umfeld oder auch, um eine native mobile Anwendungen anzuschließen. Dann kann ich eine Service-API da noch drauf tun. Die ist offensichtlich optional, weil wir eigentlich auf Webanwendungen abzielen, aber wenn ich sie dann unbedingt haben will/muss, dann kann ich sie eben auch haben.

Stefan Tilkov: Ich glaube, das ist ein ganz wichtiger Punkt, weil das häufig erst mal verwirrend ist: Man kann sich das nicht vorstellen: Wir reden hier von solchen Service-Ansätzen und auf einmal ist die Service-API selbst optional. Das liegt daran, dass das UI typischerweise der Zugriffsweg ist, über den man an so ein System dran kommt.

Eberhard Wolff: Dann haben wir als nächstes Thema, dass Self-contained Systems Daten und Logik enthalten sollen. Was ist damit gemeint?

Stefan Tilkov: Gemeint ist im Prinzip die gute alte Bündelung von Verantwortung für einen zusammenhängenden Bereich, den man möglichst nicht auseinander reißen sollte. Das bedeutet, dass die Daten, die in diesem System verwaltet werden, mit der Logik, die die Integrität dieser Daten sicher stellt, und die die Abläufe, Geschäftsprozesse, Regeln auf diesen Daten durchführt, dass das ein gekapselter Teil sein soll. Ich möchte das gerne in diesem System drin haben. Dass so ein System innen drin auch noch mal aus technisch unterschiedlichen Teilen bestehen kann, das ist geschenkt, das lassen wir gerade mal außen vor, wir schauen praktisch von außen drauf. Aber wenn ich so ein System habe, dann ist das verantwortlich für diesen Teil. Und es soll eben gerade nicht, um auf die Daten zuzugreifen, die es für seine Kernfunktionalität braucht, auf andere Services zugreifen, sondern es soll das selbst verantworten. Das ist einfach ein Bestandteil der Autonomie, die da drin ist.

Eberhard Wolff: Wenn jetzt das System die Daten hat, was mache ich dann?

Stefan Tilkov: Wie gesagt, dass ist der gleiche Trade-off, den wir auch an anderen Stellen haben. Redundanz ist immer ein Trade-off, bei dem ich zwei Ziele gewichten muss. Wenn ich Redundanzen erzeuge, dann mache ich mir erst mal Ärger, das hat wahrscheinlich jeder schon mal bemerkt. Ich muss Daten abgleichen (hoffentlich nicht alle, sondern einen Teil), aber irgendwie muss ich mich darum kümmern. Ich muss das mindestens synchronisieren, ich muss mich möglicherweise um systemübergreifende Integrität kümmern, ich muss mich vielleicht um „transaktionale Integrität“ kümmern. Das sind alles Probleme, die ich nicht hätte, wenn das alles in einem einzigen System wäre.

Tatsächlich gibt es gute Argumente dafür, alles in einem einzigen System zu lassen. Das ist genau so lange gut, wie dieses eine System nicht so groß wird, dass es anfängt, richtig zu schmerzen. Dann wäre es besser gewesen, man hätte mehrere Systeme gemacht. So sehe ich das hier auch: Die Systeme versuchen, für ihre eigenen Daten verantwortlich zu sein und diese Probleme, die da entstehen, die bringen mir im Gegenzug etwas. Ich schaffe mir die Probleme nicht, weil ich sie so schön finde oder so viel Spaß daran habe, sondern ich akzeptiere die Nachteile, weil ich Vorteile damit erreichen möchte. Diese Vorteile sind genau diese Autonomie, sowohl Autonomie zur Entwicklungs- und Entscheidungszeit, weil ich eben nicht darüber diskutiere, was ich da machen muss, weil das eben meine Daten sind, meine Logik ist und ich das Ganze als große Meeting-Verweigerungsstrategie betrachten kann. Ich muss mich nicht mit den anderen Teams treffen und abstimmen, was da in meinem System drin ist. Das ist meine Sache, das entscheide ich mit meinem Team selbst.

Diesen Aspekt, den es zur Entwicklungs- und Designzeit gibt, den gibt es eben auch zur Laufzeit, weil zur Laufzeit eben dieses System für die Daten verantwortlich ist. Wenn dieses System nicht mehr da ist, dann sind genau diese Use Cases nicht mehr ereichbar. Alle anderen, die also andere Systeme, andere Daten brauchen, funktionieren noch weiter. Ich habe nicht gleich einen Totalausfall des Netzes.

Eberhard Wolff: Vielleicht an der Stelle noch ein Thema: Ich würde argumentieren, dass jedes nicht triviale System mit irgendeinem anderen Backend-System oder so etwas kommuniziert. Das wäre auch meine Erwartungshaltung bei Self-contained Systems. Ich glaube, dass die Aussage, sie sollen Daten und Logik enthalten, nur in gewissen Grenzen gilt. An der Stelle, an der ich sage, es gibt ein anderes System und dem muss ich jetzt, wenn zum Beispiel eine Bestellung kommt, das sagen und die machen die Bezahlung. Dann ist die Aussagen von Self-contained Systems nicht: Nein, dieses Bezahlsystem muss in mein Self-contained System rein integriert werden, sondern so ein Backend-System, würde ich erwarten, wäre einfach da. Und das ist eine unabhängige Frage davon, ob wir jetzt Self-contained Systems oder so machen.

Stefan Tilkov: Ich würde es an einem Beispiel festmachen. Was ist eine der Kardinalssünden, der Todsünden der SOA-Welt gewesen? Zu stark auf Trennung von Datentöpfen und auf Redundanzvermeidung zu gehen. Nicht in allen SOA-Initiativen, aber ich habe das zumindest häufiger gesehen, dass man sagt, es gibt nur noch eine Stelle, an der Kunden gespeichert werden, es gibt genau eine Stelle, an der Bestellungen gespeichert werden.

Nehmen wir das mal an als Beispiel. Das würde bedeuten, wenn ich ein Bestellsystem habe und ein Kundensystem, kann das Bestellsystem nicht mehr alleine arbeiten, sobald es irgendetwas mit dem Kunden zu tun hat. Bestellsysteme haben nun mal was mit dem Kunden zu tun, es ist ganz schwierig, ein Bestellsystem zu bauen, das so tut als gäbe es keine Kunden. Wenn das jetzt immer mit dem Kundensystem sprechen muss, dann ist das faktisch nur ein System.

Für diesen Schnitt, wie wir ihn uns vorstellen, würde man in dem Bestellsystem eben einen Teil der Kundendaten vorhalten, vielleicht nicht alle, nur die bestellrelevanten. Es gibt vielleicht auch Kundendaten, die sind fürs Accounting relevant, und Kundendaten, die sind fürs Provisionieren relevant, die gehören woanders hin. Das Bestellsystem hätte aber einen bestimmten Ausschnitt und würde das auch im Rahmen seiner eigenen Request-Response-Cycle selbst verwalten. Die Erfahrung, die ich gemacht habe, ist, dass solche Systeme wie das Kundensystem dann häufig verschwinden. Wenn man jetzt einfach anfängt, die Fachlichkeit durch zu modellieren, das ist so ein bisschen Domain-driven-Design-Bounded-Context-Ansatz (da machen wir sicher auch mal eine Epsiode zu), dann verschwinden diese entitätsbasierten zentralen Dinge, weil sie eben nur Töpfe sind, die sehr künstlich entstehen. Die entstehen nur, weil man versucht, diese Redundanzen um jeden Preis zu vermeiden. Und am Ende machen sie mehr Probleme, als man Nutzen hat. Genau das wollen wir vermeiden, wenn wir die Sachen auseinander ziehen.

Eberhard Wolff: Ich glaube, das ist ein total wichtiger Punkt. Genau genommen würde ich argumentieren, dass wir hier bei dem System gar nicht Redundanzen einführen, sondern eben, wie du ja gesagt hast, eigentlich eine saubere Modellierung machen. Das heißt, an der Stelle, an der ich sage, ich habe die Kundendaten und die Kundendaten gibt es eben in der Bestellabwicklung und im Accounting, wenn ich auf der Flughöhe bin, habe ich halt das Gefühl, das sind redundante Daten. Wenn ich irgendwie reinsteche, stelle ich fest, das sind eben nicht redundante Daten, weil das unterschiedliche Dinge sind. Wenn ich eine Bestellung verarbeiten will, muss ich vielleicht wissen, wo ich das Zeug hinschicke, während ich halt fürs Accounting wissen muss, wie der seine Rechnung beabsichtigt zu bezahlen. Das sind unterschiedliche Themen und das bedeutet, dass ich eben gerade nicht redunante Kundendaten habe, sondern bestimmte Aspekte des Kunden in verschiedene Systeme aufteile. Das ist auch ein bisschen die Antwort, glaube ich, auf diese Frage: Kommen wir nicht zu super redundanten Systemen?

Stefan Tilkov: Sehe ich genauso.

Eberhard Wolff: Weitere Eigenschaft: Keine gemeinsame UI. Das ist für mich ein Ergebnis auch aus der Forderung nach autonomer Webanwendung. Wenn ich sage, ich habe eine autonome Webanwendung, baue ich letztendlich meine eigene UI zusammen, und das bedeutet, dass eben jedes System einen Teil dieser UI umsetzt. Das heißt, wir können nicht eine gemeinsame UI haben. Wir können jetzt nicht sagen, wir haben irgendwo diese UI, die jetzt für alle Self-contained Systems das Benutzer-Interface implementiert, das ist einfach ein Widerspruch dazu. Das führt natürlich zu der Frage, ob dann nicht alle das selbe entwickeln müssen, wie wir mit einem gemeinsamen Look and Feel beispielsweise umgehen, was ja keine unrealistische Forderung ist.

Stefan Tilkov: Und hast du da auch eine Antwort drauf, auf diese Frage?

Eberhard Wolff: Die Frage, müssen alle das Gleiche programmieren: Ich glaube, dass das bis zu einem gewissen Maße tatsächlich der Fall ist. Aber das ist irgendwie ein Trade-off zwischen Wiederverwendung und Unabhängigkeit. Wenn ich jetzt sagen würde, wir benutzen alle die selbe Technologie, und wir versuchen gemeinsam irgendwelchen Code zu bauen, den wir wiederverwenden können, dann bedeutet das, dass wir sehr viele Abhängigkeiten haben und das ist genau das, was wir nicht wollen. Wir wollen autonome Teams und autonome Leute haben, die da arbeiten.

Mit dem gemeinsamen Look and Feel, das ist nach meinem Empfinden etwas, was man dann umsetzen muss. Das ist auch genau das, was wir bei dieser Frontend-Integrations-Frage diskutiert haben. Das bedeutet konkret, dass man dort einen Styleguide haben muss oder kann, dass man irgendwie gemeinsame Assets haben muss, vermutlich. Das ist für mich eigentlich ein Teil der Schnittstellenabsprache. Ich glaube, ein Teil der Story von den Self-contained Systems ist, dass man sagt: Die UI ist viel, viel wichtiger und die UI ist ein Integrationspunkt. Darüber ergibt sich, dass die UI letztendlich eine Schnittstelle ist. Und wenig überraschend brauchen wir Schnittstellenabsprachen. Die sind nur „komisch“. Normalerweise würde man sagen: Schnittstellenabsprache, wir reden über Datentypen. Hier ist es so, dass wir bei der Schnittstellenabsprache darüber reden, wie zum Beispiel gemeinsame Assets aussehen. Das ist, glaube ich, auch eine Art von Schnittstellenabsprache, weil ich wissen muss, wenn ich einen Link baue oder irgendwelche Sachen rein integriere, wie die sich eingentlich verhalten auf der UI-Ebene. Das ist nur total anders, als wir das normalerweise gewohnt wären oder wie normalerweise Schnittstellenabsprachen definiert sind.

Stefan Tilkov: Du hast jetzt viel zur Integration gesagt. Das ist natürlich ein ganz wichtiger Punkt. Lass mich noch etwas zu dem Auseinanderschneiden sagen, das die Intergration erst notwendig macht. Ich glaube, ein ganz wichtiger Gedanke, der sich durch ganz viele Ansätze durchzieht - seien es nun Microservices oder eben auch Self-contained Systems - ist diese Idee, dass ich Dinge zusammen halte, die zusammen gehören. Das ich die nicht nach irgendwelchen technischen Grenzen teile und Teams habe, da ist mein Datenbankteam und da ist mein Netzwerkteam und da ist mein Backendlogik- und da ist mein Frontendlogikteam.

Genau diesem Gedanken folgend ist bei Self-contained Systems ein starker Fokus darauf, dass ich auch das UI mit der Logik und den Daten zusammen halte. Ich will dieses Team haben und dieses Team ist crossfunktional besetzt, ein interdisziplinäres Team und das kümmert sich ganz besonders auch um das, was die Anwender sehen. Das ist kein unwichtiges Detail, das man irgendwen machen lässt, von dem man nicht so viel hält, weil er nur Frontend macht, sondern das ist ein ganz zentraler Bestandteil der Funktionalität, die mein System ausliefert. Das ist erst mal etwas ganz Abstraktes, was ich auch in anderen Technologien machen könnte. Jemand, den ich sehr schätze, Udi Dahan, hat schon vor ein paar Jahren sehr schöne Vorträge gehalten - von ihm können wir auch ein bisschen Material verlinken - zu Autonmous Components, nennt er das, glaube ich, oder Autonomous Business Components, wo er auch schon diese Idee hat, dass das User Interface dazu gehört zu diesen Backend-Komponenten, die auch die Daten dann verwalten.

Was Self-contained Systems hinzufügt, sind die technischen Restriktionen, die technischen Vorteile, die sich daraus ergeben, dass ich das ganze Web-basiert mache. Wenn ich das nicht so abstrakt mache, nur von UI im Allgemeinen rede, sondern ganz konkret von Web-UIs, dann gibt es eben einen, wie du gesagt hast, bestehenden Mechanismus, um Dinge zu integrieren. Das ist eine große Stärke, weswegen wir eben auch darauf herumreiten, dass es Webanwendungen sein sollen, damit es eben diesem Architekturansatz folgt.

Eberhard Wolff: Der Punkt ist da, dass man im Extremfall tatsächlich Self-contained Systems nur über Links integriert und das bedeutet, dass die fast nichts von einander wissen.

Stefan Tilkov: Also auch von verschiedenen Firmen entwickelt und auf verschiedenen Kontinenten betrieben werden, in verschiedenen Clouds?

Eberhard Wolff: Genau. Du musst eine URL kennen und dann ist eigentlich auch schon alles andere egal: Ob dann eine HTML-Seite oder ein PDF oder irgendetwas anderes zurückkommt, ist zum Beispiel schon etwas, was egal ist, sodass man da tatsächlich eine sehr starke Entkoppung bekommt.

Stefan Tilkov: In diesesm Moment fragen sich Leute meistens: Was soll denn das, wie soll denn das alles gehen? Eines meiner Lieblingsbeispiele ist die mittlerweile extrem verbreitete Integration von Identitätssystemen über so ein Single-Sign-On oder einen OAuth-Mechanismus. Wenn ich mich mit meinem Facebook-Account (den ich nicht habe) oder meinem Twitter-Account oder meinem Google-Account irgendwo anders anmelde, dann passiert eine typische Integration, wie wir sie uns vorstellen. Da passieren ein paar Redirects, dann werde ich auf das andere System geschickt, melde mich da an, dann komme ich wieder zurück. Das ist ein schönes Beispiel für eine Integration, bei der diese Systeme sehr, sehr lose gekopppelt sind, zum großen Teil übers Frontend integriert sind, nicht nur, da passiert dann im Backend auch noch eine Kommunikation, um Access Tokens zu validieren unter Umständen oder um Grants in Access Tokens umzutauschen. Aber vom Prinzip her ist das ein sehr, sehr schönes Beispiel, wie gut das funktionieren kann.

Eberhard Wolff: Nächste Eigenschaft ist: Keine gemeinsame Geschäftslogik.

Stefan Tilkov: Das ist, glaube ich, auch eine Erkenntnis, die viele Leute mittlerweile gewonnen haben, nämlich dass Re-Use durchaus negative Seiten hat. Wiederverwendnung haben wir lange Zeit als das schönste, wichtigste, größte aller Ziele vor uns hergetragen, wir müssen unbedingt Dinge wiederverwenden. Man hatte diese Idee zu verschiedenen Zeitpunkten in der IT-Geschichte mit unterschiedlichen Sachen. Mal waren es Bibliotheken, dann Objekte, dann Klassenbibliotheken und dann Frameworks, die alles wunderbar wiederverwendbar machen.

Mittlerweile ist man sich durchaus bewusst, dass, wenn ich Code zwischen zwei verschiedenen Systemen teile, das eben auch eine Menge von Nachteilen mit sich bringt. Das sind technische, auf der einen Seite: Beide Systeme müssen in der Lage sein, diesen Code technisch zu integrieren. Das bedeutet, sie müssen vielleicht in derselben Version irgendeiner Runtime oder eines Betriebssystems sein, sie müssen vielleicht diesselbe Version von benutzten Bibliotheken haben. Dann habe ich große Restriktionen, was das Deployment angeht: Ich muss jetzt unter Umständen in beiden Systemen dieselbe Version dieser Bibliothek haben, und ich muss das dann immer in beiden gleichzeitig synchronisieren und weiterentwickeln. Die gesamte Evolution wird so stark gekoppelt, dass man das eben als Nachteil betrachten kann. Und deshalb ist hier eben die Idee: So etwas machen wir nicht, sondern die Logik gehört einem System, nicht zwei Systemen, und wenn ich diese Logik tatsächlich wiederverwenden will, dann verzweige ich eben in dieses System. Das mache ich über eine UI-Integration, das mache ich vielleicht über andere Arten der Integration, wie asynchrone Kommunikation oder von mir aus auch einen synchronen Aufruf, wenn es nicht anders geht. Aber ich versuche zu vermeiden, dass ich eine gemeinsamen Bibliothek von Dingen durch mehrere Systeme durchziehe.

Eberhard Wolff: Ich würde vielleicht noch einen Schritt weiter gehen und sagen, wenn man das Bedürfnis hat, Geschäftscode wieder zu verwenden - es geht ja um Geschäftscode, nicht um technischen Code - dann ist der Schnitt irgendwie komisch. Eigentlich sollte eben eine Domäne in einem System drin sein und das impliziert, dass eben der Geschäftscode in einem dieser Systeme drin ist und ich will ihn gar nicht wiederverwenden. Das ist so ein bisschen nicht die orthodoxe Sicht darauf.

Stefan Tilkov: Man kann da auch gut so typische Konflikte sehen, die man in solchen Architektur-Diskussion dann oft hat, denn aus taktischer Sicht ist das oft erst mal schwer zu argumentieren und zu verkaufen. Ich habe zum Beispiel eine Schnittstelle, da tausche ich irgendwelche Daten aus, da tausche ich jetzt einen Auftrag oder eine Bestellung oder irgendetwas anderes zwischen zwei Systemen aus, vielleicht auch nach unserem Prinzip asynchron oder irgendetwas anderes. Dann ist erst mal, wenn da zwei Teams sind und beide Teams entwickeln mit derselben Technologie in der selben Programmiersprache in der selben Umgebung – was bei Neuentwicklungprojekten häufig der Fall ist - dann ist es erst mal schwer zu argumentieren, warum die denn jetzt nicht einfach den gleichen Code verwenden dürfen für diese Schnittstellenklassen.

Das ist eben eher eine mittel- bis langfristige Sicht, warum man das nicht tun will. Man will eben nicht dauerhaft diese Notwendigkeit haben, genau diesen Code auf beiden Seiten gleich zu halten, sondern will das bewusst beiden überlassen. Deswegen finde ich, was du eben gesagt hast, wichtig: Es gibt Dinge, da ist es anders, da hat man eben nicht diese Abhängigkeit zur Fachlichkeit. Da ist es dann völlig in Ordnung, wenn beide Seiten die selbe Bibliothek von irgendetwas benutzen, solange, das ist auch immer ein ganz wichtiger Punkt, sie selbst entscheiden, ob sie das tun und wann sie das tun und wann sie das nicht mehr tun und mit welcher Version dieser Bibliothek sie das tun. Da muss der technische Code den gleichen Restriktionen unterliegen wie irgendeine beliebige Bibliothek, die ich von der Apache Software Foundation herunterlade oder von irgendeinem Github-Projekt, das ist einfach eher eine Pull- statt eine Push-Entscheidung.

Eberhard Wolff: Du hast es ja selber schon gesagt: Re-Use ist etwas, wovon wir jahrelang gesagt haben, was halt total wichtig und toll ist. Die Ergebnisse sind irgendwie schlecht. Ich komme praktisch nie zu einem Kunden, wo irgendwie die Aussage ist: Wir haben übrigens dieses wiederverwendbare Framework, das ist total super und macht uns die Arbeit viel einfacher.

Stefan Tilkov: Das wäre eine Liability, eine Belastung.

Eberhard Wolff: Exakt. Und das müsste eigentlich anders sein, weil halt eine Vielzahl an Leuten genau das versucht haben und jetzt eigentlich sagen müssten: Ja, haben wir, war erfolgreich, ist total super. Und wenn man feststellt, dass sich das nicht so entwickelt hat, wie man sich das vorstellt, dann muss man daraus irgendwie Konsequenzen ziehen. Die Konsequenz, die wir da empfehlen, ist, weniger darauf zu fokussieren.

Dann haben wir einen Punkt, der ist tatsächlich relativ frisch und Ergebnis einer Diskussion, die wir vor einiger Zeit hatten, die sagt, dass gemeinsame Infrastruktur minimalisiert sein soll, oder dass es davon möglichst wenig geben soll. Ich glaube, die Diskussion hat sich genau entzündet an dieser message-orientierten Middleware. Da ist die Aussage, wenn wir die bauen, dann sorgt das irgendwie dafür, dass wir etwas haben, worauf sich alle beziehen, wovon alle abhängen und das führt dazu, dass eben zum Beispiel alle Systeme ausfallen, wenn dieses System nicht mehr da ist.

Analog ist zum Beispiel das mit Datenbanken: Jedes Self-contained System hat ein eigenes Datenmodul. Das heißt, jedes Self-contained System muss ein eigenes Datenbankschema haben, die könnten aber in einer Datenbankinstanz gemeinsam laufen. Ist das eine gute oder eine schlechte Idee? Es ist insofern eine schlechte Idee, dass ich dann eben wieder diese Systeme hinten zusammenklebe und dann eben auch bei einem Ausfall der Datenbank alle Systeme stehen. Ich muss gestehen, dass ich sozusagen froh bin, dass da nicht steht, es gibt keine ǵemeinsamen Infrastrukturen, denn das würde ich unrealistisch finden. Die Aussage ist also: Minimiere das. Das ist ein bisschen so wie mit der asynchronen Kommunikation. Ich würde argumentieren, Self-contained Systems, die sich eine Datenbank teilen, aber getrennte Datenbankschemata haben, sind eine valide Entscheidung und sind ein Trade-off eben zwischen Verfügbarkeit und Aufwand, um das Ding halt irgendwie zu betreiben. Das, was wir hier mit diesem Punkt sagen wollen, ist: Seid vorsichtig. Wenn ihr gemeinsame Infrastruktur habt, kommt ihr relativ schnell eben auch in Verfügarkeitsthemen.

Stefan Tilkov: Das ist immer so eine Grenze, an der man jetzt überlegen muss, wie weit will man das Ganze aufweichen. Da kämpfen sozusagen Dogma und Pragmatismus oder Purheit, die Reinheit der Lehre sozusagen, mit den Restriktionen der Realität. Ich glaube nicht, dass es darauf eine Antwort gibt. Das ist, glaube ich, immer sehr situationsspezifisch. Man sollte sich aber einfach sehr, sehr bewusst sein, wenn man so eine Entscheidung trifft. Wenn man sagt, ich habe hier zum Beispiel einen Betrieb, der darauf ausgelegt ist, Oracle-Datenbanken zu betreiben, der hat dafür eine tolle Backup-Strategie und der hat dafür alle möglichen tollen anderen Sachen, dann kann es sein, dass ich deswegen entscheide, dass bitte alle einfach eine Oracle-Datenbank benutzen und es diesem Betrieb überlasse, dann zu entscheiden, ob er dafür ein oder fünf oder zwanzig Datenbanken-Server einrichtet.

Ich kann verstehen, warum man das entscheidet. Man muss sich halt bewusst sein, dass die Systeme jetzt nicht mehr ganz so self-contained sind, wie sie wären, wenn sie ihre eigene Datenbank hätten. Denn dann könnte das eine System entscheiden, jetzt von Oacle auf eine NoSQL-Datenbank umzustellen. Das kann es nicht so einfach tun, wenn der Betrieb vorschreibt, dass es da drin ist. Also natürlich kann es das immer noch tun, aber diese Entscheindung habe ich ja sozusagen vorher ein bisschen ausgehebelt, weil ich diese Vorschrift dazu gemacht habe, das Ganze nicht zu tun. Das ist so ein bisschen der Trade-off.

Eberhard Wolff: Das glaube ich nicht. An der Stelle, an der ich sage, dass jeder ein eigenes Schema hat und zwischen den Schemata keine Relationen sind, kann ich die Aufteilung auf physische Datenbankinstanzen eigentlich relativ leicht revidieren. Was halt konkret passieren würde, wäre, dass ich dieses Schema nehme, es auf auf einen anderen Oracle-Server packe und dann irgendwelche Datenbank-Connection-Strings ändern muss und dann hätte sich das halt.

Stefan Tilkov: Nehmen wir dann ein Beispiel: Du hast vielleicht ein cooles, neues Datenbank-Feature benutzt, dass eben eine bestimmte Version der Datenbank verlangt. Das ist so eine typische Einschränkung. Du hast da jetzt eine gemeinsame Plattform, sozusagen.

Wir können auch andere Beispiele nehmen. Du hattest diesen Messaging Middleware genannt. Das können wir genauso nehmen, das ist mein Kafka oder so. Da habe ich jetzt eine Kafka-Installation, die von irgendwem administriert wird. Dann bedeutet das, dass das nächste Update dieser Kafka-Installation mit allen Teams, mit allen Self-contained Systems abgestimmt sein muss, weil alle darunter leiden werden. Ich kann nicht die halbe Kafka-Installation upgraden, das mache ich dann schon mit der ganzen. Dieses Gemeinsame hat immer den Vorteil, dass es eben gemeinsam ist und man deswegen Dinge wiederverwendet und Dinge nur einmal macht. Und es hat den Nachteil, dass man das gemeinsam hat und Dinge nur einmal macht, das ist eben ein ganz klassischer Trade-off.

Eberhard Wolff: Genau. Wenn wir über eine Bibliothek reden würden, also über eine Code-Bibliothek oder auch über eine Frontend-Technologie, da könnten wir eh, dadurch wie Self-contained Systems aufgestellt sind, diese Entscheidung jeweils lokal revidieren. Das heißt, wenn ich sage, ich habe eine bestimmte Spring-Version und das will ich ändern, kann ich das in meinem Self-contained System tun. Das ist auch der Grund, warum wir, glaube ich, bei den UIs sagen, dass es keine gemeinsame UI geben darf, weil ich dann eben auch die Technologieentscheidungen in Bezug auf UI-Technologien pro Self-contained System treffen kann, was meiner Ansicht nach hilfreich ist. Denn man kann im Laufe seines Projektes davon ausgehen, dass da immer mehr unterschiedliche Dinge irgendwo aufpoppen und es einen größeren Technologiezug geben wird und es unrealistisch ist, anzunehmen, dass man bis ans Lebensende dieses Prokjektes auf einen kleinen Technologiestack setzen kann.

Stefan Tilkov: Du meinst, Leute haben ein Problem, die sich vor einem Jahr entschieden haben, für die nächsten Jahre Angular 1 zu machen? Ich bin irritiert.

Eberhard Wolff: Genau.

Damit haben wir jetzt in dieser Folge erklärt, was eigentlich Self-contained Systems sind, wie das definiert ist und was die wesentlichen Eigenschaften davon sind. Da stellt sich natürlich die Frage, warum würde man das tun wollen, was sind ein paar Herausforderungen und wo kommt das alles her, wer benutzt das. Das ist genau das, was wir in der nächsten Folge über Self-contained Systems dann diskutieren werden.