Drei Fragen zum IOSP
Inhaltsverzeichnis zum Aufklappen
Ein Gespräch mit Stefan Lieser über das Integration Operation Segregation Principle (IOSP) und seine Anwendung
Flow Design gilt als sehr nützliche Entwurfsmethodik, da es die Teamkommunikation verbessert und ein gemeinsames Problemverständnis fördert. Durch die grafische Darstellung des Datenflusses ermöglicht es eine frühzeitige, sprachunabhängige Modellierung der Lösung. Das Integration Operation Segregation Principle (IOSP) unterstützt dabei die Erstellung leicht testbarer Methoden, während die strukturierte Zerlegung von Anforderungen und die parallele Bearbeitung im Team die Effizienz steigern.
Stefan Lieser ist Experte für Clean Code und Flow Design und hat Ende 2008 die Clean Code Developer Initiative mitbegründet. Er arbeitet als Trainer und Berater zu den Themen Clean Code Developer, Entwurf mit Flow Design sowie Softwarearchitektur. In seinem Buch „Mit Flow Design zu Clean Code“ [1] beschreibt der Geschäftsführer der CCD Akademie GmbH einen Softwareentwicklungsprozess, bei dem das systematische Zerlegen der Anforderungen sowie der Entwurf im Vordergrund stehen. Somit ist er der richtige Ansprechpartner für die folgenden drei Fragen:
Was ist das IOSP?
Stefan Lieser: Die Abkürzung steht für Integration Operation Segregation Principle. Das Prinzip besagt, dass die beiden Aspekte Integration und Operation zu trennen sind.
Als Operation bezeichnen wir Methoden und Funktionen, die Logik enthalten. Es handelt sich also um detailreichen Code. In einer Operation sind erlaubt:
- Ausdrücke wie x + 42 (arithmetisch) oder auch y == 7 (boolesch),
- Aufrufe fremder Methoden und Funktionen, also solche aus der Runtime und aus Frameworks oder Bibliotheken.
Wichtig ist hier die Unterscheidung zwischen eigenen und fremden Methoden. Fremde Methoden sind solche, die wir nur aufrufen, für deren Quellcode wir aber nicht verantwortlich sind. Es handelt sich also um Methoden aus Frameworks und Runtime, die wir in unser Softwareprojekt einbinden. Wir müssen die Methode nicht im Detail verstehen und sie hat in der Regel auch nichts mit unserer Domäne zu tun.
Allerdings müssen wir die Verantwortung für unsere eigenen Methoden übernehmen. Und leider sind sie oft an der Aufrufstelle nicht so leicht verständlich, so dass wir oft gezwungen sind, in den Quellcode zu schauen. Eigene Methoden liegen also auf einer höheren Abstraktionsebene.
Eine Operation sollte außerdem dem Single Responsibility Principle (SRP) entsprechen. Dies stellt sicher, dass ein guter Name für die Methode gefunden werden kann. Dies stellt auch sicher, dass die Methoden kurz und leicht verständlich sind.
In einer Integration wird Logik zu einem größeren Ganzen zusammengefügt. Daher dürfen in einer Integration nur eigene Methoden aufgerufen werden. Dies können wiederum Integrationen, aber auch Operationen sein. Lediglich der Aufruf von fremden Methoden und Ausdrücken ist in Integrationen verboten, da dies den Operationen vorbehalten ist.
Es gibt unterschiedliche Auffassungen darüber, ob Kontrollstrukturen wie if, while, for, foreach und switch in einer Integration erlaubt sind. Einerseits können Kontrollstrukturen den Code mit Details überfrachten. Andererseits kann ein dogmatisches Verbot den Code schwer verständlich machen.
Bei einer if-Anweisung darf natürlich kein Ausdruck (z.B. if(x == 42)) in der Integration stehen. Dieser wäre dann nicht isoliert testbar. Besser ist es daher, den Ausdruck in eine Funktion auszulagern (z.B. if(IsMagic(x)). Dies verbessert zum einen die Lesbarkeit, da der Ausdruck nicht mehr interpretiert werden muss. Der Name der Funktion sollte die Bedeutung transportieren. Zum anderen kann der Ausdruck durch die Auslagerung in eine eigene Funktion isoliert getestet werden. Dies ist insbesondere bei komplizierten Ausdrücken ein großer Vorteil.
Schleifen sind in der Regel unproblematisch, wenn sie kanonisch über alle Elemente einer Aufzählung iterieren. Auch hier gilt, dass eine Schleife keine Ausdrücke enthalten sollte, außer bei der for-Schleife über alle Elemente: for(i = 0; i < n; i++) { … }
Wie bei allen Prinzipien sollte auch bei der Anwendung des IOSP nicht dogmatisch vorgegangen werden. Der wichtigste Schritt ist immer das zweifelsfreie Erkennen einer möglichen Verletzung des Prinzips. Wichtig ist dann die Abwägung, ob die Werte Korrektheit oder Wandelbarkeit durch die Verletzung des Prinzips gefährdet sind. Im Zweifelsfall ist die Einhaltung des Prinzips sicherer.
Warum sollte man das IOSP einhalten?
Stefan Lieser: Da Operationen keine eigenen Methoden aufrufen, sind sie unabhängig von anderen Teilen der Codebasis. Sie sind somit Blätter im Abhängigkeitsgraphen. Das macht es einfacher, sie automatisiert zu testen. Es werden keine Attrappen benötigt, da die Operationen bereits frei von Abhängigkeiten sind. Da eine Operation keine weitere eigene Methode aufruft, liegt sie auf einer niedrigen Abstraktionsebene. Genauer gesagt: Sie liegt ausschließlich auf niedriger Abstraktionsebene. Es geht nur um Details. Damit ist das Prinzip des Single Level of Abstraction (SLA) erfüllt, das besagt, dass eine Methode nur auf einer Abstraktionsebene liegen sollte. Dies erleichtert das Verständnis einer Operation. Es ist auch einfacher, die Operationen kurz zu halten, da sie keine anderen der eigenen Methoden aufrufen dürfen.
Ähnliches gilt für Integrationen. Auch sie erfüllen das SLA, da sie nur auf einer hohen Abstraktionsebene liegen. Eine Integration ruft nur andere eigene Methoden auf. Sie enthält keine Details. Dadurch sind auch sie leicht verständlich.
Das Extrahieren des Integrationscodes fasst den Ablauf zusammen, der zur Lösung eines Problems notwendig ist. Auf einer hohen Abstraktionsebene kann nachgelesen werden, wie das Problem angegangen wird. Wenn Integration und Operation vermischt werden, ist diese abstrakte Zusammenfassung nicht an einer Stelle verfügbar. Stattdessen müssen alle Details gelesen werden, um den Prozess zu destillieren.
Die Einhaltung des IOSP unterstützt die Testpyramide optimal. Diese besagt, dass die Anzahl der Tests von den Systemtests über die Integrationstests zu den Unit Tests ansteigen soll. Es sollte also wenig Systemtests, etwas mehr Integrationstests und viele Unit Tests geben.
Wenn man seinen Code nach dem IOSP aufteilt, erhält man einen Abhängigkeitsbaum, der das Testen optimal unterstützt. Systemtests sind mehr oder weniger unabhängig von der internen Struktur immer möglich. Für die Integrationstests ist es hilfreich, dass die Integrationsmethoden selbst keine eigene Logik enthalten. Es genügen daher wenige Integrationstests, da diese lediglich sicherstellen müssen, dass alle Pfade durch die Integrationsmethoden mindestens einmal ausgeführt werden.
Die Operationen sind Einheiten im Sinne der Definition von Unit Tests. Sie sind nicht von anderen eigenen Methoden abhängig. Dies macht das Schreiben von Unit-Tests einfach, da nur sehr selten Attrappen verwendet werden müssen. Grundsätzlich widerspricht das IOSP nicht dem Dependency Inversion Principle (DIP), es können also auch Attrappen mittels Dependency Injection in Tests verwendet werden.
Setzt man jedoch ausschließlich auf das DIP, ist es an vielen Stellen notwendig, mit Attrappen im Test zu arbeiten. Diese Tests sind schlechter lesbar, oft zerbrechlich und verwenden interne Details der Implementierung.
Und wer hat’s erfunden?
Stefan Lieser: Nicht die Schweizer und auch nicht die Amerikaner. Tatsächlich haben Ralf Westphal und ich das IOSP erfunden.
Wir haben uns in den 2010er Jahren die Frage gestellt, wie man Softwareentwicklung radikal vereinfachen kann. Dabei ist neben dem Flow Design als Entwurfsmethodik auch das IOSP entstanden. Wir stellten fest, dass bei der Anwendung des Dependency Inversion Principle (DIP) zwei weitere Prinzipien verletzt werden:
- das Single Responsibility Principle (SRP) und
- das bereits erwähnte Single Level of Abstraction (SLA).
Methoden, die das DIP einhalten, sind für zwei Verantwortlichkeiten zuständig: Sie enthalten die detaillierte Logik für ihre eigentliche Verantwortung (operationale Verantwortung). Darüber hinaus integrieren sie Aufrufe anderer Methoden, auch wenn dies über die Indirektion einer Schnittstelle geschieht (Integrationsverantwortung).
Das SLA wird verletzt, wenn die DIP eingehalten wird, da die Methode einerseits die Detail-Logik enthält, andererseits aber auch high-level Aufrufe anderer eigener Methoden enthält.
Hinweise:
Wollen Sie sich mit Stefan Lieser über Flow Design und das Integration Operation Segregation Principle austauschen? Haben Sie Fragen oder Anmerkungen? Weitere Informationen finden Sie unter https://ccd-akademie.de/.
[1] Mit Flow Design zu Clean Code
Hier finden Sie Informationen zum Thema Flow Design.
Wenn Ihnen der Beitrag gefällt oder Sie darüber diskutieren wollen, teilen Sie ihn gerne in Ihrem Netzwerk.
Es gibt weitere Beiträge aus der t2informatik Blogserie „Drei Fragen …“:

Michael Schenkel
Leiter Marketing, t2informatik GmbH
Im t2informatik Blog veröffentlichen wir Beträge für Menschen in Organisationen. Für diese Menschen entwickeln und modernisieren wir Software. Pragmatisch. ✔️ Persönlich. ✔️ Professionell. ✔️ Ein Klick hier und Sie erfahren mehr.