sdn magazine 127

32
Nummer 127 december 2015 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network www.sdn.nl IN DIT NUMMER O.A.: Roslyn analyzers voor jouw coderichtlijnen < Runtime DataSets < Unit Testing made easy with Dependency Injection < Getting started met NuGet in de Enterprise < SOFTWARE DEVELOPMENT NETWORK MAGAZINE 127 ISSN: 2211-6486

Upload: doancong

Post on 11-Jan-2017

220 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: SDN magazine 127

Nummer 127 december 2015 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network

www.sdn.nl

IN DIT NUMMER O.A.:

Roslyn analyzers voor jouw coderichtlijnen <Runtime DataSets <

Unit Testing made easy with Dependency Injection <Getting started met NuGet in de Enterprise <

SOFTWARE DEVELOPMENT NETWORK

MAGAZINE

127

ISSN: 2211-6486

Page 3: SDN magazine 127

magazine voor software development 3

ColofonUitgave:Software Development NetworkDrieëntwintigste jaargangNo. 127 • december 2015

Bestuur van SDN:Marcel Meijer, voorzitterRob Suurland, penningmeesterRemi Caron, secretaris

Redactie:Marcel Meijer([email protected])

Aan dit magazine werd meegewerkt door:Roel Hans Bethlehem, Bob Swart, Maartenvan Stam, Arjen Bos, Fanie Reynders, RobSuurland, Remi Caron, Marcel Meijer en natuurlijk alle auteurs!

Listings:Zie de website www.sdn.nl voor eventuelesource files uit deze uitgave.

Contact:Software Development NetworkPostbus 506, 7100 AM WinterswijkTel. (085) 21 01 310E-mail: [email protected]

Vormgeving en opmaak:Reclamebureau Bij Dageraad, Winterswijkwww.bijdageraad.nl

©2015 Alle rechten voorbehouden. Niets uitdeze uitgave mag worden overgenomen opwelke wijze dan ook zonder voorafgaandeschriftelijke toestemming van SDN. Tenzijanders vermeld zijn artikelen op persoonlijketitel geschreven en verwoorden zij dus nietnoodzakelijkerwijs de mening van het be-stuur en/of de redactie. Alle in dit magazinegenoemde handelsmerken zijn het eigen-dom van hun respectievelijke eigenaren.

AdverteerdersMicrosoft 2Achmea 32

Adverteren?Informatie over adverteren en de adverten-tietarieven kunt u vinden op www.sdn.nlonder de rubriek Magazine.

voorwoord

Beste SDN Magazine lezer,

Het zijn weer de donkere dagen van het jaar. Je gaat na je werk in het donker en komtthuis in het donker. Voordeel is wel weer de gezellige lichtjes en warme sfeer in allehuizen. Helaas wil het nog niet echter winteren, maar dat zal straks wel in alle hevig-heid toeslaan.

Ik hoop dat Sinterklaas je weer voorzien hebt van mooie nieuwe hardware. Misschienwel een uit het artikel in dit magazine. Anders hoop ik dat de er iets moois onder dekerstboom ligt. Mocht je aan beide tradities niet meedoen, dan hoop ik dat je jezelftoch verwent hebt na het harde werken van afgelopen jaar.

Dit magazine is wel perfect voor deze donkere dagen. Lekker weggedoken op debank de artikelen van je collega’s lezen. Hoe zij met de nieuwe technieken hebbengespeeld en hoe zij het hebben ingezet. Altijd leuk om de ervaringen te lezen voor-dat je er zelf mee gaat werken. Cary, Danny, Gerald, Pepijn, Sander, Marcel en Bobhebben hun uiterste best gedaan om hun ervaringen mooi vorm te geven. Over Delphi 10, Runtime datasets, Dependency injection Unit tests, Xamarin Forms, Roslyn analysers, Projecten en Software en Microsoft Hardware.

Weet je dat Iedereen het in zich heeft om een artikel te schrijven? En weet je dat wijaltijd kansen geven om dat ook te doen? Dus heb je zin om zelf een artikel te schrijven of een sessie te doen, meldt je bij ons. We helpen je graag verder.

Rest mij eigenlijk alleen nog om jullie een goed uiteinde en een prachtig begin te wensen. Laten we hopen dat 2016 een succesvol jaar voor ons allemaal mag zijn. Een jaar met geweldige opdrachten, carriere kansen en nieuwe vriendschappen.Een goed 2016.

Groeten,Marcel Meijer eindredacteur Magazine en Voorzitter SDN •

Page 4: SDN magazine 127

Inhoud03 VoorwoordMarcel Meijer

04 Inhoudsopgave

04 Agenda

05 Roslyn analyzers voor jouw coderichtlijnenPepijn Sitter

10 Xamarin.Forms, platform specifieke implementaties met de DependencyService

Gerald Versluis

13 Runtime DataSetsCary Jensen

16 Why the project metaphor doesn’t fit software development

Sander Hoogendoorn

18 Unit Testing made easy with Dependency Injection

Danny van der Kraan

22 Microsoft hardwareMarcel Meijer

24 Beveilig de toegang tot Azure Storage met SAS tokens

Sander van de Velde

26 Getting started met NuGet in de enterpriseCornell Knulst

• maart Magazine 128

• 30 maart - 1 april Build Conference

• 8 april SDN event

• 19 april Global Azure Bootcamp

• mei Magazine 129

• mei TechDays

• 10 juni SDN event

• september Magazine 130

• 16 september SDN event

• 26 - 30 september Ignite Conference

• november Magazine 131

Agenda 2015/2016

Page 5: SDN magazine 127

.NET Pepijn Sitter

Maar waarom zouden we dit met analyzers doen? Kunnen we dit nietmet andere tools doen? Ja, dat kan. Via de analyzers kan je echter eenaantal handige dingen doen. Je kan de analyzers in je project vastleggen door ze uit een NuGet server te halen. Dan is uitrollen enup-to-date houden erg gemakkelijk. Je hebt ook alle mogelijkhedendie de Roslyn compiler biedt tot je beschikking voor het analyserenvan code, in C#. Dat betekent dat je op een relatief eenvoudige manier analyses kan implementeren die voor jouw organisatie of project belangrijk zijn. En op elk gewenst moment een richtlijn kanaanpassen op jouw werkelijkheid.

Veel organisaties hebben richtlijnen waarin beschreven staat hoe omte gaan met source code. In het meest simpele geval zijn dit namingconventies, zoals een private variabele die met een underscore moetbeginnen. Maar ook uitgebreidere richtlijnen in coding standard bestaan er ook. Dit allemaal om de kwaliteit en de uniformiteit te verhogen. Zorgen dat iedereen deze conventies en richtlijnen over eenlangere tijd ook daadwerkelijk toepast is nog niet zo eenvoudig. Er zijnveel tools/plug-ins op de markt die elke ontwikkelaar kan installeren enook lokaal kan configureren via een settings bestand. Nadeel daaraanis dat die mogelijk niet door iedereen worden geïnstalleerd of ge-update als er aanpassingen op de richtlijnen zijn. Persoonlijk vindik dit altijd vrij bewerkelijk en zou ik graag willen dat als er richtlijnen zijn, iedereen er zich aan moet houden. Een build server die een bepaaldeset aan regels afdwingt kan een oplossing zijn al is de roundtrip metanalyses niet de meest efficiënte manier. Ik wil zo snel mogelijk software opleveren, want daar doen we het eigenlijk toch voor?

KwaliteitMaar wat betekent kwaliteit dan eigenlijk? Kwalitatief goede codeschrijven doen we met een reden. Om zo snel mogelijk nieuwe features of bugs op te lossen. Een absolute vereiste tegenwoordigwaarin de oplevermomenten veel frequenter zijn. Dat gaat het gemakkelijkst als je code op een zodanige wijze is opgezet dat dit ookdaadwerkelijk mogelijk is. Als ik denk aan kwalitatief goede code denk ik aan makkelijk te onderhouden code. Dit betekent wat mij betreft dat als ik een nieuwefeature toevoeg of een bug oplos er weinig tot geen veranderingen inde huidige code aangebracht moeten worden. Weinig refactor werkdus. Om dit te bereiken worden vaak de begrippen uit SOLID aangehaald, wat soms tot verwarring leidt.

Roslyn analyzers voor jouw coderichtlijnenRoslyn is Microsofts open-source compiler en analyse APIs voor C# en VB.NET. Met Roslyn kanje gebruik maken van alle analyse uitkomsten van de compiler over je source code. Hiermee ontstaan er nieuwe mogelijkheden om bijvoorbeeld uitbreidingen voor Visual Studio en codeanalyzers te bouwen. In dit artikel gaan wij zelf code analyzers bouwen die een bepaalde set aancoderichtlijnen controleert.

Ik zou het onder de volgende begrippen onderbrengen:- Beschrijvende code- Zoveel mogelijke ontkoppelde code

Meten is weten?Wat betekenen deze begrippen precies? Hoe halen we de subjectivi-teit eruit? Was het maar zo simpel dat er één set richtlijnen was dievaststelt wat kwalitatief goede code is. Dan kon of zelfs moest ieder-een die volgen. De gedefinieerde begrippen zijn vrij te interpreteren. Wekunnen ze echter verder concretiseren. Als ik coderichtlijnen zoumaken op basis van de twee begrippen zou ik dit als volgt doen:

1) Geen eigen statics makenAfhankelijk van je codestijl zou je mogelijk geen statics willen hanteren. Static classes hebben als potentieel nadeel dat ze op veelverschillende plekken gebruikt worden. En dus ook soms misbruiktworden. Ze groeien na verloop van tijd uit tot grote utility classesdie een grotere koppeling hebben met andere delen van je codebase. Of zelfs meerdere code bases. Dit zal de onderhoudbaarheidniet ten goede komen.

2) Methodes niet meer dan 30 regelsEen code smell die mogelijk aangeeft dat een methode te veel doet.Waarom 30 regels? Dan is de methode op de meeste beeldscher-men in zijn geheel te lezen. Is natuurlijk eenvoudig aan te passen.

3) Geen commentaarMet commentaar loop je altijd het risico dat het niet consequentwordt bijgehouden. En dan gaat het eigenlijk zijn doel voorbij. Zouje ook kunnen hanteren voor XML comments, maar die laten wevoor nu intact.

4) Maximaal 6 dependencies in de constructor meegevenOm je code onderhoudbaar te maken worden andere functionali-teiten in andere classes vastgelegd. Meestal met interfaces, somszijn het concrete implementaties. Om ontkoppeling van je code laagte houden zou je ervoor kunnen kiezen om een maximum te stellenaan het aantal dependencies die aan een constructor worden mee-gegeven. Of zelfs parameters in zijn algemeenheid. In ons geval stel-len we een limiet van 6 aan het aantal objecten die meegegevenmogen worden.

magazine voor software development 5

Page 6: SDN magazine 127

.NET

MAGAZINE

6

Klik op de Download .NET Compiler Platform SDK Templates knop:

Voordat je je eigen analyzer kan maken moet je ook de .NET compi-ler SDK downloaden en installeren. Deze komt in de vorm van een extension:

Start daarna Visual Studio even opnieuw op. Nu kan je via File->NewProject en zoeken op analyzer zien dat je nu een eigen analyzer kanmaken:

Klik op OK om je nieuwe analyzer solution aan te maken.

Je solution bestaat uit drie projecten:

De analyzer, een unit test project en een Visual Studio extension project. In de analyzer project zitten twee .cs files. De Diagnostic-analyzer.cs heeft de echte analyzer code en de CodeFixProvider.csbevat code om een code fix voorstel aan de ontwikkelaar aan te bieden. De namen vertelden het eigenlijk al. Met CodeFixes kan je bijvoorbeeld een naamsaanpassing van een variabele doen.

Dit is natuurlijk geen dekkende lijst van richtlijnen. Het zijn voorbeeldenvan zaken die in ieder geval meetbaar zijn en we dus af kunnen dwingen in een Roslyn analyzer. En dat is precies wat ik wil laten zien.

AnalyzersIn Visual Studio 2015 projecten zit standaard een Analyzers reference:

Hierin zitten een hoop regels die standaard worden gebruik binnen elknieuw projecten. Als je Open Active Rule-Set rechtermuis klikt zie je alleregels die tot je beschikking staan. Een regel kan resulteren in eenerror, warning of information bericht. En ze kunnen ook helemaal uit ofonzichtbaar worden gezet.

Precies zo’n set gaan wij ook maken.

Een eigen analyzer makenAls je als je op File->New Project klikt en op analyzer zoekt moet je‘Download the .NET compiler platform SDK’ selecteren:

Page 7: SDN magazine 127

.NET

De analyzer doet het werk om de betreffende code te vinden. Als jehem nu runt wordt er een nieuw Visual Studio opgestart waarin dezeanalyzer als extension is geïnstalleerd:

In de nu lopende instantie van Visual Studio is dus onze simpele analyzer geïnstalleerd. En deze doet niet veel. Hij verwacht dat namenvan elementen van classes en interface (eigenlijk een type anders daneen array, pointer of een type parameter volgens de documentatie)met totaal uppercase letter geschreven is. Het lampje, hopelijk een spaarlamp, icoon geeft aan dat er ook eenCode fix voor is:

En hij geeft meteen het resultaat weer als de code fix wordt uitgevoerd. Netjes.

De code die dit voor elkaar krijgt zit in DiagnosticAnalyzer.cs:

[DiagnosticAnalyzer(LanguageNames.CSharp)]

public class Analyzer1Analyzer : DiagnosticAnalyzer

{

public const string DiagnosticId = "Analyzer2";

// You can change these strings in the Resources.resx file.

If you do not want your analyzer to be localize-able, you can

use regular

strings for Title and MessageFormat.

private static readonly LocalizableString Title = new Loca-

lizableResourceString(nameof(Resources.AnalyzerTitle),

Resources.ResourceManager, typeof(Resources));

private static readonly LocalizableString MessageFormat =

new LocalizableResourceString(nameof(Resources.AnalyzerMes-

sageFormat),

Resources.ResourceManager, typeof(Resources));

private static readonly LocalizableString Description =

new LocalizableResourceString(nameof(Resources.AnalyzerDe-

scription),

Resources.ResourceManager, typeof(Resources));

private const string Category = "Naming";

private static DiagnosticDescriptor Rule = new Diagnostic-

Descriptor(DiagnosticId, Title, MessageFormat, Category,

Dia-

gnosticSeverity.Warning, isEnabledByDefault: true, descrip-

tion: Description);

public override ImmutableArray<DiagnosticDescriptor> Sup-

portedDiagnostics { get { return

ImmutableArray.Create(Rule); } }

public override void Initialize(AnalysisContext context)

{

// TODO: Consider registering other actions that act on

syntax instead of or in addition to symbols

context.RegisterSymbolAction(AnalyzeSymbol,

SymbolKind.NamedType);

}

private static void AnalyzeSymbol(SymbolAnalysisContext

context)

{

// TODO: Replace the following code with your own analy-

sis, generating Diagnostic objects for any issues you find

var namedTypeSymbol = (INamedTypeSymbol)context.Symbol;

// Find just those named type symbols with names contai-

ning lowercase letters.

if (namedTypeSymbol.Name.ToCharArray().Any(char.IsLo-

wer))

{

// For all such symbols, produce a diagnostic.

var diagnostic = Diagnostic.Create(Rule, namedTypeSym-

bol.Locations[0], namedTypeSymbol.Name);

context.ReportDiagnostic(diagnostic);

}

}

}

De analyzer is afgeleid van een DiagnosticAnalyzer en deze heeft eenInitialize methode. Hierin registreer je acties die worden uitgevoerd alsbepaalde syntax in de code door de compiler wordt gevonden. In ditbasisvoorbeeld wordt de methode AnalyzeSymbol aangeroepen alser een symbool wordt gevonden van het type NamedType, een classbijvoorbeeld. De AnalyzeSymbol methode krijgt een context mee vande analyse en kan dan actie ondernemen. In dit geval bepalen of detype naam van het symbool een lowercase karakter bevat. Zo ja, danwordt er een diagnostic rule aangemaakt. In dit geval van het typewarning. Meer is het niet.

De Code Fix zit iets anders in elkaar, maar laat ik hier verder even buiten beschouwing.

magazine voor software development 7

Page 8: SDN magazine 127

.NET

MAGAZINE

8

Roslyn terminologieIn het simpele voorbeeld zagen we al een aantal begrippen naar vorenkomen. De Roslyn compiler heeft een eigen manier van in kaart bren-gen van source code. Hiervoor heeft het ook nieuwe terminologie geïn-troduceerd die je bij het maken van analyzers zal moeten begrijpen.

TriviaIn Roslyn terminologie is alles wat geen code is trivia. Iets wat niet bijzonder bijdraagt aan de code zoals whitespaces, commentaar enpreprocessor directives.

Syntax TokensEen Syntax Tokens is het kleinste element in Roslyn. Dit zijn de keywords, identifiers, literals en punctuatie karakters.

Syntax NodeEen Syntax Node bevat een element zoals een declaraties, statements, clauses en expressions.

Syntax TreeDe Syntax Tree stopt alle nodes, tokens en trivia bij elkaar in eenboomstructuur. Alles is tevens te herleiden naar de originele sourcecode, want die is ook opgeslagen in de SyntaxTree. De verschillendeelementen kan je via de Syntax Visualizer zichtbaar maken(blauw=node, groen is een token, wit en grijs = trivia):

Dit zijn ze zeker nog niet allemaal, maar wel de elementen die wij inonze voorbeelden gaan gebruiken.

Onze richtlijnenOns doel was om de eerder gedefinieerde richtlijnen via individueleanalyzers af te dwingen. Per geval gaan we dat hieronder doen. Eenanalyzer bestaat altijd uit twee gedeeltes. De Intialize methode op basiswaarvan de analyse uitgevoerd wordt en de daadwerkelijk code die deanalyse uitvoert.

In alle gevallen ga ik ervan uit dat er een DiagnosticDescriptor is aan-gemaakt waarmee een melding aan de ontwikkelaar wordt getoond.Met daarin altijd de locatie van de methode in de source code. En soms optionele parameters waarin bijvoorbeeld de naam van eenelement wordt meegegeven die in de melding kunnen worden getoond. Of het een error, warning of info melding is kan je natuurlijkook helemaal zelf bepalen.

Geen eigen statics maken/aanroepenAnalyses van modifiers van methodes, classes, properties of fieldsworden gedaan door in je Initialize methode een actie te registreren opeen Symbol:

context.RegisterSymbolAction(AnalyzeNoStaticExceptMainMethod,

SymbolKind.NamedType, SymbolKind.Method,

SymbolKind.Property, SymbolKind.Field);

En de AnalyzeNoStaticExceptMainMethod methode ziet er zo uit:

private static void AnalyzeNoStaticExceptMainMethod(SymbolA-

nalysisContext context)

{

var symbol=(ISymbol)context.Symbol;

if(symbol.IsStatic== true)

{

if ((String.Equals(symbol.Name, "Main") == true) &&

(symbol.Kind == SymbolKind.Method)==false)

{

var diagnostic = Diagnostic.Create(Rule, symbol.Loca-

tions[0], symbol.Name);

context.ReportDiagnostic(diagnostic);

}

}

}

Methodes niet meer dan 30 regelsAnalyses van complete methodes worden gedaan door in je Initializemethode een actie te registreren op een SyntaxNode:

context.RegisterSyntaxNodeAction(AnalyzeMethodTooLong,

SymbolKind.MethodDeclaration);

En de AnalyzeMethodTooLong methode ziet er zo uit:

private static void AnalyzeMethodTooLong(SyntaxNodeAnalysis-

Context context)

{

var method = (MethodDeclarationSyntax)context.Node;

if(method.Body.Statements.Count>30)

{

var diagnostic = Diagnostic.Create(Rule, method.GetLoca-

tion(), context.Node);

context.ReportDiagnostic(diagnostic);

}

}

Geen commentaarAnalyses op de aanwezigheid van commentaarregels wordt gedaandoor in je Initialize methode een actie te registreren op een Syntax-Tree. Wat intuïtief niet iets is wat je zou verwachten, want nu moet jezelf de elementen uit de SyntaxTree halen en daar waar nodig eenmelding voor geven:

context.RegisterSyntaxTreeAction(AnalyzeNoComments);

De AnalyzeNoComments methode ziet er zo uit:

Page 9: SDN magazine 127

.NET

magazine voor software development 9

private void AnalyzeNoComments(SyntaxTreeAnalysisContext con-

text)

{

SyntaxNode rootNode =

context.Tree.GetCompilationUnitRoot(context.CancellationTo-

ken);

var singleLineComments = rootNode.DescendantTrivia()

.Where(trivia => trivia.IsKind(Symbol-

Kind.SingleLineCommentTrivia));

foreach(var commentedLine in singleLineComments)

{

var diagnostic=Diagnostic.Create(Rule, commentedLine.Get-

Location());

context.ReportDiagnostic(diagnostic);

}

}

Maximaal 6 dependencies in de constructor meegeven.Analyse op een constructor wordt gedaan door in je Initialize methodeeen actie te registeren op SyntaxNode. In dit geval een Syntax-Kind.ConstructorDeclaration:

context.RegisterSyntaxNodeAction(AnalyzeMethodWithTooMany

Dependencies,

SymbolKind.ConstructorDecla-

ration);

De AnalyzeMethodWithTooManyDependencies methode ziet er zo uit:

private static void AnalyzeMethodWithTooManyDependencies

(SyntaxNodeAnalysisContext

context)

{

ConstructorDeclarationSyntax constructor = (ConstructorDe-

clarationSyntax)context.Node;

int identifierParametersFound = 0;

foreach (ParameterSyntax param in constructor.Parameter-

List.Parameters)

{

if (param.Type.IsKind(SyntaxKind.IdentifierName) ==

true)

identifierParametersFound++;

}

if (identifierParametersFound > 6)

{

var diagnostic = Diagnostic.Create(Rule,

constructor.GetLocation());

context.ReportDiagnostic(diagnostic);

}

}

ConclusieMet wat simpele voorbeelden heb ik hopelijk laten zien dat het relatiefeenvoudig is om je eigen Roslyn analyzers te implementeren. Het iszeker mogelijk om hele uitgebreide analyzers te maken die preciesdoen wat jij belangrijk vindt in jouw sourceode. Alle analytische func-tionaliteit die in Roslyn zit kan je volledig inzetten. De lastigheid zalwaarschijnlijk niet in je analyzer zitten, maar eerder in welke concreterichtlijnen jij of jouw organisatie belangrijk vindt om toe te passen. Endit als kwalitatief goede software beschouwt. Je kan in ieder geval allekanten uit om de regels ook af te dwingen. Elke ontwikkelaar moethiervoor wel wat extensies installeren, maar is niet meer afhankelijk

van een configuratie bestand die handmatig ingeladen moet worden.De koppeling in je project met je analyzers die in een NuGet serverstaan maakt het een stuk eenvoudiger. •

Pepijn Sitter

Pepijn is werkzaam bij Eporta als.NET consultant met een bijzondereinteresse in het maken van testbaresoftware. Dit doet hij als architect,(lead) developer en/of Scrum mas-ter op projecten bij opdrachtgevers.

TIP:New version Windows10 Core availableDownload the November update for Windows 10 IoT Core.Built for devices, Windows 10 IoT Core enables you to createcool connected projects, amazing applications, and muchmore. It leverages the Windows development environment youknow -- adapted to run on embedded devices like theRaspberry Pi 2.

The November update of Windows 10 IoT Core requires VisualStudio 2015 Update 1 for development purposes such as debugging and deploying images.

http://ms-iot.github.io/content/en-US/Downloads.htm

Page 10: SDN magazine 127

MOBILE Gerald Versluis

Om het de gebruiker zo eenvoudig mogelijk te maken zitten er tegen-woordig een hoop hulpmiddelen op de telefoon of tablet. Deze kunnen zowel software- als hardwarematig zijn. Denk bijvoorbeeld aande GPS mogelijkheid die gebruikt kan worden voor navigatie, de vingerafdrukscanner om gevoelige informatie te beveiligen of de Text-To-Speech mogelijkheid voor de slechtziende gebruiker. Als ontwik-kelaar wil je deze mogelijkheden dan natuurlijk ook in jouw app kunnenverwerken.

Maar hoe verhoudt zich dit tot de cross-platform aanpak van Xama-rin? Sommige sensoren en functionaliteiten zijn niet beschikbaar opieder platform en als ze dat wel zijn dienen ze op een vrij specifiekemanier aangesproken te worden omdat ze toch net anders reageren.

Voordat Forms er was, was het implementeren van dit soort functio-naliteit vanzelfsprekend. Op dat moment maakte je gebruik van deiOS, Android en Windows Phone project templates die de Xamarinlibraries bevatten. Deze libraries hebben alle mogelijkheden aan boordom een vertaalslag te maken van C# naar de native equivalent of genoeg hulpmiddelen om deze mapping zelf te maken. Op het mo-ment dat je dus voorbeeldcode of SDK documentatie kon vindenbouwde je dit per platform in.Met de komst van Xamarin.Forms wil je juist zoveel mogelijk, ook UI,code gedeeld maken. Anders zou je met compiler directives of andere hacks aan de gang moeten om te bepalen welk platform enwelke bijbehorende functionaliteit je aan zou moeten roepen.

Xamarin heeft een abstractielaag als onderdeel van Forms ingebouwdde DependencyService, om dit probleem voor te zijn. Hiermee is hetmogelijk om toch de platform specifieke implementatie te schrijven,hier kan niet aan worden ontkomen, maar deze is wel op een nette

In het vorige nummer schreef ik een korte introductie over Xamarin.Forms. Zoals de naam al doetvermoeden bevat dit vooral componenten voor de user-interface, maar het bestaat uit nog eenaantal onderdelen die niet direct met het visuele aspect te maken hebben. Deze maken hetmogelijk om het hergebruik van code over de verschillende platformen te vergroten. In dit artikel zal ik de zogenaamde DependencyService beschrijven. Een ingebouwd DependencyInjection framework waarmee op een uniforme manier, toch platform specifieke code kan worden geschreven die op een gedeelde manier kan worden aangeroepen.

Xamarin.Forms, platform specifieke implementatiesmet de DependencyService

manier met één aanroep vanuit onze gedeelde code uit te voeren.Runtime zal dan de juiste implementatie worden geïnjecteerd.

De termen injecteren en Dependency Injection (DI ook wel bekend alsInversion of Control) zijn nu al een aantal keer gevallen. Voor de mees-ten zal dit bekende materie zijn, is het dat niet dan raad ik je aan je erin te verdiepen. Het is een mooie techniek en zal de werking van deDependencyService een stuk duidelijker maken. Ook zonder dezevoorkennis zal het concept ook snel genoeg duidelijk worden.De DependencyService is eigenlijk niet meer dan een klasse met tweetaken. De ene taak is het kunnen registreren van andere klasses en demogelijkheden die zij bieden en de andere taak is het kunnen opvra-gen van een instantie van een van deze klasses wanneer je hem nodighebt.

De sleutel bij dit verhaal zijn interfaces. De registraties die je doet bijeen DI container, in dit geval de DependencyService, zullen in bijnaalle gevallen instanties van een interface zijn. Wanneer je een instantie opvraagt van een van deze interfaces zal het je op dat puntniet zoveel uitmaken welke implementatie dat precies is - lees: de implementatie op welk platform dit is - als deze maar voldoet aan degevraagde interface.

Om gebruik te maken van de DependencyService hebben we eigenlijk drie dingen nodig:• De interface: deze beschrijft de functionaliteiten die we aan kunnenroepen

• Registratie: het laten weten aan de DependencyService dat er eenimplementatie beschikbaar is van een bepaalde interface

• Locatie: dit is gebaseerd op een ander veel gebruikt design pattern,het Service Locator pattern en houdt in dat er een plek is, in onsgeval de DependencyService, waar je een stuk functionaliteit opkan halen zonder een specifieke klasse te hoeven instantiëren endus zonder de exacte locatie hiervan te weten.

MAGAZINE

10

De sleutel ligt in de interfaces

Met de komst van Xamarin.Forms wil je juist zoveel mogelijk code en ook UI delen

Page 11: SDN magazine 127

MOBILE

We maken hier duidelijk via een attribute dat we het type Android-TextToSpeech willen registreren.Vervolgens herhalen we dit bij de iOS versie waar het idee hetzelfde is,alleen de implementatie uiteraard anders. Op het moment van schrij-ven is iOS de enige die Nederlands ondersteund en dus kunnen wedeze daadwerkelijk ook nog een beetje verstaan. In het SDN.Rss.iOSproject maken we de klasse iOSTextToSpeech aan en implementerende welbekende interface op zijn eigen manier.

Tenslotte doen we dit nog een keer voor de Windows Phone versie.

In onze gedeelde code kunnen we nu door de DependencyServiceaan te roepen onze functionaliteit benaderen. Dit doen we wederomop basis van de interface en afhankelijk van het platform zal de DependencyService de implementatie injecteren en uitvoeren. Om de code binnen onze PCL af te maken gaan we naar de

Tot zover het conceptuele gedeelte, waarschijnlijk wordt dit alles eenstuk duidelijker aan de hand van een voorbeeld.Om een concreet beeld te geven van hoe dit er in de praktijk uitziet zalik de code van de vorige keer, onze SDN Rss reader, uitbreiden metde mogelijkheid om artikelen voor te laten lezen door middel vanText-To-Speech (TTS). Deze functionaliteit is op alle platformen beschikbaar, er is echter (nog) geen abstracte manier om deze aan tespreken. Dit is dus een mooi voorbeeld om te tonen hoe we dit zelf perplatform kunnen implementeren.

Om het geheugen op te frissen zal ik nog even kort de structuur vanons project kort uitleggen. De solution bestaat uit vier projecten: eengedeeld PCL project wat in feite onze app is en drie projecten, eenper platform.

In ons gedeelde project maken we de interface aan die beschrijft hoeonze functionaliteit eruit ziet. Mijn ITextToSpeech zal in dit geval maareen methode bevatten namelijk de Speak functie die als parametereen string meekrijgt met de tekst die uitgesproken gaat worden.De volgende stap na de interface is het registreren van de klasses.Hiervoor dienen we eerst iets registreerbaars te hebben en dus gaanwe onze platform specifieke implementaties maken en deze registre-ren bij de DependencyService. We beginnen bij de Android versie.We maken een nieuwe klasse AndroidTextToSpeech aan in onsSDN.Rss.Droid project, deze implementeert de ItextToSpeech interface en dus moeten we de Speak methode definiëren.

Je ziet dat we hier een aantal naar Java neigende objecten gebruikenwat in feite de Xamarin mappings zijn naar de daadwerkelijk AndroidJava code. Op deze manier spreken we de TTS functionaliteit op Android aan.

Het daadwerkelijke registreren bij de DependencyService doen wedoor de volgende regel boven de namespace te plaatsen.

magazine voor software development 11

Page 12: SDN magazine 127

MOBILE

RssNodePage.xaml pagina. Dit is de pagina die het gekozen artikelweergeeft. Hier voegen we in de ToolBar van onze pagina een knoptoe die de tekst laat voorlezen.

Wanneer je het vorige artikel hebt gelezen valt je misschien op dat ikhet uiterlijk nog wat onder handen heb genomen zodat deze er wat representatiever uitziet.

Achter deze knop hebben we nu maar een simpele regel code nodigom het geselecteerde artikel te laten voorlezen.Hier zien we dat we aan de statische DependencyService klasse eenimplementatie opvragen van onze ITextToSpeech interface. Deze latenwe vervolgens de Speak methode aanroepen. Op het moment datdeze aanroep gedaan wordt zal de platform specifieke implementatie,die geregistreerd is bij de DependencyService, worden gelocaliseerden geïnstantieerd en daarop zal de aanroep van de Speak methodeplaatsvinden.

Code-technisch hebben we nu de mogelijkheid ingebouwd om de artikelen te laten voorlezen, er rest nu alleen nog een stukje configu-ratie. Door de groeiende bewustheid van de eindgebruikers over demogelijkheden die allemaal op een hedendaags apparaat zitten, wil-len ze hier ook meer controle over. Voor ieder platform zijn er daaromeen aantal permissies die je als ontwikkelaar aan moet zetten waarmeeje toegang vraagt tot een bepaald stuk functionaliteit. Bijvoorbeeldvoor het gebruik maken van de GPS, de mogelijkheid om automatischeen telefoongesprek te starten, gebruik te maken van de camera,maar ook om de microfoon en/of speaker te gebruiken vereist eenstukje configuratie.

Afhankelijk van het platform wordt er dan in de app store getoondwelke toegang desbetreffende app krijgt tot functionaliteit en sensoren. In sommige gevallen wordt er zelfs nog extra toestemminggevraagd aan de eindgebruiker of deze dit inderdaad toe wil staan,het meest voorkomende voorbeeld hiervan is waarschijnlijk de GPSsensor.

Gelukkig is het instellen hiervan niet erg moeilijk, het is echter wel ietsdat je gauw over het hoofd ziet. Ook hoeft een bepaalde permissieniet voor alle platformen te worden geactiveerd. Welke wel of nietnodig zijn en wanneer is terug te vinden in de documentatie van desbetreffend platform. In dit geval hoeft het alleen voor WindowsPhone.

Ga hiervoor naar het WinPhone project en dubbelklik onder Propertiesop WMAppManifest.xml.Onder het tabblad Capabilities staat vervolgens een lijst met alle mogelijkheden en aan de rechterkant een korte beschrijving. Voor nuvolstaat het om de optie ID_CAP_SPEECHRECOGNITION aan te zijn,mogelijk staan er al een aantal meer standaard aan.

Bij Android en iOS zitten dus soortgelijke mogelijkheden en zijn dezete benaderen via de respectievelijke projecteigenschappen.Het leukste is natuurlijk om dit alles dan ook te zien werken. Helaas isde Text-To-Speech in geen van de gevallen te testen door de beschikbare emulatoren en dus zul je de code op een fysiek apparaatmoeten zetten om dit te horen werken. Hoewel waarschijnlijk iets minder leuk dan wanneer je het zelf doet heb ik deze app beschik-baar gemaakt in de respectievelijke app stores zodat je het toch zelfkunt proberen.

Mocht je het toch zelf willen proberen of de code nog eens in zijn geheel willen doornemen dan is deze wederom te vinden op GitHub:https://github.com/SDNRss. •

Gerald Versluis

Gerald is een full stack .NET ontwikkelaar met een voorliefdevoor web en mobile apps. Sinds2008 is hij professioneel betrokkengeweest bij verschillende grote enkleine projecten in rollen als ontwik-kelaar, scrum master en consultant.

Op dit moment is hij werkzaam als Senior .NET developer bij Kembit en eigenaar van Verslu.is IT. Behalve het ontwikkelen vindthij het erg leuk om kennis te delen door te spreken, bloggen en artikelen te schrijven.Mail: [email protected]: @jfversluisWeb: http://verslu.is

MAGAZINE

12

Door de groeiende mogelijkheden ophedendaagse apparaten verwachtengebruikers dat ook

OPROEP!Lijkt het je leuk een bijdrage te leveren aan (het volgende) SDNmagazine?

We nodigen je van harte uit om een artikel te schrijven over jevakgebied,over ontwikkelingen en/ of achtergronden. Stuur jekopij naar [email protected], er zit een auteur in ons allemaal!

Page 13: SDN magazine 127

DELPHI Cary Jensen

While it can be useful to use DataSets in this way at design time, it can also be problematic. For example, if your application includesmany forms, you might end up with many different DataSets distributed across many of these forms, making it difficult to managethe various queries used by these DataSets.

Fig. 1. DataSets that are activated at design time can be used toview meta data and data during your design session

Many Delphi developers turn to data modules to simplify the use ofmany different DataSets. In those cases, the developers may place alarge number of DataSets on one or more data modules. While this approach consolidates the DataSets to a small number of modules, it adds another layer of complexity in that individual forms that use these DataSets must know to active, and then deactivate,individual DataSets that they need.

One alternative to using design time DataSets is to create your DataSets on an as-needed basis at runtime. While you lose the designtime visualization of your data, you gain greater control over individualDataSet lifecycle.In this article I am going to share a runtime DataSet framework that I have been using successfully in a number of applications. In this framework the DataSets used by a form are created on demand. In addition, this framework has the added benefit that it simplifies the use of parameterized queries, thereby avoiding any chance forSQL injection.

Runtime DataSets: The BasicsThe core element of this framework is a data module on which one ormore connection components are placed. In the data module

implemented in the code sample that accompanies this article thereis a single connection component, and it is a FireDAC connection. Thisdata module is shown in the designer in Figure 2.

Fig. 2. The data module in this article's code sample

In this particular data module there are two public methods: Active-Connection and ExecuteQuery. ActiveConnection does exactly whatit says, it makes the FDConnection active.

ExecuteQuery is a method that takes either two or three parametersand, if successful, returns an active FDQuery. The first parameter is astring that contains the SQL (structured query language) query to beexecuted, while the second parameter is a special record object thatcan hold the values of any parameters required by the query (we'llcome back to this record in a moment). The final, optional parameteris a TComponent reference, which, when supplied, provides theFDQuery's owner. As you surely know, an object's owner helps manage the lifecycle of an object, ensuring that if the owner gets freedthat the owned object is also freed.

ExecuteQuery and TSQLParamsOne of the key elements of this framework is the TSQLParams recordtype, a structure designed to hold the values of any parameters thatthe query might require. Here is the TSQLParams type declaration.

/// <summary>

/// A structure to hold the parameters of a parameterized

query

/// or stored procedure call

/// </summary>

TSQLParams = record

private

FSQLParams: array of variant;

Runtime DataSetsOne of the unique features of Delphi is its support for DataSets at design time. Specifically, youcan place a DataSet, such as an SQLDataSet or FDQuery on a form or data module, point it toa properly configured connection component (in this case, a SQLConnection or an FDConnection, respectively), and make that DataSet active at design time. You can then viewthe meta data of the DataSet using the Fields Editor or display the underlying data in data awarecontrols, as shown in Figure 1. This capability has been in Delphi since its first release, and todate few other development environments support this capability.

magazine voor software development 13

Page 14: SDN magazine 127

DELPHI

function GetSize: Integer;

public

constructor Create(Size: Integer); overload;

procedure SetSize(Size: Integer);

procedure Add(index: Integer; value: Variant);

procedure Reset(Size: integer);

function Value(index: Integer): Variant;

property Size: Integer read GetSize;

end;

In the simplest case, the record's overloaded constructor is called,passing to it the number of parameters required by the query. If oneor more parameters are required, you following the call to the con-structor with calls to the Add method of the record, one call for eachof the query parameters. The following code shows the implementa-tion of both the Create and Add methods of the TSQLParams type.

constructor TSQLParams.Create(Size: Integer);

begin

SetLength(FSQLParams, Size);

end;

procedure TSQLParams.Add(index: Integer; value: Variant);

var

i: Integer;

begin

i := Length(FSQLParams);

if (Index < 0) or (Index > i - 1 ) then

raise EIndexOutOfRangeException.Create

('Index out of range. Index must ' +

'be between 0 and ' +

IntToStr( i - 1 ));

FSQLParams[index] := value;

end;

Why, you might ask, is TSQLParams declared as a record, as oppo-sed to a class. I'm glad you asked, because it is one of the reasonswhy this framework is so simple. When a record is declared local to amethod or procedure, it is stored on the stack, and therefore is dis-carded when the subroutine exits. There's no need to free it (in fact,you can't free it, as records do not support destructors).

Another interesting aspect of the TSQLParams record is that it storesits parameters in a dynamic array of variants. This is convenient, sinceit makes it completely unnecessary to worry about the data type ofthe individual parameters. The data type of each parameter is deter-mined by the type of data you assign to the parameter, as well as thevalue of the predicates used in the WHERE clauses of your queries.This works nicely in part because all of the query DataSets that I amfamiliar with declare their TParam (or TParameter, depending on theDataSet) types as variants.Now that you understand the TSQLParameter record type, we canturn out attention to ExecuteQuery. Here is how ExecuteQuery is declared:

//...

public

function ExecuteQuery( QryString: string;

Params: TSQLParams; AOwner: TComponent = nil):

TFDQuery;

And here is how it is implemented.

function TDataModule1.ExecuteQuery( QryString: string;

Params: TSQLParams; AOwner: TComponent): TFDQuery;

var

i: Integer;

begin

Result := TFDQuery.Create(AOwner);

Result.Connection := FDConnection1;

Result.SQL.Text := QryString;

if Params.Size <> 0 then

begin

for i := 0 to Params.Size - 1 do

begin

Result.Params[i].Value := Params.Value(i);

end;

end;

Result.Open;

end;

As you can see, ExecuteQuery begins by constructing an FDQuerywhich is then wired to the available FDConnection. If an owner is provided, it is used in the constructor invocation (the query is createdwithout an owner if one is not provided). Next, the string representingthe query is assigned to the FDQuery's SQL.Text property. If the SQLstatement is parameterized (and parameters have been provided),these are assigned to the associated parameters of the FDQuery. Final,the FDQuery is executed, after which it is returned to the calling code.

There are three examples of queries that are executed using Execu-teQuery in this sample project. The first query is executed from theOnCreate event handler of the main form, and is used to populate theListBox on this main form with the customer numbers found in the underlying Customer table. In this case, since the query is created andfreed entirely within the OnCreate method, no owner is passed in theinvocation of ExecuteQuery, as shown in the following code.

procedure TForm1.FormCreate(Sender: TObject);

var

Query: TFDQuery;

Params: TSQLParams;

begin

DataModule1 := TDataModule1.Create(Application);

try

DataModule1.ActivateConnection;

except

CustomerQuery.Enabled := False;

OrdersQuery.Enabled := False;

exit;

end;

Query := DataModule1.ExecuteQuery(

'SELECT CustNo FROM Customer',

TSQLParams.Create(0));

try

while not Query.Eof do

begin

ListBox1.Items.Add(Query.Fields[0].AsString);

Query.Next;

end;

finally

Query.Free;

end;

ListBox1.ItemIndex := 0;

end;

MAGAZINE

14

Page 15: SDN magazine 127

DELPHI

The other two queries do identify an owner, which in both cases is theform on which the query results are displayed. This use of owner ensures that the queries are freed when the form itself is freed.Here is the code associated with the button labeled Customer Query,and it returns the record from the customer table associated with thecustomer number selected in the list box.

procedure TForm1.CustomerQueryClick(Sender: TObject);

var

Params: TSQLParams;

begin

FreeDataSetIfNecessary;

Params := TSQLParams.Create(1);

Params.Add(0, StrToFloat(ListBox1.Items[ListBox1.ItemIn-

dex]));

DataSource1.DataSet := DataModule1.ExecuteQuery(

'SELECT * FROM Customer ' +

' WHERE CustNo = :cust',

Params, Self);

end;

And here is the code associated with the button labeled Orders Query,and which makes use of two parameters. Figure 3 shows how themain form looks after a query associated with this button is executed.

procedure TForm1.OrdersQueryClick(Sender: TObject);

var

Params: TSQLParams;

e: Extended;

begin

if not TryStrToFloat( ItemsTotalEdit.Text, e) then

begin

ShowMessage( ItemsTotalEdit.Text + ' is not a valid num-

ber');

exit;

end

else

begin

FreeDataSetIfNecessary;

Params := TSQLParams.Create(2);

Params.Add(0, StrToFloat(ListBox1.Items[ListBox1.ItemIn-

dex]));

Params.Add(1, e);

DataSource1.DataSet := DataModule1.ExecuteQuery(

'SELECT * FROM Orders ' +

' WHERE CustNo = :cust ' +

' and ItemsTotal > :val',

Params, Self);

end;

end;

Both of these methods make use of a utility method called FreeData-SetIfNecessary. This method ensures that whatever FDQuery is assigned to the data source is freed explicitly before a new FDQueryis created. This step ensures that only those FDQueries that are currently in use are in memory, and those which are no longer neededare freed without waiting for the form (the owner) to be destroyed. Thefollowing is the implementation of FreeDataSetIfNecessary:

procedure TForm1.FreeDataSetIfNecessary;

begin

if DataSource1.DataSet <> nil then

DataSource1.DataSet.Free;

end;

Fig. 3: A query with two parameters has been executed using ExecuteQuery

The Benefits of ConsolidationIf you have never used a technique like this before, you might question its utility, especially in light of the fact that you lose the designtime visibility of data. But there are a number of benefits to the consolidation of your project's queries into one, or a small handful, ofmethod calls. For example, let's say that you decide that you want re-cord how long each of your queries take to execute. Using the ap-proach outlined in this article, doing so is simple. By adding a few extralines of code that measure how long the query execution takes to theExecuteQuery method, and writing these results to a table on yourdatabase, you can instantly profile all the queries in your application.Similarly, if you want to log the individual queries, along with the valuesof the parameters passed to these queries, that too is easy, requiringonly the addition of some code to your one ExecuteQuery method.Yes, you need to make sure that you code is efficient and stable, sinceit will be executed with every query. On the other hand, once you getit right, it's correct across your application.

Authors note: Logging queries and their parameters can uninten-tionally expose sensitive data. You need to keep this in mind, andtake proper precautions, if you decide to implement query logging.

For features like these, profiling and logging, you should also considermaking these features easy to turn on and off, using some outsideconfiguration such as through a database configuration table or an inifile. That way you can turn profiling or logging on when you need if fortesting, and leave it off the rest of the time, in order to maximize theperformance of your queries.The sample project shown in this article can be downloaded from thefollowing site. Note that it was created in Delphi X Seattle. If you areusing a different version of Delphi, you might need to adjust the data-base parameter of the FDConnection on the project's data module topoint to the correct location for the sample DBDemos.gdb databasein your version of Delphi.http://www.JensenDataSystems.com/Runtimedatasets.zip •

Cary Jensen

Cary Jensen is Chief Technology Of-ficer of Jensen Data Systems. Since1988 he has built and deployed da-tabase applications in a wide rangeof industries. Cary is an Embarca-dero MVP, a best selling author of

more than two dozen books on software development, and holdsa Ph.D. in Engineering Psychology, specializing in human-com-puter interaction. His latest book is Delphi in Depth: ClientDataSets2nd Edition. You can learn more about this book athttp://www.JensenDataSystems/cdsbook2.

magazine voor software development 15

Page 16: SDN magazine 127

GENERAL

Looking at this project from a mile high, it appears to be a regular construction project. The requirements were specified, the contractorcame up with a price and a date, and about a year-and-a-half laterthe project was delivered. One might suggest that this model for construction projects is a fairly suitable model for software develop-ment projects as well. You specify the requirements, set the price anddelivery date, and of you go. And many managers and project managers actually do suggest this model for software developmentprojects, supported by the fact that we have been using this modelsince the seventies, most often referred to as waterfall or linear.Unfortunately, the waterfall or linear model, where we identify with allthe requirements and pour them in concrete before we start the actualconstruction, doesn’t really work that well. Many, many contractorsfail to meet their budget or deadline, or only deliver a very small partof the agreed requirements. Recent publications on large governmentprojects in the Netherlands show dramatic negative results and failingprojects.

Clients blame contractors, and contractors in their turn blame clientsfor demanding the projects to be executed following this linear model.Many projects end in court and our beloved software developmentdiscipline has a negative public image.

So where does it all go wrong? Let me try and explain.

Software development is a very young disciplineWhen we try to model our software development projects to a metaphor coming from civil engineering we bypass the notion that civilengineering has been around for thousands of years. There is a worldof experience and knowledge in construction from the Babylonians,the Greek, the Egyptians, the Middle Ages, Renaissance and industrialrevolutions. Two thousand years ago the Romans already used concrete. All this experience contributes to how construction projectsare executed today.

In 2009 I hired a building contractor to build a house. Together with an architect and the con-tractor I worked out the features. We wanted a basement, we carefully picked the materials, thelocation of the windows, the placement of the rooms, the bathroom, the attic and everything thecontractor needed to come up with a price and a delivery date. About a year-and-a-half laterthe house was completed.

Why the project metaphor doesn’t fit software development

Sander Hoogendoorn

MAGAZINE

16

Roman concrete

Page 17: SDN magazine 127

GENERAL

Continuously I get the response that if all the features are deliveredon-time and on-budget the project is a success. But is it?

Please consider Microsoft Word. A product with thousands of features of which most people only use a very limited number of.Would it have been a successful product even if it only delivered thislimited set of features? For a fraction of the budget it now took tobuild? My guess is it would. I traded in Microsoft Word for a simple,straightforward text editor long ago.

What if, instead of using the project model decides to build our software feature by feature? And if we would only build the minimumversion of those features that does just enough. We could continuou-sly ask the client how he of she wants to spend the next bit of time andmoney. Should we build a more fancy version of the current feature,or the minimum version of the next feature on the list? Every productbuild like this would have the minimum set of features, built for a minimal budget in a minimal amount of time. Delivered earlier than itwould have been using a project model – linear or agile for that matter. Delivered cheaper that using a project model. And with onlythose features we really need. Built like this, Microsoft Word wouldhave been a lean and mean editor, without all the abundant featuresit now has.

How many feature do you need in a text editor?

So I rest my case. In my opinion software should not be built using aproject model. Never. Software should rather be implemented featureby feature, delivering a minimal viable product. And in case you’rewondering, my house was neither delivered on-time nor on-budget. So please stop doing projects. •

Software development on the other hand is a very young discipline.Where mathematics and concrete have been around for a very longtime, programming languages are only about sixty years old. Hence,applying a project model from a discipline from a thousands years olddiscipline might not fit very well. We just don’t have this experience.Yet.

Construction projects also failNevertheless, even with these thousands of years of experience andtechnology development, construction projects using this one-passmodel also still fail. Right after my new house was delivered by thecontractor, we started noticing a terrible smell from the toilets. Aftertwo weeks the situation got worse. We couldn’t even flush the toiletanymore. The system was totally constipated. To cut a long storyshort, the contractor had totally forgotten to connect the house to thecity’s central sewerage. Repairing this “bug” meant that my just finished garden was ruined.So the single-pass model doesn’t really fitconstruction either. And building a single house is not that big a project. When you investigate much larger construction projects, projects that have actually implemented the agreed requirements on-time and on-budget are exceptions, not the rule. So if constructionprojects don’t even work on a linear model, how could software development projects?

In software development requirements can changeAnd there is more. When I had my house built, I needed to take a lotof decisions up front. Although I didn’t have to decide about how highon the wall the sockets were going to be placed, it isn’t hard to figureout that adding a basement after a house is fully completed is a lot harder than installing it before the floors are added. And the same goesfor the sewerage. You could well say that most of the architecture anddesign needs to be done up-front. Software development however, isvery, very different. Software can always change. Even late in a project we can change our requirements, the user interface, and eventhe architecture. Therefore, we do not need this big up-front design.

The fact that (too) many projects still rely on this big up-front design,is because we are applying the wrong model to our projects. Applying a big up-front design in software development projects hasa negative effect on the outcome of these projects, because it disallows change. And change is beneficial. Being able to change during a project, even late in the project, simply improves quality, andimproves the ability to maximize the benefits of the software we buildfor our clients. The fact that we can change our requirements, design and even ourarchitecture make software development projects very different otherconstruction projects. Software is fluid, non-linear, and we should benefit from this.

Projects are not the right metaphorAnd in my opinion, that’s not all. As said, after we worked out the features of my new house my contractor came up with a price and adelivery date. So we fixed the features, the price and the delivery date.Essentially the same three factors that are used to monitor the successof software development projects. Often I ask project managers todescribe when they consider their projects to be successful.

Sander Hoogendoorn

Sander is an independent consul-tant; as a mentor, trainer, coach,software architect, developer, writer, speaker, for his company ditisagile.nl (after the Dutch title ofmy latest book This Is Agile).Over the past decade, in my rolesas Principal Technology Officer andGlobal Agile Thoughtleader at

Capgemini. During this period I’ve learned a great deal and havecontributed to the innovation of software development at Capgemini and its many international clients.

magazine voor software development 17

Page 18: SDN magazine 127

.NET Danny van der Kraan

I have introduced Dependency Injection by giving an example in whichwe show some late binding [1]. After that I've showed a possible routeto take if certain dependencies depend themselves on run-time values [2]. And there's an article about how to apply Aspect OrientedProgramming (AOP) by using Dependency Injection's Interception [3].Now I'd like to talk about how Inversion of Control (IoC) via Depen-dency Injection (DI) helps you write better unit tests and eventuallyapply Test Driven Development (TDD). But before we can do that I feelwe should first talk about automated tests itself. Because these arecrucial for doing healthy TDD. In particular I noticed some confusionabout integration tests and unit tests. So what is the definition of aunit test? What is a good unit test? And why does this difference matter so much?

Integration Test versus Unit TestTo get a good grip on this I think we should compare integration testswith unit tests.

Fig. 1: Integration testable

Integration TestMost automated tests are actually integration tests. It doesn't matterif you used MS Test’s Unit Test item template. Whether a test is an integration test or not is actually about what is tested factually. If the'unit of work' under test actually spans a couple of components working together, often including external components like a database, a file, a web service, etc., to test if they all play their part,then it is an integration test.

Fig. 2: Unit testable

An integration test is allowed to be slow, due to its nature. That is whyoften they are run during a nightly build or something similar. Figure 1illustrates connected code components which would have to be tested via an integration test with long running processes like callinga web service, persisting data in the database and writing data to a fileon the hard drive.

Unit TestTests that define a clear 'unit of work', without any external componentinvolved, and just enough components to test that what must be tested, is an unit test. To emphasize the remark about external components; a unit test can't extend to persistence layers like data-bases, or files on disk, or web services somewhere on the internet.And if too much components are involved, the test does too muchand can't be read easily.Unit tests are for teams to keep proving codestill works as intended. Components not directly involved in the cur-rent test need to be faked (stubbed or mocked).

Synopsis: An example in which we walk through a case in which Dependency Injection madewriting automatic tests, and in particular unit tests, a delight. Which also makes the disciplineTest Driven Development much more an option. Find the example used for this post on my GitHub: [9]

Unit Testing made easy with Dependency Injection

MAGAZINE

18

If you don't care about TDD, it is perfectly fine to focus on the fact thatwriting automated tests (unit tests inparticular) is very easy if you apply DI

Page 19: SDN magazine 127

.NET

Don't worry if some terms are not familiar. I am working on an in-deptharticle about unit testing and TDD, but if you read "The Art of Unit Tes-ting" by Roy Osherove [4] you will know everything you need to knowand more! He has for instance an extensive (and much better) definition of a unit test on his website [5]. Figure 2 illustrates with redcrosses where the connections in figure 1 would need to be severedto make it unit testable:

So why does this matter?Unit Tests need to be fast, concise and easy to read. In an Agile Scrumenvironment for instance where you need to release a potentiallyshippable increment at the end of every sprint you need to maximizeyour feedback loops. You want to know on codebase level at everymoment if everything is still in order. That is why a Scrum team shouldstrive for automated unit tests that fire off with every source controlcheck in. And that is why they need to be fast. Because if they areslow you don't want to fire them off with every check in. And becausethey need to be fast and need to tell you at a glance where somethingis wrong, they need to be small and concise. Because they are smalland concise you will have a lot of tiny unit tests. And the Scrum teamwill need to maintain them. If unit tests are not readable they will be ignored and poorly maintained, effectively killing off the effect of unittesting. I've summarized this in figure 3:

Fig. 3: Maximize feedbackloop

Now that I've illustrated the difference it is time to move on to actualCode, Build, Test!

Unit test without DII started adding (as I thought) unit tests to the solution. It has beenproven to be a good practice if you make a separate project for yourtests and keep them out of your main project [6]. I started out by usingthe Unit Test Project template. All this mainly does is add the correctassemblies to start using MS Test basically. Plus the tests show up inVisual Studio's Test Explorer out of the box. For this example however I've used XUnit instead of MS Test (if you are interested inmy reasons why you can check out a post at Mark Seemann's blog[7]). The tests and classes from figure 1 would look like Listing 1.

So what are the problems with the unit test above? The test takes toolong. And it needs to assert too much. If you add up the millisecondsyou'll be looking at 8000 milliseconds in total. Of course fictive and abit exaggerated for the purpose of this example, but even half of thatwould be way too much for a simple unit test. This is caused by callsto external components which simply take longer processing time.

Listing 1: First attempt at SomeService and its unit test

So as figure 2 showed us we need to sever the connections (read:Dependencies) and actually not write something to the database, or call a web service, or write a log file, if we simply want to unit testDoStuff. To be able to do this we need to stop initializing everything inthe DoStuff method. That is where Dependency Injection is going to help us. Listing 2 shows our second attempt with ImprovedSome-Service:

magazine voor software development 19

Page 20: SDN magazine 127

.NET

MAGAZINE

20

Listing 2: ImprovedSomeService

And the unit test could be something along the lines of:

Listing 3: Second attempt at unit test with ImprovedSomeService

As you can see in listing 3 Dependency Injection makes it very easy tofake all the components that are not needed in the 'unit of work' athand. In this example the free library FakeItEasy [8] is used to createmocks and stubs. The unit test begins by making some fakes (FakeI-tEasy makes syntactically everything a fake and the context decideswhether it is used as a mock or a stub). These fakes are injected intothe service via its constructor. Then the test simply proceeds by asserting if some calls to certain methods actually happened and whether the return value is true from the method DoStuff. This test isfocused and concise, plus the time this test takes is not even worthmentioning.

TDDIt should be easy to see via listing 3 how Dependency Injection canmake your pain with TDD a little lighter. Let's throw the familiar diagramon here to provide some context:

Fig. 4: TDD cycle

As you know you write the test first, so imagine we had the requirement to 'do' some 'stuff'. I write the test first, so I try to call aDoStuff method which didn't exist. This is the red state. I generate themethod. The test becomes green. I refactor this by making SomeService class, putting the DoStuff method in there and initializing SomeService to call DoStuff on it in the test. And you repeat the process by wanting to know in the test if DoStuff failed orsucceeded. The test is red. DoStuff needs a Boolean return value andwe return true in the method. Test is green. During refactoring we couldfor instance only return true if some operation actually succeeded.This operation could for instance be putting stuff in the database. So in the DoStuff method of SomeService I call WriteStuffToDb on thenon-existent class SomeRepository. Making the test become redagain. I generate the class and the method. I am not interested rightnow in the actual implementation of the call, so to make the test greenI fake the class and test if the method is called at all. Then I refactorthis so the implementation of ISomeRepository is injected through theconstructor making it easy for the next iterations to insert dummy repositories. And so on...

ConclusionI showed you the difference between integration tests and unit tests.Then I showed you how Dependency Injection makes unit testing a loteasier. Finally I brought some TDD into the mix. You can find all thecode and more on my GitHub: [9].

Links1. Introduction Dependency Injection: https://dannyvanderkraan.wordpress.com/2015/06/15/real-world-example-of-dependeny-injection/

2. Dependency Injection based on run-time values:https://dannyvanderkraan.wordpress.com/2015/06/29/real-world-example-of-dependency-injection-based-on-run-time-values/

Used Ninject as IoC Container because the API is awesome!

Page 21: SDN magazine 127

.NET

magazine voor software development 21

3. AOP with Interception:https://dannyvanderkraan.wordpress.com/2015/09/30/real-world-example-of-adding-auditing-with-dependency-injections-intercep-tion/

4. Art of Unit Testing: http://artofunittesting.com/

5. Definition of a Unit Test: http://artofunittesting.com/definition-of-a-unit-test/

6. Great discussion about seperate projects for tests: http://stackoverflow.com/questions/2250969/should-unit-tests-be-in-their-own-project-in-a-net-solution

7. Reasons for XUnit: http://blog.ploeh.dk/2010/04/26/WhyImmigratingfromMSTesttoxUnit.net/

8. FakeItEasy: https://github.com/FakeItEasy/FakeItEasy

9. GitHub: https://github.com/DannyvanderKraan/DependencyInjectionMak-es UnitTestingSimple •

Windows HelloIn het vorige magazine hebben we al iets laten zien vanWindows Hello (http://windows.microsoft.com/en-us/windows-10/getstarted-what-is-hello). Eigenlijk is hetde verzamelnaam om op andere wijze in te loggen danmet een gewoon wachtwoord. Zoals bijvoorbeeld een Picture wachtwoord, maar ook een vingerafdruklezer enmet je gezicht kun je inloggen.Wist je dat de Xbox de mogelijkheid om in te loggen metje lichaam al veel langer heeft? Daar konden door de Kinect camera de verschillende spelers herkent worden.Feitelijk was dat de eerste versie van Hello.

In de nieuwe hardware van Microsoft Surfacebook, Surface Pro 4 en Lumia 950 zit standaard een camera diegeschikt is voor het inloggen met je gezicht. Het is nu ook mogelijk je Kincect V2 for Windows te gebruiken. De drivers daarvoor zijn in Public preview. Via de Kinect for Windows Developers news kun je meerinformatie krijgen. In een volgend magazine komen we hierop terug.

https://www.youtube.com/watch?v=UErzChu7sVI

Danny van der Kraan

Danny van der Kraan is a passio-nate software engineer with a widearea of interest. From desktop ap-plications with WPF MVVM andMSSQL to distributed architectureswith NServiceBus, Azure Storageand ASP.NET MVC. Currently wor-king for Sound of Data with cutting

edge technologies to provide all kinds of innovative solutions in awide area where means of communication (phone, SMS, What-sApp) and customers meet. Follow these adventures on the blog:https://dannyvanderkraan.wordpress.com/

Page 22: SDN magazine 127

DIVERSEN

Windows Phone 950 XL

Lang is er uitgekeken naarhet vlaggenschip telefoonvan Microsoft, de Lumia950.

Fig. 2: Lumia 950XL

Deze is er in twee varianten een gewone (5.2 inch) en een XL(5.7 inch). Deze telefoon zijn standaard uitgerust met Windows 10. Alsje al gespeeld hebt met de previews van Windows 10 Mobile, dan kenje de verschillen al. Mocht je nog niet zover gekomen zijn of je daar nogniet aan gewaagd te hebben, dan hier een paar. Bij Windows 8.1 wasbijna alles gedaan vanuit het oog van de telefoon eigenaar. De peoplehub was ver geïntegreerd met de verschillende social networks. Als jeeen contact selecteerde dan kon je (mits aanwezig) ook zijn activitei-ten op de social networks zien. Dit is geen onderdeel meer van decontact lijst van Windows 10. De Mail client is gewijzigd en is nu deUniversal app die we ook op andere platformen kennen.

Persoonlijk vind ik het erg prettig werken, maar als je veel gebruiktmaakte van de linked mailboxes dan ga je dat missen. Je kunt de verschillende mailboxen wel apart pinnen op je startscherm. In eenvergelijking tussen de 950 en 950XL hebben we gezien dat de mailapp zich wel anders gedraagt bij de hogere resolutie van de XL.

En zo zijn er nog wel een paar dingetjes. De vierkante plaatjes zijn nurond en we hebben de beschikking over de Edge browser.

In oktober Microsoft kondigde veel nieuwe hardware aan. Uiteraardwas daar de vierde opvolger van de Surface Pro, maar ook een Surfacebook, Band 2 en nieuwe telefoons. De laatste twee werdenverwacht en iedereen keek er reikhalzend naar uit. Nu zijn alle aangekondigde devices verkrijgbaar en heb ik ze de afgelopen veel-vuldig gebruikt. Laten we ze een voor een aflopen.

Surface Pro 4Surface Pro 4 is het enige device dat ik niet gekocht heb. De grootsteverschillen ten opzichte van de Pro 3 zijn niet al te groot. De webcambevat nu ook een infrarood camera waardoor deze te gebruiken is metWindows Hello (zie elders is dit magazine). Ze hebben uiteraard deCPU geüpgraded, maar ook het scherm iets opgerekt zonder het apparaat groter te maken. Dat is handig, want nu is de docking-station van de Pro 3 nog steeds bruikbaar.

Met deze nieuwe versie is er wel een upgrade gekomen van de Type-cover. Het typevermogen op de vorige type cover kwam al redelijkovereen met een normaal toetsenbord, maar daar is nu een extrastapje gemaakt. Tussen de toetsen zit nu iets meer ruimte en de toet-sen lijken iets hoger. Het mouse pad is breder. Er is ook een variantmet een fingerprint reader. Deze is er vooralsnog alleen in het zwart enniet verkrijgbaar in Nederland.

Fig. 1: Typecover

Handig aan dit toetsenbord is de FN toets. Daarmee kun je aangevenof de toetsen aan de bovenkant zicht moeten gedragen als Functietoetsen of de Windows 10 functies moeten uitvoeren (geluid harderzachter etc). En deze knop kun je locken, dus je hoeft nooit meer ver-schillende toetsen gelijktijdig ingedrukt te houden.Deze upgrade van de type cover kan ook gewoon gebruikt worden opde Pro 3.

Het mooie van Windows 10 is, dat op zowel je Raspberry PI 2 als op je computer/laptop je opeen manier kunt ontwikkelen. Een Universal Windows App voor je laptop Windows zal zonderveel aanpassingen kunnen draaien op een Raspberry PI 2.

Marcel Meijer

Microsoft hardware

MAGAZINE

22

Page 23: SDN magazine 127

DIVERSEN

magazine voor software development 23

Fig. 3: 950 XL met Windows 10 Mobile en 930 met WindowsPhone 8.1

Hier en daar is het even wennen, maar over het algemeen kan ik erprettig mee werken zowel zakelijk als privé.Een grappige gimmick is de integratie met Windows Hello. De cameraondersteunt nu ook deze functie. Dat doet hij redelijk goed, ook in hetlicht en in het donker. Het staat wel een beetje raar om je gezicht zodicht bij het scherm te houden.

Ander gave gimmick is Continuum. Het is al veel gezegd, maar onzetelefoons van tegenwoordig zijn krachtiger dan de computers van bijvoorbeeld de Spaceshuttle.

Dus waarom zouden we een telefoon niet op een scherm kunnen aansluiten voor de meest voorkomende zaken zoals browsen, mail of documentverwerking. Tegenwoordig zijn al onze zakelijke toepassin-gen als webapplicatie beschikbaar en dus kunnen we met een thinclient prima uit de voeten.

Met de los verkrijgbare Display dock kun je Lumia 950aansluiten op een HDMI scherm. Op de dock zitten

USB poorten voor bijvoorbeeld een toetsen-bord of muis. Uiteraard kunnen

deze ook via Bluetooth aangesloten worden.

Fig. 4: Display dock

Fig. 5: Continuum in werking

Het koppelen aan een scherm kan ook via de Microsoft Wireless Display adapter. Dat scheelt nog meer kabels.

De applicaties die nog niet beschikbaar zijn, zie je als donker in hetStart menu. Dit lijkt mij een goede toekomst te hebben, zeker voorsales presentaties etc. Nu nog een high definitie handzame beamer ofeen beam functionaliteit op een telefoon.

Fig. 6: Bands

Microsoft BandTwee jaar geleden kwam ineens de Microsoft band in beeld. Niemandwas er op voorbereid en zag het ding aankomen. De voorraad was beperkt en de belangstelling was erg groot. De band was een Fitnessband met Smart watch functionaliteit (daar komt nog een artikel over).Na de eerste opwinding kwamen natuurlijk de minpunten naar boven.Het apparaatje is nogal vierkant en het laadpunt zat op een ongeluk-kige plek, daar was hij onderhevig aan corrosie. Maar over de functionaliteit was iedereen het eens, een mooie apparaat.

Veel van de commentaren heeft Microsoft gehoord en een oplossingvoor bedacht. Met de nieuwe versie is hij minder vierkant en is hetaansluitpunt verplaatst naar de sluiting weg van zweet en vocht. Hij isook meer gestyled met een gebogen scherm en een premium uitstraling. Aan de functionaliteit is niet veel gedaan, want dat zat redelijk snor.

SurfacebookDe grote verrassing bij de presentatie van de nieuwe hardware was deSurfacebook. Hoe goed de Surface Pro 3/4 ook is, door het toetsen-bord wiebelt het als het in je schoot ligt. De meeste laptop liggen enwerken dan gewoon beter. De Surface Pro is ook eerst een tablet endan een laptop. De Surfacebook heeft een vast en stevig toetsenbord.

Page 24: SDN magazine 127

DIVERSEN

MAGAZINE

24

Fig. 7: Surfacebook

Het toetsenbord heeft dezelfde indeling als de nieuwe Typecover.Met behulp van een knop kan het scherm losgekoppeld worden enheb je alsnog een tablet.

Fig. 8: Surface Pro, Samsung, Surfacebook

De Surfacebook is ruim groter dan een Surface Pro. Maar valt absoluut niet in het niets bij de andere normale laptops. Ik heb hemkunnen vergelijken met een Lenovo Yoga Pro 3. De Yoga heeft eenbreder scherm, maar voor de rest doet hij niet onder.

In het begin was ik niet heel erg tevreden. De hardware en softwarewaren niet goed op elkaar afgestemd, waardoor het ding regelmatighing of niets meer wilde doen. Dat is nu heel anders, er zijn twee firmware updates geweest en die hebben veel pijnpunten opgelost.Mijn Surfacebook doet wat ik er van verwacht en ligt lekker in mijnschoot als ik aan het werk ben op de bank.

ConclusieMicrosoft heeft met hun nieuwe Windows 10 hardware laten zien datze terug zijn waar ze ooit begonnen zijn. De hardware begint er steedsmooier en gestyled uit te zien.

Ze luisteren ook naar de op- en aanmerkingen uit de markt/commu-nity. Helaas geven ze weinig feedback via deze kanalen terug. Leukespullen voor onder de boom of in de Sinterklaaszak. •

Marcel Meijer

Marcel is Teamlead van het Devel-opment team bij ifunds. Wij makenproducten voor ledenadministratiesen goede doelen gebaseerd op Dynamics CRM. Daarnaast is Marcel voorzitter, bestuurslid, eventorganisator en eindredacteur bij deSDN. Sinds 2010 mag hij zich MVP noemen.

Page 25: SDN magazine 127

SDN > Update

magazine voor software development 25

Delphi Nieuws

Na het XE tijdperk, dat 4 jaar geleden begon en in totaal 7 releaseskende, is het nu tijd voor het Delphi 10 tijdperk. Embarcadero blijftvasthouden aan een nieuwe versie elke 6 maanden, dus rond april2016 kunnen we de volgende Delphi 10 verwachten, maar dan misschien 10.1, en met een andere stadnaam. Misschien deze keereen stad uit Europa. Het zal wel geen Helmond worden, maar misschien Parijs of London (of Milaan, waar de huidige Delphi Productmanager vandaan komt).

IderaEen andere optie voor de volgende stadsnaam bij Delphi is Houston.Dat is namelijk de stad waar de nieuwe eigenaar van Delphi vandaankomt: Idera. Voor wie het nog niet gehoord had: nog maar korte tijdgeleden heeft Idera het hele bedrijf Embarcadero overgenomen, inclusief dus de ontwikkelafdeling die Delphi, C++Builder en RAD Studio maakt. Idera maakt database tools, en dat doet Embarcaderoook, en de koop was met name bedoeld om de bestaande (maar ooknieuwe) klanten van Idera een complete(re) verzameling tools en oplossingen te bieden. Dat de Delphi ontwikkelafdeling er ook bij zat,wat een bonus, maar vanuit Idera gezien niet een onwelkome. Deontwikkeltools, en dan met name Delphi, zijn van strategisch belang,omdat de database tools van Embarcadero in Delphi zijn geschreven.De naam Embarcadero zal overigens (voorlopig) gewoon blijven bestaan, dus een hoop klanten en gebruikers zullen niks merken (of gemerkt hebben) van de hele overname.

Updates en SubscriptionWat wel een verschil is ten opzichte van een jaar geleden is het belangvan een actieve subscription (in de USA steevast "update subscrip-tion" genoemd). Het bestaat inmiddels al bijna 10 jaar, en was tot voorkort de goedkoopste manier om jaarlijks aan je nieuwe versie van Delphi, C++Builder of RAD Studio te komen. Subscription kan je afsluiten bij de aankoop van een New User of Upgrade, en is dan geldig voor een periode van 12 maanden (waarbij je voor het aflopenvan deze periode, deze steeds weer kan verlengen met opnieuw 12maanden, tegen een prijs die elk jaar met zo'n 4% omhoog gaat).Naast de nieuwe versies, kreeg je bij een subscription ook jaarlijks 3zgn. "incident support calls" met Embarcadero zelf, voor problemenen/of bugs waar je zelf (of met je reseller) niet uitkwam. Dat heeft heelwat mensen geholpen om workaround of oplossingen te verkrijgenvoor problemen die kennelijk niet vaak genoeg voorkwamen om ineen reguliere update of hotfix van Delphi op te laten lossen.

Sinds een aantal jaar zijn er geen één maar twee releases van Delphiper jaar. En dus is het nog goedkoper om je subscription actief tehouden, zeker vergeleken met de optie om maar eens in de 2 of 3nieuwe versies een upgrade te kopen.Sinds dit jaar is er echter nog een groot verschil: wie Delphi, C++Buil-der of RAD Studio koopt zonder subscription daarbij af te sluiten,

die krijgt alleen de zgn. RTM versie, plus eventuele kritische bug fixesof updates. Maar niet de niet-kritische bug fixes of uitbreidingen. Zokwam XE8 Update 1 in twee versies uit: een kleine variant voor wiegeen subscription had, en een volledige versie met alle fixes voor wiewel subscription had.

Vanaf Delphi 10 Seattle is het nog wat explicieter geworden: Update#1 is alleen uitgekomen voor mensen met subscription. Er zijn kennelijk geen kritische fixes gedaan waar iedereen (zonder subscrip-tion) van kan profiteren.

Dit klinkt misschien als zeer onredelijk, maar vanuit het oogpunt vanEmbarcadero (en Idera) is het een kwestie van het belonen en bedienen van je trouwe klanten. En het blijft niet bij de laatste versievan Delphi, want inmiddels zijn er ook updates uitgebracht met defixers in Delphi 10 en Delphi XE8 die je in Delphi XE7 en XE6 kan gebruiken. Deze updates zijn dan alleen beschikbaar voor wie een actieve subscription heeft, maar het zorgt er wel voor dat je dus ookje oudere versies van Delphi kan blijven gebruiken. Je bent niet verplicht om de meest recente versie van Delphi te gebruiken zodradeze uitkomt; ook oudere versies (in dit geval tot 3 versies terug) worden nog onderhouden. En als je een project gestart bent in DelphiXE6 dan kun je nog steeds van de meest recente bug fixes profiteren.Dat was vroeger nauwelijks het geval; zodra een nieuwe versie uitkwam hoefde je echt nauwelijks meer te rekenen op fixes voor oudere versies.

Tot slot nog een speciale aanbieding: wie Delphi, C++Builder of RADStudio 10 Seattle heeft aangeschaft, maar daar toen geen subscrip-tion bij nam, en daar inmiddels - na het uitkomen van Update #1, ende updates voor oudere versies van Delphi - een beetje spijt van heeft,die kan nog tot 15 december alsnog subscription aanschaffen. Dieloopt dan niet meer voor een jaar, maar van het moment dat de Delphi 10 licentie werd aangeschaft. Maar dat is in ieder geval wel eengoedkope manier om aan de updates en nieuwe versies te komen.

Delphi 10 Seattle Update #1 hotfixesDe tijd vliegt. Twee jaar geleden zaten we nog aan Delphi XE5 Update #2, vorig jaar deze tijd aan Delphi XE7 Update #1, maar inmiddels zitten we in een nieuw cyclus van releases: Delphi 10 Seattle, waarvan Update #1 november is verschenen, en een tweetal hotfixes op deze update in december. Seattle is trouwens gekozen omdat dat zowel de stad is waar Microsoft (Redmond)als Amazon.com hun hoofdkwartier hebben.

Korting van 5%voor SDN ledenVoor SDN leden geldt nog steeds de aanbieding van Bob SwartTraining & Consultany betreffende 5% korting op een Delphi ofRAD Studio licentie als er tegelijkertijd een subscription wordtafgesloten. Zie http://www.eBob42.com/SDN voor meer details.

Page 26: SDN magazine 127

ALM Cornell Knulst

Waarom eigenlijk NuGet in de enterprise?Het op een goede manier inrichten van software configuratie management (SCM) onderdelen als versie-, artifact1- en dependencymanagement is vandaag de dag belangrijker dan ooit. Dit als een gevolg van steeds complexer wordende software projecten. Waar inhet verleden systemen vaak als grote monolieten uitgerold werden opeen enkele productieomgeving, worden vandaag de dag systemengebouwd middels het samenvoegen van verschillende componenten2

die vaak ook nog gedistribueerd uitgerold worden. Het is vaak een uitdagende en complexe taak om dit op een goede manier uit tevoeren en bij te houden.

Tevens wordt vandaag de dag steeds meer gebruik gemaakt van third-party componenten. Dit brengt mogelijke veiligheidsrisico’s met zichmee. Wist u bijvoorbeeld dat het gebruik van een <4.2.1 AntiXSS library kan leiden tot het vrijgeven van vertrouwelijke informatie3? Deste belangrijker is het daarom om inzicht te hebben in de dependenciesvan uw softwarecomponenten. Maar hoe dit te bereiken? Hoe houdenwe bij welke dependencies ons component heeft op andere

componenten? Hoe secure zijn deze dependencies (zowel intern alsextern)? Wat als er een nieuwe versie van een dependency beschik-baar komt? En hoe komen we erachter wat de indirecte dependencieszijn waar ons component van afhankelijk is? Het is exact bij dit soortdependency management vragen waar het gebruiken van NuGet helptin het vinden van een antwoord, mits het compile-time linking betreft.

De bovengenoemde vragen zijn echter slechts wat vragen omtrentdependency management. Bij het introduceren van NuGet zal ook rekening gehouden moeten worden met de versiemanagement en artifact management onderdelen van SCM. Denk hierbij aan vragenals: waar bewaren we de artifacts van onze componenten? Hoe zorgen we ervoor dat deze artifacts centraal benaderbaar zijn zodatwe vanuit ons component kunnen linken naar deze gedeelde artifacts?Welke licentieovereenkomsten gelden voor het third-party artifact gebruik? En welk versienummer geven we de verschillende artifactsvan de komende release?

Het zal niet verbazen dat het goed implementeren van NuGet in uw organisatie vanwege deze vele aspecten van SCM een complexeexercitie kan zijn. Aan de andere kant kan een goede implementatieveel kwesties die er zijn op het gebied van SCM oplossen. Onder-staand een opsomming van de meest geziene kwesties:

• KW01 - Er is onduidelijkheid over de locatie op een share of in hetversiebeheersysteem waar de juiste versie van een artifact gevon-den kan worden;

• KW02 - Het is niet eenvoudig om het versienummer van een artifactte achterhalen wegens een onjuiste toepassing van de assemblyversion attributes4;

• KW03 - Er is onduidelijkheid over de bij elkaar horende set van gedeelde artifacts omdat artifacts als losse eenheden worden opgeslagen op een filesystem, share of in het versiebeheersysteemen er geen registratie van bij elkaar horende artifacts wordt bijgehouden;

MAGAZINE

26

Met de introductie van NuGet in 2010 kregen we als .NET community eindelijk een eigen package manager. Een concept dat we met name te danken hadden aan het succes van Mavenbinnen de Java community. Toch wordt de NuGet technologie, nu, 5 jaar later, binnen veel enterprise organisaties nog slechts beperkt gebruikt. Hoewel NuGet dankzij de opkomst vanopen source vaak nog wel gebruikt wordt voor het managen van de third-party afhankelijk-heden, wordt het slechts beperkt gebruikt voor het managen van de afhankelijkheden tusseninterne softwarecomponenten. Dit is best opmerkelijk wanneer je bedenkt dat NuGet juist opdit gebied veel voordelen kan bieden. Dit artikel heeft daarom als doel u een inkijk te geven inhet gebruiken van NuGet in de enterprise, inclusief de potentiële voordelen en een stappenplanom het versneld in te kunnen regelen.

Getting started metNuGet in de enterprise

1 Definitie artifact: een resulterend outputbestand van een build2 Definitie component: een eenheid van software die onafhankelijk te vervangen en te updaten valt (Martin Fowler).3 Zie https://technet.microsoft.com/nl-nl/library/security/ms12-007.aspx.4 Zie http://bit.ly/1OZUbxV voor de verschillende opties

Page 27: SDN magazine 127

ALM

magazine voor software development 27

• KW04 - Er is geen inzicht in de versie-specifieke afhankelijkhedentussen de verschillende softwarecomponenten;

• KW05 - Dependency management tussen componenten is ingeregeld middels het van elkaar afhankelijk maken van de verschillende componenten builds en hun output. Componentenhebben hierdoor geen eigen deployment pipeline meer en ook eendeel van de individuele componenten builds is hierdoor niet herhaalbaar

Kwesties als hierboven leiden tot waste in het softwarevoortbren-gingsproces en kunnen daarnaast grote gevolgen hebben. Neem alsvoorbeeld een situatie waarin niet duidelijk is waar de juiste versiesvan artifacts gevonden kunnen worden, welke set van artifacts bij elkaar horen of welke versie van dependencies überhaupt benodigdzijn om ons component te laten werken. In een dergelijke situatie is dekans groot dat dit leidt tot een uitrol van de verkeerde versies van componenten op de test-, acceptatie-, en zelfs productieomgevingen.Het wordt helemaal zuur wanneer dit leidt tot instabiel gedrag op productie met als gevolg een verlies aan inkomsten, reputatie of klant-vertrouwen.

Het toepassen van een package manager als NuGet kan helpen inhet voorkomen van bovengenoemde problemen. Hoe dit bereikt wordtvolgt in het vervolg van dit artikel waar we kijken naar de verschillendeonderdelen die bij het implementeren van NuGet in de enterprise aanbod komen.

Getting started met het implementeren van NuGet in de enterpriseHet implementeren van NuGet in de enterprise kan op veel verschil-lende manieren gedaan worden. Helaas leidt dit niet altijd tot de meestgeschikte en efficiënte implementatie. Ook wordt niet altijd het volle-dige potentieel van een package manager als NuGet benut. Vanuit mijn ervaring in het begeleiden van verschillende NuGet implementaties bij klanten, heb ik daarom een stappenplan voor u opgesteld die rekening houdt met de belangrijkste implementatie-overwegingen

STAP 1: Bepalen van de gewenste indeling van interne NuGetpackagesEen juiste indeling van interne NuGet packages is essentieel om NuGetin de enterprise goed te laten functioneren. Developers moeten duidelijk kunnen te zien wat de uniciteit en functie van de verschillendepackages is. Verder is het zaak goed na te denken over het aantalpackages dat gemaakt gaat worden. Elke package heeft namelijk zijneigen lifecycle. Bij een groter aantal packages neemt de beheerslastop packages (bijhouden versionering, dependencies en .nuspec) toe.Om ondersteuning te bieden aan het maken van de juiste keuze, onderstaand wat overwegingen die belangrijk zijn om mee te nemen.

Packagen van gedeelde softwarecomponenten vs alle software-componentenHet is verstandig te besluiten of enkel de artifacts/resources van de gedeelde softwarecomponenten gepackaged dienen te worden of dathet gewenst is om alle interne softwarecomponenten te packagen.Vaak wordt gekozen voor het enkel packagen van gedeelde soft-warecomponenten als bijvoorbeeld een intern logging component.

Het packagemechanisme van NuGet kan echter ook goed gebruiktworden om per softwarecomponent een bundel van executables, libraries, configuratiebestanden en installatie scripts te maken die vervolgens door een deployment tool als OctopusDeploy5 gebruikt kunnen worden om het softwarecomponent over de verschillende omgevingen uit te rollen.

Niveau van packagenDenk goed na over het gewenste niveau van packagen. Is het bijvoorbeeld verstandig een NuGet package per softwarecomponentte maken of juist per artifact? Helaas valt hier niet een eenduidig antwoord op te geven. Wanneer binnen uw organisatie de software-componenten erg klein zijn, zou het packagemodel per software-component erg geschikt kunnen zijn. Is dit echter niet het geval, danis wellicht het packagemodel per artifact geschikter. De meest geschikte optie kan dus per situatie verschillen. Sterker nog, in depraktijk kom ik zowel een softwarecomponent-, artifact- als hybridepackagemodel tegen. Het gaat erom dat packages niet te groot of teklein te zijn.

Om tot een juiste packagemodel keuze te komen is het verstandig re-kening te houden met de onderstaande voor- en nadelen van de ver-schillende packagemodellen. Zorg er verder voor dat het niveau vanpackagen aansluit bij de solutionindeling in Visual Studio. Binnen eensolution kunnen gerust meerdere NuGet packages gemanaged wor-den, maar voorkom situaties waarin de projecten van deze packagesvan elkaar afhankelijk zijn. Neem als richtlijn het volgende principebe-sluit:

Ongeacht het niveau van packagen dat gekozen wordt helpt hetmaken van NuGet packages in het voorkomen van KW03. De bij elkaar horende set van artifacts zitten in een enkele package of zijnmet elkaar verbonden middels het package dependency mechanisme.Omdat NuGet dit standaard ondersteunt is een eigen separate registratie niet meer benodigd. Denk wel vooraf goed na over eventu-ele afhankelijkheden tussen interne packages. Leg deze vast in de.nuspec file om zo kwesties als KW04 te voorkomen.

“Binnen een solution leggen we projectreferenties en geenonderlinge NuGet referenties. Referenties naar artifacts buiten de solution leggen we met behulp van NuGet”.

5 http://docs.octopusdeploy.com/display/OD/Packaging+applications

Page 28: SDN magazine 127

ALM

MAGAZINE

28

Naamgeving van NuGet packagesDenk goed na over de juiste naamgevingen van de NuGet packages.Het is belangrijk dat elke package een duidelijke, onderscheidendenaam krijgt zodat developers geen verkeerde referenties leggen. Aante raden valt de naamgeving van de softwarecomponenten terug telaten komen in de NuGet packagenaam. Daarnaast valt het aan teraden de voorgestelde package naamgevingen door de lead develo-pers van de teams te laten valideren.

STAP 2: Inrichten repositoriesOmdat het publiceren van interne packages naar een publieke feedniet wenselijk is, is het zaak een interne NuGet feed aan te maken omde zojuist geïdentificeerde interne packages beschikbaar te makenvoor uw developers. Het aanmaken van een interne feed zorgt ervoordat er één centrale locatie is waarbinnen de packages gemanagedworden en dat gebruikers een enkel toegangspunt hebben waarin zijde packages kunnen vinden. Dit voorkomt het KW01 probleem waarniet duidelijk is op welke locatie een NuGet package gevonden kanworden.

Fig. 1: NuGet repository hosting producten

ToolselectieEr zijn verschillende producten die het eenvoudig aanmaken van eenprivate NuGet feed mogelijk maken. Denk hierbij aan MyGet, InedoProGet, JFrog Artifactory, NuGet Server en bijvoorbeeld SonatypeNexus. Elk heeft zo zijn eigen functionaliteiten. Wanneer binnen uw organisatie ook andere typen artifacts als Docker images, NPM packages en Maven artifacts bestaan, valt het aan te raden een toolselectie te doen die ook dergelijke typen artifact repositories ondersteunt. Het voordeel hiervan is een enkele artifact managementtool die vragen als geldende licentieovereenkomsten van third-partypackages centraal kan beantwoorden. Momenteel bieden enkel InedoProGet, JFrog Artifactory en Sonatype Nexus ondersteuning voor niet-NuGet gebaseerde artifact repositories.

Repository indelingWanneer uiteindelijk een keuze is gemaakt voor een artifact manage-ment tool, kan gestart worden met het aanmaken van de benodigderepositories. Geadviseerd wordt om een onderscheid te maken in drietypen van NuGet feeds/repositories:

• Een ThirdParty feed/repository voor het managen van externeNuGet packages;

• Een Releases feed/repository voor het managen van de interne, stabiele, release packages;

• Een Snapshots feed/repository voor het managen van packagesdie onder constante ontwikkeling zijn.

De ThirdParty feed valt aan te raden om in de centrale builds niet afhankelijk te zijn van publieke URL’s. De scheiding tussen een Releases en Snapshots feed is benodigd om het mogelijk te makendat een release build enkel toegang heeft tot stabiele packages. Een groot voordeel van de bovenstaande indeling betreft het los kunnen verlenen van toegang per repository. Waar het bijvoorbeeldwenselijk is om de Releases en Snapshot repository enkel te vullenvanuit de build, is het voor de ThirdParty repository wenselijk dit enkelmogelijk te maken voor bevoegde administrators.

Repository instellingenHoud bij het configureren van de repository rekening met de onder-staande zaken:• Schrijftoegang tot repositoriesDenk goed na over wie schrijftoegang krijgen tot de verschillende repositories. Er zijn twee manieren waarop dit valt in te regelen: middels een AD account of middels een API-key. Wanneer gekozenwordt voor de API-key optie, is het belangrijk deze op een beveiligdelocatie op te slaan.

• Disable package overschrijvingen in de repositoryWanneer packages overschreven worden in de repository, ziet destandaard NuGet cliënt tooling dit niet als nieuwe versie. Hierdoorbestaat de kans dat developers onwetend, lokaal blijven werkenmet een oudere, gecachte versie van de package. Ook maakt hetenablen van packageoverschrijvingen het mogelijk om tussentijdsproductiepackages te overschrijven. Omdat de NuGet cliënt tooling packageoverschrijvingen niet tegenhoudt, is het benodigdom het overschrijven van packages te disablen op de repository.

STAP 3: Bepalen van richtlijnen voor versiemanagementÉén van de meest verwarrende onderdelen van NuGet in de enterprise betreft versiemanagement. Er zit namelijk een verwarrendverschil tussen de Microsoft artifact versionering en het NuGet versioning (SemVer) formaat.

Fig. 2: SemVer formaat

Formaat van versienummeringWaar Microsoft de <major version>.<minor version>.<build num-ber>.<revision> standaard hanteert voor haar artifacts, geldt voorNuGet packages de Semantic Versioning structuur Major.Minor.Patch-identificatie. Niet alleen het formaat is anders, ook de betekenis van dederde nummerpositie in de reeks is totaal anders (lees build- versuspatch/revision nummer). Welke optie nou te kiezen bij het toepassenvan NuGet voor interne packages?

Kijkend naar publieke NuGet packages die opgeleverd worden zienwe twee uitwerkingen. De eerste variant respecteert het verschil inversionering tussen artifacts en NuGet packages. In de andere variantworden het build- en revision nummer van de artifacts in de NuGetpackage omgedraaid tot het formaat: <major version>.<minor ver-sion>.<revision>. <build number>. Een voorbeeld hiervan is deNewtonsoft.Json.7.0.1 package. De trend die we zien is dat de pac-kagenummers meer en meer op deze laatste variant aansluiten. Hetvalt dan ook aan te raden de interne nummering van artifacts hieropaan te sluiten.

Model van versienummeringVeel organisaties hebben moeite met het bepalen van het juiste versienummer voor een artifact. Belangrijk hierbij is om rekening tehouden met de onderstaande uitgangspunten:• Major version: wordt handmatig opgehoogd als gevolg van significante productwijzigingen (bijv. platform of architectuur);

• Minor version: wordt handmatig opgehoogd als gevolg van eenincrementele release (bijv. extra features) van het product;

• Revision: wordt handmatig opgehoogd om patches uit te leverenop een eerder gemaakte release. Denk hierbij bijvoorbeeld aan hotfixes;

• Build: wordt per build automatisch opgehoogd en uniek gemaakt.

Page 29: SDN magazine 127

ALM

magazine voor software development 29

Naast de bovenstaande richtlijnen, is het belangrijk een onderscheidte maken in prerelease (onderhanden) en stable (gereleasde) packages, zie http://docs.nuget.org/Create/Versioning. Packages dieuiteindelijk uit een release build komen geven we een stable versie enworden geplaatst in de releases repository. Packages waaraan nogconstant ontwikkeld wordt geven we een prerelease identificatie enplaatsten we in de snapshots repository.

Tot slot: het goed managen van package versionering kan een complexe opdracht zijn. Bij veel organisaties die ik begeleid hebmaakte men bijvoorbeeld gebruik van feature- of component branches. Je dient dan goed na te denken over een “versie-promotie”model die aansluit bij de branch structuur.

STAP 4: Aanpassen van de buildHet is belangrijk te garanderen dat alle interne packages uit een centrale build komen. We willen er namelijk zeker van zijn dat packages die in de centrale repositories staan ook daadwerkelijk voldoen aan de kwaliteitsnormen (code analysis, unit testing, .. ) vanonze centrale build. Om dit te garanderen is het van belang op zowelde Snapshots als Releases repository enkel het buildaccountpushrechten te geven. Met betrekking tot de ThirdParty repositorygeldt een ander uitgangspunt, zie hiervoor stap 5.

Implementeren van NuGet in de buildHet implementeren van de benodigde NuGet taken in het buildprocesis sinds TFS2015 voor een standaard TFS2015 build erg eenvoudig.Er zijn namelijk standaard taken voor het packagen en publishen vanNuGet packages. Let er wel op dat de juiste build-definitie wordenaangesloten op de juiste repository; sluit release builds aan op de Releases repository en overige builds aan op de Snapshots repository. Wanneer uw organisatie nog gebruik maakt van een pre-TFS2015 build-definitie (XAML), valt aan te raden gebruik temaken van de NuGetter6 template voor het eenvoudig versioneren,packagen en publiceren van NuGet packages.

Fig. 3: Overzicht van de standaard NuGet buildtaken in Visual Studio 2015

Lokale repository per developerWanneer developers lokaal een NuGet package willen testen is dit mogelijk door op basis van een lokale folder een eigen repository in terichten. Let wel dat een developer in dit geval goed dient na te denken over het versienummer van zijn lokaal te testen package. Wanneer hij een versie kiest die uiteindelijk ook vanuit een centralebuild gaat gelden, bestaat namelijk het gevaar dat deze testpackageblijft bestaan in zijn lokale NuGet cache. Wanneer de centrale buildvervolgens dezelfde versie beschikbaar maakt, ziet NuGet als gevolghiervan op de cliënt machine geen reden om deze te vervangen.

Het automatisch updaten van package referentiesEen veelgehoorde vraag die ik tijdens implementaties krijg is of hetniet mogelijk is automatische package updates (zowel intern als extern)uit te laten voeren door de centrale build(s). Dit biedt het voordeel datdevelopers niet telkens zelf hoeven te updaten naar de laatste versie

van packages. Hoewel dit waar is, zou ik het automatisch updatennaar nieuwe packageversies vanuit de centrale build willen afraden.Het gevolg is namelijk allereerst dat de build op zichzelf niet meer herhaalbaar is (KW05). Draaien we de build namelijk in de toekomstnogmaals op dezelfde source code, dan kan het maar zo zijn dat wenu tegen package A versie 2.2.3 hebben aangebouwd in plaats vanversie 2.2.2. Omdat het updaten naar nieuwe packageversies een erggrote impact kan hebben (denk bijvoorbeeld ook aan indirecte dependencies die meekomen) dient het updaten naar nieuwe packageversies verder een bewuste keuze te zijn waarbij developersin een preview window genotificeerd worden van de consequenties.

Uitsluiten publieke NuGet feedsHet is belangrijk ervoor te zorgen dat er vanuit de buildservers geenconnectie met publieke NuGet feeds gemaakt kan worden. Dit garandeert dat alle packages die we gebruiken voorkomen in één vande interne repositories. Stap 5 beschrijft waarom dit wenselijk is.

STAP 5: Strategie voor omgaan met third-party packagesHet gebruik van third-party NuGet packages brengt de nodige risico’smet zich mee. Weet u bijvoorbeeld welke licentieovereenkomsten uaangaat bij het gebruiken van third-party NuGet packages? Of weetu welke security vunerabilities zich in de verschillende third-party packages bevinden? Om deze risico’s te beperken is het zaak eenjuiste manier van werken te vinden met als doel onveilige packagesvan buitenaf te isoleren en het aangaan van onwenselijke licentie-overeenkomsten te voorkomen. Maar waar te beginnen?

Selecteren juiste repository tool - correctief scannen van licenties envulnerabilitiesHet is belangrijk een juiste repository host tool te vinden die ons helptin het identificeren van deze zaken. Drie van de producten die we eerder benoemd hebben, Inedo ProGet, JFrog Artifactory en Sona-type Nexus bieden hier in de basis ondersteuning voor. Elke tool heeftbijvoorbeeld zijn eigen manier om het licentiegebruik van packages tebeperken of inzichtelijk te maken. Onderstaand een voorbeeld van deArtifactory tool waar u als gebruiker kunt aangeven welke typen vanlicenties geaccepteerd worden binnen uw organisatie.

Fig. 4: Licentie configuratie artifactory

Vervolgens wordt er in het buildproces een scan gedaan op packages die niet de juiste licentieovereenkomst hebben en wordt ditteruggegeven middels errors en warnings.Naast het licentiegebruik zouden we ook graag willen dat de repository tool ons helpt in het correctief uitsluiten en identificeren vanpackages met vulnerabilities. Kijkend naar de security vulnerability opties van de genoemde drie producten heeft alleen Sonatype Nexushier een directe implementatie voor (aangekondigd). Waar het in Sonatype Nexus momenteel al mogelijk is om Maven repositories tescannen op security vulnerabilities en geaccepteerd licentiegebruik,wordt dit ook voor NuGet repositories geimplementeerd (verwacht Q12016). Onderstaand een voorbeeld van een dergelijke repository scanrapportage.

6 https://nugetter.codeplex.com/

Page 30: SDN magazine 127

ALM

MAGAZINE

30

Fig. 5: Repository scan Sonatype Nexus

Een alternatief voor de Sonatype Nexus scan op security vulnerabili-ties, vormt SafeNuGet7. SafeNuGet is een MSBuild taak die hetmogelijk maakt om tijdens het builden te scannen op het gebruik vanNuGet packages. Wanneer tijdens het builden het gebruik van eenonveilige NuGet package wordt gedetecteerd, toont de build eenwaarschuwing. Dit wordt bepaald aan de hand van een unsafepac-kages.xml8 bestand die u zelf dient bij te houden. Per regel dient opgegeven te worden welke package onveilig is en op basis van welkeURI dit besluit genomen is. Het nadeel van deze aanpak is dat u zelfdit bestand dient bij te houden. Het voordeel is dat u de ruimte hebtte werken volgens een eigen controleniveau.

Voorkomen van ongewenste packagesBinnen veel organisaties zie ik dat men gebruik maakt van deproxy/mirroring functionaliteit van de verschillende tools om automa-tisch nieuwe publieke packages binnen te halen in de ThirdParty repository. Hoewel dit uw developers in offline situaties een rijkere setaan third-party packages biedt, valt dit niet aan te raden. Het gevolgis namelijk dat ongeacht licenties en security vulnerabilities alle packages gewoon beschikbaar gesteld worden voor uw developers.Tevens zie ik vaak dat er vanuit architectuur richtlijnen zijn met betrekking tot het gebruik van third-party componenten. Denk hierbijbijvoorbeeld aan logging componenten. Wanneer dit ook in uw organisatie het geval is, is het onnodig om nog packages van anderepartijen te blijven downloaden.

Om de bovengenoemde redenen valt het aan te raden de ThirdPartyrepository een op zich zelf staande, hosted repository te maken. Welis het belangrijk om vervolgens het gecontroleerd toevoegen van externe packages mogelijk te maken. Denk hierbij bijvoorbeeld aanhet aanmaken van een share waarop geautoriseerde gebruikers alslead developers en arhitecten de gewenste nieuwe packages kunnentoevoegen. Zij zijn vervolgens ook verantwoordelijk voor het scannenvan de packages die geplaatst worden op deze share. Met behulpvan een script kan vervolgens gekozen worden voor het automatischtoevoegen van deze packages aan de ThirdParty repository. Het voor-deel van een dergelijk preventief proces is dat ondanks de controleover het third-party package gebruik, developers toch de mogelijk-heid krijgen om ook van nieuwe third-party packages gebruik te kunnen maken.

STAP 6: Delen van veranderende manier van werken met developersHet werken met NuGet voor dependency management zal voor developers een aantal zaken doen veranderen. Het is daarom verstandig voor developers een training of handleiding te makenwaarin de NuGet workflow beschreven staat. Onderstaand volgen wataandachtspunten als input voor dit document.

Actief nadenken over dependency managementÉén van de grootste veranderingen voor een developer betreft het actief nadenken over de dependencies van zijn componenten. Waar voorheen een artifact die we linkten gewoon op zijn locatie overschreven kon worden met de huidige versie uit de build, dient nubewust nagedacht te worden tegen welke versie we ons componentgaan uitleveren. Dit actieve nadenken heeft als gevolg dat we ervoormoeten zorgen dat bij het uitvoeren van een NuGet update (automa-tisch updaten naar hoogste versie) commando, enkel geüpdatet wordtnaar die versies die binnen de range van versies valt die wenselijk is.Met behulp van het allowedVersions attribuut kan dit aangegeven worden in de zogenoemde packages.config file. In deze file liggen deNuGet referenties van ons project opgeslagen. Onderstaand een voorbeeld waarin we bijvoorbeeld afdwingen dat het SomePackagecomponent bij het uitvoeren van een update maximaal geüpdatetwordt naar een versie vanaf 2.0 tot 3.0.

Fig. 6: AllowedVersions attribuut NuGet

Aanpassingen standaard NuGet.configOm ervoor te zorgen dat developers vanuit de NuGet cliënt toolingook de interne feeds tot hun beschikking hebben, is het nodig datdeze als packagesource geregistreerd worden in de NuGet.config9 fileop de cliënt machines. Om te garanderen dat alle developers dezelfdeconfiguratie hebben, valt aan te raden om een generieke uitwerkingvan de NuGet.config te maken en te verspreiden met daarin de juistefeed registraties.Een andere goede toevoeging op de standaard NuGet.config configuratie betreft het aanpassen van de repositoryPath10 setting.Wanneer een nieuwe package wordt geïnstalleerd kijkt NuGet eerstnaar de lokale NuGet cache. Wordt de package daar niet gevondendan download NuGet deze package alsnog en plaatst hem in de lokale cache. Zonder het instellen van een repositoryPath zal NuGetvervolgens een kopie van de package plaatsen in de packages folderonder de solution. Naar deze kopie wordt vervolgens vanuit het Visual Studio project verwezen. Het instellen van een repositoryPath kan eenaanzienlijk hoeveelheid schijfruimte besparen doordat er, in plaats vaneen kopie per solution, enkel een kopie voor de gedeelde repository-Path folder gemaakt wordt die over de solutions heen gedeeld wordt.Figuur 7 geeft dit weer.

Niet inchecken artifacts in versiebeheerMet de komst van NuGet krijgen developers een eenvoudig mecha-nisme tot hun beschikking om lokaal missende packages(artifacts)binnen te halen. Waar artifacts voorheen gezamenlijk met de code lokaal werden binnengehaald vanuit het versiebeheersysteem, is ditin het geval van NuGet niet meer benodigd. We kunnen NuGet namelijk instellen om missende packages te downloaden tijdens hetbuilden.

Fig. 7: Default package locatie vs RepositoryPath locatie

Om dit te bereiken dienen de onderstaande tags toegevoegd te worden aan de NuGet.config file:

7 https://github.com/OWASP/SafeNuGet8 https://github.com/OWASP/SafeNuGet/blob/master/feed/unsafepackages.xml9 https://docs.nuget.org/consume/nuget-config-defaults10 https://docs.nuget.org/consume/nuget-config-settings

Page 31: SDN magazine 127

ALM

magazine voor software development 31

<packageRestore>

<add key="enabled" value="True" />

<add key="automatic" value="True" />

</packageRestore>

Het is vervolgens niet meer benodigd artifacts op te slaan in ons versiebeheersysteem. Het gebruik van NuGet bespaart ons dus nietalleen schijfruimte op de development machines (zie eind vorige kopje)maar ook in het versiebeheersysteem! Vooral wanneer u TFS versioncontrol gebruikt bespaart dit beheerskosten als: minder schijfruimtevoor de TFS collection database, minder data die opgeslagen dient teworden bij het back-uppen en snellere doorlooptijden in het restorenvan een TFS collectie. Ook leidt het niet opslaan van artifacts in het versiebeheersysteem tot snellere tijden bij het binnenhalen van desources.

Whatif switchOmdat een NuGet package een diepe dependency graaf kan hebbenen dit grote gevolgen kan hebben op de referenties van het project, ishet verstandig eerst te kijken wat de gevolgen zijn van het installeren,de-installeren of updaten van een package. In het geval van het gebruiken van de Visual Studio 2015 package manager UI wordt ditstandaard aangegeven bij het uitvoeren van één van de bovenge-noemde acties. In de praktijk is het echter vaak flexibeler om de package manager console te gebruiken omdat dit meer opties biedten geen UI interventie vereist. Om ook vanuit de package managerconsole feedback te krijgen op de gevolgen van het installeren,de-installeren of updaten van een package, kan gebruik gemaakt wor-den van de -whatif switch die sinds NuGet 2.8 toegevoegd is aan deNuGet powershell commando’s.

Fig. 8: NuGet review changes window Visual Studio 2015

STAP 7: Migreren naar de nieuwe manier van werkenHet migreren naar een NuGet in de enterprise implementatie vereist dejuiste aandacht en een goede planning. Niet alleen dienen de centralebuilds- en buildserver aangepast en de repositories aangemaakt teworden, ook dienen de verschillende developers hun cliënt machineop een juiste manier te configureren. Dit houdt in: het installeren vande juiste NuGet versie en het updaten van de lokale NuGet.config naarde generieke, gedeelde versie. Eventueel dienen verder de juiste credentials opgegeven te worden in deze NuGet.config11 en dienteventuele extra tooling geïnstalleerd te worden. Denk hierbij bijvoor-beeld aan de NuGet package explorer12 waarmee u eenvoudig de inhoud van een NuGet package kunt inzien.

Na de benodigde installaties dient voor de in stap 1 onderkende com-ponenten één voor één een NuGet package aangemaakt te worden.Om dit goed te kunnen stroomlijnen is het belangrijk een dependencygraaf van de interne componenten te maken. Begin met de compo-nenten die zelf geen dependencies hebben op interne componenten.Dit zijn vaak de gedeelde componenten. Migreer vervolgens één vooréén alle componenten naar een versie die enkel project referenties eneventueel ook NuGet referenties (in plaats van referenties naar lokalefiles/GAC) heeft. Wanneer dit gedaan is, is het als laatst nog belang-rijk ervoor te zorgen dat de package enkel de gewenste artifacts bevat

en ook de juiste versie krijgt (nuspec aanpassing). Synchroniseer vervolgens de code van het gepackagede component met het versiebeheersysteem en publiceer de package middels het uitvoerenvan een centrale build.Vaak wordt te licht gedacht over het migratietraject. Op basis van deeerder gedane NuGet implementaties moet zeker rekening gehoudenworden met een totale doorlooptijd van 2 weken. Indien binnen uworganisatie verschillende teams werken in verschillende branches, ishet verstandig eerst de functionele merge uit te voeren en vervolgensop de samengevoegde branch de technische NuGet migratie te star-ten. Het migreren naar NuGet past namelijk de projectreferenties aanwat als gevolg heeft dat het mergen van twee losse naar NuGet gemigreerde branches, inclusief functionele wijzigingen, een zeer complexe en foutgevoelige exercitie is. Dit kan leiden tot het nogmaalsmoeten uitvoeren van de migratie op de samengevoegde branch wegens ontbrekende project files en NuGet referenties.

STAP 8: Uitwerken ondersteunende rapportagesWanneer eenmaal de migratie is uitgevoerd en alles weer naar behoren draait, is het verstandig rapportages in te regelen die het de-pendency gebruik van de softwarecomponenten monitort. Waar in hetverleden dit vaak een uitdagende taak was, kan dit nu eenvoudig gedaan worden middels het scannen van de verschillende NuGet packages.config bestanden. Een dergelijk dashboard kan veel voor-delen opleveren. Zo geeft het architecten direct inzicht in de daad-werkelijke afhankelijkheden die er liggen tussen software-componenten, maar kan het ook helpen in het identificeren van hetgebruik van verouderde packages of third-party packages. Om u eenvoorbeeld te geven van wat er mogelijk is, onderstaand een dash-board die we voor één van onze klanten hebben uitgewerkt en waarinhet packagegebruik per Git repository wordt weergegeven.

Fig. 9: Dependency dashboard van NuGet packages per Git repository

Voor nu zijn dit de belangrijkste zaken waar u rekening mee dient tehouden bij het migreren naar NuGet in de enterprise. •

11 https://docs.nuget.org/consume/nuget-config-settings12 http://bit.ly/1L5t7K9

Cornell Knulst

Cornell Knulst werkt als consul-tant/trainer bij Info Support. In de rolvan ALM Consultant heeft hij ALMimplementaties begeleidt? bij ver-schillende klanten binnen het zorg-,overheids- en financedomein . Hier-

bij ligt de focus niet alleen op het implementeren van de benodigdetooling (Microsoft Visual Studio ALM suite), maar juist ook op depeople (het opleiden van mensen) en process (het verbeteren vande processen) kant. Cornell's blogs zijn te vinden onderhttps://blogs.infosupport.com/ en http://www.solidalm.com/.