In dit derde deel worden de principes die in de voorgaande delen zijn behandeld uitgewerkt in een simpele voorbeeldimplementatie.
Deel 1 behandelt de basisprincipes. Deel 2 gaat over de business domein component.
Doelstelling
Teneinde de beweringen in de voorgaande artikelen te ondersteunen met voorbeelden uit de praktijk, wil ik in dit artikel een eenvoudige implementatie uitwerken. Deze implementatie heeft tot doel de lezer een helder beeld te geven van wat de uitwerking van de ideeën in de praktijk behelst, en de pragmatiek van het architectuurmodel te bewijzen. Hier is geen sprake van rocket-science, alleen uitvoerbaar door genieën of bovengemiddeld begaafde ontwikkelaars! Dat zou onder andere één van de vooronderstellingen al onderuit halen, namelijk resultaten op korte termijn.
Een waarschuwing is wel op zijn plaats: om didactische redenen is het voorbeeld eenvoudig gehouden. Nadeel daarvan is echter dat juist de belangrijkste argumenten om deze architectuur business-centred te houden komen uit overwegingen van reductie van complexiteit die juist in een simpel voorbeeld niet aan de orde zijn[2]. Ik wil de lezer dan ook gaarne uitnodigen om de voorbeelden op te schalen in de fantasie. Pas bij een complexere situatie zal de kracht van het model opgang doen. Ook de overwegingen van kostenbesparingen zullen in dit voorbeeld niet expliciet bewezen kunnen worden, dit zal zelfs in een pilot project niet een-twee-drie duidelijk kunnen worden.
Basiscomponenten
Laten we beginnen met een scenario dat zo simpel mogelijk is – misschien bedrieglijk simpel omdat het gekenmerkt wordt door iets dat in de praktijk nooit voorkomt: slechts twee classes.
In de beschrijving van dit domein model wordt bijvoorbeeld het doen van mailings mogelijk gemaakt (denk erom: het gaat om business functionaliteit!). Het model is tot stand gekomen door in interactie met de gebruiker of opdrachtgever use cases vast te leggen die aan die persoon duidelijk maken wat er tot zijn beschikking komt, en daarnaast het domein te modelleren dat de business logica bevat.
Laten we dit model implementeren in een business component dat komt te draaien op een applicatieserver. Zoals gezegd wil ik in dit voorbeeld gebruik maken van een Smalltalk implementatie voor het domein component, ondermeer om een belangrijk doel van dit component min of meer af te dwingen: onafhankelijkheid van technische aspecten.
De volgende drie componenten komen aan de orde in dit scenario:
- Domein component (instanties van de bovenstaande classes)
- Adapter component
- Database (eventueel een legacy database)
In de figuur is te zien dat de drie hoofdcomponenten gemodelleerd zijn als UML packages, met bidirectionele relaties gestereotyped als:
- send – objecten in packages sturen boodschappen naar objecten in de andere package
- event – objecten in package sturen geen boodschappen naar objecten in de andere package, maar genereren events die niet (of nauwelijks) een koppeling met de objecten die de events afhandelen behelzen
Deze wijze van koppeling van componenten is bedoeld om de koppeling tussen de componenten losser te maken (in feite unidirectioneel) waardoor bijvoorbeeld aan de eis dat het domein component volledig onafhankelijk is van de database component beantwoord kan worden.
Een belangrijke vraag die nu beantwoord dient te worden is: op welke wijze worden vanuit het domein component events gegenereerd die door andere componenten afgevangen worden, en wat is het resultaat van dat afvangen van die events?
De event afhandeling gebeurt door gebruik te maken van een Adapter Framework.
Adapter Framework
De koppeling van de domein objecten met de buitenwereld vindt plaats door middel van een uiterst simpel maar tevens extreem flexibel mechanisme, middels adapters.
Alle objecten die met behulp van events met de buitenwereld dienen te praten hebben dezelfde eigenschap: ze zijn een subclass van een class die de volgende functionaliteit bevat:
Model::addDependent: [3]voegt een ontvanger van events toe
::removeDependent: verwijdert een ontvanger van events
::changed:with: stuurt een update event naar alle geregistreerde observers
De class Model is een standaard Smalltalk class, aanwezig in de standaard Smalltalk class library in de namespace[4] Smalltalk.UI. Ontwikkelaars van domein classes hoeven op geen enkele wijze meer weet te hebben van observers (= ontvangers van events). Het enige dat gebeurd wanneer objecten iets doen waarin mogelijkerwijs een ander geïnteresseerd zou kunnen zijn is: changed:with: naar zichzelf sturen. Deze code verwacht dus twee argumenten, het eerste object gewoonlijk een String die iets beschrijft over de aard van de event, het tweede een optioneel Object dat extra informatie kan geven over de aard van de verandering.
Zoals in bovenstaande illustratie te zien is zorgt het framework vervolgens voor de afhandeling van events, door naar alle geregistreerde observers de boodschap update te sturen. Belangrijk detail waar ik nog op terug kom is dat de observers in dit geval vrijwel altijd adapters zullen zijn.
Doordat dit mechanisme steunt op standaard (c.q. framework) functionaliteit, valt te verwachten dat in dat gedeelte dat het meest technologie-onafhankelijk dient te zijn, namelijk de business component, de koppeling met de buitenwereld het meest eenvoudig is. In Java en andere programmeertalen is dit component vrijwel identiek te bouwen. Enkele observaties in verband met Java:
- Er dient rekening gehouden te worden met het feit dat dit component een hoge graad van concurrency (c.q. multithreading) zal gaan bevatten. Daar ga ik hier niet nader op in maar dit zal bepaalde eisen stellen aan de applicatieserver waarin het component gedeployed gaat worden. Een Java implementatie kan dan bijvoorbeeld (voor dit component!) niet in een EJB worden gebouwd omdat binnen een dergelijke bean concurrency niet toegestaan is.[5]
- De methode update zal uiteindelijk (meestal via één of meer adapters aan de rand van het framework) naar de buitenwereld gaan in de vorm van een event. Dit kan een CORBA event zijn, en synchroon of asynchroon afgehandeld worden, en eventueel gerouteerd worden via een message broker. Ook daar wil ik hier niet op ingaan.
- Dat het updaten van observers (of dependents zoals ze in Smalltalk genoemd worden) op deze wijze gladjes zal verlopen is hopelijk duidelijk, maar de kritische lezer zal aan kunnen voeren dat dit alleen kan wanneer objecten zich al hebben geregistreerd als dependents. Wanneer, hoe en door wie is dit gebeurd? Dat zijn belangrijke vragen waarop ik momenteel een beperkt antwoord wil geven door te zeggen dat juist dit complexe aankoppelen en afkoppelen van objecten binnen het framework zèlf afgehandeld zal worden. Nadat het framework een zekere mate van stabilisatie heeft doorgemaakt zal dit proces niet meer zichtbaar zijn voor ontwikkelaars – en dus ook geen tijd meer tijd vragen in het ontwikkelproces.
Aspect adapters
De adapter die hierboven besproken is, wordt ook wel een aspect adapter genoemd. Wat wordt hieronder verstaan?
Deze objecten functioneren als een soort universele lijm waardoor willekeurige componenten aan elkaar gekoppeld worden. Door de adapter te configureren op het moment dat deze gemaakt wordt met de benodigde methodes (in dit geval de get en set methodes), gebeurt het volgende:
- Iemand vraagt aan de adapter om zijn waarde met de boodschap getValue.
- De adapter vraagt aan zijn getMethod om zichzelf uit te voeren (deze is op zijn beurt geconfigureerd met de ontvanger van de boodschap, welke boodschap, en welke argumenten – het is als het ware het-sturen-van-een-boodschap tot object gemaakt)
- De adapter stuurt het antwoord door naar de zender van de getValue boodschap
Dit configureren van extreem generieke adapters die willekeurig welke boodschap sturen wanneer ze getValue of setValue gevraagd wordt is een voorbeeld van wat reflectie genoemd wordt. Talen die substantiële ondersteuning hebben voor reflectie komen het meest in aanmerking om de domein component mee te implementeren. Talen als Smalltalk en objectgeoriënteerde Lisp dialecten zijn hierin het meest volwassen. Java iets minder, maar talen als C++ of VisualBasic zijn hiervoor eigenlijk niet goed geschikt.
Het gevolg van het gebruik van dit soort adapters is vrij ingrijpend. Alle clients namelijk van deze adapter classes hoeven zich niet meer druk te maken over de interface van de objecten waarvan ze de services nodig hebben: zij maken eenvoudig gebruik van de value interface. Hierdoor worden deze objecten eenvoudiger, en dat is een belangrijk winstpunt bij de bouw van complexe systemen.
Terug naar het scenario van de verhuizing. De persoon die de boodschap heeft gekregen waarin hem gevraagd wordt te verhuizen zal de update boodschap sturen naar de adapter die zich heeft geregistreerd als een dependent. We hebben gezien hoe dit soort adapters reageert op value boodschappen – hoe nu bij update boodschappen?
In sterk vereenvoudigde vorm gebeurt het volgende: deze generieke adapter stuurt de update boodschap eenvoudig door naar objecten die zich bij hem hebben geregistreerd als dependent. Eén van die objecten is een database connector die weet heeft van een relationele database, tabellen in die database, en de gedefinieerde kolommen. Deze configuratie van adapters vormen samen een component die de OR (object-relationeel) mapping mogelijk maakt. Dit object geeft door aan de database dat een bepaald veld (dat via-via dus gekoppeld is aan het adres van de persoon) gewijzigd dient te worden.
De database is hiermee geworden tot een service component. In een situatie dat de database niet lokaal beschikbaar is, maar elders beheerd wordt en alleen bereikt kan worden via bijvoorbeeld een XML bericht dat asynchroon afgehandeld wordt, zal dit geen enkel gevolg hebben voor het domein component: alleen de buitenste adapters zullen vervangen worden door speciale gateway adapters. Deze zullen trouwens dezelfde value interface hebben waardoor clients niet eens merken dat er andere wegen bewandeld worden.
Nogmaals: alle logica, alle complexiteit die bij de business hoort, wordt gemodelleerd in het domein component. Technische componenten bevatten geen business logica. Verschillende applicaties die met het domein component communiceren, bevatten ook geen business logica zodat deze zich bevindt op één plek geconcentreerd.
Wat is het doel van dit hoofdstuk? Ik hoop duidelijk gemaakt te hebben op welke wijze het domein component geïsoleerd is van de buitenwereld, en dat het door die isolatie onafhankelijk van aangekoppelde service componenten kan draaien als een executable component op een applicatieserver.
Een eenvoudig maar uiterst effectief Java framework waarin bovenstaand voorbeeld geïmplementeerd kan worden is het Service Architecture Framework, te downloaden via deze website. Dit kan gebruikt worden in elke Java en J2EE omgeving (en wordt daar ook gebruikt in grote projecten!).
En nu aan het werk
Met het voorwerk dat verricht is wanneer eenmaal de adapter laag gebouwd is kunnen we ons vanaf nu concentreren op wat werkelijk interessant is: oplossingen voor de business!
Zaken als persistency mapping en GUI koppeling zijn wellicht in een vroeg stadium al nodig en dus gebouwd. Gaande de rit zullen er nog veel meer services in de services laag (zie deel 1) aangekoppeld worden maar we merken dat dit meer en meer een routine klus wordt. Aankoppelen van een logging component dat in een eigen proces naar een bestand schrijft dat door een ETL-tool wordt overgepompt naar een datawarehouse? Aankoppelen van een Security Server (bijvoorbeeld een AAS als SiteMinder van Netegrity of Policy Director van IBM)? Een herhaling van zetten. De keuze van producten die bepaalde services kunnen aanbieden wordt een enorm stuk eenvoudiger. De vraag is meer: in hoeverre laten deze producten toe dat het overgrote deel van wat men business logica noemt buiten deze producten wordt afgehandeld? Met name bij CRM en ERP systemen is dat moeilijker te realiseren. Maar zelfs bij zoiets eenvoudigs als Message Brokers zien wij dat ontwikkelaars, onbekend met deze strategie, vallen voor de verleiding de tool te misbruiken en toch weer stukjes business logica erin programmeren.
Weet u nog wat we wilden bereiken?
Nu kunnen we ons hopelijk concentreren op wat de gebruikers willen. Belangrijk is dat het ontwikkelteam binnen dit paradigma komt te werken. Hiervoor is het noodzakelijk in het begin begeleiding te hebben in de vorm van mentors die in de praktijk hebben ondervonden dat het vasthouden aan deze visie loont: in eenvoud van oplossingen, in onderhoudbaarheid. Onder de druk van deadlines en krimpende budgetten is het een menselijke eigenschap terug te vallen op wat men kent en wat in het verleden succesvol is geweest. Business centred architecturen vragen een ander denkraam en het is in de praktijk gebleken dat met name eerste projecten zorgvuldig begeleid tot succes komen en kunnen dienen als referentieproject binnen een algemeen transitietraject naar een nieuwe relatie tussen business en IT.
En nu naar de gebruiker
Voor het succesvol toepassen van een business-centred architectuur is de wijze waarop de business zichzelf representeert van wezenlijk belang. Je zou kunnen zeggen dat daar alles om draait. Het is echter zelden het geval dat een business zichzelf heeft gemodelleerd. En mocht dat al zo zijn dan is het zelden in termen van die business, maar in kromme taal omdat dat nodig was om IT’ers aan het werk te krijgen.
Een voorbeeld: wat is de business behoefte van schepen die gebruik maken van de Rotterdamse haven? Zoals een IT architect mij verzekerde: informatie. En wel informatie over de beschikbaarheid van steigers, kranen enz.
Mijn respons is altijd hetzelfde: “is er wel een informatiebehoefte?” Wat binnen een bedrijf als de Rotterdamse haven nodig is, is dat schepen beter, sneller, veiliger en goedkoper kunnen laden en lossen. Het is het bedrijfsproces dat moet optimaliseren. Voor een verzekeraar zou een business doelstelling kunnen zijn het verkopen van meer verzekeringen. Mensen of systemen die daarbij een ondersteunende rol spelen kunnen weliswaar een behoefte aan informatie hebben maar dat is een secundaire behoefte.
Een voorbeeld uit de praktijk waar deze architectuur is toegepast, komt uit de politiewereld. Politiemensen maken al jaren gebruik van een systeem dat informatie levert of iemand bekend is bij de politie en waaróm. Zo kan een politieman een paspoort gebruiken bij een aanhouding om de naam en geboortedatum van iemand te gebruiken voor een bevraging van dit systeem. Het systeem antwoordt dan dat er sprake is van een vuurwapengevaarlijke persoon. Dan zal de politiebeambte een andere houding aannemen dan wanneer de persoon totaal niet voorkomt in het systeem.
Een beginnende modelleur zou kunnen zeggen: “het systeem levert informatie over de bekendheid van een persoon bij de politie”. Iemand die getraind is om business doelen te herkennen in een probleembeschrijving zal echter zeggen: “het doel van het systeem is om de politiebeambte te ondersteunen bij het bepalen van zijn houding in een confrontatie met een persoon”.
Enkele links
- Voorbeeld referentie implementatie in Java van een framework voor adapters: SAF.jar.
- Dit is natuurlijk de belangrijkste reden waarom benchmarks slechts een éénzijdig beeld kunnen geven. Ook de geruchtmakende Pet Shop vergelijking tussen .NET en J2EE waarbij .NET fenomenaal leek te scoren gaat hier mank: het is met veel kunst en vliegwerk mogelijk laagdrempelige en eenvoudig te bedienen tools te maken voor applicatie-ontwikkeling. De lakmoesproef is echter iets wat niet direct te meten valt: is de oplossing schaalbaar? Juist in de schaalbaarheid gaan bijna alle oplossingen onderuit.
- Class beschrijvingen van domein component classes zijn in de Smalltalk syntax. Hier betekent Model>>changed:with: dat in de class Model een methode is gedefinieerd genaamd changed:with:De dubbele punten geven aan dat er runtime achter die dubbele punten argumenten worden ingevoegd, achter elke dubbele punt één object. Voorbeeld code in Smalltalk:janssen verhuisNaar: Amsterdam op: Date todayDe boodschap is hier verhuisNaar:op: die gestuurd wordt naar de ontvanger janssen, met als argumenten Amsterdam en Date today (vandaag dus).
- Smalltalk namespaces zijn equivalent aan Java packages (en UML packages). De Java Observer class is equivalent aan de Smalltalk Model class.
- Martin Fowler probeert hier een lans te breken voor wat hij POJO’s noemt (Plain Old Java Objects) in zijn nieuwste boek Patterns of Enterprise Application Architecture. Dit is precies wat ik ook (met wisselend succes overigens …) propageer voor de domain component.
Leave a Reply