De SOLID-principes bestaan uit vijf richt­lij­nen voor schone, on­der­houd­ba­re en flexibele code in ob­ject­ge­o­ri­ën­teerd pro­gram­me­ren. Door deze principes toe te passen en na te leven, ontstaat er een be­grij­pe­lijk soft­wa­re­ont­werp dat ook na lange ont­wik­ke­lings­pe­ri­o­des nog steeds goed func­ti­o­neert. Met deze principes kan niet alleen betere code worden ge­schre­ven, maar kan ook bestaande code ge­mak­ke­lij­ker worden on­der­hou­den.

Wat zijn de SOLID-principes en wie heeft ze ont­wik­keld?

Goede broncode begint met regels, pro­gram­meer­pa­ra­dig­ma’s en een geschikte pro­gram­meer­stijl voor ef­fi­ci­ën­te en schone code. Dit is precies wat de vijf SOLID-principes, bedacht door Robert C. Martin, Bertrand Meyer en Barbara Liskov, ga­ran­de­ren. Door deze principes te volgen bij ob­ject­ge­o­ri­ën­teerd pro­gram­me­ren (OOP) met talen als Python of Java, schrijf je niet alleen betere code, maar zorg je ook voor ef­fi­ci­ën­ter co­de­on­der­houd, duurzaam en flexibel soft­wa­re­ont­werp en meer vei­lig­heid op de lange termijn.

De naam SOLID staat voor de solide pro­gram­meer­ba­sis die iedereen die wil leren pro­gram­me­ren zou moeten hebben. Het acroniem zelf is bedacht door Michael Feathers, die de eerste letters van elk van de vijf principes heeft gebruikt om het te creëren:

  • En­kel­vou­dig ver­ant­woor­de­lijk­heids­prin­ci­pe: Een klasse mag slechts één reden hebben om te ver­an­de­ren.
  • Open-gesloten principe: software-en­ti­tei­ten (klassen, modules, functies, enz.) moeten openstaan voor uit­brei­ding, maar gesloten zijn voor wij­zi­gin­gen.
  • Liskov-sub­sti­tu­tie­prin­ci­pe: Sub­klas­sen moeten alle methoden en ei­gen­schap­pen van de su­per­klas­se kunnen overnemen en im­ple­men­te­ren.
  • Interface-se­gre­ga­tie­prin­ci­pe: In­ter­fa­ces mogen niet meer methoden bevatten dan nodig is voor het im­ple­men­te­ren van klassen.
  • Principe van af­han­ke­lijk­heids­om­ke­ring: Klassen mogen niet af­han­ke­lijk zijn van andere klassen, maar van in­ter­fa­ces of abstracte klassen.

Welke voordelen bieden de SOLID-principes?

Waar geen regels zijn, ontstaat chaos, en dit wordt vooral merkbaar bij het pro­gram­me­ren. Zelfs kleine fouten, on­nauw­keu­rig­he­den en hiaten kunnen goede broncode op de lange termijn volledig on­bruik­baar maken als ze ‘on­be­han­deld’ blijven. Soms zijn complexe klassen die de im­ple­men­ta­tie be­moei­lij­ken of sub­klas­sen die in­di­vi­du­e­le ei­gen­schap­pen van hun su­per­klas­sen missen, al voldoende. De SOLID-principes zorgen ervoor dat er zo min mogelijk code hoeft te worden ge­re­pa­reerd met re­fac­to­ring.

SOLID-principes maken code:

  • Duidelijk, over­zich­te­lijk en aan­trek­ke­lijk: software en codes zijn ge­mak­ke­lij­ker te begrijpen, ef­fec­tie­ver en zien er gewoonweg beter uit.
  • Eenvoudig te on­der­hou­den: dankzij de een­vou­di­ge en dui­de­lij­ke structuur is het voor meerdere me­de­wer­kers een­vou­di­ger om zowel nieuwe code als leg­a­cy­co­de te on­der­hou­den en te beheren.
  • Aan­pas­baar, uit­breid­baar, her­bruik­baar: door ver­be­ter­de lees­baar­heid, ver­min­der­de com­plexi­teit en ver­ant­woor­de­lijk­he­den, en ver­min­der­de af­han­ke­lijk­heid van klassen, kan code beter worden bewerkt, aangepast en uit­ge­breid via in­ter­fa­ces, en flexibel worden her­ge­bruikt.
  • Minder fout­ge­voe­lig: schone code met een een­vou­di­ge structuur betekent dat wij­zi­gin­gen in een deel van de code niet per ongeluk andere delen of functies be­ïn­vloe­den.
  • Veiliger en be­trouw­baar­der: Door kwets­baar­he­den, in­com­pa­ti­bi­li­tei­ten en fouten te ver­min­de­ren of te eli­mi­ne­ren, worden de func­ti­o­na­li­teit en be­trouw­baar­heid van een systeem verbeterd, wat op zijn beurt de vei­lig­heid ten goede komt.

Wat betekenen de SOLID-principes precies?

De SOLID-principes behoren tot de gouden regels voor goed pro­gram­me­ren en zouden bekend moeten zijn bij iedereen die met ob­ject­ge­o­ri­ën­teerd pro­gram­me­ren werkt. Hieronder leggen we elk principe in detail uit.

SRP: Principe van enkele ver­ant­woor­de­lijk­heid

Robert C. Martin heeft de oor­spron­ke­lij­ke definitie voor dit principe opgesteld in ‘Agile Software De­vel­op­ment: Prin­ci­ples, Patterns and Practices’, waarin hij schrijft:

Citaat

“Elke soft­wa­re­mo­du­le moet één en slechts één reden hebben om te ver­an­de­ren”.

Het Single Res­pon­si­bi­li­ty Principle (SRP) stelt dat elke klasse in ob­ject­ge­o­ri­ën­teerd pro­gram­me­ren (OOP) slechts één ver­ant­woor­de­lijk­heid mag hebben. Dit houdt in dat er slechts één reden mag zijn om een klasse te wijzigen. In te­gen­stel­ling tot wat vaak wordt gedacht, betekent dit niet dat een klasse of module slechts één taak mag hebben. Het betekent veeleer dat deze alleen ver­ant­woor­de­lijk mag zijn voor spe­ci­fie­ke taken die idealiter niet over­lap­pen met andere gebieden.

Een over­lap­ping van ver­ant­woor­de­lijk­he­den, zoals het aanbieden van functies voor ver­schil­len­de be­drijfs­seg­men­ten, kan van invloed zijn op de func­ti­o­na­li­teit van de klasse wanneer er wij­zi­gin­gen worden aan­ge­bracht in één segment. Het hebben van meerdere ver­ant­woor­de­lijk­he­den en talrijke af­han­ke­lijk­he­den kan ertoe leiden dat een enkele wijziging op één gebied co­de­fou­ten ver­oor­zaakt of dat er aan­vul­len­de wij­zi­gin­gen nodig zijn.

Het Single Res­pon­si­bi­li­ty Principle (SRP) is bedoeld om sa­men­han­gen­de modules te creëren met spe­ci­fie­ke, duidelijk om­schre­ven functies of objecten. Dankzij de dui­de­lij­ke, ge­struc­tu­reer­de opzet met minimale af­han­ke­lijk­he­den en on­af­han­ke­lij­ke im­ple­men­ta­ties kunnen wij­zi­gin­gen en aan­pas­sin­gen ef­fi­ci­ën­ter, sneller en soepeler worden door­ge­voerd.

Opmerking

Klassen, ook wel ob­ject­ty­pen genoemd, zijn de centrale elementen in ob­ject­ge­o­ri­ën­teerd pro­gram­me­ren (OOP). Ze kunnen worden gezien als blauw­druk­ken voor objecten, waarin hun kenmerken worden be­schre­ven, zodat het mogelijk is om objecten en concepten uit de echte wereld na te bootsen in software. Klassen, ook wel modules genoemd, worden vaak ver­ge­le­ken met be­stands­ty­pen.

OCP: Open Closed Principle (Open-gesloten principe)

Volgens Robert C. Martin en Bertrand Meyer in ‘Object Oriented Software Con­struc­ti­on’ luidt het OCP als volgt:

Citaat

“Software-en­ti­tei­ten (klassen, modules, functies, enz.) moeten openstaan voor uit­brei­ding, maar gesloten zijn voor wij­zi­gin­gen”.

Het OCP zorgt ervoor dat u de kern van de software niet hoeft te her­schrij­ven om wij­zi­gin­gen door te voeren. Als er in­grij­pen­de co­de­wij­zi­gin­gen nodig zijn, bestaat het risico op subtiele fouten en code smells. Een goed ge­struc­tu­reer­de code moet in­ter­fa­ces bieden die kunnen worden gebruikt om deze uit te breiden met extra functies. Het sleu­tel­woord hier is klasse-over­er­ving.

Nieuwe functies en uit­brei­din­gen met dui­de­lij­ke nieuwe functies en methoden die moeten worden ge­ïm­ple­men­teerd, kunnen eenvoudig aan een su­per­klas­se worden toe­ge­voegd via een interface in de vorm van sub­klas­sen. Op deze manier hoeft u niet te knoeien met de ge­schre­ven, stabiele code. Het ver­een­vou­digt het onderhoud en de in­stand­hou­ding van software en verbetert aan­zien­lijk de ef­fi­ci­ën­tie van het her­ge­bruik van stabiele code-elementen via in­ter­fa­ces.

LSP: Liskovs sub­sti­tu­tie­prin­ci­pe

Volgens Barbara H. Liskov en Jeannette M. Wing in ‘Be­ha­vi­o­ral Subtyping Using In­va­ri­ants and Con­s­traints’ stelt de LSP dat:

Citaat

“Laat q(x) een ei­gen­schap zijn die be­wijs­baar is voor objecten x van type T. Dan moet q(y) be­wijs­baar zijn voor objecten y van type S, waarbij S een subtype is van T”.

Het klinkt misschien cryptisch, maar het is eigenlijk heel eenvoudig te begrijpen: ge­kop­pel­de of uit­ge­brei­de sub­klas­sen moeten func­ti­o­ne­ren zoals hun su­per­klas­sen of ba­sis­klas­sen. Dit betekent dat elke subklasse de ei­gen­schap­pen van zijn res­pec­tie­ve su­per­klas­se moet behouden door middel van over­er­ving en dat deze ei­gen­schap­pen niet mogen worden gewijzigd in de subklasse. Ze moeten in principe ver­vang­baar zijn, vandaar het sub­sti­tu­tie­prin­ci­pe. Su­per­klas­sen daar­en­te­gen mogen worden gewijzigd.

Laten we ter ver­dui­de­lij­king eens kijken naar het klassieke voorbeeld van Robert C. Martin over recht­hoe­ken en vier­kan­ten. In de meet­kun­de­les leren we het volgende principe: elk vierkant is een rechthoek, maar niet elke rechthoek is een vierkant. Een vierkant heeft niet alleen rechte hoeken zoals recht­hoe­ken, maar alle zijden zijn ook even lang.

Bij het pro­gram­me­ren leidt het aannemen dat ver­ge­lijk­ba­re of schijn­baar identieke klassen aan elkaar ge­re­la­teerd of van elkaar af­han­ke­lijk zijn tot fouten, mis­ver­stan­den en on­dui­de­lij­ke code. Om deze reden is in pro­gram­me­ren de klasse ‘Rechthoek’ geen vierkant en is de klasse ‘Vierkant’ geen rechthoek. Beide zijn ont­kop­peld en worden af­zon­der­lijk ge­ïm­ple­men­teerd. Zonder een ge­ïn­te­greer­de ver­bin­ding tussen de klassen kunnen mis­ver­stan­den niet leiden tot fouten tussen klassen. Dit verhoogt de vei­lig­heid en sta­bi­li­teit bij het om­wis­se­len van im­ple­men­ta­ties in sub­klas­sen of su­per­klas­sen, zonder re­per­cus­sies.

ISP: Interface Se­gre­ga­ti­on Principle (principe van in­ter­fa­cese­gre­ga­tie)

Volgens Robert C. Martin in ‘The Interface Se­gre­ga­ti­on Principle’ wordt ISP als volgt ge­de­fi­ni­eerd:

Citaat

“Klanten mogen niet worden gedwongen om af­han­ke­lijk te zijn van in­ter­fa­ces die ze niet gebruiken”.

De ISP stelt dat ge­brui­kers geen in­ter­fa­ces moeten gebruiken die ze niet nodig hebben. Met andere woorden: om klanten de functies van bepaalde klassen te kunnen bieden, worden nieuwe, kleinere in­ter­fa­ces op maat gemaakt voor spe­ci­fie­ke vereisten. Dit voorkomt dat in­ter­fa­ces te groot worden en zorgt ervoor dat er geen sterke af­han­ke­lijk­he­den tussen klassen ontstaan. Het voordeel is dat software met ont­kop­pel­de klassen en ver­schil­len­de kleine in­ter­fa­ces die op maat zijn gemaakt voor spe­ci­fie­ke vereisten, ge­mak­ke­lij­ker te on­der­hou­den is.

DIP: Principe van af­han­ke­lijk­heids­om­ke­ring

Volgens Robert C. Martin in ‘The De­pen­d­en­cy Inversion Principle’ luidt het vijfde en laatste SOLID-principe als volgt:

Citaat

“A. Modules op hoog niveau mogen niet af­han­ke­lijk zijn van modules op laag niveau. Beide moeten af­han­ke­lijk zijn van ab­strac­ties. B. Ab­strac­ties mogen niet af­han­ke­lijk zijn van details”.

Het DIP zorgt ervoor dat spe­ci­fie­ke func­ti­o­na­li­tei­ten en af­han­ke­lijk­he­den binnen bron­co­de­laag­jes op abstracte in­ter­fa­ces ver­trou­wen, en niet direct op elkaar. Soft­w­are­ar­chi­tec­tu­ren zijn doorgaans ge­or­ga­ni­seerd in hogere ge­brui­kers­ni­veaus en lagere, meer abstracte niveaus. Lo­gi­scher­wijs zou je kunnen denken dat de abstracte basis het gedrag van de bovenste lagen be­ïn­vloedt. Het DIP sig­na­leert hier echter een po­ten­ti­eel probleem, omdat het af­han­ke­lijk­he­den creëert voor de hogere niveaus op de lagere niveaus, wat tot problemen kan leiden.

In plaats van hogere niveaus aan lagere niveaus te koppelen, moeten klassen in hoge en lage niveaus af­han­ke­lijk zijn van abstracte, tus­sen­lig­gen­de in­ter­fa­ces. De in­ter­fa­ces halen func­ti­o­na­li­tei­ten die op hogere niveaus nodig zijn uit lagere niveaus en maken deze be­schik­baar. Op deze manier kan een bottom-up hi­ë­rar­chie van af­han­ke­lijk­he­den worden vermeden, wat na verloop van tijd tot fouten in de code kan leiden. Dit ver­ge­mak­ke­lijkt de her­bruik­baar­heid van modules en maakt wij­zi­gin­gen in lagere klassen mogelijk zonder dat dit gevolgen heeft voor hogere niveaus.

Wat gebeurt er als de SOLID-principes niet worden nageleefd?

Het creëren van schone, leesbare code die het onderhoud ver­een­vou­digt, moet een primaire doel­stel­ling zijn bij soft­wa­re­ont­wik­ke­ling. Als ont­wik­ke­laars es­sen­ti­ë­le richt­lij­nen zoals de SOLID-principes over het hoofd zien, kan de code ernstig ver­slech­te­ren als gevolg van kwets­baar­he­den, re­dun­dan­tie, op­ge­hoop­te fouten en bui­ten­spo­ri­ge af­han­ke­lijk­he­den. In extreme gevallen kan de code na verloop van tijd on­bruik­baar worden. Dit is een be­lang­rijk probleem bij agile soft­wa­re­ont­wik­ke­ling, waar vaak veel mensen aan complexe co­de­rings­ta­ken werken.

De gevolgen van onzuivere code of slecht co­de­on­der­houd zijn onder meer:

  • Code smell: Wanneer code niet volgens de vereiste normen is ge­schre­ven, kan dit leiden tot code smell of ‘smelly code’, wat func­ti­o­ne­le fouten en in­com­pa­ti­be­le programma’s tot gevolg kan hebben.
  • Code rot: Als code niet wordt on­der­hou­den of ge­re­pa­reerd door middel van re­fac­to­ring of een kostbare co­de­re­view, kan code fi­guur­lijk ‘rotten’ en zijn func­ti­o­na­li­teit volledig verliezen. Een andere term voor on­lees­ba­re, in­ge­wik­kel­de code is spa­ghet­ti­co­de.
  • Be­vei­li­gings­ri­si­co’s: De problemen die zich voordoen, zijn niet beperkt tot storingen, complex onderhoud en com­pa­ti­bi­li­teits­pro­ble­men. Er zijn ook be­vei­li­gings­lek­ken die malware de mo­ge­lijk­heid bieden om de code te mis­brui­ken, waaronder zero-day exploits.

Wie heeft de SOLID-principes ont­wik­keld?

De oorsprong van de SOLID-principes ligt in ver­schil­len­de principes die voor het eerst werden ge­ïn­tro­du­ceerd door Robert C. Martin (‘Uncle Bob’), een van de ini­ti­a­tief­ne­mers van agile pro­gram­me­ren, in het jaar 2000 in zijn essay getiteld ‘Design Prin­ci­ples and Design Patterns’. De SOLID-principes zijn bedacht door Robert C. Martin, Bertrand Meyer en Barbara Liskov. De pakkende afkorting werd populair gemaakt door Michael Feathers, die de be­gin­let­ters van de vijf es­sen­ti­ë­le principes her­schik­te tot een ge­mak­ke­lijk te onthouden volgorde.

Welke ver­ge­lijk­ba­re pro­gram­meer­prin­ci­pes zijn er?

In soft­wa­re­ont­wik­ke­ling zijn principes algemene of zeer spe­ci­fie­ke richt­lij­nen en aan­be­ve­lin­gen voor actie. Naast de SOLID-principes, die zijn ont­wik­keld voor ob­ject­ge­o­ri­ën­teerd pro­gram­me­ren, zijn er nog andere pro­gram­meer­prin­ci­pes voor schone code, waaronder:

  • DRY-principe (Don’t repeat yourself) voor functies met een enkele, unieke re­pre­sen­ta­tie
  • KISS-principe (Keep it simple, stupid) voor code die zo eenvoudig mogelijk is opgebouwd
Ga naar hoofdmenu