Die SOLID Prin­ci­ples bestehen aus fünf Praktiken und Richt­li­ni­en für sauberen, wartbaren und flexiblen Code beim ob­jekt­ba­sier­ten Pro­gram­mie­ren. Die Anwendung und Ein­hal­tung der Prin­zi­pi­en er­mög­licht ein leicht ver­ständ­li­ches Software-Design über lange Ent­wick­lungs­zeit­räu­me hinweg. Auf diese Weise lässt sich nicht nur besserer Code schreiben, sondern auch be­stehen­der Code besser pflegen.

Was sind die SOLID Prin­ci­ples?

Am Anfang eines guten Quell­codes stehen Regeln, Pro­gram­mier­pa­ra­dig­men und ein an­ge­mes­se­ner Pro­gram­mier­stil für einen ef­fi­zi­en­ten und sauberen Code. Genau dafür sorgen die fünf SOLID Prin­ci­ples, die von Robert C. Martin, Bertrand Meyer und Barbara Liskov geprägt wurden. Wer bestimmte Prin­zi­pi­en in der ob­jekt­ori­en­tier­ten Pro­gram­mie­rung (OOP) mit Sprachen wie Python oder Java beachtet, schreibt nicht nur besseren Code, sondern sorgt lang­fris­tig auch für eine ef­fi­zi­en­te­re Code-Pflege, ein nach­hal­ti­ges und flexibles Software-Design und mehr Si­cher­heit.

Die Be­zeich­nung SOLID steht zum einen für die solide Ent­wick­lungs­ba­sis für alle, die Pro­gram­mie­ren lernen wollen. Zum anderen setzt sich die Abkürzung aus den jeweils ersten Buch­sta­ben der fünf Prin­zi­pi­en (nach Michael Feathers) zusammen:

  • Single Re­spon­si­bi­li­ty Principle: Eine Klasse soll nur eine Ver­ant­wor­tung (nicht Aufgabe) und nur einen Grund für eine Änderung haben!
  • Open Closed Principle: Klassen sollen für Er­wei­te­run­gen offen und für Än­de­run­gen ge­schlos­sen sein!
  • Liskov Sub­sti­tu­ti­on Principle: Sub­klas­sen sollen alle Methoden und Ei­gen­schaf­ten der Su­per­klas­se erben und im­ple­men­tie­ren können!
  • Interface Se­gre­ga­ti­on Principle: Schnitt­stel­len sollen nicht mehr Methoden enthalten, als für im­ple­men­tie­ren­de Klassen er­for­der­lich sind!
  • De­pen­den­cy Inversion Principle: Klassen sollen nicht von anderen Klassen, sondern von Schnitt­stel­len oder abs­trak­ten Klassen abhängen!

Welche Vorteile bieten die SOLID Prin­ci­ples?

Wo keine Regeln gelten, tritt Chaos ein – das wird beim Pro­gram­mie­ren deutlich. Bereits kleine Fehler, Un­ge­nau­ig­kei­ten und Lücken können „un­be­han­delt“ auf längere Sicht einen guten Quellcode völlig un­brauch­bar machen. Dafür braucht es nicht viel: Es genügen schon komplexe Klassen, die eine Im­ple­men­tie­rung er­schwe­ren, oder Sub­klas­sen, denen einzelne Ei­gen­schaf­ten ihrer Su­per­klas­sen fehlen. Die SOLID Prin­ci­ples sorgen dafür, dass es möglichst wenig Reparatur von Code durch Re­fac­to­ring braucht.

Die Vorteile einer Anwendung der SOLID Prin­ci­ples umfassen:

  • Klar, sauber und schön: Software und Codes sind leichter ver­ständ­lich, nach­voll­zieh­ba­rer, ef­fek­ti­ver und einfach schöner.
  • Leicht zu pflegen: Durch die über­sicht­li­che, klare Struktur lässt sich sowohl neuer als auch his­to­risch ge­wach­se­ner Code selbst mit mehreren Be­tei­lig­ten einfacher warten und pflegen.
  • Anpassbar, er­wei­ter­bar, wie­der­ver­wend­bar: Durch die bessere Les­bar­keit, geringere Kom­ple­xi­tä­ten und Ver­ant­wor­tun­gen sowie re­du­zier­te Ab­hän­gig­kei­ten von Klassen lässt sich Code besser be­ar­bei­ten, anpassen, durch Schnitt­stel­len erweitern und flexibel wie­der­ver­wen­den.
  • Weniger feh­ler­an­fäl­lig: Durch sauberen Code mit einfacher Struktur wirken sich Än­de­run­gen an einem Teil nicht ungewollt auf andere Bereiche oder Funk­tio­nen aus.
  • Sicherer und zu­ver­läs­si­ger: Durch weniger oder gar keine Schwach­stel­len, In­kom­pa­ti­bi­li­tä­ten oder Fehler ver­bes­sert sich die Funk­tio­na­li­tät und Zu­ver­läs­sig­keit von Systemen und somit auch die Si­cher­heit.

Die SOLID Prin­ci­ples im Überblick

Die SOLID Prin­ci­ples zählen zu den goldenen Regeln für gutes Pro­gram­mie­ren und sollten daher allen, die sich mit ob­jekt­ba­sier­ter Pro­gram­mie­rung be­schäf­ti­gen, geläufig sein. Wir stellen die fünf Prin­zi­pi­en im Detail vor.

SRP: Single Re­spon­si­bi­li­ty Principle (Prinzip der ein­deu­ti­gen Ver­ant­wort­lich­keit)

Die Original-De­fi­ni­ti­on gemäß Robert C. Martin in „Agile Software De­ve­lo­p­ment: Prin­ci­ples, Patterns and Practices“ besagt:

Zitat

„Es sollte nie mehr als einen Grund dafür geben, eine Klasse zu ändern.“

Das SRP besagt, dass für jede Klasse in der OOP nur eine Ver­ant­wor­tung gelten soll. Für Än­de­run­gen an der Klasse darf es somit nur einen Grund geben. Entgegen häufigen Miss­ver­ständ­nis­sen bedeutet das nicht, dass eine Klasse oder jedes Modul nur genau eine Aufgabe haben darf. Sie sollte jedoch nur für spe­zi­fi­sche Aufgaben die Ver­ant­wor­tung tragen, die sich möglichst nicht mit anderen Bereichen über­schnei­den.

Ein Über­schnei­den von Ver­ant­wort­lich­kei­ten, zum Beispiel durch das Be­reit­stel­len von Funk­tio­nen für un­ter­schied­li­che Ge­schäfts­be­rei­che, kann im Fall von Än­de­run­gen an einem Bereich, Aus­wir­kun­gen auf die Funk­tio­na­li­tät der Klasse haben. Durch mehr als eine Ver­ant­wor­tung und zu viele Ab­hän­gig­kei­ten kann eine Änderung in einem Bereich mehrere weitere Än­de­run­gen oder Code-Fehler nach sich ziehen.

Das SRP hat somit zum Ziel, kohärente Module zu ent­wi­ckeln, die für eine klar ver­ständ­li­che Aufgabe oder klar de­fi­nier­te Objekte zuständig sind. Durch die klar struk­tu­rier­te Form mit re­du­zier­ten Ab­hän­gig­kei­ten und ent­kop­pel­ten Im­ple­men­tie­run­gen lassen sich spätere Än­de­run­gen und Mo­du­la­tio­nen einfacher, schneller und ohne Kom­pli­ka­tio­nen durch­füh­ren.

Hinweis

Klassen, auch als Ob­jekt­ty­pen bekannt, bilden das zentrale Element in der ob­jekt­ori­en­tier­ten Pro­gram­mie­rung (OOP). Sie lassen sich als Bauplan mit At­tri­bu­ten für reale, ähnliche und zu kon­stru­ie­ren­de Objekte in Software-Objekten verstehen. Klassen, auch als Module bekannt, werden daher oft mit Da­tei­ty­pen ver­gli­chen.

OCP: Open Closed Principle (Prinzip der Offen- und Ver­schlos­sen­heit)

Gemäß Bertrand Meyer und Robert C. Martin in „Object Oriented Software Con­s­truc­tion“ besagt das OCP:

Zitat

„Software-Entitäten (Klassen, Module, Funk­tio­nen etc.) sollten sowohl offen für Er­wei­te­run­gen als auch ge­schlos­sen für Mo­di­fi­ka­tio­nen sein.“

Das OCP sorgt dafür, dass Sie eine Software nicht im Kern um­schrei­ben müssen, um Än­de­run­gen zu im­ple­men­tie­ren. Sind tief­grei­fen­de Code-Mo­du­la­tio­nen er­for­der­lich, entstehen Risiken für subtile Fehler und Code Smell. Ein gut struk­tu­rier­ter Code sollte sich mit Schnitt­stel­len (In­ter­faces) versehen lassen, über die er sich um zu­sätz­li­che Funk­tio­nen erweitern lässt. Das Stichwort lautet hier Klassen-Vererbung.

Neue Features und Er­wei­te­run­gen mit über­sicht­li­chen neuen Funk­tio­nen und Methoden, die es zu im­ple­men­tie­ren gilt, lassen sich einfach per Schnitt­stel­le an eine Su­per­klas­se in Form von Sub­klas­sen andocken. Auf diese Weise müssen Sie nicht am ge­schrie­be­nen, stabilen Code „her­um­pfu­schen“. Das er­leich­tert die Wartung und Pflege von Pro­gram­men und gestaltet die Wie­der­ver­wend­bar­keit stabiler Code-Elemente durch Schnitt­stel­len deutlich ef­fi­zi­en­ter.

LSP: Lis­kov­sches Sub­sti­tu­ti­ons­prin­zip (Er­setz­bar­keits­prin­zip)

Gemäß Barbara H. Liskov und Jeannette M. Wing in „Be­ha­vi­oral Subtyping Using In­va­ri­ants and Cons­traints“ besagt das LSP:

Zitat

„Sei q (x) eine Ei­gen­schaft des Objekts x vom Typ T, dann sollte q (y) für alle Objekte des Typs S gelten, wobei S ein Subtyp von T ist.“

Was auf den ersten Blick kryptisch klingt, lässt sich leicht verstehen: Ver­knüpf­te oder er­wei­ter­te Sub­klas­sen müssen wie ihre Su­per­klas­sen oder Ba­sis­klas­sen funk­tio­nie­ren. Das bedeutet, dass jede Subklasse mittels Vererbung die Ei­gen­schaf­ten ihrer je­wei­li­gen Su­per­klas­se erhalten muss und diese Ei­gen­schaf­ten in der Subklasse keine Än­de­run­gen erfahren dürfen. Sie müssen vom Prinzip her ersetzbar sein – daher Er­setz­bar­keits­prin­zip. Su­per­klas­sen hingegen dürfen sich durch Än­de­run­gen mo­di­fi­zie­ren lassen.

Zur Ver­an­schau­li­chung dient das klas­si­sche Beispiel von Robert C. Martin vom Rechteck und Quadrat. Im Geo­me­trie­un­ter­richt gilt die Er­kennt­nis: Jedes Quadrat ist ein Rechteck, aber nicht jedes Rechteck ist ein Quadrat. Ein Quadrat teilt sich vielmehr die Ei­gen­schaft „Recht­wink­li­ge Seiten“ mit der Ober­klas­se der Rechtecke, weist jedoch die zu­sätz­li­che Ei­gen­schaft „Gleich lange Seiten“ auf.

Anders beim Pro­gram­mie­ren: Hier führt die Annahme, dass ähnliche oder scheinbar iden­ti­sche Klassen sich auf­ein­an­der beziehen oder von­ein­an­der abhängig sind, zu Fehlern, Miss­ver­ständ­nis­sen und unklarem Code. Aus diesem Grund ist beim Pro­gram­mie­ren die Klasse „Rechteck“ kein Quadrat und die Klasse „Quadrat“ kein Rechteck. Beide werden „ent­kop­pelt“ und getrennt im­ple­men­tiert. Ohne in­te­grier­te Ver­bin­dung zwischen den Klassen kann ein Miss­ver­ständ­nis nicht zu klas­sen­über­grei­fen­den Fehlern führen. Das erhöht die Si­cher­heit und Sta­bi­li­tät beim Austausch von Im­ple­men­tie­run­gen in Sub­klas­sen oder Su­per­klas­sen ohne Aus­wir­kun­gen.

ISP: Interface Se­gre­ga­ti­on Principle (Schnitt­stel­len­auf­tei­lungs­prin­zip)

Das ISP definiert sich nach Robert C. Martin in „The Interface Se­gre­ga­ti­on Principle“:

Zitat

„Clients sollten nicht dazu gezwungen werden, von In­ter­faces ab­zu­hän­gen, die sie nicht verwenden.“

Das ISP besagt, dass An­wen­de­rin­nen und Anwender nicht gezwungen sein sollen, Schnitt­stel­len (In­ter­faces) zu verwenden, die sie nicht brauchen. In anderen Worten: Um Clients die Funk­tio­nen von be­stimm­ten Klassen zur Verfügung zu stellen, werden neue, kleinere Schnitt­stel­len auf konkrete An­for­de­run­gen zu­ge­schnit­ten. So lässt sich ver­hin­dern, dass In­ter­faces zu groß werden und starke Ab­hän­gig­kei­ten zwischen Klassen entstehen. Der Vorteil: Software mit ent­kop­pel­ten Klassen und mehreren kleinen, auf konkrete For­de­run­gen zu­ge­schnit­te­nen In­ter­faces lässt sich leichter pflegen.

DIP: De­pen­den­cy Inversion Principle (Ab­hän­gig­keits-Umkehr-Prinzip)

Das fünfte und letzte der SOLID-Prin­ci­ples lautet nach Robert C. Martin in „The De­pen­den­cy Inversion Principle“ wie folgt:

Zitat

„A. Module hoher Ebenen sollten nicht von Modulen niedriger Ebenen abhängen. Beide sollten von Abs­trak­tio­nen abhängen. B. Abs­trak­tio­nen sollten nicht von Details abhängen. Details sollten von Abs­trak­tio­nen abhängen.“

Das DIP sorgt dafür, dass konkrete Funk­tio­nen und Ab­hän­gig­kei­ten in Quellcode-Ebenen auf abs­trak­ten Schnitt­stel­len und nicht auf­ein­an­der aufbauen. Zur Erklärung: Software-Ar­chi­tek­tu­ren lassen sich grob in höhere Be­nut­zer­ebe­nen und nied­ri­ge­re oder tiefere abstrakte Ebenen un­ter­schei­den. Rein logisch lässt sich annehmen, dass die abstrakte Basis das Verhalten der höheren Ebenen bestimmt. Das DIP sieht hierin jedoch eine Feh­ler­an­fäl­lig­keit, da es zu Ab­hän­gig­kei­ten der höheren Ebenen von tieferen Ebenen kommt.

Statt höhere Ebenen an nied­ri­ge­re Ebenen zu koppeln, sollten Klassen in hohen und niedrigen Ebenen von abs­trak­ten, zwi­schen­ge­schal­te­ten Schnitt­stel­len abhängen. Die Schnitt­stel­len rufen Funk­tio­na­li­tä­ten, die in höheren Ebenen benötigt werden, von unteren Ebenen ab und stellen sie bereit. Auf diese Weise lässt sich eine „Bottom-to-Top-Hier­ar­chie“ aus Ab­hän­gig­kei­ten vermeiden, die mit der Zeit zu Fehlern im Code führen kann. Das er­leich­tert die Wie­der­ver­wend­bar­keit von Modulen und er­mög­licht Än­de­run­gen an unteren Klassen ohne Aus­wir­kun­gen auf höhere Ebenen.

Web­hos­ting
Das beste Web­hos­ting zum Spit­zen­preis
  • 3x schneller und 60 % günstiger
  • Maximale Ver­füg­bar­keit mit > 99.99 %
  • Nur bei IONOS: Bis zu 500 GB Spei­cher­platz inklusive

Was passiert bei Nicht­ein­hal­tung der SOLID Prin­ci­ples?

Ein schöner, leicht lesbarer Code, der Pflege so leicht wie möglich macht, sollte das Ziel jeder Software-Ent­wick­lung sein. Geraten Richt­li­ni­en wie die SOLID Prin­ci­ples jedoch in Ver­ges­sen­heit, altert Code durch Schwach­stel­len, Red­un­dan­zen, an­ge­häuf­te Fehler und zu viele Ab­hän­gig­kei­ten sehr schlecht. Im schlimms­ten Fall wird der Code mit zu­neh­men­der Zeit un­brauch­bar. Das stellt vor allem in der agilen Software-Ent­wick­lung ein großes Problem dar, denn hier arbeiten meist viele Be­tei­lig­te an einem komplexen Code.

Zu den Folgen, die un­sau­be­rer Code oder schlechte Code­pfle­ge mit sich bringen, zählen:

  • Code Smell: His­to­risch ge­wach­se­ne Schwach­stel­len aus un­sau­be­rem Code, bekannt als Code Smell oder „müf­feln­der Code“, führen zu Funk­ti­ons­feh­lern und in­kom­pa­ti­blen Pro­gram­men.
  • Code Rot: Kommt es nicht zur Wartung oder Reparatur durch Re­fac­to­ring oder ein kost­spie­li­ges Code Review, kann Code im über­tra­ge­nen Sinne „verfaulen“ und seine Funk­tio­na­li­tät voll­stän­dig einbüßen. Eine andere Be­zeich­nung für un­les­ba­ren, ver­wor­re­nen Code ist Spaghetti-Code.
  • Si­cher­heits­lü­cken: Nicht nur Ausfälle, kom­pli­zier­te Pflege oder In­kom­pa­ti­bi­li­tä­ten sind eine Folge, sondern auch Si­cher­heits­lü­cken, die Schad­soft­ware die Chance auf Exploits sowie Zero-Day-Exploits eröffnen.

Wer hat die SOLID Prin­ci­ples ent­wi­ckelt?

Der Ursprung der SOLID Prin­ci­ples liegt in mehreren Prin­zi­pi­en, die erstmals von Robert C. Martin („Uncle Bob“), einem der In­itia­to­ren der agilen Pro­gram­mie­rung, in seinem Essay „Design Prin­ci­ples and Design Patterns“ im Jahr 2000 ein­ge­führt wurden. Die Gruppe der fünf SOLID Prin­ci­ples wurde von Robert C. Martin, Bertrand Meyer und Barbara Liskov mit­ge­prägt. Das ein­gän­gi­ge Akronym bestehend aus den fünf An­fangs­buch­sta­ben der Prin­zi­pi­en wiederum wurde von Michael Feathers pro­pa­giert, indem er fünf der we­sent­li­chen Prin­zi­pi­en neu ar­ran­gier­te.

Welche ähnlichen Pro­gram­mier­prin­zi­pi­en gibt es?

In der Soft­ware­ent­wick­lung stehen Prin­zi­pi­en für all­ge­mei­ne oder sehr konkrete Leit­li­ni­en und Hand­lungs­emp­feh­lun­gen ähnlich wie die SOLID Prin­ci­ples, die ein Set aus Prin­zi­pi­en für das Paradigma der ob­jekt­ori­en­tier­ten Pro­gram­mie­rung bieten. Weitere Pro­gram­mier­prin­zi­pi­en für Clean Code sind etwa:

  • DRY-Prinzip (Don’t repeat yourself) für Funk­tio­nen mit einer einzigen, ein­deu­ti­gen Dar­stel­lung
  • KISS-Prinzip (Keep it simple, stupid) für einen möglichst einfach kon­stru­ier­ten Code
Zum Hauptmenü