Modelgedreven ontwikkelstraat in .NET (1): Model

 
25 oktober 2008

Zoals door mij in een eerdere post aangegeven begin ik bij deze met een serie posts over een modelgedreven ontwikkelstraat in .NET. Ik spreek van ontwikkelstraat maar bedoel hier eigenlijk alleen de client-side tooling binnen visual studio met eventuele extensions in de vorm van een met behulp van DSL Tools gemaakte UML Class diagram kloon.

Uitgangspunten bij het gaandeweg ontwikkelen en uitbreiden van deze ontwikkelstraat zijn:

  • Ontkoppeling van business model van techniek – een modelgedreven aanpak
  • Minimalisering van repetatieve stukken code d.m.v. codegeneratie
  • Flexibiliteit

Om dan maar meteen te beginnen start ik met het maken van het model met behulp van Microsoft DSL Tools. Met opzet heb ik ervoor gekozen om zoveel mogelijk het standaard model dat meegeleverd wordt met DSL tools te gebruiken; als je deze toolkit installeert krijg je vanzelf de optie om een dergelijke DSL te maken. Ik ben uitgegaan van de standaard template die bij de DSL tools meegeleverd worden voor het maken van class diagrams, met een paar kleine aanpassingen. De losse DSL als installeerbare add-in kan je hier downloaden.

Om de verschillende aspecten van het modelgedreven ontwikkelen te illustreren zal ik bij posts in deze serie telkens het onderstaand model gebruiken ter illustratie. Over hoe en wat betreft dit model zal ik verder niet ingaan; feit is dat we een verzameling classes met associaties, attributen en operaties hebben. Betreft het flexibiliteitsuitgangspunt hierboven vereis ik ook dat dit model altijd kan muteren, dus dat zullen we later ook bekijken.

Ok leuk, model. En nu? In feite bevat dit model al heel veel gegevens die we in verschillende implementaties – wie ze ook maakt – zullen zien terugkomen. Waarschijnlijk worden alle classes in het model opgenomen in een class in code. Daarnaast zullen waarschijnlijk alle attributen terugkomen als fields, evenals de associaties. Operations worden vaak als methodes die de daadwerkelijke logica bevatten opgenomen.

Zo zie je dat je op basis van dit model een aantal aspecten apart kunt benoemen voor implementatie. De modelgedreven benadering die ik wil hanteren in deze serie posts pakt een aantal van deze aspecten en definieert voor elk van deze aspecten een aparte transformatie richting de implementatie. Zo kunnen we deze aspecten, die vaak voor veel of alle elementen van een bepaald type in het model gelden, éénmalig definieren en zo transformeren richting een implementatie. Let wel op; we moeten flexibiliteit hierbij scherp in de gaten houden. Het proces verloopt als volgt:

Waar ik specifiek op in wil gaan is de per thema verschillende transformatie. Ik spreek van thema’s omdat aspecten een wat verwarrende term zou kunnen zijn (vgl. Aspect Oriented Programming, dat ongeveer hetzelfde doet maar dan pas na compileren van code). De transformaties zal ik toelichten aan de hand van een codevoorbeeld van wat je tegenkomt in typische handmatige transformaties van modellen naar code, om vervolgens een zogenaamd text template te maken dat kan worden losgelaten op het hierboven genoemde model. Tevens zal ik in een aantal gevallen aangeven wat de samenhang is met handgeschreven code (“Custom code” in bovenstaand plaatje) en of we eventueel nog wat aanvullende metadata vereisen vanuit ons model.

Ik start hierbij met het eerste voorbeeld; de generatie van de classes met fields en properties voor elk attribuut in het model.

Handgeschreven Code
Normaal gesproken zouden we de fields/properties als volgt implementeren:

private DateTime date;
public DateTime Date
{

get
{
     return this.date;
}
set
{
     this.date = value;
}

}

Een zeer eenvoudig voorbeeld, maar dit betekent voor een gemiddeld project (zeg 20 modelclasses met ieder 10 attributen – dat is al 200x!) potentieel toch al honderden keren ditzelfde stukje code met eenvoudige getters/setters. Vaak is het zo dat gedurende een project er ook nog eens een verandering aan get/set code plaatsvindt. Denk aan validatielogica (waar ik later op zal terugkomen) of een notificatiemechanisme voor veranderingen (de welbekende INotifyPropertyChanged in .NET). Dan zouden we bijvoorbeeld de volgende settercode schrijven: 

set
{

if(this.date != value)
{
     this.date = value;
          if(PropertyChanged!=null)
               this.PropertyChanged(this, new PropertyChangedEventArgs(“Date”));
}

}

Maar het zou net zo goed kunnen dat we een propertyChanging event zouden willen gooien dat eventueel nog een cancel zou kunnen introduceren. Kortom, simpel voorbeeld dat potentieel al heel veel verschillende repetatieve patronen laat zien.

Template
Om het bovengenoemde patroon automatisch te transformeren gebruiken we text templates. In Visual Studio 2008 zit een feature die je standaard al in staat stelt deze templates te transformeren:

T4 Templates, zoals deze .tt files genoemd worden, stellen je in staat vanuit een bepaalde bron code te genereren. De bron is in ons geval het model, en we kunnen met een ASP/PHP-achtige syntax iteratief onze code bijelkaar sprokkelen. Het voorbeeld hieronder geeft aan hoe voor elk attribuut in een class code gegenereerd wordt. Let hierbij op dat code tusse <# en #> de code van de template is en alle code en tekst die ertussen staat code is die in richting output geschreven wordt.

<#
foreach(ModelAttribute attribute in modelClass.Attributes)
{
#>
private <#= attribute.Type #> <#= attribute.Name.ToLower() #>;
<#
if(attribute.Generate)
{
#>
public <#= attribute.Type #> <#= attribute.Name[0].ToString().ToUpper() + attribute.Name.Substring(1) #>
{
get
{
return this.<#= attribute.Name.ToLower() #>;
}
set
{
if(this.<#= attribute.Name.ToLower() #> != value)
{
this.<#= attribute.Name.ToLower() #> = value;
if(PropertyChanged!=null)
     this.PropertyChanged(this, new PropertyChangedEventArgs(“<#= attribute.Name.ToUpper() #>”));
}
}
}
<#
}
#>

Hier omheen staat uiteraard een iteratieve loop die over alle classes in het model loopt.

Ten slotte: het startproject (met daarin de complete en uitgebreide properytgenerator template) is hier te downloaden. Ik zal spoedig posten over andere thema-gebaseerde codegeneratie op basis van dit patroon.


Werken met ?
Kijk dan bij onze mogelijkheden voor zowel starters als ervaren engineers.


Categorieën: Architectuur, Development, .Net

Tags: , , , , ,