Liever geen Inversion of Control

 
22 oktober 2007

Okay! Ik ben tegen de Spring manier van ontwikkelen! Ik heb een hekel aan het zogenaamde ‘inversion of control‘(IoC)! Het is niet de manier hoe wij onze software zouden moeten ontwikkelen. Om dit op een conferentie of gesprek met medeontwikkelaars te melden leidt meestal tot een verbaasde stilte. Vervolgens proberen verschillende mensen mij uit te leggen waarom Spring en IoC zo geweldig en nuttig zijn. En ik kan het niet anders brengen: Ze hebben ongelijk!

Software ontwikkelen is omgaan met complexiteit. Alles wat we doen heeft een bepaald effect op de complexiteit van de applicatie die we ontwikkelen. Veel acties zijn gericht op het omgaan met deze complexiteit of het reduceren van de schijnbare complexiteit. De geschiedenis van programeertalen laat een doorlopende zoektoch zien naar mogelijkheden om complexiteit te verbergen achter verschillende vormen van abstractie. Van procedures tot object orientatie tot component-based developement tot moderne vormen als service oriented architecture. Al deze technieken bieden nieuwe encapsulatielagen die hopelijk de lelijke details van de onderliggende lagen verbergen. Maar met elke nieuwe laag is ook de complexiteit van de applicaties mee gestegen zodat we steeds weer dezelde problemen tegenkomen.

How past IoC nu in dit plaatje? Stel we hebben een software applicatie. De kern van de applicatie is redelijk schoon en ons project is goed onderhoudbaar en beheerbaar.

core.jpg

Het plaatje hierboven schetst onze applicatie. De oppervlakte van de core geeft de complexiteit van de applicatie weer. Op zichzelf geeft het plaatje eigenlijk niet zoveel weer. Er is een bepaalde hoeveelheid complexiteit, maar zonder een referentie betekent dit niets. Nu komen er nieuwe eisen voor ons project. De kern van onze applicatie groeit. Een aantal componenten wordt toegevoegd aan de kern. Misschien willen we email versturen vanuit de applicatie of moet er een raportage gemaakt worden. Moderne ontwerpfilosofien geven aan dat we dit soort onderdelen moeten ontwerpen met een contract en interface zodat de kern de componenten op een schone en vervangbare manier kan aanroepen.

core-comp.jpg

Met de nieuwe componenten toegevoegd, ziet onze applicatie er nu uit zoals in het bovenstaande plaatje geschets. Elk component dat we hebben toegevoegd heeft de complexiteit van de kern verhoogd. Het gearceerde gedeelte geeft de verhoogde complexiteit weer. Deze complexiteit zit niet noodzakelijk in de componenten zelf maar in de code die we nodig hebben om met elk component te integreren. Bij elke actie die ook een email als resultaat moet hebben komt een klein stukje code dat het email-component aanstuurt. Op zichzelf voegt dit natuurlijk niet heel veel complexiteit toe, maar elke component maakt het allemaal net iets complexer. Dit wil zeggen dat we niet oneindig veel componenten kunnen blijven toevoegen. Op een bepaald moment is het maken van de verandering zo duur dat het niet meer de moeite waard is om een nieuw component toe te voegen.

Nu dit verhaal met IoC. IoC belooft ons dat we de componenten niet meer zelf hoeven te beheren. Dit zou componenten eenvoudig vervangbaar en testbaar maken. In essentie worden de contracten en interfaces van het vorige voorbeeld vervangen door de container beheerde stubs, waarbij de echte componenten tijdens runtime de stubs vervangen. Dit wil zeggen dat de implementatie van de componenten geen onderdeel meer uitmaken van de kern van onze applicatie. In het plaatje hieronder heb ik dit proberen te schetsen.

core-comp-ioc.jpg

Het is op zich een goed idee. Door gebruik te maken van IoC voor de componenten hebben we een bepaalde graad van ontkoppeling bereikt. Het is nu eenvoudiger om het component te vervangen. De complexiteit van de applicatiekern is echter niet signifikant kleiner. Nog steeds verhoogt elk component de complexiteit van onze kern. In het plaatje hierboven brobeer ik dit weer te geven. Het gearceerde gedeelte is nauwelijks kleiner dan in het vorige plaatje. Dit is mijn belangrijkste bezwaar met IoC. Het lost het verkeerde probleem op. In plaats van het verlagen van de complexiteit maakt het het mogelijk om een bestaand component te vervangen door een ander component met dezelfde specifieke rol. Een email-component kan vervangen worden door een andere email-componenten (of een dummy), maar een nieuw component toevoegen verhoogd nog steeds de complexiteit van de kern.

Wat is dan een betere manier om de componenten te koppelen aan de applicatiekern? Hoe kunnen we een schaalbaarheid bereiken zodat het toevoegen van een nieuw component de complexiteit van de kern van de applicatie niet verhoogd. Het antwoord ligt in de richting van de koppeling. In de voorbeelden hierboven loopt de koppeling van de kern naar de componenten. Vanuit de kern werden de verschillende componenten aangeroepen. Dit geeft een relatie waar een enkeling alle andere aanroept. Een bottleneck situatie. Als we de richting van de koppeling omdraaien krijgen we een veel beter hanteerbare situatie. Dan roept steeds een enkel compoent een enkele applicatiekern aan. De kern heeft nu geen kennis van de componenten en dus geen koppeling met de componenten. De complexiteit van de kern is nu onafhankelijk van de hoeveelheid componenten die het systeem kent. De kern van de applicatie is dus veel beheersbaarder.

De kern is echter wel de natuurlijke aanroeper van de componenten. Er moet een email verstuurd worden nadat er iets in de kern gebeurt is. Het is heel logisch om bij het uitvoeren van de actie vervolgens het component aan te spreken. De oplossing wordt eigenlijk in de probleemomschrijving al gegeven: ‘Er moet een email verstuurd worden nadat er iets in de kern gebeurt‘. Email versturen volgt op een gebeurtenis, een event. De kern-applicatie genereert events op basis van de acties die in de kern plaats vinden. Componenten kunnen reageren op deze events. De kern genereert echter altijd de zelfde events. Welke of hoeveel componenten er naar deze event luisteren is voor de kern niet belangrijk. Het plaatje hier onder probeert dit te illustreren..

core-comp-event.jpg

Zoals te zien in het plaatje verhoogt het toevoegen van nieuwe componenten de complexiteit van de kern van de applicatie nu niet. De kern heeft geen kennis van de componenten, dus behalve toevoegen kunnen we ook zonder veel impact componenten weghalen of vervangen. Dit was nou net het grote voordeel van IoC. Door een applicatie dus op deze manier op te zetten bereiken we de voordelen van IoC zonder dat de componenten complexiteit aan de kern-applicatie toevoegen. Waarom moeten we ons dan bezig houden met IoC als er een alternatief is dat de belangrijkste voordelen van IoC heeft, maar daarnaast beter omgaat met complexiteit?

Als je hier nieuw bent, wil je je misschien inschrijven voor onze RSS feed.
Bedankt voor je bezoek!

Gerelateerde bijdragen


Werken met Ralf Wolter?
Kijk dan bij onze mogelijkheden voor starters en/of ervaren IT'ers.


Categorieën: Development

Tags: , , , ,


Reacties (7)

  • Erik de Vries schreef:

    Hi Ralf, goed stuk.
    Ben het helemaal met je stelling en oplossingsrichting eens!

    Geplaatst op 13 december 2007 om 8:51 Permalink

  • Jasper Floor schreef:

    Ik heb eigenlijk nooit IoC begrepen totdat ik dit stuk las. Nu snap ik ook waarom ik het niet snapte. Ik nam namelijk aan dat het handig was en dat het aan mij lag dat ik dat niet zag. Ik moet natuurlijk begrijpen dat mijn inzicht onfeilbaar ;)

    Geplaatst op 25 maart 2008 om 14:02 Permalink

  • Erwin Vervaet schreef:

    Het valt me op dat je eerst aangeeft hoe IoC niet werkt om vervolgens een vorm van IoC naar voor de schuiven als alternatief (een Observer pattern):

    “Als we de richting van de koppeling omdraaien krijgen we een veel beter hanteerbare situatie.”

    Ik denk dat je IoC en DI (Dependency Injection) niet mag verwarren.

    Geplaatst op 08 april 2008 om 19:41 Permalink

  • Ralf Wolter schreef:

    Het observer pattern keert de koppeling om. Dat zou je als inversion of control kunnen zien. Het is echter niet de inversion of control die de IoC frameworks naar voren schuiven.

    In het algemeen beschouw ik dependency injection als een pattern los van de context en IoC als een methode die component koppeling middels DI. Letterlijk betekend IoC natuurlijk iets anders, en daar valt de manier die ik hier beschrijf ook onder.

    In dat geval is het observer pattern meer inversion of control dan dependency injection, dat immer alleen de tot stand koming van de koppeling voor zijn rekening neemt.

    Geplaatst op 08 april 2008 om 20:59 Permalink

  • Jochen Zeischka schreef:

    Hey Ralf,

    ik moet zeggen dat ik het niet eens ben met je stelling dat in de laatste situatie (events) de kern niet complexer wordt ondanks het toevoegen van componenten.

    Je zult namelijk bij elk event data moeten meegeven aan de component die het event afhandelt. Die data zullen aan een bepaald contract moeten voldoen. En dus verhoogt de complexiteit opnieuw lineair met het aantal componenten dat aangeroepen wordt of events afhandelt.

    Geplaatst op 07 mei 2009 om 10:17 Permalink

  • Hoi Jochen,

    Volgens mij draai je nu de contractverantwoordelijkheid om. Het idee dat Ralf stelt is dat de kern juist constant blijft en eventuele extra subscribers het zullen moeten doen met de door de kern gestelde contracten. Deze contracten zijn ook specifiek voor de in deze kern geautomatiseerde processen en zouden als zodanig geen uitbreidingen behoeven als er alleen een component wordt aangesloten.

    Een andere situatie treedt op als de kern meer functionaliteiten gaat aanbieden, dan zal er wel uitbreiding plaats moeten vinden (maar nooit verandering van bestaande contracten).

    Geplaatst op 10 mei 2009 om 8:53 Permalink

  • Wouter schreef:

    Het zijn allemaal addins:
    http://msdn.microsoft.com/en-us/magazine/cc163476.aspx

    Geplaatst op 21 oktober 2010 om 19:59 Permalink

Trackback & Pingback (1)

  1. Van While True » Blog Archive » Alternative to IoC / DI op 29 juni 2008 at 22:47

    [...] is the dependency of additional frameworks from ‘pure’ business logic components. Other people agree that there are some downsides to [...]

Plaats een reactie

Jouw emailadres wordt nooit gepubliceerd of gedeeld. Benodigde velden zijn met * gemarkeerd.