Bronvermelding [1] Beck et al.
Manifesto for Agile Software Development. http://agilemanifesto.org
[2] Evans
Domain Driven Design. Addison Wesley, Boston (2004)
[3] Wirfs-Brock, McKean.
Object Design: Roles, Responsibilities and Collaborations. Addison Wesley, Boston (2003)
[4] Martin, Martin
Agile Principles, Patterns, and practices in C#. Prentice Hall, Upper Saddle River (2007)
[5] Kleppe et al.
MDA Explained. Addison Wesley, Boston (2003)
[6] Shore, Warden.
The Art of Agile Development. O’Reilly, Sebastopol (2007)
[7] Nilsson
Applying Domain-Driven Design and Patterns. Addison Wesley, Boston (2006)
[8] Génova et al.
Mapping UML Associations into Java code. Journal of Object Technology, ETH Zurich (2003).
[9] Cook et al.
Domain Specific Development with Visual Studio DSL Tools. Addison Wesley, Boston (2006).
Modelgedreven Software Ontwikkeling
[10]
André Boonzaaijer 5 oktober 2008
24
1
Inhoud Inleiding ........................................................................................................ 3 Modellering .................................................................................................. 5 Scoping ................................................................................................... 5 Initiele draft ............................................................................................ 7 Dive ......................................................................................................... 8 Interaction Design ................................................................................ 10
Bijlage 1: Manifesto for Agile Software Development
We are uncovering better ways of developing software by doing it and helping others do it. Through this work we have come to value:
Planning ................................................................................................ 11 Architectuur ................................................................................................ 12 Basisstructuur ....................................................................................... 13 Layering ................................................................................................ 14
Individuals and interactions over processes and tools Working software over comprehensive documentation Customer collaboration over contract negotiation Responding to change over following a plan
Componenten ....................................................................................... 15 Feedback Modellering .......................................................................... 17 Ontwikkelstraat .......................................................................................... 19
That is, while there is value in the items on the right, we value the items on the left more.
Code generatie ..................................................................................... 19 Source Control ...................................................................................... 19 Continuous Integration ......................................................................... 20 Planning / Work Item Tracking ............................................................. 20 Bijlage 1: Manifesto for Agile Software Development ................................ 23 Bronvermelding .......................................................................................... 24
Kent Beck Mike Beedle Arie van Bennekum Alistair Cockburn Ward Cunningham Martin Fowler
James Grenning Jim Highsmith Andrew Hunt Ron Jeffries Jon Kern Brian Marick
Robert C. Martin Steve Mellor Ken Schwaber Jeff Sutherland Dave Thomas
© 2001, the above authors this declaration may be freely copied in any form, but only in its entirety through this notice.
2
23
Inleiding Softwarebouw is een complexe onderneming. Er is al veel over gezegd en geschreven, en ik pretendeer niet de oplossing voor alle problemen gevonden te hebben. Het onderwerp waar ik in dit werk specifiek op in wil gaan is het neerzetten van een ontwikkelraamwerk met daarbij specifiek de focus op requirementsverzameling en vertaling richting software. Rode draad binnen alle onderwerpen die behandeld worden is het ‘Manifesto for Agile Software Development’ [1], ook opgenomen in bijlage 1. Alvorens dit boek verder te lezen is het aan te raden om dit door te nemen. Dit verheldert vooraf al waarom bepaalde onderdelen minder expliciet belicht worden. De basis die ik hiervoor gebruik is het door Eric Evans [2] omschreven: “Domain Driven Design” (DDD) . Deze ontwerpmethodiek stelt het te automatiseren probleemdomein centraal in het werken naar een oplossing. Hiertoe wordt gestreefd naar het definiëren van een ‘ubiquitous language’ – een taal die zowel ontwikkelaars als domeindeskundigen begrijpen. Daarnaast wordt het domein omschreven in deze taal als model centraal maar ontkoppeld van techniek in de software opgenomen. Er is in de afgelopen jaren al ontzettend veel geschreven over DDD. In de meeste publicaties op dit gebied ligt de focus vooral op de technische invulling en ontkoppeling van het domeinmodel. In mijn optiek is het probleem om te komen tot een goed domeinmodel een veel interessanter onderwerp. Ik zal dan ook in dit boekje vooral ingaan op het vertalen van domein- of klantspecifieke omschrijvingen, die ik zal aanduiden met Customer Specific Models (CSP’s) naar domeinmodellen die ook voor ontwikkelaars begrijpelijk zijn. In het tweede deel zal ik meer ingaan op de vertaling van Domain Model (DM) naar wat ik noem Object Models (OM’s). In de meeste publicaties over DDD worden deze als ‘gelijk’ gezien. Ik trek ze met opzet uit elkaar. Ik vind het bijvoorbeeld niet logisch om met domeindeskundigen te praten over design patterns. Dit zijn wel onderdelen die in (domeinspecifieke) onderdelen van de software terugkomen, bij velen dus ook in het 22
3
domeinmodel. Om domeinmodellen echter twee kanten op communiceerbaar te houden mogen deze alleen concepten en constructies bevatten die alle partijen begrijpen.
Plan workitems minimaal wekelijks in in een centrale meeting. Zorg ervoor dat iedereen evenveel Must-have en Should-have load heeft, en dat de items ook in die volgorde worden opgepakt. Spreek daarnaast ook duidelijk af wat er met het ‘overige’ werk uit vorige iteraties gedaan wordt. In principe heeft een nieuwe iteratie een nieuw thema en kan het beter zijn om daarin niet terug te kijken. Als echter de must-haves uit iteratie n-1 niet allen afgekomen zijn kan het noodzakelijk zijn om deze naar het begin van iteratie n te tillen. Een mogelijke oplossing kan zijn om een ‘tusseniteratie’ te introduceren om het overblijfsel uit een eerdere iteratie op te pakken. Deze kan dan ook korter zijn (misschien maar 1 of 2 dagen) maar dit heeft als voordeel dat je bij je thema blijft.
Het laatste deel van dit boekje zal vooral ingaan op een aantal concrete handvatten die ingezet kunnen worden voor het opleveren van software – d.w.z. inrichting van acceptatietests, hulpmiddelen voor ontwikkelteams etc. Dit vat ik onder het kopje ‘Ontwikkelstraat’.
4
21
dat systeem bewerkt worden. Daarnaast is het belangrijk afspraken te maken over: -
-
Communicatie tussen teamgenoten over genomen acties in het versiebeheersysteem Update en commit je sources minimaal een aantal keren per dag, liefst bij het afronden van elk work item (zie hieronder ‘work item tracking’). Commit nooit gebroken source code.
In veel moderne systemen is het mogelijk om hier regels voor aan te maken (check-in policies) maar zoals alle systemen begint het met het gedrag van de mensen die ermee moeten werken.
Continuous Integration Continuous Integration (of kortweg CI) is in de agile ontwikkelstraat niet meer weg te denken. Het betreft in feite een centrale servergebaseerde component die een bepaalde source repository in de gaten houdt op wijzigingen. Op moment dat er dingen gewijzigd zijn wordt door dit component een script uitgevoerd. Dit soort scripts zijn veelal een combinatie van het afvuren van een ‘build’ van de dan recente sources alsmede het uitvoeren van een aantal unit-tests. Een continuous Integration oplossing is een constante monitor op de kwaliteit van de dan geldende actuele source code en is als zodanig een essentieel onderdeel voor projecten met een korte iteratieperiode.
Planning / Work Item Tracking Zowel voor planning vooruit alsmede het kunnen meten van verzet werk is het bijhouden van ‘work items’ een belangrijk onderdeel. Zoals al eerder is aangegeven onder het hoofdstuk Modellering is het belangrijk dat werk opgeknipt wordt in overzichtelijke brokken en dat hier een prioriteit aan gegeven wordt. Zo kunnen projectleden ook werk aan elkaar toewijzen en op verschillende momenten werken om hun lijstje af te werken zonder dat daar continue discussie en overleg voor nodig is.
20
Modellering Essentieel in het software ontwikkelproces is de afstemming tussen opdrachtgever (ofwel “klant”) en opdrachtnemer (ofwel “software bouwer”). Eric Evans [2] omschrijft deze afstemming als het creëren van een Ubiquitous Language. Dit is een vorm van werken die mij de afgelopen jaren heeft geïnspireerd; ik heb veel van zijn ideeën nu een aantal keer toegepast. Mijn grote voorkeur gaat uit naar het modelleren van een klantprobleem. Wat we van oudsher onder modelleren verstaan is het kiezen van een bepaalde modelsoort en hiervan een invulling maken voor een specifiek probleem. Ik zie het breder dan dat; ook code schrijven beschouw ik als modelleren. Ik heb hiertoe in het vorige hoofdstuk een cyclus opgenomen met hoe ik over de evolutie van een model nadenk; van klantspecifiek model naar software. UML class diagrammen hebben voor domeinmodellering mijn grote voorkeur. Het domeinmodel is in mijn optiek een vertaling van een omschrijving in klantspecifieke taal naar eentje in een meer generieke taal; hiertoe moet een taal gebruikt worden die meer mensen begrijpen. Of UML nu wel of niet de beste keuze is wil ik graag in het midden laten; feit is dat verreweg het grootste deel van de moderne software engineers UML in ieder geval deels kent – vandaar deze keuze. Maar hoe vlieg je het modelgedreven ontwikkelen zoals hij het omschrijft nu aan? Wat komt er allemaal in een ‘domeinmodel’ terecht, en wellicht nog belangrijker voor velen, wanneer weet ik dat ik mijn model correct heb opgesteld? Ik zal in dit deel proberen een aantal zeer concrete technieken te beschrijven waar je direct mee aan de slag kunt.
Scoping Een van de meest belangrijke zaken als je iteratief te werk wilt gaan (met een iteratie bedoel ik één cyclus in het hierboven omschreven cyclisch ontwikkelmodel) het inperken van wat je in een iteratie gaat uitvoeren. Het is echter zeer wenselijk om na iedere iteratie min of meer productieklare software op te leveren. Dit heeft een aantal grote voordelen zoals planbaarheid van tests en dergelijke. Over het hoe en waarom van 5
opleveren van werkende software ga ik hier niet verder in, maar diverse bronnen in het gebied van XP [4,6]] kunnen hier op nageslagen worden. Productieklare software, hoe kunnen we dat beloven? Belangrijk is om verticale strepen te trekken door de applicatie. Van user interface tot en met database tabase moet alles van de applicatie geraakt worden om dit te bewerkstelligen. Toch is het zo dat er voor welke smalle streep je ook kiest ook andere onderdelen van het systeem geraakt kunnen worden. Denk bijvoorbeeld aan het uitwerken van een orderregistratiemodule; tiemodule; hiervoor is het waarschijnlijk noodzakelijk om een bepaalde minimale kennis en/of implementatie in het systeem te hebben van concepten als ‘klant’ of ‘product’. Een grafische weergave van de impact van een iteratie op de modelleringactiviteiten heb ik hieronder weergegeven. Voor een iteratie is het belangrijk om op hoog abstractieniveau met een groter aantal concepten bezig te zijn die geraakt worden door de daadwerkelijk relevante concepten. De meest relevante concepten worden wel tot op het laagste abstractieniveau uitgewerkt.
Ontwikkelstraat Zodra er meer dan één ontwikkelaar aan een project komt te werken zijn een aantal (server side) onderdelen in een ontwikkelstraat onontbeerlijk. Daarnaast kan het bij teams met maar één ontwikkelaar wel degelijk meerwaarde hebben om deze onderdelen in te vullen (denk aan standaardisering en opschalen van de projectgrootte). Het is echter in de dagelijkse werkzaamheden minder van toepassing. Binnen de in dit boekje gepresenteerde werkwijze gaan we eigenlijk standaard uit van meerdere ontwikkelaars in een team; de hieronder genoemde onderdelen zijn dus eigenlijk standaard aanwezig in elke ontwikkelstraat.
Code generatie De modelleringscyclus die hier wordt voorgesteld impliceert een vorm van model lifecycle management die zeer gebaat zou kunnen zijn bij (gedeeltelijke) code generatie. Het model wordt beschouwd als een centraal punt van definitie (in welke vorm dan ook – UML ligt in mijn optiek het meest voor de hand). Vervolgens is het wenselijk om bepaalde aspecten van een model (associaties tussen modelclasses, koppelvlakken met omringende componenten) te kunnen genereren en synchroniseren met het model. <
>
Source Control Een standaard plaats om sources te beheren als subversion (svn) of Team Foundation Server (TFS) komen meer en meer voor in software onwtikkelstraten. Er zijn talrijke open source en gratis alternatieven als Visual SVN of Tortoise SVN, dus voor de investeringskosten hoeft het niet gelaten te worden. Het verdient aanbeveling om voor een dergelijk systeem in gebruik te nemen bewustwording te kweken in het team en standaarden af te spreken voor inchecken en uitchecken van sources. Het uitdiepen van een bepaald smal stuk van het model duid ik ook wel aan als het nemen van een ‘dive’. De scoping van de modelleringactiviteiten te
Werken in een sourcecontrolsysteem vereist een minimale mindshift; sources die in een dergelijk systeem beheerd worden moeten ook altijd via
6
19
2. 3.
4. 5. 6. 7.
Validatielogica definieren / implementeren Generatie / implementatie objectmodel equivalent a. Inpassen binnen toegepaste design patterns b. Schrijven unit tests Ontsluiting richting servicelaag Aansluiten nieuwe servicelaag op UI Mappen object richting database Analyse richting overige componenten
Heel plat en concreet kan bij elke mutatie van het domeinmodel de bovenstaande development workflow uitgevoerd worden. Het is aan te bevelen om de meest voorkomende mutaties in dit soort workflows vast te leggen. Veel meer dan bovenstaand stappenplan hoeft het niet te zijn. Door het echter op deze manier vast te leggen is uitbreiding van bestaande applicaties ineens een stuk beter over te dragen aan anderen.
nemen in één iteratie zijn dus onder te verdelen in twee onderdelen die ik nu zal behandelen.
Initiele draft Het brede ondiepe stuk in het bovenstaande T-model stellen we samen in een model dat ik aanduid met ‘initiele draft’. Dit model bevat de concepten die relevant zijn met bijbehorende definities en een aanzet van hun onderlinge relaties. In feite is dit dus de start van het eerder omschreven DM. Hoe kom je nu echter concreet op een dergelijk DM? Een veel gebruikte techniek is het ‘zoeken naar zelfstandig naamwoorden’. Hier is zeker een basis mee te leggen. Concreet gezegd kan de klant in eerste instantie vertellen wat het probleemdomein inhoudt; wie zijn betrokken, wat zijn de taken of doelen van de betrokkenen en hoe hangt dit alles samen. Een techniek die ik zelf graag toepas in dit soort sessies is ‘notuleren op postits’ – tijdens de uitleg schrijft één van de mensen alle (significante) zelfstandig naamwoorden met een eventuele korte definitie op één post-it per stuk. Na deze eerste verkennende gesprekken hebben we dus al een fysieke delivery; een stapel post-its. Uiteraard is dit een vrij onsamenhangend geheel; het zou zelfs zo kunnen zijn dat de structuur van een potentieel te bouwen systeem op dit moment minder duidelijk is voor de opdrachtnemer dan voor deze activiteit. Structurering is een volgende stap die met veel opdrachtgevers in hun ‘eigen’ domein vaak prima te doen is; vanuit de stapel post-its gaan we een eerste draft van een domeinmodel samenstellen. Hou hierbij in gedachten: De verzamelde post-its zijn allen object-kandidaten, geen class-kandidaten! Dit is een essentieel verschil. Een eerste draft domeinmodel bevat vaak maar zo’n 10 a 20 domeinclasses, waar er wel honderd of meer domeinobjecten geadresseerd kunnen zijn! Doordat we alle termen op post-its hebben geschreven kunnen we doormiddel van een groot vel papier of white board het eerste model gaan draften. Je zult het snel eens worden over de meest voor de hand liggende
18
7
class kandidaten – deze kunnen eigenlijk al vanaf het begin een vaste prominente plaats innemen op het papier. Associaties tussen deze kandidaten kunnen we meteen met een stift trekken. Vervolgens zal er een aantal actoren of stakeholders genotuleerd zijn; deze hangen we voor nu apart van het model. De ‘kleinere’ objecten zoals ‘ordernummer’ kunnen bij hun corresponderende class geplakt worden. Het is tijdens het draften van dit model belangrijk om continue vragen te blijven stellen over de samenhang van de verschillende concepten in het probleemdomein. Blijf hierbij alert op aannames die domeinspecialisten al snel maken; de associaties tussen concepten moet zo expliciet mogelijk worden uitgewerkt. Wees echter niet bang om fouten te maken in het model in deze fase; we komen later terug op dit model en we zullen zien dat we ruim voldoende gelegenheid hebben om dit model te verifiëren.
Dive Na een breedteanalyse op hoog abstractieniveau gaan we op een klein deel de diepte in. Blijf hierbij sturen op het smal houden van deze detailuitwerking om de zaak binnen beperkte tijd te kunnen uitdiepen. Deze dive voeren we uit aan de hand van één specifiek scenario. Een scenario is een concrete omschrijving van een aantal opeenvolgende stappen die in context van het probleemdomein genomen moeten worden om een bepaald doel te bereiken. Een handig startpunt van scenariodenken is het einde; wat is het doel dat we met dit scenario willen bereiken? Denk hierbij aan het facturatiescenario dat als doel een facuur heeft maar ook het reserveren van een stoel in een vliegtuig dat als doel een nieuwe reservering heeft, of een medewerker die verhuist. Vaak is het zo dat het doel een nieuw object in het systeem is of dat er een statusverandering van een bepaald object in het systeem moet plaatsvinden. Bij het aanmaken van een nieuw object start je dus eigenlijk met het definieren van een constructor of factory methode die een nieuw object oplevert; bij een statusovergang maak je een methode op een klasse aan.
1. 2. 3.
Voor sommige van deze koppelingsstrategieën wordt het relevant om bij de start van de levenscyclus van een applicatie te kiezen welke componenten gebruikt moeten worden. We noemen dit proces ook wel bootstrapping. Ook hiervoor zijn verschillende strategieën mogelijk. Als er gekozen wordt voor IoC containers wordt de bootstrapping vaak al door het gebruikte framework opgelost. Bij interface of event gebaseerde koppeling zal er bij start van een applicatie een bootstrap-proces ingeregeld moeten worden. Het verdient aanbeveling om hierover na te denken. Bootstrapping gebeurt in feite in elke applicatie in C# / .NET in de main() methode. Eenzelfde soort punt bestaat voor een webapplicatie in de global.asax in de Session_Start(), of meer statisch georiënteerd in de Application_Start(). Let bij webapplicaties goed op en doordenk de gekozen strategie goed aangezien dit minder voorspelbaar verloopt dan een (single) client applicatie. Bij (eenvoudige) service gebaseerde implementatie verdienen windows service hosts en/of consolehosts dan ook de voorkeur boven hosting in IIS, aangezien de ontwikkelaar geen invloed heeft op proces recycling en dergelijke.
Feedback Modellering Na een eerste dive, waarin vaak veel architectuurwerk gedaan moet worden, ontstaat er een aantal ‘stappenplannen’ waarin alle onderdelen van de te bouwen applicatie aangeraakt worden en deels geïmplementeerd. Zo kan er bijvoorbeeld een stappenplan voor het toevoegen van een domeinclass ontstaan dat er als volgt uitziet: 1.
8
Koppeling via inversion of control <> Koppeling via events / delegates (Observer / Observable pattern) <> Koppeling via code generatie <>
Toevoegen class aan domeinmodel
17
Vervolgens is het de vraag welke artefacten uit het businessdomein we allemaal nodig hebben om de statusovergang of objectcreatie te kunnen realiseren. Wederom is het hier handig om al deze artefacten op post-its (nieuwe kleur!) te notuleren en bij het bijbehorende doelobject op te plakken. Als de lijst eenmaal compleet is kunnen we gaan discussiëren welke class in ons draftmodel verantwoordelijk zou moeten zijn voor het beheren van bepaalde artefacten. Zo kan het goed zijn dat voor het verhuizen van een medewerker een nieuwe straat, huisnummer en postcode noodzakelijk is. Als er echter al een klasse ‘Adres’ aanwezig is zou het kunnen zijn dat dit aan deze klasse gedelegeerd kan worden. Bij het moeten invoeren van nieuwe waarden kan het wel eens lastig worden om de vraag aan een bepaald object te stellen. Hiervoor kunnen we een extra object introduceren: de User. [Bron] De virtuele repository als hierboven omschreven delegeert de CRUD activiteit naar een component die dit kan uitvoeren. Deze benadering veroorzaakt een tweetal relevante vragen: -
Wie garandeert – bij goede ontkoppeling – dat deze component aanwezig is? Hoe koppel ik deze component correct gericht aan de domeincomponent?
De eerste vraag is een kwestie die in de praktijk gek genoeg niet speelt. In feite is het vrij triviaal om hier een signaleringsmechanisme voor te maken maar de ervaring leert dat dit toch nooit nodig is. Het kan echter zeer relevant worden als ervoor gekozen wordt om de datacomponent op een aparte locatie te hosten (N-Tier architectuur) en dan dient er wel degelijk rekening mee gehouden te worden. Voor nu ga ik niet verder op dit punt in. Bedenk echter wel dat bij grotere ontkoppeling er ook minder validatie van de code is op compile time. <> De tweede vraag, de koppeling tussen domeincomponent en datacomponent , is op meerdere manieren mogelijk. Ik presenteer hier drie mogelijke oplossingen.
16
Nu we alle specifieke post-its verdeeld hebben over het model is het een kwestie van de sequence opschrijven voor dit scenario. Dit kan nu vrij simpel door alle classes die de anders gekleurde post-its hebben gekregen een eigen swimlane te geven in een nieuw sequence diagram. Het zou nu triviaal moeten zijn om de sequence op te schrijven.
Initiele draft Om dit toch wat theoretische verhaal wat meer concreet te maken zal ik nu een klein voorbeeld uitwerken. Schrijf tijdens het lezen van de volgende alinea alle belangrijke zelfstandige naamwoorden – in enkelvoud – op. <> <> Dive <>
9
Componenten
<>
Interaction Design Tot nu toe heb ik in het omschrijven van de kennisoverdrachtssessies van klant aan engineers niets gezegd over requirements verzameling vanuit gebruikersinteractie met het systeem. Dit is een activiteit die in mijn optiek parallel uitgewerkt dient te worden en zeker niet overgeslagen kan worden; een domeinmodel kan vooral op dit gebied incompleet zijn! Aan de andere kant is het ook zo dat er veel systemen zijn met mindere gebruikersinteractie of juist interactie geïnitieerd vanuit het systeem zelf. Wat dat betreft is het goed om zowel vanuit de ‘ubiquitous language’ te werken als vanuit scherm mock-ups of storyboards.
Een meer natuurlijke manier van opdeling in lijn met wat eerder is gezegd betreft domain driven design is componentsgewijze opdeling, met één centrale businesscomponent. In feite mapt dit direct naar de hierboven omschreven structurering van de oplossing. We buigen het koppelvlak van de business logic layer als het ware rond zodat deze van alle kanten benaderd kan worden. Dit stelt ons tevens in staat om meer componenten aan te sluiten op hetzelfde businesscomponent.
Storyboarding is een techniek die ikzelf het liefst begin op een whiteboard en zo samen met een klant kom tot een draft user interface. Ook dit ‘model’ is aan verandering onderhevig, dus het is handig om hier zo snel mogelijk een demonstrabele electronische versie van te maken zodat men ermee kan spelen. Deze activiteit, parallel uitgevoerd aan domeinmodellering, kan potentiele gaten in domeinmodel opvullen en vice versa.
Door de interfacing van verschillende componenten op deze businesscomponent dienen we goed na te denken welke ‘diensten’ deze businesscomponent aanbiedt. Zo zijn er een aantal standaardfaciliteiten die door user interfaces vaak gebruikt worden, veelal aangeduid als CRUD (Create, Read, Update en Delete) activiteiten. In meer standaard 2 of 3laags architecturen worden deze zaken afgehandeld door een onderliggende database. Bedenk goed dat in de componentgebaseerde architectuur als hierboven omschreven dus helemaal geen database aanwezig hoeft te zijn!
Om terug te komen op het cyclische model; voor veel klanten is het CSP min of meer gelijk aan een aantal schermvoorbeelden met uitleg bij de op de schermen uit te voeren taken. In dit geval kan domeinmodellering veel meerwaarde bieden voor ‘verborgen’ scenario’s en functionaliteiten die weinig tot geen user interactie vereisen.
Wie biedt nu de CRUD interface aan die een user interface (vaak) verlangt? Eric Evans [2] spreekt van een repository component buiten het domein maar waar andere componenten ook gebruik van maken. De meer ‘pure’ oplossing waarbij alle componenten slechts één afhankelijkheid hebben – die met de businesscomponent – is wat ik persoonlijk mooier vind.
Een val van een 100% UI gedreven benadering is een explosie van gerapporteerde bugs/issues uit gebruikerstesten. Als 80% van de UI staat maar slechts 10% van de achterliggende logica en opslag zijn er dus voor 70% van het systeem incomplete use-cases geïmplementeerd. Communiceren van alles dat wel en niet is geïmplementeerd is meer werk dan het simpelweg enkel opleveren wat is gebouwd; maak dus onderscheid tussen ‘demo-UI’ elementen en daadwerkelijk geimplementeerde onderdelen! (hou je bij je verticale strepen…)
Er zijn meerdere strategieën mogelijk om deze vorm van repository integratie te bewerkstelligen zonder de ontkoppeling te offeren. Zo kan een virtuele repository opgenomen worden in het domein die alle functionaliteiten delegeert naar een (later) aangesloten component. Koppelmogelijkheden zijn dan publish/subscribe of inversion of control. <>
10
15
Layering
Planning
Een veel gebruikte vorm van architectonische opdeling is layering. Een kenmerk van layering is dat onderdelen die bij elkaar horen in een eigen ‘laag’ opgedeeld worden en dat deze lagen een éénweg afhankelijkheid kennen naar beneden. Alles rust bij layering dus op de onderste laag, en dit is vaak de datalaag.
Vaak wordt planning onder het kopje ‘proces’ geschoven in standaard software engineering methodes. In mijn optiek vloeit de basisplanning direct voort uit de modelleringscyclus. Door het T-model te hanteren en de scope continue zoveel mogelijk in te perken is het mogelijk om met vaste iteratieperiodes te gaan diven. Een aanvullend concreet hulpmiddel dat hierbij kan helpen is het hanteren van een MoSCoW lijst. Door samen met betrokkenen de (beperkte!) workitem-lijst voorafgaande aan uitvoering van een iteratie door te nemen met een ingeperkt aantal Must-haves, Shouldhaves, Could-haves dwing je mensen na te denken over prioriteit van zaken.
Deze vorm van opdeling wordt vaak en met succes toegepast. Toch sluit het niet geheel aan met de hier omschreven manier van structureren; immers er is een ketting aan afhankelijkheden. Om echt probleemgericht te werken en het de business logic centraal te stellen hebben we een andere manier van opdelen nodig.
De eerste twee iteraties zijn waarschijnlijk nodig voor de projectteamleden om gevoel te krijgen bij workitemgrootte in context van het project, dus er zal initieel op basis van ‘trial-and-error’ geprobeerd moeten worden welke aantallen handig zijn. Het is belangrijk voor deze planning om de ‘velocity’ van een project te kennen, maar dat is reëel gesproken in het begin gewoon niet te doen. Ervaring hierin loont, het is dus zeker handig om in het begin een (klein) aantal meer ervaren mensen te laten meelopen. Om ergens te beginnen is het goed om workitems te nemen die om en nabij een dag kosten, zodat met een team van twee mensen er ongeveer 5 Must haves en 5 Should haves gemaakt kunnen worden in een eerste iteratie. Denk eraan zoveel mogelijk verticaal te blijven werken, hoe moeilijk dat vaak ook is!
Dit neem overigens niet weg dat layering een goed concept is dat wel degelijk goed toe te passen is en toegepast wordt. Er wordt alleen een afhankelijkheid richting een datalaag gecreëerd die wat strakker is dan soms wenselijk. In de praktijk is dit echter in de meeste gevallen geen probleem.
14
11
Architectuur Modellen kunnen - naar mate verder uitgewerkt – een volledige en accurate simulatie van de te automatiseren business executeren. Met executeerbare modellen zijn we er echter niet; ze moeten in een bepaalde context draaien en vaak is het noodzakelijk dat zaken opgeslagen worden en is een bepaalde gebruikersinteractie wenselijk. Een eerste stap richting een opleverbare oplossing noem ik expliciet in het circulaire model en dat is de conversie van DM naar OM. Niet iedereen zal het hiermee eens zijn maar in mijn optiek zijn deze twee stadia van een model niet te voorkomen. In het DM wil je bij concepten blijven die opdrachtgevers ook begrijpen. In een OM komen zaken als design patterns, algoritmiek en koppelingen om de hoek kijken. Dit soort zaken doet harten van software engineers vaak sneller kloppen maar hiermee moeten opdrachtgevers niet lastig gevallen hoeven worden. Architectuur binnen deze systematiek bestaat grofweg uit twee delen; het neerzetten van een uitbreidbare structuur voor het te bouwen systeem als geheel alsmede het neerleggen van een aantal richtlijnen voor deze steeds verdere uitbreidingen. De eerste is vrij handig concreet neer te zetten; vaak wordt hier over ‘framework ontwikkeling’ gesproken. Dit zou een goed e thema kunnen zijn van een 0 iteratie, of eventueel iets dat uit de gereedschapskoffer getoverd wordt. Veel lastiger is het concreet maken van de richtlijnen voor de transformatie van domeinmodel naar objectmodel. Een transformatie van domeinmodel naar objectmodel zou voor 80% uit standaard stappen en routines moeten bestaan (ontwikkeling van een DSL ligt voor de hand?) maar helaas is dit in de praktijk niet zo. Hoewel het in mijn optiek wel zo zou moeten zijn, er is geen standaard manier om een many-to-many associatie uit een UML diagram te vertalen naar een Java of C# implementatie. <> Naast de transformatie van het model zelf is het belangrijk om hier rekening te gaan houden met koppelingen tussen het model en externe, technische componenten. Hieronder vallen user interface, database en 12
andere technisch georiënteerde onderdelen. We willen deze koppeling zo los mogelijk realiseren, en hiervoor zijn een aantal strategieën van toepassing. Denk aan IOC / DI (Inversion of Control of Dependency Injection) of event-gebaseerde communicatie (Observer / Observable pattern). Toch moet een oplossing wel werkbaar en onderhoudbaar blijven! Houdt dingen in dit opzicht dus ook zo simpel mogelijk. Een ‘active record’ pattern (of liever gezegd ‘Persistent Object’) hoeft helemaal niet verkeerd te zijn als dit de eenvoud ten goede komt. Iets dat veel initiele onduidelijkheid kan voorkomen is een goede duidelijke keuze voor de structurering van een oplossing. Denk hierbij aan indeling in namespaces of packages. Een goede duidelijke keuze en ook het communiceren hiervan zodat bij uitbreidingen helder is waar wat moet komen kan veel ellende voorkomen.
Basisstructuur Zorg voor een component dat de domeinlogica (object model) bevat. Je kunt ervoor kiezen om het domein model te scheiden in een eigen component (zo zijn er ook meerdere object modellen mogelijk bij één domeinmodel) maar dit is niet noodzakelijk. Daarnaast zijn er vaak twee hoofdcomponenten die in vrijwel elk systeem voorkomen aanwezig: een user interface en een database component. <projectnaam>.Domain <projectnaam>.UI <projectnaam>.UI.Winforms <projectnaam>.UI.Web <projectnaam>.Data <projectnaam>.Data.Ado
//Domein / Object model //Algemene UI zaken //Windows forms specifieke zaken //Web specifieke zaken //Algemene data access zaken //Dataontsluiting via ADO
UML heeft voor het vastleggen en communiceren van dit soort structuren een diagramsoort, namelijk het package diagram. Hiermee is ook aan te geven wat de afhankelijkheden tussen de componenten zijn.
13