Suche
Die Fachlichkeit im Fokus - Teil 1

Domain-driven Design: Ketchup oder Mayo?

Stefan Priebsch

(c) Shutterstock / stockcreations

Sie sind Softwareentwickler? Wunderbar. Schön, dass Sie da sind. Ich brauche nämlich Ihren Rat. Ich möchte eine Pommesbude eröffnen und Sie sollen die Software dafür entwickeln. Interesse? Gut, dann lassen Sie uns loslegen.

Viele Projekte beginnen mit einer Menge Fragezeichen. Wenn die Anforderung etwa lautet: „ich brauche eine grafische Bedienoberfläche, mit der ich den Inhalt der Menükarte verwalten kann“, dann sind damit schon viele Fragen beantwortet – zumindest scheint es so. Wenn aber die Anforderung lautet: „ich möchte eine Pommesbude eröffnen“ oder vielleicht noch „ich möchte eine Pommesbude eröffnen und brauche dafür die Software“, dann stellen sich jedem Entwickler vermutlich erst einmal ganz viele Fragen. Wo soll man anfangen, und wo soll man aufhören? Was passiert denn eigentlich so alles in einer Pommesbude?

Nun, eine Pommesbude ist doch ganz einfach. Da gibt es Pommes und vielleicht noch ein paar andere Speisen und dazu Getränke. Das kann ja nicht schwierig sein.

So meint man. Lassen Sie uns mal genauer hinschauen. Und damit es für diesen Artikel nicht zu kompliziert wird, nehmen wir an, dass es in unserer Pommesbude tatsächlich nur Pommes gibt – und Mineralwasser (Cola ist ungesund).

Geschäftsprozesse

Versuchen wir im ersten Schritt, den wichtigsten Geschäftsprozess zu verstehen, nämlich die Zubereitung von Pommes. Wir brauchen dafür auf jeden Fall einen Tiefkühlschrank (wir ignorieren die Frage, ob das Mineralwasser gekühlt werden muss, einfach einmal). Nun ja: Wenn die Pommes tiefgekühlt sind, dann brauchen wir in der Tat einen Tiefkühlschrank, wenn die Pommes aber selbst aus frischen Kartoffeln zubereitet werden, dann nicht.

Als Nächstes brauchen wir eine Fritteuse. Das ist dann richtig, wenn die Pommes frittiert werden – Tiefkühlpommes aber könnte man auch im Backofen zubereiten. Ob allerdings selbst gemachte Pommes aus dem Backofen schmecken, das ist fraglich.

Wo kommen denn eigentlich die Pommes her? Werden sie angeliefert oder abgeholt. Woher wissen wir, wann wir neue Pommes holen – oder bestellen – müssen? Das können wir aktuell nicht beantworten, also stellen wir die Frage erst einmal zurück. Sie gehört vermutlich auch nicht zum Kerngeschäftsprozess.

Wenn die Pommes zubereitet sind, dann werden sie serviert. Kommt Papp-, Plastik- oder Porzellangeschirr zum Einsatz? Während wir Pappteller vermutlich nicht wiederverwenden wollen, wäre es eher unwirtschaftlich, Porzellanteller nach jeder Verwendung wegzuwerfen. Wir müssen sie also abspülen. Machen wir das von Hand oder mit einer Spülmaschine? Welche Art Spülmaschine kommt zum Einsatz und wie lange braucht sie, um eine Ladung zu säubern? Das ist wichtig, denn wir müssen ja genug Geschirr vorrätig haben, um auch durch das Mittagsgeschäft zu kommen. Interessant ist auch die Frage, wo wir das benutzte Geschirr lagern, bis es in die Spülmaschine kommt.

Gar nicht so einfach

Wir sehen, dass ein (scheinbar) triviales Business wie eine Pommesbude beim näheren Hinsehen schon gar nicht mehr so einfach ist. Ein erfahrener Betreiber wird Antworten auf die meisten oder gar alle dieser Fragen haben, aber in vielen Punkten wird man letzten Endes von der Anzahl der Kunden abhängig sein; oder genauer gesagt vom maximalen Durchsatz – also der Anzahl von Kunden pro Zeiteinheit.

Viel schwieriger wird es, wenn wir zum ersten Mal eine Pommesbude eröffnen wollen und keine Erfahrung in diesem Geschäftsfeld haben. Es gibt nämlich noch zahlreiche weitere Fragen, die beantwortet werden müssen: Wohin mit dem Abfall? Woher bekommen wir Strom und Wasser? Welche gesetzlichen Pflichten sind zu erfüllen (beispielsweise Hygienevorschriften)? Akzeptieren wir nur Bargeld oder auch Kreditkarten, EC-Karten oder vielleicht Bitcoins?

Nehmen wir Vorbestellungen an und bieten wir auch salzarme Pommes für gesundheitsbewusste Kunden? Woher bekommen wir denn überhaupt unsere Kunden? Was tun wir dafür, dass unsere Kunden wiederkommen? Ist unsere Pommesbude fest installiert oder beweglich? Welche Auswirkungen hat das denn?

Mit wie viel Personal betreiben wir die Pommesbude? Wie rechnen wir deren Gehalt ab? Und welche Aufzeichnungen müssen wir führen, damit Steuerberater und Finanzamt zufrieden sind? Müssen wir Buch darüber führen, wie viele Portionen Pommes wir jeden Tag verkaufen, oder genügt es, dem Finanzamt die Summe der Tageseinnahmen zu melden?

Die wichtigste Lektion haben Sie vermutlich gerade schon gelernt? Es gibt keine einfachen Geschäftsmodelle, wenn es um Software geht. Je näher man hinsieht, desto mehr Welten tun sich auf. Und überall gibt es unbeantwortete Fragen. Der größte Fehler, den man nun machen kann, ist, ohne ein fundiertes Verständnis des Geschäftsmodells und der Geschäftsprozesse loszulegen und Software zu entwickeln. Das Ergebnis, selbst wenn die Software absolut fehlerfrei, nachhaltig und einfach wartbar sein sollte, wäre wohl eher zufällig „passend“. Wie soll man auch die richtige Software entwickeln, wenn man ins Blaue hineinarbeitet?

Geht nicht, gibt’s nicht

Software ist in einer gewissen Weise sehr starr, was die Anpassbarkeit an sich verändernde Geschäftsprozesse betrifft. Klar kann man sich vom Kunden zusichern lassen, dass er die Pommes selbst machen will. Aber wenn dieser nach zwei Wochen Stress im laufenden Betrieb erkennt, dass er ab sofort tiefgekühlte Pommes zubereiten will, dann müssen eben der Ofen ausgebaut und die Fritteuse sowie der Tiefkühlschrank eingebaut werden.

Natürlich sind solche Änderungen in Software leichter umzusetzen als in Hardware. Vielleicht treibt gerade dies uns immer wieder dazu, technische Entscheidungen viel zu leichtfertig zu treffen. Wer etwa eine relationale Datenbank einsetzt, muss SQL verwenden. Eine Suchmaschine ist für viele Anwendungsfälle besser geeignet als eine relationale Datenbank, versteht aber eine völlig andere Abfragesprache. Technische Entscheidungen haben also Konsequenzen, unter anderem in Form von Schnittstellen, denen wir uns unterwerfen.

Es ist daher wichtig, Technik und Realisierungsdetails so lange wie möglich aus der Diskussion auszuklammern. Das ist für Entwickler nicht immer leicht. Wir denken gerne schon frühzeitig darüber nach, was alles möglich wäre. In der Diskussion mit dem Kunden heißt es dann immer wieder „ja, das können wir alles umsetzen“ – dem Kunden wird aber nicht klar, dass der Entwickler hier von Alternativen sprach, und es beileibe nicht einfach ist, viele verschiedene Anforderungen mit einem System zu erfüllen.

Interessanterweise kann man sich auch in der Realisierung sehr gut um technische Abhängigkeiten herumdrücken. Der Schlüssel zum Erfolg ist dabei Abstraktion. Wenn alles SQL in einigen Klassen konzentriert ist, dann sind die Queries nicht nur sehr leicht (isoliert) zu testen, sondern der Rest der Anwendung weiß nichts davon, dass überhaupt eine relationale Datenbank eingesetzt wird. Damit das funktioniert, muss man das D (Dependency Inversion) in SOLID richtig verstanden haben [1]. Hier geht es nämlich nicht nur, wie oft verkürzt dargestellt, um „Dependency Injection verwenden“, sondern um die Frage, in welche Richtung Abhängigkeiten zeigen.

„Kennt“ die Geschäftslogik einer Anwendung die Datenbank (oder irgendeinen anderen Persistenzmechanismus), dann ist dies eine Abhängigkeit in genau der falschen Richtung. Dependency Inversion sagt (in diesem Fall) aus, dass die Geschäftslogik nicht vom Datenzugriff abhängig sein darf, sondern der Datenzugriff von der Geschäftslogik abhängen muss. Um dies zu erreichen, müssen beide ein gemeinsames Interface implementieren, das als Bestandteil der Geschäftslogik zu definieren ist.

Wenn man sich dies einmal mit Kästchen und Pfeilen aufmalt, dann erkennt man, dass eine klassische Schichtenarchitektur genau die „falsche“ Abhängigkeit zwischen Geschäftslogik und Datenzugriff propagiert. Falls Sie sich gewundert haben, woher Probleme mit der Wartbarkeit von Anwendungen in diesem Spannungsfeld kommen, dann haben Sie jetzt die Antwort dafür. Das ist der Preis, den man dafür bezahlt, wenn man zu früh technische Entscheidungen trifft und sich dadurch von technischen Details abhängig macht.

Aber wir haben in unserem Gedankenspiel „Pommesbude“ ja noch nicht mit der Realisierung begonnen. Dennoch neigen Entwickler oft dazu, mit dem Kunden eine viel zu technische Diskussion zu führen. „Wir können diese m-zu-n-Relation problemlos in die Datenbank abbilden, und mit den richtigen Indexen bekommen wir da auch kein Performanceproblem“ – lauter technische Details, für die sich ein Pommesbuden-Gründer bestimmt nicht interessiert, zumal er sie vermutlich gar nicht erst versteht.

Sprachregelung

Wir müssen also weg von technischen Details und weg vom Fachjargon. Viel besser wäre es, wenn wir den Pommesbuden-Gründer in seiner Welt abholen könnten. Warum also von irgendwelchen technisch geprägten Begriffen sprechen? Wir wären viel kundenfreundlichere Entwickler, wenn wir die Sprache unseres Kunden sprechen würden – und nur dessen Sprache, ohne den ganzen technischen Kram.

Doch das hört sich leichter an, als es ist. Haben wir mehr als einen Ansprechpartner, wird das Ganze nämlich schnell unübersichtlich. Stellen wir uns vor, unser Kunde wäre ein Pommesbuden-Konzern. Wir berufen ein Meeting ein, um die zentralen Begriffe und deren Bedeutung zu klären. Nach ein wenig Vorgeplänkel stellen wir unsere zentrale Frage: „Was sind eigentlich Pommes?“. Ein anwesender Koch antwortet: „Frittierte Kartoffelstreifen“ und erzählt kurz davon, dass Pommes zweimal mit unterschiedlicher Temperatur frittiert werden müssen. Der Controller spricht eine Weile über die Kostenseite von Pommes, bis er vom Einkäufer unterbrochen wird. Dieser führt aus, dass der Einkauf säckeweise erfolgt, woraufhin der QA-Verantwortliche über seine ständige Sorge, die Kühlkette könnte unterbrochen werden, fabuliert. Den Buchhalter interessiert hauptsächlich, mit welchem Mehrwertsteuersatz die Pommes verkauft werden. Kurzum: Das Meeting bringt auch nach zwei Stunden kein sinnvolles Ergebnis. Was ging schief?

Eine gemeinsame Sprache zwischen Entwicklung und Kunde zu finden, ist auch deshalb so schwer, weil die verschiedenen Beteiligten des Kunden noch nicht einmal eine einheitliche Sprache sprechen. Es gibt verschiedene Kontexte, in denen die gleichen Begriffe eine völlig unterschiedliche Bedeutung haben können. Während der eine Pommes als Zutat für eine Mahlzeit sieht, sind es für einen anderen lediglich der Inhalt eines Sacks, der bewegt werden muss. Die Leute sprechen zwar von den gleichen Dingen, haben aber jeder für sich ein völlig unterschiedliches Bild im Kopf. Das führt schnell zu Missverständnissen.

Besonders schlimm wird es, wenn man als Entwickler versucht, die völlig unterschiedlichen Anforderungen in ein einheitliches Objektmodell abzubilden. Dies würde zu extrem aufgeblähten Objekten führen. Einkauf und Lagerhaltung dürften sich für das Verfallsdatum und die Lagerdauer von Pommes interessieren, ein Koch würde vermutlich allenfalls als qualitätssichernde Maßnahme vor dem Öffnen einer Packung prüfen, ob die Pommes noch haltbar sind. Für den Kassierer stellt sich eine Portion Pommes lediglich als ein bestimmter Preis dar, je nach Situation vielleicht versehen mit einem Mehrwertsteuersatz.

Um erfolgreich Software zu entwickeln, müssen die unterschiedlichen Kontexte sauber getrennt werden. Software sollte nicht mehrere solcher geschäftlichen Kontexte umspannen. Dazu müssen die Kontexte natürlich zuerst einmal identifiziert werden. Das erfolgt anhand der „Sprachgrenzen“; innerhalb eines Kontexts hat ein Begriff eine bestimmte Bedeutung. Dort, wo sich die Bedeutung eines Begriffs ändert, grenzen zwei Kontexte aneinander. Oftmals fallen Kontexte in Unternehmen mit unterschiedlichen Abteilungen zusammen, aber eben nicht immer.

Was wäre, wenn wir wichtige Geschäftsobjekte so entwerfen, dass diese Aspekte aus verschiedenen Kontexten vereinen? Das Ergebnis wären extrem komplexe, schwergewichtige und wenig kohärente Objekte, also Objekte, deren verschiedene Attribute und Methoden wenig Zusammenhang haben. Allein das Single-Responsibility-Prinzip würde schon fordern, ein solches Objekt in mehrere kleinere Objekte aufzuteilen, denn es gibt mehrere Gründe für eine Änderung.

Es zeigt sich wieder einmal, dass kleinere Objekte die besseren Objekte sind. Und je mehr diese an den tatsächlichen Use Cases ausgerichtet sind, desto effizienter wird die Softwareentwicklung. „Maximise the amount of work not done“, so steht es bereits im agilen Manifest. Das konsequente Design von Software anhand von Nutzungsfällen ist eine wichtige Voraussetzung dafür.

Die in diesem Artikel vorgestellten Ideen sind der Kern eines Ansatzes, der von den Autoren Eric J. Evans [2] und Vaughn Vernon [3] „Domain-Driven Design“ genannt wird. Im zweiten Artikel dieser Serie werden wir uns einige Entwurfsmuster ansehen, mit denen ein solcher Entwicklungsansatz technisch umgesetzt werden kann.

Geschrieben von
Stefan Priebsch
Stefan Priebsch
Diplom-Informatiker Stefan Priebsch ist Mitgründer von the PHP Consulting Company (thePHP.cc) und berät Firmen zum Einsatz von PHP und verwandten Technologien, wenn er nicht gerade als Zwillingsvater im Privatleben Skalierungsprobleme löst.
Kommentare
  1. Abundzu2016-08-31 02:55:10

    Wenn man Software öfter mal in die Hardware Welt projizieren würde, kämen viele Fragen gar nicht erst auf. Die Buchhaltung hat mit der Herstellung nichts zu tun, und wenn dann nur über eine Schnittstelle(wie Bestellung,Rechnung,Lieferung und entsprechende Dokumente). Wieso sollte Software also diese Schnittstellen virtuell brechen? Genau deshalb kommt einem bei den verschiedenen Fragen bzw. Sichten von Beteiligten nur ein Gedanke in den Sinn: was wird gewollt (und wer ist der entsprechende Ansprechpartner)? Software als Schnittstelle zum Kunden? Zum Hersteller? Interne Verwaltung? ... Und nur darauf wird die Entwicklung begrenzt. Dadurch entfällt doch auch das Problem der kontextbezogenen sprachgrenzen. Werden mehrere Bereiche berührt, müssen entsprechend mehrere Entwicklerteams (mit untereinander jew. zum Kontext bezogener Kommunikation) zum Einsatz kommen. Die Modularität sollte damit schon in der Entwicklung stärker eingesetzt werden und nicht nur im Produkt. Den DDD Ansatz kenne ich nicht zur Genüge, aber der Gedanke, dass dabei die eine oder andere Vorgehensweise schon vorher existierte und nun in einem neuen buzzword schön verpackt vermarktet wird, besteht natürlich :) ... Aber es sich näher anschauen lohnt sich sicherlich, letztendlich muss man ja mit dem Trend gehen (bis auf scrum, scrum ist ein übel)

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.