16. Jun 2025
Lesedauer 13 Min.
SOLID versus CUPID – Gegner oder Verbündete?
Softwaredesign
Die SOLID-Prinzipien gelten für Entwicklungsteams als goldene Regeln, um guten Code zu schreiben. Dan North übte 2016 Kritik daran und präsentierte als Gegenentwurf CUPID.

Prinzipien spielten in der Softwareentwicklung schon immer eine wichtige Rolle. Im Gegensatz zu konkreten Entscheidungen oder Mustern sind Prinzipien eher so etwas wie die Leitplanken für die Entwicklung: Sie geben dem Team Orientierung und befähigen es, gute Entscheidungen über das Softwaredesign und den Code selbstständig treffen zu können. Der aus Irland stammende Softwarearchitekt und Buchautor Eoin Woods hat es in einer Keynote im Jahr 2009 einmal wie folgt formuliert [1]: „Decisions and patterns give people solutions; principles help them design their own.“Gleichzeitig heißen Prinzipien aber auch deshalb so, weil es keine unumstößlichen Gesetze oder starre Regeln sind. Es existiert zumeist auch kein über alle Zweifel erhabener Beweis, dass ein Prinzip immer und unter allen Umständen richtig ist. Jahrzehntelange Erfahrungen aus Tausenden Projekten in der Softwareentwicklung haben aber gezeigt, dass die heutzutage populären Entwurfsprinzipien meistens gute Ratgeber sind und in den allermeisten Fällen befolgt werden sollten.Ein Beispiel dafür ist das Geheimnisprinzip (englisch: Information Hiding). Dieses wurde erstmals vom kanadischen Software-Engineering-Pionier David Lorge Parnas beschrieben, und zwar bereits vor über 50 Jahren. In einem 1972 veröffentlichten Paper über Modularisierung [2] empfiehlt Parnas, dass ein Softwarebaustein seine internen Daten und andere Implementierungsdetails vor einem Zugriff von außen schützen sollte. Durch diese Kapselung kann die Implementierung angepasst werden, ohne dass die Verwender des Moduls diese Änderungen spüren.Weitere weithin bekannte Klassiker sind die allgemeingültigen Prinzipien wie zum Beispiel KISS (Keep it simple, stupid!), DRY (Don’t repeat yourself!), YAGNI (You ain’t gonna need it!) oder das Prinzip der geringsten Überraschung (Principle of Least Astonishment; kurz: PLA oder POLA). Letzteres besagt, dass ein Baustein (Modul) eines Softwaresystems sich so verhalten sollte, wie es die meisten Verwender erwarten, und diese nicht von unvorhersehbaren Seiteneffekten überrascht oder überrumpelt werden sollen.
SOLID
Ein sehr populärer Satz an Entwurfsprinzipien für das Softwaredesign sind die, deren Anfangsbuchstaben das Akronym SOLID ergeben. Der englische Begriff „solid“ bedeutet übersetzt in etwa solide, fest oder stabil. Diese fünf Prinzipien zielen vor allem darauf ab, die Evolvierbarkeit (siehe Kasten Evolvierbarkeit (Software)) und Erweiterbarkeit von objektorientierter Software zu verbessern.Evolvierbarkeit (Software)
Evolvierbarkeit ist ursprünglich ein Begriff aus der Evolutionsbiologie. Zu evolvieren heißt, sich im Zuge der Evolution zu verändern, sich weiterzuentwickeln, aber auch etwas Neues hervorzubringen oder herauszubilden. Evolvierbarkeit beschreibt also in der Biologie die Fähigkeit einer Spezies, sich an verändernde Umweltbedingungen anpassen zu können.
Obwohl der Ursprung dieser Prinzipien unter anderem auf die Arbeiten des französischen Informatikers Bertrand Meyer oder der MIT-Professorin Barbara Liskov zurückzuführen ist (siehe Bild 1), wurden sie vor allem durch den US-amerikanischen Softwareentwickler und Buchautor Robert Cecil Martin populär, der insbesondere durch sein Buch über Clean Code [3] einen hohen Bekanntheitsgrad erreicht hat.

Die historischen Ursprünge der SOLID-Prinzipien (Bild 1)
Autor
Wenngleich die SOLID-Prinzipien vielen aus der Leserschaft bekannt sein dürften (siehe auch den Artikel von Bernhard Pichler unter [4]), hier noch einmal die Kurzbeschreibungen:
- Single Responsibility Principle (SRP): Eine Software-Entität (zum Beispiel eine Komponente, Klasse oder Methode/Funktion) sollte nur exakt eine einzige, klar definierte Verantwortlichkeit haben. Anders formuliert: Es sollte nur einen einzigen Grund geben, eine Software-Entität ändern zu müssen.
- Open/Closed Principle (OCP): Software-Entitäten sollten offen für Erweiterungen, aber geschlossen für Modifikationen sein. Neue Funktionalität sollte nahezu ausschließlich durch das Hinzufügen neuen Codes realisiert werden. Bereits bestehender, funktionierender und gut getesteter Code sollte dabei weitgehend unangetastet bleiben.
- Liskov Substitution Principle (LSP): Abgeleitete Klassen müssen die „Verträge“ ihrer Basisklassen, zum Beispiel Klassen-Invarianten, bereitgestellte Schnittstellen und andere Zusicherungen, vollumfänglich erfüllen. Werden Objekte einer Basisklasse durch Objekte ihrer abgeleiteten Klassen ersetzt (substituiert), so darf das für die Verwender dieser Objekte keinen Unterschied machen.
- Interface Segregation Principle (ISP): Eine Klasse sollte nicht gezwungen werden, Teile einer Schnittstelle zu implementieren, die sie nicht nutzt oder für die sie keine sinnvolle Implementierung anbieten kann. Daher sollten Schnittstellen möglichst schmal sein, wodurch diese auch universeller eingesetzt werden können.
- Dependency Inversion Principle (DIP): Hochrangige Module (englisch: High-Level Modules; HLM) sollten nicht direkt von niederrangigen Modulen (englisch: Low-Level Modules; LLM) abhängen. Beide sollten von Abstraktionen abhängen. Dieses Prinzip fördert einerseits eine lose Kopplung, zudem kann damit die Richtung von Abhängigkeiten designt werden.
Dan Norths Kampfansage: CUPID
Dieser Prinzipiensammlung hat der britische Softwareentwickler und Technology-Consultant Daniel Terhorst-North, der Anfang der 2000er-Jahre vor allem durch seine agile Spezifikationsmethode Behavior-Driven Development (BDD) bekannt geworden war, einen Satz von ebenfalls fünf Prinzipien – Dan North nennt sie Eigenschaften (Properties) – gegenübergestellt. Auch deren Anfangsbuchstaben bilden ein Akronym: CUPID, englisch für Amor (Cupido), den Gott der Liebe in der römischen Mythologie. CUPID zielt auf allgemeinere Aspekte der Softwareentwicklung ab. Das heißt, sie sind nicht so stark auf das objektorientierte Softwaredesign fokussiert, sondern unabhängig von Programmierparadigmen. Doch wie kam es dazu?Es geschah in einem Pub
Die CUPID-Eigenschaften wurden erstmals im März 2021 in Dan Norths Blog-Artikel „CUPID – the back story“ [5], der ihre Entstehungsgeschichte beleuchtet, namentlich erwähnt, waren aber schon vorher gelegentlich Thema in einigen seiner Konferenzvorträge.Im Jahr 2016 wurde Dan North eingeladen, bei einer PubConf-Veranstaltung in London zu sprechen. Hierbei handelte es sich um ein Side-Event der NDC-Konferenzen, dessen Veranstaltungsort, wie der Name es schon vermuten lässt, ein britischer Pub war. Die Sprecher hielten dort vor einem ausgelassenen Publikum Vorträge im sogenannten Ignite-Stil, das heißt, gezeigt wurden pro Vortrag 20 Folien mit 15 Sekunden Zeit pro Folie und einem automatischen Vorlauf.Für seinen eigenen Ignite-Talk hatte sich Dan North eine Herausforderung gestellt: Es zu schaffen, jedes SOLID-Prinzip mit unbewegter Miene zu widerlegen und eine bessere Alternative anzubieten. Das Ergebnis war der Kurzvortrag mit dem Titel „Why Every Single Element of SOLID Is Wrong!“ [6]. North positionierte CUPID darin als Gegenentwurf zu SOLID.In einem weiteren Blog-Artikel aus dem Jahr 2022 mit dem Titel „CUPID — for joyful coding“ [7] vertieft Dan North die fünf Eigenschaften, die aus seiner Sicht die Arbeit mit Software zu einem Vergnügen machen.Das Akronym CUPID steht dabei für:- Composable: Softwarebausteine (Komponenten, Module) sollten einfach zusammensetzbar sein und sich leicht zu neuen Systemen kombinieren lassen. Deshalb sollten alle Abhängigkeiten vermieden werden, die nicht unbedingt notwendig sind.
- Unix Philosophy: Beim Entwurf von Softwaresystemen, die diese Eigenschaft besitzen, sollte der „Single Purpose“, also der Zweck, im Mittelpunkt stehen, und nicht das Single Responsibility Principle. Single Purpose fördere eine zweckorientierte Outside-In-Perspektive auf den zu entwickelnden Code, wogegen SRP eher eine Inside-Out-Perspektive fördert, bei der es um die interne Struktur und Organisation von Code geht. Hintergrund: Der große Erfolg von Unix-/
Linux-Betriebssystemen ist unter anderem auch auf deren flexibles Komponentenmodell zurückzuführen. Dabei erfüllt jede Komponente (zum Beispiel ls, rm, sed oder cat) genau einen Zweck. - Predictable: Das Verhalten des Systems und seiner Komponenten sollte vorhersagbar sein und sich bei wiederholten Ausführungen konsistent und deterministisch verhalten. Das beabsichtigte Verhalten von Code sollte aus seiner Struktur und Benennung ersichtlich sein. Auch Code, der absichtlich nichtdeterministisches Verhalten haben soll, zum Beispiel ein Zufallszahlengenerator, hat definierte Randbedingungen oder funktionale Grenzen.
- Idiomatic: Der Code sollte idiomatisch sein, das heißt, er sollte den gängigen Konventionen und Best Practices der verwendeten Programmiersprache folgen. Anders formuliert: Schreiben Sie den Code immer so, wie ihn auch ein Experte der jeweiligen Programmiersprache geschrieben hätte.
- Domain-based: Der Code sollte domänenfokussiert sein, das bedeutet, dass er die Konzepte, Begriffe und Logik der Fachlichkeit (Problem-Domäne) widerspiegelt. Bei einer guten Benennung von Komponenten, Typen und Operationen geht es eben nicht nur darum, Klarheit zu schaffen und Fehler zu vermeiden, sondern auch darum, den Lösungsraum im Code abzubilden. Sprechen die Stakeholder beispielsweise von Kunden (Customer), so sollte im Code nicht auf einmal der Begriff Nutzer (User) verwendet werden. Ein Kriterium für domänenfokussierten Code ist, dass externe Personen, die einer Diskussion eines Entwicklungsteams zuhören, kaum unterscheiden können, ob das Team über den Code oder die Fachlichkeit diskutiert.
Dan Norths Kritik an SOLID
Zunächst zu Dan Norths grundsätzlichen Kritikpunkten an SOLID, die später noch eingeordnet werden.Dan North bezeichnet die SOLID-Prinzipien als zu vage und als nicht genügend richtungsweisend. Zum einen kritisiert er, dass sie insgesamt zu stark auf objektorientierte Programmierparadigmen abzielen würden. Für zum Beispiel rein funktionalen Code seien sie daher ungeeignet.Zudem findet er, dass das Konzept des Prinzips an sich problematisch sei. Prinzipien sind aus seiner Sicht zu schwarz-weiß und daher eher wie starre Regeln: Entweder man hält sich daran oder nicht.Weiterhin enthalte SOLID seiner Auffassung nach Dinge, die einstmals gute Ratschläge waren. Sie entstanden vor der Jahrtausendwende, in einer Epoche der IT, als Softwareentwicklung noch eine andere Disziplin war, als sie es heutzutage ist. Seit ihrer Entstehung hat sich vieles weiterentwickelt. Daher sei SOLID aus der Zeit gefallen und könnte mittlerweile auch leicht falsch interpretiert werden.Dan North nimmt sich auch jedes einzelne SOLID-Prinzip kritisch vor; seine Standpunkte sollen beispielhaft an drei Prinzipien erläutert werden.Pointlessly Vague Principle
Das Single Responsibility Principle (SRP) beispielsweise besagt, dass der Code einer Software-Einheit nur eine Aufgabe erfüllen sollte. Dan North nennt dies das „Pointlessly Vague Principle“ (deutsch etwa: nutzlos-schwammiges Prinzip) und fragt: Was ist denn überhaupt „eine Aufgabe?“ Ist beispielsweise der Datenmigrationsprozess ETL – Extract–Transform–Load – eine Aufgabe, oder sind es gleich drei Aufgaben?Stattdessen schlägt Dan North vor, einfachen Code zu schreiben und dabei die Heuristik anzuwenden, dass er „in den Kopf passt“. Er meint damit, dass man nur dann über etwas gut nachdenken kann, wenn es eine Granularität beziehungsweise Größe hat, die es den Developern erlaubt, es vollumfänglich analytisch zu erfassen. Code sollte daher auf jeder Abstraktionsebene „in den Kopf passen“, sei es auf Methoden-/Funktionsebene, auf Klassen-/Modulebene, auf Komponentenebene oder sogar auf der Ebene verteilter Anwendungen.Das OCP – nicht mehr zeitgemäß?
Das Open-Closed Principle (OCP) hält Dan North schlichtweg für aus der Zeit gefallen. OCP war seiner Ansicht nach ein weiser Rat in einer Zeit, in der es aufwendig, zeitintensiv und damit teuer war, Code zu ändern. Eine kleine Änderung führte damals oftmals dazu, dass Millionen Zeilen eng miteinander verwobenen C- oder C++-Codes neu vom Compiler übersetzt werden mussten, was viel Zeit in Anspruch nahm. Auch war es riskant, Code zu ändern, weil damals eine hohe Testabdeckung noch nicht so üblich war und es nur wenige zuverlässige Refactoring-IDEs (außerhalb von Smalltalk) gab, die Modifikationen am Code sicher und einfach ermöglichten.Stattdessen lautet Dan Norths fast schon banaler Ratschlag: Wenn man Code für etwas anderes benötigt oder dieser eine neue Funktionalität bekommen soll, sollte man diesen Code einfach ändern, damit er etwas anderes tut! Heutzutage betrachtet man Code eher als formbar, vergleichbar mit Lehm, und somit als etwas Flexibles, während die Metapher aus den alten Tagen eher an starre Bausteine erinnerte, die, wenn einmal implementiert, niemals mehr angefasst werden sollten.Moderne Entwicklungswerkzeuge mit eingebauten Refactoring-Funktionen sowie eine hohe Testabdeckung und eine durch KI-Assistenten unterstützte Programmierung (zum Beispiel durch Microsoft Copilot) machen es mittlerweile sehr einfach möglich, simplen Code zu schreiben, der leicht und risikoarm zu ändern ist. Dadurch erhält man einen Code, der sowohl offen als auch geschlossen ist, wie auch immer man ihn benötigt.ISP: Eher Pattern als Prinzip?
Beim Interface Segregation Principle (ISP) kritisiert Dan North, dass dieses eigentlich gar kein Prinzip sei, sondern eher ein Muster. Bei seinen Recherchen fand North heraus, dass dieses Prinzip beziehungsweise Muster entstand, als Robert C. Martin mit einer sogenannten „Gott-Klasse“ [8], also einer Klasse mit viel zu vielen Verantwortlichkeiten, inmitten einer Drucksoftware kämpfte. Martins Ansatz zur Vereinfachung bestand darin, jede Stelle zu finden, an der die Gott-Klasse verwendet wurde, um zu ermitteln, welche Untermenge an Methoden gemeinsam verwendet werden und somit „zusammengehören“ (Kohäsionsprinzip). Diese Methoden hat er dann in entsprechende Schnittstellen zusammengefasst. Dadurch wurden die verschiedenen Verantwortlichkeiten der Gott-Klasse deutlich; eine Erkenntnis, die von Robert C. Martin wiederum dazu genutzt wurde, diese viel zu große Klasse zu zerteilen.Einordnung
Hat Dan North recht? Gehen die SOLID-Prinzipien in die falsche Richtung? Sind sie möglicherweise veraltet? Sollten wir sie denn jetzt vergessen und stattdessen bevorzugt oder gar ausschließlich CUPID als die wesentlichen Leitlinien für den Softwareentwurf heranziehen?Nein, natürlich nicht! CUPID steht in keiner Weise im Widerspruch zu SOLID. Ich störe mich zunächst an der pauschalisierenden Aussage, dass die SOLID-Prinzipien nur Objektorientierung als Kontext haben. Das ist nur insofern richtig, als dies das vorherrschende Programmierparadigma war, für das diese Prinzipien ursprünglich beschrieben wurden. Aber sie gehen, abgesehen vielleicht von dem doch sehr speziellen Liskov Substitution Principle, über OO hinaus. Gilt das SRP denn nicht mehr, wenn wir es mit einer rein funktionalen Programmiersprache zu tun haben? Ich denke schon, dass es eine sehr gute Idee ist, dass auch eine Funktion, die in Haskell, Clojure, Erlang oder F# entwickelt wird, nur eine einzige, wohldefinierte Verantwortlichkeit haben sollte. Sind zu breite und zu umfangreiche Schnittstellen, die das ISP verletzen, in Nicht-OO-Sprachen tolerierbar? Wahrscheinlich nicht.Des Weiteren blendet Dan North aus, dass es Verantwortlichkeiten auf unterschiedlichen Abstraktionsniveaus gibt. Das Prinzip Single Level of Abstraction (SLA) fordert nämlich, dass sich komplexe Aufgaben aus Teilaufgaben zusammensetzen, die auf dem nächstniedrigeren Abstraktionsniveau angesiedelt sind. Das bedeutet: Sowohl der Datenmigrationsprozess Extract–Transform–Load (ETL) erfüllt insgesamt das SRP, seine drei Teilfunktionalitäten erfüllen das SRP aber genauso, nur eben eine Abstraktionsebene tiefer. Das Integration Operation Segregation Principle (IOSP) [9] besagt genau das: Trenne die integrierenden Elemente, die komplexere Abläufe orchestrieren, von den Elementen der nächstniedrigeren Abstraktionsebene, die dann die Teilaufgaben dieses komplexen Ablaufs ausführen.Darüber hinaus fällt es mir schwer, das CUPID-Prinzip Unix Philosophy und das SRP zu differenzieren. Der genaue Unterschied zwischen „Single Responsibility“ und „Single Purpose“ erschließt sich mir nicht. Das verallgemeinerte SRP lautet: „Auf seiner Abstraktionsebene sollte jede Entität in einem Softwaresystem nur eine wohldefinierte Verantwortlichkeit (Aufgabe) haben.“ Und das ist für mich quasi dasselbe wie die Unix Philosophy, dass jede Komponente nur genau einen Zweck erfüllen soll.Dass Robert C. Martin das ISP als Erkenntnis aus einem Refactoring einer Gott-Klasse abgeleitet hat, ist meines Erachtens kein Argument dafür, es als Muster und nicht als Prinzip zu betrachten. Ganz im Gegenteil: Die meisten Prinzipien hat man sich nicht auf dem Reißbrett ausgedacht, sondern sie sind in der Regel das Ergebnis langjähriger guter oder schlechter Erfahrungen. Zudem sind Muster definiert als bewährte und dokumentierte Lösungen für immer wiederkehrende Entwurfsprobleme. Bekannte Entwurfsmuster aus dem berühmten Buch der sogenannten „Gang of Four“ (GoF) [10], wie Strategy, Observer, Visitor oder Composite, sind elegante Lösungen für ganz spezifische Probleme in einem ganz speziellen Kontext. Das Prinzip hingegen, Schnittstellen möglichst schmal und universell zu halten, ist da viel allgemeiner.Das Predictable aus CUPID entspricht meiner Ansicht nach dem bereits zuvor in diesem Artikel angesprochenen Principle of Least Astonishment, welches zwar kein SOLID-Prinzip ist, aber im Clean Code Development durchaus verbreitet ist.Bei Idiomatic und Domain-Focused hingegen hat Dan North meines Erachtens einen Punkt. Idiomatisch bedeutet, dass Developer den Quelltext so verfasst haben, wie es State of the Art ist und wie es Fachkundige in dieser Programmiersprache auch tun würden. Und es bedeutet eben nicht, dass ein prozedurales C-Programm, das so aussieht, als sei es in den 1980er-Jahren geschrieben worden, nur mit einem modernen C++-Compiler übersetzt wird, um dann von „C++-Programmierung“ zu sprechen.Und ja, natürlich sollte der Quelltext sprachlich die Konzepte der Fachlichkeit widerspiegeln, aber auch die Struktur der gesamten Anwendung sollte sich an der Anwendungsdomäne orientieren. Das fördert die Kommunikation und die Kollaboration zwischen dem Entwicklungsteam und den externen Stakeholdern. Der zunehmend an Popularität gewinnende Softwareentwurfsansatz Domain Driven Design (DDD) [11], bei dem das Modell der zu entwickelnden Software maßgeblich aus den An- und Vorgaben von Experten der Anwendungsdomäne (Fachlichkeit) abgeleitet wird, soll genau das unterstützen.Fazit
Ein Prinzip ist dann gut, wenn es dem Entwicklungsteam echte Orientierung bietet, von diesem selbstständig anwendbar ist und dabei hilft, ein gemeinsames Verständnis im Team zu entwickeln, und es muss außerdem auch in der Praxis umsetzbar sein. Zudem sollte im Code zu erkennen sein, ob nach diesem Prinzip gehandelt wurde.Dan Norths CUPID-Eigenschaften sind oberflächlich betrachtet nicht falsch, erfüllen aber meines Erachtens diese Qualitätskriterien für gute Prinzipien nicht immer. Zudem dürfte es herausfordernd für Anwendende sein, zu unterscheiden, was denn jetzt der genaue Unterschied beispielsweise zwischen Single Responsibility (aus SOLID) und Single Purpose (aus CUPID) ist. Es wird wohl eine weitgehend unumstrittene Vorstellung in unserer Disziplin darüber geben, dass kleine Module/Klassen mit einer klar definierten Aufgabe besser sind als große „Gemischtwarenläden“.Auch ich betrachte SOLID nicht als heiligen Gral. Wir haben heute eine ganze Reihe von in der Regel unvollständigen Perspektiven auf Softwaredesign, und sie alle bieten einen gewissen Wert. Sie alle unterstützen sich gegenseitig. Daher finde ich es irritierend, zu sagen, dass alle Ratschläge aus SOLID falsch seien.Dan Norths Gegenvorschläge zu SOLID könnten alle zu der generalisierten Aussage „schreibe einfach einfachen Code“ zusammengefasst werden. Sie haben den Charakter eines Manifests, und SOLID ist eine mögliche Konkretisierung dieses Manifests. Und da gefällt mir tatsächlich seine Hilfestellung, dass der Code auf jeder Granularitätsebene „in den Kopf passen“ sollte, sehr gut. Das ist kein schlechter Maßstab.Fussnoten
- [1] Eoin Woods, Using Design Principles to Unify Architecture and Design, http://www.dotnetpro.de/SL2506-07CUPID1
- [2] David Lorge Parnas, On the criteria to be used in decomposing systems into modules, https://doi.org/10.1145/361598.361623
- [3] Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship. Prentice Hall, 2009, ISBN 978-0-13-235088-4,
- [4] Bernhard Pichler, SOLIDe Architektur, dotnetpro 4-5/2025, Seite 88 ff., http://www.dotnetpro.de/A2504-05SOLID
- [5] Daniel Terhorst-North, CUPID – the back story, https://dannorth.net/cupid-the-back-story/
- [6] Daniel Terhorst-North, Why Every Element of SOLID is Wrong, http://www.dotnetpro.de/SL2506-07CUPID2
- [7] Daniel Terhorst-North, CUPID – for joyful coding, http://www.dotnetpro.de/SL2506-07CUPID3
- [8] „Gottobjekt“ bei Wikipedia, http://www.dotnetpro.de/SL2506-07CUPID4
- [9] Ralf Westphal, Integration Operation Segregation Principle (IOSP), http://www.dotnetpro.de/SL2506-07CUPID5
- Erich Gamma et al., Design Patterns: Elements of Reusable Object-Oriented Software, Prentice Hall, 1995, ISBN 978-0-201-63361-0,
- Eric Evans, Domain-Driven Design: Tackling Complexity in the Heart of Software, Addison-Wesley, 2003, ISBN 978-0-321-12521-7,