Architekturprinzipien

Der Begriff „Architektur“ bzw. „Software-Architekt“ hat in der Softwareentwicklung nicht den besten Ruf. Man denkt unwillkürlich an umfangreiche Konzepte, fehlenden Pragmatismus, Elfenbeintürme, Architektur-Reviews, merkwürdige UML-Diagramme voller Halbwahrheiten, „upfront design“, usw. usf. So ganz ohne Leitlinien geht es aber natürlich auch nicht…
Gerade bei einer Neuentwicklung auf der grünen Wiese hat man also eine faire Chance, es in diese oder jene Richtung komplett zu versauen. In Lhotse haben wir uns im Laufe des Projektes auf folgende Prinzipien geeinigt:

  1. Makro-Architektur:
    1. Vertikaler Systemschnitt
    2. Shared Nothing
    3. RESTful Architecture
    4. Zentrale Verantwortung für Daten und Datenversorungsprozesse
  2. Mikro-Architektur
    1. Buy when not core
    2. Gemeinsame Basistechnologien

1. Makro-Architektur

Makroarchitektur
Bei der Makro-Architektur geht es um die „Architektur im Großen“: Welche Teilsysteme gibt es, wie arbeiten sie zusammen und an welche Prinzipien müssen sich alle Teilsysteme und Teams halten.

1.A) Vertikaler Systemschnitt

Eine „klassische“ Architektur teilt sich in Schichten und Module:

Schichtenarchitektur

Häufig spiegelt sich dass dann auch in der Team-Struktur wieder: Ein oder wenige Teams pro Layer. Diese Aufteilung ist nicht ganz unproblematisch:

  • Für viele Anforderungen muss die Arbeit mehrere Teams eng koordiniert werden weil mehrere Schichten betroffen sind.
  • Die Anzahl der Teams ist in der Regel schlecht skalierbar. Die Anzahl der Entwickler pro Team sowieso.
  • Engpässe in einzelnen, zentralen Teams werden zu einem Problem für andere Teams.
  • Die Code-Base wird sehr schnell sehr groß. Niemand durchblickt mehr das Gesamtsystem.
  • Die Teams sind durch die gemeinsame Code-Base eng verbunden. Selbst das updaten einer verwendeten Library kann zum Geduldspiel werden.

Man könnte noch lange so weitermachen, aber hier geht es um die Lhotse-Architektur: und da haben wir uns für einen vertikalen Schnitt durch das System entschieden:
vertikale Schnitte
Jedes grüne Kästchen ist eine eigenständige Anwendung mit eigener Datenhaltung und eigenem Frontend. Manche Teams haben mehr als eine „Vertikale“, aber keine Vertikale wird von mehreren Teams entwickelt.

Eigene Datenhaltung bedeutet dabei auch, dass sich Vertikalen keinen Zustand über die selbe Datenbank teilen dürfen. Eine geteilte Datenbank würde wieder eine enge Kopplung zwischen den Systemen erzeugen: sie müssten sich über das Schema der Daten einig sein.
Der interne Aufbau einer Vertikalen liegt vollständig in der Verantwortung des Teams. Insbesondere gibt es keine gemeinsame Code-Base. Das führt zwar gelegentlich zu Parallelentwicklung, dafür müssen aber nicht die abweichenden Bedürfnisse mehrerer Teams in eine gemeinsam genutzte Library gedengelt werden.

1.B) Shared Nothing

Der Begriff „shared nothing“ drückt aus, dass sich die Teilsysteme untereinander, aber auch die einzelnen Instanzen einer geclusterten  Vertikalen, keinen gemeinsamen Zustand in der Anwendung halten. Es gibt also keine In-Memory Caches, über die sich Cluster-Knoten miteinander unterhalten müssen, keine HTTP-Sessions, die zwischen den Instanzen repliziert werden, usw.
Da sich einzelne Instanzen nichts teilen, müssen sie auch nicht miteinander kommunizieren und kein Load-Balancer muss Rücksicht darauf nehmen, welche „Session“ auf welche Knoten geleitet werden muss (das ist u.a. bei Deployments sowie für die Ausfallsicherheit wichtig).
Zustand in jeder Form wird also nur außerhalb des Systems gestattet: Im Browser, der Datenbank, einem Memcache oder in einem HTTP-Cache. Probleme mit der Cache-Coherency werden auf diese Weise vollständig vermieden.

1.C) RESTful Architecture

Natürlich müssen die einzelnen Vertikalen trotz aller Eigenständigkeit miteinander kommunizieren. Außerdem gibt es den Bedarf, für beispielsweise externe Apps oder ähnliches technische Schnittstellen bereitzustellen. Und dann gibt es natürlich auch noch die Integration der Teilsysteme in eine gemeinsame Shop-GUI und die Konfiguration des Shops durch eine Backoffice-Application (aka „Shopoffice“).
Damit alle diese Dinge möglich sind, haben wir uns auf eine REST Architektur geeinigt. REST heißt dabei nicht „wir tauschen XML-Dokumente für HTTP aus und verwenden auch PUT und DELETE“; wir nehmen das etwas ernster:

  • Definierte Resourcen
  • Verwendung definierter Media-Types (falls möglich vorhandene, ansonsten Vendor-Specific)
  • Beachtung der definierten HTTP Verben, Status Codes und Header
  • Das unaussprechliche HATEOAS Prinzip (erinnert mich immer an PCMCIA – People Can’t Memorize Computer-Industries Acronyms), also die Verwendung von Links bzw. „Hyermedia Controls“ in den Ressourcen um die Möglichkeiten der Zustandsübergänge (das ST in REST) navigierbar zu gestalten.
  • Unterstützung von HTTP Caches.

Unter anderem ist dabei ein Open-Source Projekt (http://github.com/otto-de/jsonhome) entstanden, mit dem eine Anwendung ein json-home Dokument veröffentlichen oder auch konsumieren kann.

1.D) Daten und Datenversorung

Da es sich bei der Anwendung um einen Online-Shop handelt, stehen die Chancen gut, dass viele Teilsysteme etwas über Produkte wissen müssen. Wenn sie aber keine gemeinsame Datenbank verwenden, wie werden dann Informationen geteilt? Dafür haben wir zwei Varianten:

  • Schaffung von Redundanzen über Datenversorgungsprozesse.
  • Ad-Hoc Anfragen über REST Schnittstelle

Die Datenversorgung erfolgt dabei stets asynchron im Hintergrund. Kein Kunde soll auf derartige Prozesse warten müssen. Inkonsistenzen zwischen den Systemen werden dabei bewusst in Kauf genommen.
Die Zugriffe zwischen den Systemen erfolgen dabei grundsätzlich über PULL-Mechanismen wie z.B. AtomPub Feeds da sich auf diese Weise die Kopplung zwischen den Systemen reduzieren lässt. Da wir ohnehin mit Inkonsistenzen rechnen müssen, kommt es auch nicht auf ein paar Sekunden Zeitversatz gegenüber einer Aktualisierung per PUSH an.
Sind solche Inkonsistenzen nicht akzeptabel, dürfen Systeme ausnahmsweise auch Ad-Hoc Anfragen an andere Vertikalen stellen; das versuchen wir jedoch zu vermeiden, da es eine enge Kopplung der Systeme mit sich bringt.
Der Kern des Architektur-Prinzips ist jedoch, dass für alle Daten nur eine Vertikale führend ist. Alle anderen Systeme greifen nur über REST-Schnittstellen auf die führende Vertikale zu und halten sich bei Bedarf redundante Daten. Die „Wahrheit“ über ein Datum liegt in der Hand des führenden Systems.

2. Mikro-Architektur

Im Gegensatz zur Makro-Architektur geht es bei der Mikro-Architektur um die „Architektur im Kleinen“, also die der einzelnen Vertikalen:
Mikro-Architektur
Da die Hoheit über die Vertikalen in der Verantwortung der zuständigen Teams liegen, gibt es hier keine übergreifenden Richtlinien. Es ist nicht vorgeschrieben, welche Frameworks verwendet werden müssen oder wie die Struktur der Anwendung auszusehen hat. Nur ein paar flankierende Absprachen:

2.A) Buy when non core

Wir sehen unsere Kernkompetenz nicht darin, beispielsweise eine eigene Datenbank oder eigene Frontend-Frameworks zu entwickeln. Stattdessen bedienen wir uns hier am Markt und kaufen entweder Dinge ein oder verwenden schlicht ein „Produkt“ aus dem Open-Source Umfeld. Was genau als „Core“ definiert ist, liegt dagegen wieder in der Entscheidung des Teams.

2.B) Gemeinsame Basistechnologien

Zur Zeit verwenden alle Teams die MongoDB als DBMS. Im Prinzip könnte eine Vertikale sich auch für eine andere Persistenzlösung entscheiden. Allerdings würde das betriebliche Aufwände nach sich ziehen, weshalb wir solche Änderungen vermeiden wollen.
Es gibt noch einige weniger weitere Dinge wie Tomcat als Servlet-Container oder auch gemeinsam genutzte Monitoring-Werkzeuge, die zur Zeit in allen Teams ähnlich verwendet werden, grundsätzlich aber als Bestandteil der Mikro-Architektur definiert sind. Die Teams könnten sich also gegen solche Grundlagen entscheiden, sind aber dazu angehalten, vorher in den Ring zu steigen und ihr Vorhaben in „großer Runde“ durchzuboxen.
Anfangs haben wir auch noch eine „common“ Library entwickelt und teamübergreifend genutzt. Mittlerweile sind wir jedoch zu dem Schluss gekommen, dass die Nachteile einer solchen Bibliothek (hinterrücks werden wieder Abhängigkeiten zu 3rd-Party Libraries eingeführt) dir Vorteile überwiegen.
Was viel besser funktioniert:

„Wenn es Code gibt, den sich Teams teilen wollen, entwickelt es als Open-Source Projekt, veröffentlicht es auf GitHub und behandelt es wie eine 3rd-Party Dependency“.

Bisher sind auf diese Weise drei GitHub Projekte (http://github.com/otto-de) entstanden:

  • hmac-auth: zwei Libraries (client, server) für die HMAC-Authentication + Authorization beim Zugriff auf REST Ressourcen.
  • jsonhome: Libraries zum publizieren und konsumieren von json-home Dokumenten.
  • wickettester: Unit-Testing für Wicket-basierte Web Applications.

Zwei weitere sind in Vorbereitung:

  • mongo-migrations: Tools für die on-the-fly Migration von MongoDB Dokumenten.
  • job-execution-framework: Ein Framework für die Steuerung, Ausführung und Kontrolle von asynchron laufenden Jobs.

Guido Steinacker, Jahrgang 1969, Diplom-Informatiker. Nach mehreren Stationen in der Software-Entwicklung verschiedener mittelständischer Unternehmen stieß er 2009 zu OTTO. 2010 entwickelte er im Rahmen von Prototypen die Grundlagen für die neue Shop-Architektur von otto.de und ist mittlerweile als Executive Software-Architekt im Bereich E-Commerce tätig.

Veröffentlicht in Architektur
10 comments on “Architekturprinzipien
  1. Guido, müsste es ganz oben in der Inhaltsübersicht nicht „Dezentrale Verantwortung für Daten und Datenversorungsprozesse“ statt „zentrale …“ heißen?

    • Guido Steinacker sagt:

      Hi Alex,
      gemeint ist, dass es für jedes Datum (z.B. ein Produkt) genau ein führendes System gibt. Der Datenversorgungsprozess für Produkte ist also „zentral“ einem Team bzw. System zugeordnet. Andere Datenversorgungen liegen in der Hoheit anderer Teams, das könnte man also auch als „Dezentrale Verantwortung“ bezeichnen – es kommt halt darauf an, wie man es betrachtet.

      Viele Grüße, Guido

  2. Als ehermaliger Konzepter beim otto.de Produktmanagement hat mich Michael Wegener letztens auf diesen beitrag aufmerksam gemacht. Meine Frage: macht diese Art der Architektur vor allem bei sehr großen Websites Sinn, oder profitieren auch kleinere Webshops (sagen wir mal bis 50 Mio Umsatz) davon?

    Gruß
    Markus

    • Guido Steinacker sagt:

      Ob die Architektur angemessen ist, hängt von verschiedenen Parametern ab:
      1. Wie wahrscheinlich ist es, dass mehr als ein oder zwei Entwicklungsteams an der Software arbeiten werden?
      2. Wie groß ist die Chance, dass die Anwendung in sagen wir mal einem Jahr ein unhandlicher Monolith mit (je nach Programmiersprache) zigtausenden Zeilen Code ist?
      3. Dann gibt es natürlich noch die Frage nach den Anforderungen hinsichtlich horizontaler Skalierbarkeit des Systems: steht zu befürchten, dass zwei bis fünf Instanzen der Software in einem Load-Balancing Cluster nicht mehr ausreichen werden?
      4. Möchte ich vielleicht in der Lage sein, irgendwann einmal einzelne Subsysteme auszutauschen, ohne gleich die gesamte Anwendung umbauen zu müssen?
      5. Habe ich dezentrale Teams an verschiedenen Standorten, die sehr unabhängig voneinander arbeiten müssen?
      6. Ist es mir wichtig, dass Teams mit verschiedenen Programmiersprachen etc. arbeiten können?

      Gruß, Guido

  3. […] the details of this architecture in an article in  OBJEKTspektrum (German), a different blog post (German) and at conferences […]

  4. […] wir 2011 mit der Neuentwicklung unseres Online-Shops otto.de starteten, wählten wir frühzeitig eine verteilte, vertikal geschnittene Architektur. Erfahrungen mit unserem Altsystem zeigten uns, […]

  5. […] 德语的Otto TechBlog )以及 Galeria Kaufhof 。在 scs-architecture.org […]

  6. […] Deployment von Microservices verschwimmen die Grenzen zwischen Mikro- und Makroarchitektur. Während das Team die Mikroarchitektur für jeden Service individuell entscheiden kann, muss man […]

Schreibe einen Kommentar

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

Folgen

Erhalte jeden neuen Beitrag in deinen Posteingang.

Schließe dich 188 Followern an

%d Bloggern gefällt das: