Zurück

Kombinatormodell

Veröffentlicht: 03.01.2023
Tags: Modellierung, Domain-Driven Design

Die Abbildung von fachlichen Strukturen und Logiken in Software Systemen stellt die Kernkompetenz von Entwicklern und Architekten dar. Über die Jahre haben sich verschiedene Ansätze dafür herausgebildet, wie dies methodisch, prozessual, und technisch gelingen kann. Dominierten früher noch Ansätze, in denen Fachbereiche deren Anforderungen so detailgetreu wie möglich in Fließtext verfasst und dann den Technikern übergeben haben, geht der Trend nun immer mehr zu agilen Prozessen und Methodiken über, die den Fachbereich eng in den Entwicklungszyklus einbinden.

Das Domain-Driven Design als Ansatz erhebt den Fokus auf die Fachdomäne zur Priorität. Bei der Erstellung des Modells der Fachdomäne versucht man diese so originalgetreu wie möglich abzubilden. Dafür müssen dessen Logiken und Geschäftsobjekte gut durchdrungen werden. Architekten, Business Analysten und Fachexperten können interessante Erkenntnisse über die Domäne erlangen und diese sowohl in die Domäne selbst, als auch in das System einfließen lassen. Ein simples Beispiel hierfür ist die Erkenntnis, dass ein Geschäftsobjekt nur als Element eines anderen Geschäftsobjektes existieren kann. Diese Form der Beziehung nennt man Komposition und sie gibt Aufschluss über die Verbindung der Lebenszyklen der Geschäftsobjekte. Gilt diese spezielle Beziehung in einer Hierarchie von Geschäftsobjekten nicht (kann also das Kindobjekt auch ohne das übergeordnete Geschäftsobjekt existieren) spricht man von einer Aggregation.

Beispiel einer Komposition und einer Agregation
Beispiel einer Komposition (links) und einer Aggregation (rechts)

Weiter lässt sich die Domäne auch auf Eigenschaften untersuchen, die aus der Mathematik stammen, zum Beispiel der Abgeschlossenheit algebraischer Strukturen. Gerade bei Domänen mit naturwissenschaftlichem Bezug (Betriebswirtschaft, Physik, Chemie, Mathematik) lassen sich solche Eigenschaften oft finden. In der Mathematik beschreibt Abgeschlossenheit eine Menge von Elementen, die über eine bestimmte Operation abgeschlossen ist. Die Operation gibt dabei für jedes beliebige Element der Menge als Parameter wieder ein Element der Menge als Ergebnis zurück. Das Prinzip lässt sich in die Programmierung übersetzen: Hier wird dann von Closure of Operations gesprochen, wenn zu einem Typ eine pure Funktion existiert, welche Objekte des Typs als Parameter entgegen nimmt und als Ergebnis ein Objekt des Typs zurückliefert. Mittels der Kombination eines solchen Typs und der dazugehörigen Funktion lässt sich dann ein Kombinatormodell aufbauen.

Achtung: Eigenschaften wie Komposition oder Abgeschlossenheit sollten immer in der Domäne verankert sein. Versucht man dem programmierten Modell diese Eigenschaften zuzuschreiben, obwohl sie sich nicht in der Domäne widerspiegeln, erhöht dies die Wahrscheinlichkeit für unerwünschtes Verhalten und die Notwendigkeit für aufwändiges Refactoring im Nachhinein.

In diesem Artikel widmen wir uns einer fiktiven Domäne, die eine Umsetzung eines Kombinatormodells erlaubt. Folgende Anforderungen gilt es abzubilden:

  • Angestellte einer Firma erhalten Freischaltungen für Türen des Firmengebäudes
  • Freischaltungen gelten immer für einen bestimmten Zeitraum
  • Freischaltungen für Angestellte müssen oft und schnell verändert werden können

Folgende Beispiele für Angestellte mit Freischaltungen sind gegeben:

  • Praktikant: Der Praktikant darf das Gebäude nur über den Haupteingang betreten. Innerhalb des Gebäudes darf er lediglich die Zugangstüre der Abteilung öffnen, in der er sein Praktikum verrichtet.
  • Büroangestellter: Der Büroangestellte darf das Gebäude über den Haupteingang oder das Tor der Tiefgarage betreten. Weiter darf er die Zugangstüre seiner Abteilung, sowie die Türe seines persönlichen Büros öffnen.
  • Hausmeister: Der Hausmeister darf grundsätzlich alle Türen öffnen.

Aus den Anforderungen lassen sich zunächst die Typen ableiten, die das System kennen sollte:

Überblick über fachliche Typen
Überblick über fachliche Typen
  • Türe: Ein Durchgang im Gebäude, für den der Angestellte eine Freischaltung benötigt.
  • Freischaltung: Eine Freigabe einer Türe für einen Angestellten in einem bestimmten Zeitraum.
  • Angestellter: Repräsentation des Angestellten, auf den sich die Freischaltungen beziehen. Hierbei handelt es sich um eine Referenz, da das abzubildende System nicht die Hoheit über dieses Geschäftsobjekt besitzt.

Aus den Beispielen wird ersichtlich, dass jeder Angestellte innerhalb der Firma eine eigene Komposition aus verschiedenen Freischaltungen besitzt. Geht man davon aus, dass sich jede Freischaltung auf eine Türe bezieht, könnten die Zutrittsrechte als Liste von Freischaltungen am Angestellten abgebildet werden. Das scheint bei einem Blick auf die verwendten Typen intuitiv. Bei der Zutrittsabfrage würde dann eine Funktion (istFreigeschaltet) diese Liste eintragsweise durchgehen, um zu prüfen, ob der Angestellte die notwendige Freischaltung besitzt. Bei Praktikanten und Büroangestellten wäre die Liste vermutlich kurz und prägnant, spätestens jedoch beim Hausmeister wäre sie unleserlich lang und müsste bei jeder Änderungen der Menge der Türen aktualisiert werden. Warum also erzeugt diese Modellierung im System einen so hohen Aufwand an Pflege, wo sie doch in der fachlichen Beschreibung so intuitiv und einfach wirkt?

Modellierung der Freischaltung als Liste
Modellierung der Freischaltung als Liste

Der Grund liegt darin, dass die Fachlichkeit eben keine Liste von Türen als Freischaltungen beschreibt. Daher ist die Abbildung als Liste solcher auch nicht so originalgetreu wie möglich. Tatsächlich beschreiben die Anforderungen eine Komposition aus Geschäftsregeln, aus denen sich die Freischaltungen ergeben. Die einzelnen Regeln können äußerst prägnant modelliert und im Kombinatormodell zusammengesetzt werden. Eine solche Funktion (und) wird klassischerweise als Verundung oder Konjunktion bezeichnet. Der Angestellte hält in diesem Modell ein kombiniertes Objekt, welches alle Eigenschaften der Freischaltung für genau diesen Angestellten unter sich vereint.

Modellierung der Freischaltung mit Kombinatoren
Modellierung der Freischaltung mit Kombinatoren

Achtung: Wir sehen in diesem Beispiel einen Kombinator bestehend aus KombinierteFreischaltung und und, welcher zwei Freischaltung Objekte kombiniert. Dieser kann jedoch problemlos erweitert werden, um drei, vier, oder eine beliebige Zahl an Freischaltung Objekten zu kombinieren. Es sollte jedoch darauf geachtet werden, dass dadurch lediglich ein fachliches und abgebildet, also keine fachliche Logik unterschlagen oder impliziert wird.

Während bei der Modellierung der Freischaltungen als Liste die Verknüpfung der einzelnen Elemente per Verundung als Implikation versteckt ist, wird sie bei der Modellierung aus Kombinatoren explizit sichtbar gemacht. Ein großer Vorteil dieser expliziten Modellierung wird im Laufe des Lebenszyklus des Systems deutlich: Das Domänenmodell ist nun auf dieselbe Art und Weise erweiterbar, wie die Domäne an sich. Es unterstützt also jene Änderungen der Domäne, die durch dessen Struktur wahrscheinlich sind. Betrachten wir hierzu folgendes Beispiel:

Als Büroangestellter mit vertraulichen Akten in meinem Büro möchte ich nicht, dass der Hausmeister freien Zugang zu dem Raum hat

Um die neue Anforderung im listenbasierten Modell umzusetzen, müssen dem Hausmeister in der Datenpflege alle Türen freigeschaltet werden, bis auf jene Bürotüren der Angestellten, die vertrauliche Akten in ihren Räumen lagern. Diese Logik ist aus der vermutlich langen Liste an Freischaltungen im Nachhinein nicht mehr ersichtlich. Das bedeutet, dass die pflegende Person bei Aktualisierungen der Türen von diesen vorher eingepflegten (jedoch nicht explizit sichtbaren) Ausnahmen wissen muss, damit dem Hausmeister nicht einfach wieder alle Türen freischaltet werden. Betrachten wir im Gegensatz dazu, wie die neue Anforderung im kombinatorbasierten Modell umgesetzt werden kann:

Modellierung der neuen Anforderung mit Kombinatoren
Modellierung der neuen Anforderung mit Kombinatoren

Mit der Spezialisierung FreischaltungMitAusnahme und der Funktion ohne ist ein neuer Kombinator definiert worden. Im Gegensatz zum Kombinator KombinierteFreischaltung verundet dieser die enthaltenen Freischaltung nicht, sondern deaktiviert die Schnittmenge.

Das Objektgeflecht, das durch die Verwendung von Kombinatoren entsteht, lässt sich ohne die im Programmcode versteckte Implementierungslogik interpretieren und verstehen. In seiner Struktur ähnelt es sehr einem Syntaxbaum. Diese Ähnlichkeit ist kein Zufall: Kombinatoren sind elementare Bestandteile von domänenspezifischen Sprachen und deren Grammatik. Sie ermöglichen das Erstellen komplexer Ausdrücke als Komposition einfacherer Bausteine. Mit dieser Eigenschaft qualifizieren sie sich als Werkzeug der objektorientierten Modellierung und schließen so den Kreis zwischen dem mathematischen/funktionalen und dem objektorientierten Paradigma.

Fazit

Bei der Erstellung des Domänenmodells lohnt es sich, die Domäne auf mathematische Eigenschaften hin zu analysieren. Lässt die Domäne die Definition von Kombinatoren zu, so erlauben diese eine sehr prägnante Modellierung, nah am Original. Diese Modellierung erleichtert die Analyse, Pflege, und Erweiterung des Systems während dessen Lebenszyklus und gibt den Daten durch ihre Repräsentation einen selbsterklärenden Charakter.



Combinator

Published: 03.01.2023
Tags: Modelling, Domain-Driven Design

The mapping of technical structures and logic in software systems is the core competence of developers and architects. Over the years, various approaches have emerged as to how this can be achieved methodically and technically. Whereas approaches in the past dominated in which stakeholders wrote their requirements in as much detail as possible in continuous text and then handed them over to the development team, the trend is now increasingly moving towards agile processes and methodologies that closely integrate stakeholders into the development cycle.

Domain-Driven Design as an approach prioritizses the business domain over technical concerns. When creating the business domain model, the aim is to depict it as faithfully as possible. To do this, its logic and business objects must be well understood. Architects, business analysts and stakeholders can gain interesting insights into the domain and incorporate these into both the domain itself and the system. An example: a given business object can only exist as an element of another business object. This type of relationship is called composition and it provides information about the connection between the life cycles of two business objects. If this special relationship does not apply in a hierarchy of business objects (i.e. the child object can exist without the parent business object), this is referred to as aggregation.

Beispiel einer Komposition und einer Agregation
Example of composition (left) und aggregation (right)

The domain can also be examined for properties that come from mathematics, for example the closure of algebraic structures. Such properties can often be found in domains with business or scientific origin (business administration and management, physics, chemistry, mathematics). In mathematics, closure describes a set of elements that is closed by a certain operation. For any element of the set given to the operation as parameter, it returns an element of given set. This principle can be translated into programming: Closure of operations describes a pure function accepting given type as parameter and return the same type. The combination of such type and associated function creates a combinator.

Important: Properties such as composition or closure should always be rooted in the domain. Attempting to apply these properties despite them not being rooted in the domain increases the likelihood of undesirable behavior and the need for complex refactoring afterwards.

For this article, we look at a fictitious domain that allows the implementation of a combinator. The following requirements need to be adressed:

  • Employees of a company are permitted to open certain doors of the company's building
  • These permissions are valid for a certain amount of time
  • Employee permissions need to be changed often and fast

Consider these examples of different employees:

  • Intern: The intern is permitted to enter the building via its main entrance only. Inside the building he is further permitted to open the door of his internships department.
  • Office worker: The office worker is permitted to enter the building via its main entrance as well as the parking garage located in the basement. Inside the building he is further permitted to open the door of his department and the door to his personal office room.
  • Facility manager: The facility manager is permitted to open all doors of the building.

From the requirements following domain types can be derived:

Überblick über fachliche Typen
Overview of domain types
  • Door: A passage int he building requiring permission for employees to be entered.
  • Permission: The permission for an employee to use a door for given time.
  • Employee: Representation of the employee to whom the permissions refer.

The examples show that every employee within the company has their own composition of different permissions. Assuming that each permission relates to a door, these could be represented by a list belonging to an employee. It seems intuitive when you look at the types used. Upon permission request, a function (isPdermitted) would then iterate through this list entry by entry to check whether the employee has the necessary permission. For interns and office workers, the list would probably be short and concise, but for the facility manager it would be illegibly long and would have to be updated every time the doors of the building change. So why does this modeling in the system require so much maintenance, when the technical description seems so intuitive and simple?

Modellierung der Freischaltung als Liste
Permission modelling as list

The reason is that within the domain permissions are not described as a list of doors per employee. Therefore, this modelling is not as true to the original as possible. In fact, the requirements describe a composition of business rules from which the permissions result. Individual rules can be modeled very succinctly and put together using a combinator. Such a cominator function (and) is traditionally referred to as a conjunction. In this model, the employee holds an object that combines all permissions for exactly this employee.

Modellierung der Freischaltung mit Kombinatoren
Permission modelling using a combinator

Important: In this example we use a combinator consisting of CombinedActivation and and, which combines two Permission objects. However, this can easily be extended to combine three, four, or any number of Permission objects. Make sure that this combinator is used only to represent an aggregation known in the domain and therefore no other domain logic is omitted or implied (as we have seen with list-based modeling).

Modeling permissions as list hides thier inner relationships, while using combinator(s) emphasizes them. A major advantage of this explicit modeling presents itself over the course of the system's life cycle: the domain model can now be expanded in the same way as the domain logic. It therefore supports changes to the domain likely to occur due to its structure. Let us consider the following example:

As an office worker with confidential files in my office, I do not want the facility manager to be permitted into my office.

In order to implement the new requirement in a list-based model, a user needs to configure the facility manager with all permissions, except for those offices with potentially confidential material. This logic is no longer apparent in the presumably long list of permission. When permissions are updated again, the user must know about these previously entered (but not explicitly visible) exceptions in order to prevent misconfiguration (hence permission to offices with confidential material). In contrast, let's take a look at how the new requirement can be implemented in the combinator-based model:

Modellierung der neuen Anforderung mit Kombinatoren
Modelling of the new requirement using combinators

A new combinator has been defined as a specialization of Permission called PermissionWithException and the function without. In contrast to the combinator consisting of CombinedActivation and and, this one does not activate all contained permissions, but deactivates the intersection.

The object structure created by using combinators can be interpreted and understood without implementation logic hidden in the program code. Its structure is very similar to a syntax tree. This similarity is no coincidence: combinators are elementary components of domain-specific languages ​​and their grammar. They enable complex expressions to be created as a composition of simpler building blocks. This property makes them suitable as a tool for object-oriented modeling, thus closing the circle between the mathematical/functional and the object-oriented paradigm.

Conclusion

While analyzing the domain model, it is worth to look out for mathematical properties. If the domain supports combinators, these allow for very concise modeling that is close to the original. This modeling facilitates the analysis, maintenance, and expansion of a system during its life cycle and gives data a self-explanatory character through its object representation.



Zurück