Skip to content

Commit e0a7315

Browse files
authored
Merge pull request #575 from JensGrote/feat/iosp-anchor
feat: add IOSP anchor and TDD Hamburg Style contract
2 parents 14015fc + 7de820a commit e0a7315

8 files changed

Lines changed: 165 additions & 1 deletion

File tree

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ repos:
1414
files: \.adoc$
1515
pass_filenames: true
1616
args: [--format, console, --config, .asciidoc-linter.yml]
17-
stages: [commit]
17+
stages: [pre-commit]
1818

1919
# Trailing whitespace
2020
- repo: https://github.com/pre-commit/pre-commit-hooks

docs/all-anchors.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ include::anchors/kiss-principle.adoc[leveloffset=+2]
109109

110110
include::anchors/single-level-of-abstraction-principle.adoc[leveloffset=+2]
111111

112+
include::anchors/iosp.adoc[leveloffset=+2]
113+
112114
include::anchors/solid-dip.adoc[leveloffset=+2]
113115

114116
include::anchors/solid-isp.adoc[leveloffset=+2]

docs/anchors/iosp.adoc

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
= Integration Operation Segregation Principle (IOSP)
2+
:categories: design-principles
3+
:roles: software-developer, software-architect, consultant, educator
4+
:related: single-level-of-abstraction-principle, solid-principles, solid-srp, cohesion-criteria, grasp, solid-dip, clean-architecture
5+
:proponents: Ralf Westphal, Stefan Lieser
6+
:tags: iosp, integration, operation, testability, flow-design, function-design, clean-code, functional-dependency
7+
:tier: 2
8+
9+
[%collapsible]
10+
====
11+
Full Name:: Integration Operation Segregation Principle
12+
13+
Also known as:: IOSP, Integration-Operation Separation, N+1 Principle
14+
15+
[discrete]
16+
== *Core Concepts*:
17+
18+
Core rule::
19+
Functions shall either only contain logic or they shall only call other functions — never both.
20+
21+
Operation:: A function that contains logic but calls no other functions of the same solution. Logic includes transformations (`x + 2`), control structures (`if`, `for`, `while`), and third-party API calls (`Console.WriteLine`, `httpClient.Send()`). Operations are the *leaves* of the function tree — they have no functional dependencies on other code of the same codebase.
22+
23+
Integration:: A function that calls other functions (operations or other integrations) but contains *no logic itself*. Its sole responsibility is composing lower-level functions into a coherent whole. Integrations are the *branches* of the function tree — they orchestrate, they do not compute.
24+
25+
Hybrid:: A function that violates IOSP by mixing both logic and calls to other functions. Hybrids are the primary source of poor testability: the logic cannot be tested in isolation without mocking the called functions, and the calling structure cannot be understood without reading the embedded logic.
26+
27+
Why it works::
28+
A reader encountering an integration can trust it to be a *readable summary* of the work at that level — pure orchestration without hidden decisions. An operation, conversely, contains only detailed logic — no distracting jumps to other parts of the codebase. This natural enforcement of the Single Level of Abstraction Principle (SLAP) is the key insight: IOSP makes SLAP *automatic* rather than aspirational.
29+
30+
How it relates to DIP (Dependency Inversion Principle)::
31+
Code that follows DIP often creates hybrids: a method both contains domain logic *and* calls abstractions (interfaces) that represent integrations. IOSP argues that these two responsibilities — logic and integration — should be separated into different functions. The result: operations no longer depend on abstractions, integrating functions do the wiring instead. This reduces the need for DIP and Dependency Injection significantly; DIP is retained only for genuine cases of alternative implementations, not for testability.
32+
33+
Testability implications::
34+
Operations are trivially unit-testable — they have no functional dependencies that require mocking. Integrations contain no logic, so there is nothing to unit-test; integration tests verify the wiring. This is a categorical improvement over hybrid code, where every test requires mock setup for the called functions.
35+
36+
Codebase structure::
37+
Following IOSP produces a strict tree structure: integrations form the upper layers (high abstraction, no logic), operations form the leaves (low abstraction, all logic). There are no functional dependencies — only "empty" dependencies from integrations to the functions they call. This makes the data flow visible and the graph acyclic by construction.
38+
39+
Key Proponents::
40+
Ralf Westphal ("Integration Operation Segregation Principle (IOSP)", 2022 — substack; "IOSP 2.0", 2023; "Radical Object-Orientation #06", 2024), Stefan Lieser ("Three Questions about the IOSP", t2informatik interview, 2025; Clean Code Developer Initiative / CCD Akademie). Both are co-founders of the Clean Code Developer Initiative (2008).
41+
42+
[discrete]
43+
== *When to Use*:
44+
45+
* Refactoring hybrid functions that mix high-level orchestration with low-level details — IOSP tells you *how* to split, not just *that* you should
46+
* TDD: structuring code so that operations emerge naturally as testable leaves, with integrations as trivial wiring
47+
* Code review: a concrete, checkable rule — a function either calls other functions *or* contains logic, never both. If a reviewer spots a hybrid, it's a clear finding
48+
* Teaching clean code: unlike SRP (which is often debated), IOSP is *crystal clear at a glance* — there is no interpretation question
49+
* Reducing DIP/IoC complexity: if the only reason for DIP is testability, IOSP eliminates that need
50+
* Architecture design with IODA (Integration-Operation-Data-API): IOSP scales to module level, producing dependency-free operational modules composed by integration modules
51+
* Designing data flows: integrations become explicit "ditch-diggers" for data to flow between operations
52+
* .NET development with IospAnalyzer: automated Roslyn Analyzer catches IOSP violations at compile time
53+
54+
[discrete]
55+
== *Related Anchors*:
56+
57+
* <<single-level-of-abstraction-principle,Single Level of Abstraction Principle (SLAP)>> - IOSP naturally enforces SLAP: integrations are high-level, operations are low-level
58+
* <<solid-principles,SOLID Principles>> - IOSP applies SRP at the function level and can reduce the need for DIP
59+
* <<solid-srp,SOLID SRP>> - IOSP is a *special case* of SRP applied at the function level, separating the responsibility of "what to compute" from "how to compose"
60+
* <<cohesion-criteria,Cohesion Criteria>> - IOSP produces functional cohesion by dedicating each function to a single kind of work (either logic or composition)
61+
* <<grasp,GRASP>> - GRASP's "High Cohesion" and "Low Coupling" are structurally supported by IOSP's tree-like composition
62+
* <<solid-dip,SOLID DIP>> - IOSP can replace DIP for the purpose of testability; DIP is retained only for genuine alternative implementations
63+
* <<clean-architecture,Clean Architecture>> - Layered abstraction at architecture scale mirrors IOSP's function-level separation
64+
====

docs/anchors/iosp.de.adoc

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
= Integration Operation Segregation Principle (IOSP)
2+
:categories: design-principles
3+
:roles: software-developer, software-architect, consultant, educator
4+
:related: single-level-of-abstraction-principle, solid-principles, solid-srp, cohesion-criteria, grasp, solid-dip, clean-architecture
5+
:proponents: Ralf Westphal, Stefan Lieser
6+
:tags: iosp, integration, operation, testbarkeit, flow-design, funktionsdesign, clean-code, funktionale-abhaengigkeit
7+
:tier: 2
8+
9+
[%collapsible]
10+
====
11+
Vollständiger Name:: Integration Operation Segregation Principle
12+
13+
Auch bekannt als:: IOSP, Integrations-Operations-Trennung, N+1-Prinzip
14+
15+
[discrete]
16+
== *Kernkonzepte*:
17+
18+
Grundregel::
19+
Funktionen sollen entweder nur Logik enthalten oder nur andere Funktionen aufrufen — niemals beides.
20+
21+
Operation:: Eine Funktion, die Logik enthält, aber keine anderen Funktionen derselben Lösung aufruft. Logik umfasst Transformationen (`x + 2`), Kontrollstrukturen (`if`, `for`, `while`) und API-Aufrufe von Drittanbietern (`Console.WriteLine`, `httpClient.Send()`). Operationen sind die *Blätter* des Funktionsbaums — sie haben keine funktionalen Abhängigkeiten zu anderem Code derselben Codebasis.
22+
23+
Integration:: Eine Funktion, die andere Funktionen aufruft (Operationen oder andere Integrationen), aber *selbst keine Logik enthält*. Ihre einzige Verantwortung ist die Komposition niedrigerer Funktionen zu einem kohärenten Ganzen. Integrationen sind die *Verzweigungen* des Funktionsbaums — sie orchestrieren, sie berechnen nicht.
24+
25+
Hybrid:: Eine Funktion, die gegen IOSP verstößt, indem sie Logik und Funktionsaufrufe mischt. Hybride sind die Hauptursache schlechter Testbarkeit: Die Logik kann nicht isoliert getestet werden, ohne die aufgerufenen Funktionen zu mocken, und die Aufrufstruktur kann nicht verstanden werden, ohne die eingebettete Logik zu lesen.
26+
27+
Warum es funktioniert::
28+
Ein Leser kann sich bei einer Integration darauf verlassen, dass sie eine *lesbare Zusammenfassung* der Arbeit auf dieser Ebene ist — reine Orchestrierung ohne versteckte Entscheidungen. Eine Operation hingegen enthält nur detaillierte Logik — keine ablenkenden Sprünge zu anderen Teilen der Codebasis. Diese natürliche Durchsetzung des Single Level of Abstraction Principle (SLAP) ist die Kern-Einsicht: IOSP macht SLAP *automatisch* statt wünschenswert.
29+
30+
Beziehung zum DIP (Dependency Inversion Principle)::
31+
Code, der DIP befolgt, erzeugt oft Hybride: Eine Methode enthält sowohl Domänenlogik *als auch* Aufrufe von Abstraktionen (Interfaces), die Integrationen darstellen. IOSP argumentiert, dass diese zwei Verantwortlichkeiten — Logik und Integration — in verschiedene Funktionen getrennt werden sollten. Das Ergebnis: Operationen hängen nicht mehr von Abstraktionen ab, integrierende Funktionen übernehmen stattdessen die Verschaltung. Dies reduziert die Notwendigkeit von DIP und Dependency Injection erheblich; DIP bleibt nur für echte Fälle alternativer Implementierungen erhalten, nicht für Testbarkeit.
32+
33+
Auswirkungen auf die Testbarkeit::
34+
Operationen sind trivial unit-testbar — sie haben keine funktionalen Abhängigkeiten, die Mocking erfordern. Integrationen enthalten keine Logik, daher gibt es nichts zu unit-testen; Integrationstests verifizieren die Verschaltung. Dies ist eine grundlegende Verbesserung gegenüber Hybrid-Code, wo jeder Test Mock-Setup für die aufgerufenen Funktionen erfordert.
35+
36+
Codebasis-Struktur::
37+
Die Befolgung von IOSP erzeugt eine strenge Baumstruktur: Integrationen bilden die oberen Schichten (hohe Abstraktion, keine Logik), Operationen bilden die Blätter (niedrige Abstraktion, gesamte Logik). Es gibt keine funktionalen Abhängigkeiten — nur "leere" Abhängigkeiten von Integrationen zu den von ihnen aufgerufenen Funktionen. Dies macht den Datenfluss sichtbar und den Graphen per Konstruktion azyklisch.
38+
39+
Schlüsselvertreter::
40+
Ralf Westphal ("Integration Operation Segregation Principle (IOSP)", 2022 — substack; "IOSP 2.0", 2023; "Radical Object-Orientation #06", 2024), Stefan Lieser ("Three Questions about the IOSP", t2informatik Interview, 2025; Clean Code Developer Initiative / CCD Akademie). Beide sind Mitbegründer der Clean Code Developer Initiative (2008).
41+
42+
[discrete]
43+
== *Wann zu verwenden*:
44+
45+
* Refactoring von Hybrid-Funktionen, die High-Level-Orchestrierung mit Low-Level-Details mischen — IOSP sagt dir *wie* du zerlegen sollst, nicht nur *dass* du es solltest
46+
* TDD: Code so strukturieren, dass Operationen natürlich als testbare Blätter entstehen, mit Integrationen als trivialer Verschaltung
47+
* Code Review: eine konkrete, prüfbare Regel — eine Funktion ruft entweder andere Funktionen auf *oder* enthält Logik, niemals beides. Wenn ein Reviewer einen Hybriden entdeckt, ist das ein klarer Befund
48+
* Clean Code lehren: im Gegensatz zu SRP (über das oft diskutiert wird) ist IOSP *auf einen Blick glasklar* — es gibt keine Interpretationsfrage
49+
* Reduzierung von DIP/IoC-Komplexität: wenn der einzige Grund für DIP die Testbarkeit ist, eliminiert IOSP diese Notwendigkeit
50+
* Architektur-Design mit IODA (Integration-Operation-Data-API): IOSP skaliert auf Modulebene und erzeugt abhängigkeitsfreie operationale Module, die von Integrationsmodulen komponiert werden
51+
* Datenflüsse entwerfen: Integrationen werden zu expliziten "Grabenbaggern" für Daten, die zwischen Operationen fließen
52+
* .NET-Entwicklung mit IospAnalyzer: automatisierter Roslyn Analyzer erkennt IOSP-Verstöße zur Compilezeit
53+
54+
[discrete]
55+
== *Verwandte Anker*:
56+
57+
* <<single-level-of-abstraction-principle,Single Level of Abstraction Principle (SLAP)>> - IOSP setzt SLAP natürlich durch: Integrationen sind high-level, Operationen sind low-level
58+
* <<solid-principles,SOLID Principles>> - IOSP wendet SRP auf Funktionsebene an und reduziert die Notwendigkeit von DIP
59+
* <<solid-srp,SOLID SRP>> - IOSP ist ein *Spezialfall* von SRP auf Funktionsebene, der die Verantwortung von "was berechnet werden soll" von "wie komponiert werden soll" trennt
60+
* <<cohesion-criteria,Kohäsionskriterien>> - IOSP erzeugt funktionale Kohäsion, indem es jede Funktion einer einzigen Arbeitsart widmet (entweder Logik oder Komposition)
61+
* <<grasp,GRASP>> - GRASPs "Hohe Kohäsion" und "Niedrige Kopplung" werden durch IOSP's baumartige Komposition strukturell unterstützt
62+
* <<solid-dip,SOLID DIP>> - IOSP kann DIP für den Zweck der Testbarkeit ersetzen; DIP bleibt nur für echte alternative Implementierungen erhalten
63+
* <<clean-architecture,Clean Architecture>> - Geschichtete Abstraktion auf Architekturebene spiegelt IOSP's Trennung auf Funktionsebene wider
64+
====

docs/changelog.adoc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
A chronological record of all semantic anchors added to the catalog. Community contributors are credited with thanks.
44

5+
== 2026-06-03
6+
7+
*New anchors:*
8+
9+
* *IOSP (Integration Operation Segregation Principle)* — a function shall either contain logic (Operation) or call other functions (Integration), but never both; the formal refinement of SRP at function level; separates integration (coordination/sequencing) from operation (business logic/computation); eliminates mock-heavy tests by avoiding new'ing in functions that contain logic; formally checkable via IospAnalyzer (Roslyn); reduces the need for Dependency Injection (DIP) at the function level (Ralf Westphal, 2022; Stefan Lieser, 2025; proposed by https://github.com/JensGrote[@JensGrote] in https://github.com/LLM-Coding/Semantic-Anchors/issues/556[#556])
10+
11+
*New contracts:*
12+
13+
* *TDD, Hamburg Style* — Ralf Westphal's design-led TDD recipe: close the requirements/logic gap before writing code via the ACD cycle (Analyze → Design → Code), then test at service boundaries with minimal mocking; composes Red-Green-Refactor, London School, Chicago School, and IOSP (proposed by https://github.com/kuerm[@kuerm] in https://github.com/LLM-Coding/Semantic-Anchors/issues/557[#557], follows from https://github.com/LLM-Coding/Semantic-Anchors/issues/458[#458])
14+
515
== 2026-06-02
616

717
*New anchors:*

docs/metadata/roles.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,14 @@ domain-driven-design:
156156
- team-lead
157157
rationale: "Domain modeling approach; architects design bounded contexts, developers implement, BAs provide domain expertise, team leads facilitate ubiquitous language"
158158

159+
iosp:
160+
roles:
161+
- software-developer
162+
- software-architect
163+
- educator
164+
- consultant
165+
rationale: "Integration Operation Segregation Principle; developers write testable functions, architects design for separation, educators teach IOSP, consultants coach Clean Code practices"
166+
159167
# CATEGORY: Requirements Engineering
160168

161169
problem-space-nvc:

skill/semantic-anchor-translator/references/catalog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,11 @@ Source: https://github.com/LLM-Coding/Semantic-Anchors
269269
- **Proponents:** Kent Beck, Robert C. Martin
270270
- **Core:** All statements inside a function should live at one abstraction level; mixing orchestration with mechanics is the main driver of unreadable code; refactor by extracting low-level details into named helpers so the outer function reads like a table of contents; formal expression of Beck's Composed Method pattern, codified as a Clean Code function-design rule by Martin
271271

272+
### IOSP (Integration Operation Segregation Principle)
273+
- **Also known as:** IOSP, Ralf Westphal's IOSP
274+
- **Proponents:** Ralf Westphal, Stefan Lieser
275+
- **Core:** A function shall either contain logic (Operation) or call other functions (Integration), but never both; the formal refinement of SRP at function level; separates integration (coordination/sequencing) from operation (business logic/computation); eliminates mock-heavy tests by avoiding new'ing in functions that contain logic; formally checkable via IospAnalyzer (Roslyn); reduces the need for Dependency Injection (DIP) at the function level; narrows the Applicator/Alternator distinction in IODA Architecture
276+
272277
### Code Smells
273278
- **Also known as:** Bad Smells in Code, Refactoring Smells
274279
- **Proponents:** Kent Beck (coined term), Martin Fowler, Robert C. Martin

0 commit comments

Comments
 (0)