+ All Categories
Home > Documents > SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van...

SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van...

Date post: 11-Aug-2020
Category:
Upload: others
View: 1 times
Download: 0 times
Share this document with a friend
48
Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network www.sdn.nl IN DIT NUMMER O.A.: Delphi XE2 en iOS targets < Background Agents met Windows Phone 7 < Microsoft Feedback Manager 11 BETA Release < Code Quality: Single Responsibility Principle < SOFTWARE DEVELOPMENT NETWORK MAGAZINE 113 ISSN: 2211-6486
Transcript
Page 1: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network

www.sdn.nl

IN DIT NUMMER O.A.:

Delphi XE2 en iOS targets <

Background Agents met Windows Phone 7 <

Microsoft Feedback Manager 11 BETA Release <

Code Quality: Single Responsibility Principle <

SOFTWARE DEVELOPMENT NETWORK

MAGAZINE

113

ISSN: 2211-6486

Page 2: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

Afgelopen zomer was Achmea’s Alex Thissen een week lang te gast bij het Windows Communication Foundation team op Microsofts hoofdkantoor in het Amerikaanse Redmond. “Er zijn op de hele wereld maar zes bedrijven die daarvoor werden uitgenodigd, dus ik beschouw het wel als een eer dat Achmea deel uitmaakt van dit selecte groepje. Microsoft luistert echt naar Achmea, ze beschouwen ons als een bedrijf dat voorop wil lopen. We spraken bijvoorbeeld over Microsofts onder-steuning van IBM Websphere MQ, waarvoor wij andere communicatie-patronen mogelijk wilden maken. Maar ook de koppeling tussen Sharepoint en SAP was onderwerp van gesprek.”Microsoft-topman Scott Guthrie, alias ‘Scott Gu’, was onlangs te gast op de Achmea-burelen. Thissen: “Ja, dat zijn inspirerende sessies. In mijn vakgebied heeft hij de status van een popster, dus je begrijpt dat het geweldig sparren is met zo’n man.”

Mep je fitBij de ontwikkeling van Visual Studio Team System (bestaande uit ontwikkelomgeving Visual Studio

2010 en de ‘Application Lifecycle Management omgeving’ Team Foundation Server 2010) was Achmea in een vroeg stadium betrokken, vertelt Thissen. “We hebben ideeën en suggesties aan-geleverd en Microsoft gewezen op bugs en verbeterpunten, zoals bijvoorbeeld bij het berekenen van de burnrate van code. Dat is nuttig voor ons én nuttig voor Microsoft.”Voor Achmea is Visual Studio Team System belangrijk bij het ontwik kelingen van software aan de voorkant, zoals webappli-caties en mobiele applicaties, en voor integratie-oplossingen met behulp van webservices. “Voor Achmea wordt het internet steeds belangrijker, niet alleen om schades te melden of verzekeringen af te sluiten, maar ook voor allerlei zaken op het gebied van preventie. Zo hebben we in opdracht van Zilveren Kruis Achmea de game ‘Mep je fit’ ontwikkeld voor Micro-softs ‘computertafel’ Surface. Ook tijdens de Olympische Winter-spelen hadden we in het Holland Heineken House een gezondheids-installatie staan; bezoekers konden

daarop onder andere hun bloeddruk en body mass index meten en sportieve prestaties vergelijken met die van topsporters.”

AgileDaarnaast draagt de Microsoft-software bij aan de toenemende vraag naar transparantie en voorspel-baarheid, vindt Thissen. “Team Foundation Server houdt alle stappen in het ontwikkelproces bij, vast-gelegd in hiërarchische workitems. Zo bieden wij onze klanten – de mensen in de business van Achmea – optimaal inzicht in het proces.”Last but not least is Thissen tevreden met MSF Agile, het processjabloon dat Visual Studio Team System voert. “Dat betekent dat we snel en flexibel kunnen bouwen, in korte iteraties met de klant. Dat is precies wat we nodig hebben, want Achmea wil razendsnel kunnen inspelen op nieuwe ontwikkelingen die zich voordoen in de markt.”

Alex Thissen: “Microsoft luistert echt naar Achmea.”

Foto

: Han

s B

arte

n

Page 3: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

magazine voor software development 3

ColofonUitgave:

Software Development Network

Twintigste jaargang

No. 113 • mei 2011

Bestuur van SDN:

Remi Caron, voorzitter

Rob Suurland, penningmeester

Marcel Meijer, secretaris

Redactie:

Marcel Meijer

([email protected])

Aan dit magazine

werd meegewerkt door:

Roel Hans Bethlehem, Bob Swart, Stefan

Kamphuis, Peter Donker, Maarten van Stam,

Alexander Meijers, Remi Caron, Marcel

Meijer en natuurlijk alle auteurs!

Listings:

Zie de website www.sdn.nl voor eventuele

source files uit deze uitgave.

Contact:

Software Development Network

Postbus 506, 7100 AM Winterswijk

Tel. (085) 21 01 310

Fax (085) 21 01 311

E-mail: [email protected]

Vormgeving en opmaak:

Reclamebureau Bij Dageraad, Winterswijk

www.bijdageraad.nl

©2012 Alle rechten voorbehouden. Niets uit

deze uitgave mag worden overgenomen op

welke wijze dan ook zonder voorafgaande

schriftelijke toestemming van SDN. Tenzij

anders vermeld zijn artikelen op persoonlijke

titel geschreven en verwoorden zij dus niet

noodzakelijkerwijs de mening van het be-

stuur en/of de redactie. Alle in dit magazine

genoemde handelsmerken zijn het eigen-

dom van hun respectievelijke eigenaren.

AdverteerdersAchmea 2

CSC 9

Unividuals 16

Compuware 25

Microsoft 41

Macaw 48

Adverteren?

Informatie over adverteren en de adverten-

tietarieven kunt u vinden op www.sdn.nl

onder de rubriek Magazine.

voorwoordBeste SDN magazine lezer,

Het belooft een hete zomer te worden, hoewel de lente tot nu niet echt geweldig is.

Op 15 juni zal ons tweede SDN event van 2012 gehouden worden, daarna zal de

TechEd Europe in alle hevigheid losbarsten in Amsterdam. Op donderdag 21 juni

vind er in België de Community Day plaats. Dit event met 40 sessies wordt georga-

niseerd door de Belgische communities en is geheel gratis. Ook de Nederlandse

communities zullen hier aanwezig zijn en enkele sessies verzorgen.

Wie heeft er al met de Windows 8 Consumer preview gespeeld? Velen zullen

moeten wennen aan de interface, tenslotte zijn we eigenlijk best verknocht geraakt

aan dat stomme Start menu. Ik ben erg benieuwd naar Windows 8 op een ARM

device, het heeft dan Windows RT. Hoewel Windows Octopus wel aardig was

geweest. Wat mis je op Windows RT machine en wordt het dan eindelijk de iPad

killer. Of heb je al gespeeld met de Visual Studio 11 Beta bits? Mis je de kleur of mag

er nog wel meer kleur uit? Tijdens de laatste MVP summit vond iedereen dat er te

weinig kleur in Visual Studio zat. Ze hebben dat duidelijk gehoord hoor, dus je mag

aannemen dat er iets zal veranderen.

Wij zijn er benieuwd naar jullie ervaringen, maar ook wat je nog mist of wat je niet mooi

vindt. Stuur je reactie naar [email protected] en wij zullen ze op de website

publiceren.

Dit magazine staat in elk geval weer boordevol interessante artikelen. Nog een

artikel over LiveBindings, een vernieuwing van de Feedback manager, Knockout.

JS en MVVM, over Agile, Delphi XE2 en iOS Datasnap Clients, Windows Azure en

WIF, Background agents op een Windows Phone 7, Messaging op de Windows

Azure Servicebus, Code Quality en Bouwen/onderhouden van applicaties in de

Cloud. Natuurlijk ook weer de columns van Sander over Estimates en Michiel over

Offline Ajax. Dit weekend kun je weer lekker in de zon lezen.

Wij wensen jullie veel leesplezier en hopen jullie gauw te mogen begroeten op een van

de komende events.

Groeten,

Marcel

Page 4: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

Inhoud03 VoorwoordMarcel Meijer

04 Inhoudsopgave

04 Agenda

05 Delphi XE2 en iOS DataSnap ClientsBob Swart

10 Microsoft Feedback Manager 11 BETA Release

Hassan Fadili

14 Een javascript implementatie van het MVVM-pattern met Knockout.js

Diederik Tiemstra

17 How to kill your estimatesSander Hoogendoorn

18 Windows Azure + WIF + Windows Azure Access Control (ACS)

Marcel Meijer

20 Background Agents met Windows Phone 7 Patrick Gilhuijs

26 LiveBindings: Taking Another Look

Cary Jensen

32 Messaging patterns met Azure Servicebus Edwin van Wijk

42 Code Quality: Single Responsibility Principle

Dennis van der Stelt

46 Offline AJAXMichiel van Otegem

47 Bouwen en onderhouden van applicaties in “de Cloud”

Ton Blankers

• Delphi Developer Dag

22 mei 2012

Breukelen

• SDN Event

15 juni 2012

Ede

• Community Day 2012

21 juni 2012

Utopolis Mechelen Belgie

• Microsoft TechEd

25-29 juni 2012

Amsterdam

• SDN event

21 september 2012

Zeist

• SDC

3/4 december 2012

Papendal (onder voorbehoud)

Agenda 2012

Page 5: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

DELPHI Bob Swart

Delphi XE2 en iOS DataSnap ClientsDe vorige keer schreef ik over Delphi XE2 en iOS toepassingen die mogelijk zijn.Het was op datmoment nog niet eenvoudig mogelijk om een DataSnap client te maken van de iOS toepassing,maar dat is met Update #4 van Delphi XE2 veranderd: vanaf nu zijn de DataSnap Mobile Connectors uitgebreid met een FPC proxy voor iOS 4.2 of iOS 5.0, en daarvan gaan we in ditartikel gebruik maken om een DataSnap client voor de iPad te maken.

DataSnap REST ApplicationMet Delphi XE2 Enterprise (en Update #4) kunnen we via File | New -Other in de Object Repository een drietal DataSnap wizards zien,waarbij we de DataSnap REST Application moeten kiezen als "server"deel voor de komende iOS Client.

De New DataSnap REST Application wizard begint met de vraag watvoor soort toepassing we willen hebben. De keuze is tussen eenStand-alone VCL toepassing (ideaal voor het testen en debuggen, endeze heb ik tijdens het SDN Event van 23 april gebruikt), een Stand-alone console toepassing (iets minder handig voor testen), of eenISAPI dynamic link library. De laatste keuze is de beste voor de daad-werkelijke deployment, met name omdat we dan IIS kunnen gebruikenin combinatie met SSL en https.

In het tweede scherm van de wizard kunnen we de verschillende features en opties van de DataSnap server kiezen. Voor deze demo is(nog) geen behoefte aan authorisatie of authenticatie, maar wel aan deMobile Connectors.

DataSnap Mobile ConnectorsDe DataSnap Mobile Connectors worden gebruikt om proxies temaken voor verschillende mobiele devices. Oorspronkelijk zat er inDelphi XE2 alleen ondersteuning voor Android (Java), Windows Phone(Silverlight), Blackberry (Java) en iOS (Objective/C), maar sinds

Update #4 is daar nu ook iOS in FreePascal bij gekomen, zodat we diedirect vanuit Delphi en Xcode kunnen gebruiken voor native DataSnapclients op iOS zonder daarvoor een andere taal als Objective/C temoeten gebruiken.

Het derde scherm betreft de keuze voor de Server Method class. Dedefault keuze is een TComponent, maar daar kunnen we geen (data

magazine voor software development 5

Page 6: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

DELPHI

acess) componenten op kwijt. Het andere uiterste, de TDSServerModule, is handig als we TDataSetProviders willen exporteren en vanhet IAppServer interface gebruik willen maken, maar dat werkt alleenmet DBX en niet met REST connecties (en de iOS DataSnap clientkan alleen via REST werken voorlopig).Blijft de keuze over voor een "normale" DataModule met method infoenabled, zodat alle public methods beschikbaar komen als server methods.

Tot slot volgt nog een laatste pagina in de Wizard waarin we om de directory worden gevraagd voor de DataSnap REST Server toepas-sing. Zorg ervoor dat je geen spaties in de directory naam zet, wantdeze naam wordt ook gebruikt als naam van het project zelf (en daarmogen ook geen spaties in voorkomen). Voor dit artikel heb ik de DataSnap REST server de naam DataSnapServerSDN gegeven.

Het resulterende DataSnapServerSDN project bestaat uit een Server-MethodsUnit1.pas en een WebModuleUnit1.pas. De Web Module unitbevat alle componenten voor de DataSnap Engine (in de vorm van deTDSServer en TDSServerClass componenten) alsmede de compo-nenten om de Mobile Connector Proxies te genereren (met name deTDSProxyDispatcher, TDSProxyGenerator en TDSServerMetaData-Provider componenten).

Mochten we later toch nog authorisatie en/of authenticatie willen toe-voegen, dan kan dat met een TDSAuthenticationManager component.

De Server Methods unit is nog leeg, maar dit is de plek waar we dataaccess componenten kunnen plaatsen. Voor dit voorbeeld zal ik gebruik maken van de EMPLOYEE tabel uit de EMLOYEE.GDB

InterBase voorbeeld database die iedere Delphi ontwikkelaar op zijn ofhaar machine zou moeten kunnen vinden.Via een TSQLConnection die wijst naar de EMPLOYEE.GDB data-base, en een TSQLDataSet die een SELECT FIRST_NAME,LAST_NAME FROM EMPLOYEE doet kunnen we de data ophalen.

Wat we nu nog nodig hebben is een functie in de TServerMethods1class die het resultaat van de TSQLDataSet teruggeeft. Er staan altwee voorbeeld server methods: EchoString en ReverseString, enonze derde functie kan daartussen komen, als volgt:

function TServerMethods1.GetEmployees: TDataSet;

begin

if SQLDataSet1.Active then

SQLDataSet1.First // reset to first record

else

SQLDataSet1.Open;

Result := SQLDataSet1

end;

Als de TSQLDataSet al open is, dan moeten we naar het eerste record, en anders moeten we de dataset openen (waarna we auto-matisch op het eerste record staan). De TSQLDataSet geven we terugals resultaat van de functie, maar we moeten hem niet sluiten, wantanders kan de client er geen data uit lezen.

Voordat we de DataSnap REST Server deployen, moeten we eerstnog even de MidasLib unit aan de uses clause toevoegen. Die zorgtervoor dat we de MIDAS.DLL zelf niet hoeven te deployen. Inmiddelskan dat zowel voor Win32 als Win64 targets, dus wie Windows Sevrer2008 R2 draait kan de ISAPI DLL als 64-bits toepassing deployen.

Voor wie met de iOS DataSnap client wil meespelen heb ik de DataSnapServerSDN.dll op mijn eigen web server gezet, en via https://beschikbaar gemaakt. De URL voor de DataSnap REST Server ishttps://www.bobswart.nl/DataSnapSDE/DataSnapServerSDN.dll Wie naar deze URL gaat kan de ReverseString server method in debrowser uitproberen.

DataSnap iOS ClientVoor het werken met de DataSnap Mobile Connectors, kunnen wegebruik maken van bovenstaande URL met daarbij als extra toevoe-ging /proxy/freepascall_ios42.zip of /proxy/freepascal_ios50.zip voorresp. iOS 4.2 of iOS 5.0 (ook compatible met iOS 5.1). Dat is dus bijvoorbeeld https://www.bobswart.nl/DataSnapSDE/DataSnap

MAGAZINE

6

Page 7: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

DELPHI

ServerSDN.dll/proxy/freepascal_ios50.zip voor de iOS 5.0 versie vande proxy.

Deze freepascal_ios50.zip bevat alle benodige files die we nodig hebben om een Delphi XE2 iOS DataSnap client te maken. Helaas iser nog een klein probleempje met de inhoud, want alhoewel Windowsniet case sensitive is, is Mac OS X dat wel, en Xcode en de FreePascal compiler ook wat betreft het gebruik van unit en file namen.Als je het archief freepascal_ios50.zip hebt uitgepakt, moet je de volgende units renamen: DSRESTParameter.pas naar DSRestParameter.pas, DSRESTTypes.pas naar DSRestTypes.pas (enbinnen deze unit ook de naam naar DSRestTypes). Voor het project opmijn server heb ik deze wijzigingen al gemaakt, dus zijn de units algoed. Maar als je zelf de DataSnap REST Server hebt gemaakt, danzul je bovenstaande wijzigingen moeten doorvoeren (zoals ik op ophet SDN Event van 23 april heb laten zien).

Hierna maken we een FireMonkey HD for iOS project, wat ik opsla alsproject DataSnapClient met een ClientForm.pasZorg dat de uitgepakte freepascal_ios50.zip in dezelfde directory staatals het DataSnapClient project, en voeg dan alle units toe aan het project zelf.

Zet nu een TListBox en een TButton op de form, en daarna kunnen wein de OnClick event handler van de button de verbinding maken metde DataSnap REST Server. Hiertoe moeten we een drietal units toe-voegen aan de uses clause: DSRESTConnection (voor de TDSRestConnection class), DSProxy (voor onze TServerMethods1class) en DB (voor de TDataSet).

De implementatie van de OnClick event handler is als volgt:

procedure TForm2.Button1Click(Sender: TObject);

var

Server: TDSRestConnection;

Proxy: TServerMethods1; // name at server

DataSet: TDataSet;

begin

Server := TDSRestConnection.Create(nil);

try

Server.Host := 'www.bobswart.nl';

Server.Port := 80;

Server.UrlPath := '/DataSnapSDE/DataSnapServerSDN.dll';

Server.Protocol := 'http';

Proxy := TServerMethods1.Create(Server);

try

DataSet := Proxy.GetEmployees;

while not DataSet.Eof do

try

ListBox1.Items.Add(

DataSet.FieldByName('FIRST_NAME').AsString + #32 +

DataSet.FieldByName('LAST_NAME').AsString);

finally

DataSet.Next

end;

finally

Proxy.Free

end;

finally

Server.Free

end;

end;

Eerst maken we een verbinding met de DataSnap REST Server, via deHost, Port, UrlPath en Protocol properties. Vervolgens maken we hiermee een instantie van de TServerMethod1 proxy, en roependaarna de GetEmployees Server method aan die de Employees TDataSet teruggeeft. Hierna vul ik de TListBox met de FIRST_NAMEen LAST_NAME, maar kunnen we in feite alle velden gebruiken dievanaf de server worden doorgegeven.

Export to XcodeHet project compileert nu aan de Delphi XE2 kant, maar dat is nietvoldoende om het op een iOS device te draaien. Hiervoor moeten weeerst de "DPR2XCODE" tool draaien, die een Xcode project om deDataSnapClient maakt, wat we vervolgens met Xcode zelf kunnenopenen op een Mac.

magazine voor software development 7

Page 8: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

DELPHI

Merk op dat ik nog Xcode 4.2 draai op een Mac met OS X 10.6, maardoor een truck (zie m'n weblog) kan ik er toch ook iOS 5.1 devices enapps mee produceren.

Het resultaat kan in de laatste screenshot gezien worden in de iOS5.1 Simulator. Uiteraard kan er veel meer gedaan worden dan alleenmaar het afbeelden van de informatie in een TListBox, maar het doelvan dit artikel was om te laten zien hoe van vanuit een iOS DataSnapclient een verbinding konden maken met een Delphi XE2 DataSnapREST Server.

ConclusieIn dit artikel heb ik laten zien hoe we met Delphi XE2 Update #4 en deextra Mobile Connectors een DataSnap iOS Client kunnen maken vooreen DataSnap REST Server. De stappen en meer details heb ik latenzien tijdens het SDN Event op maandag 23 april, en zijn in meer de-tail beschreven in mijn Delphi XE2 native iOS Development cursus-boek dat te verkrijgen is van http://www.drbob42.com/courseware •

Bob Swart

Bob Swart is werkzaam in de IT

sinds 1983 en heeft daarbij een

voorliefde voor (Turbo) Pascal en

Delphi. Bob spreekt regelmatig op

(internationale) conferenties over

Delphi en heeft honderden artikelen

geschreven, alsmede zijn eigen

Delphi cursusmateriaal voor Delphi

trainingen en workshops. Behalve

voor het geven van trainingen, is Bob ook beschikbaar voor

consultancy, coaching, ontwerp- en bouwwerkzaamheden, of

andere ondersteuning op het gebied van software ontwikkeling

met Delphi – voor zowel Win32 als .NET. Sinds de zomer van

2007 is Bob ook reseller van CodeGear producten zoals Delphi

en RAD Studio. Bob Swart Training & Consultancy is gevestigd in

Helmond Brandevoort, en beschikt over een eigen trainingsruimte

van ruim 42 vierkante meter, inclusief een testlab voor alle

mogelijke toepassingen. De voorliefde van Bob voor Pascal en

Delphi heeft hij ook tot uiting laten komen in de namen van zijn

kinderen Erik Mark Pascal en Natasha Louise Delphine.

SDN EVENT15 JUNI A.S.

REEHORST - EDE9:30 - 16:30 UUR

Reehorst, Bennekomseweg 24, 6717 LM Ede

Onderwerpen o.a.:

• TFS

• Scrum

• Security

• Interaction Design

• Lucene

Een evenement met diverse

topsprekers, waaronder

Sander Hoogendoorn.

Page 9: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

with

93000employeesworking for

2500clientsin

94 countriesand

52 years of experience

software development holds no mysteries for us

with

30009

3000emplo

eesyemplo

orking fw

2500in

94

ororking f

2500clients

ountriesc

clients

and

52

xperiencears of ey

earsoftwelopmentvde

p

n

elopmentholds no

eriestsymor usf

op-quality softwers tCSC delivechnology serviction tormainf

t ideas, prs the beso harnesus te do amazing things. Find out morors. Wsect

e the we aro its clients. We tarop-quality softwe acrxperienc. Our eyompanes cechnology servic

om both the public and prives and solutions fractict ideas, prom.ct csc.e ae do amazing things. Find out mor

s leading independent orld’e the wtries enables s all indusose acr

e taom both the public and priv

Page 10: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

DESKTOP Hassan Fadili

Dit tool biedt ondersteuning voor feedback tussen Developers en deStakeholders. Deze feedback is van dag de dag enorm belangrijk omsnel schakelen mogelijk te maken en om misverstanden te voorko-men over de te ontwikkelen en te leveren systemen. Daarom staatFeedback dus centraal tussen Developers en Stakeholders enerzijdsen tussen Stakeholders en Operations anderzijds, zoals de onder-staande schema weergeeft.

Fig. 1: Stakeholders Feedback staat centraal

Dit artikel zal de nieuwe toevoegingen en/of wijzigingen van het tool inVisual Studio 11 BETA toelichten. Op de eerdere versie van dit tool isde nodigde feedback gegeven aan de Microsoft Product Teams, metname over de werking en de flow van dit tool. Daarop hebben de teams gereageerd en zijn er een aantal aanpassingen cq uitbreidingen doorgevoerd. Deze zullen stapsgewijs toegelicht wordenin dit artikel.

Locatie van Microsoft Feedback Client als standalone toolWanneer Visual Studio 11 BETA geïnstalleerd wordt, is duidelijk te ziendat er ook een Client tool bij is gekomen namelijk Microsoft FeedbackClient zoals weergegeven in de onderstaande schema:

Wanneer men de Microsoft Feedback Client start zonder FeedbackRequest sessie, wordt er een connectie gemaakt naar de

Fig. 2: Microsoft Feedback Client Tool als onderdeel van Visual Studio 11 BETA

onderliggende Team Foundation Server. Deze kan zowel een On Premise TFS als een Hosted TFS zijn. In dit geval wordt uitgegaan vaneen Hosted TFS Service zoals hieronder is weergegeven.

Er kan gekozen worden voor een Team Project in de lijst waarop deFeedback gegeven dient te worden.

In een eerdere artikel voor dit SDN Magazine (112) is al een eerste impressie gegevens over deFeedback Manager tool die is gekomen met Visual Studio 11 Developer Preview.

Microsoft Feedback Manager 11BETA Release

MAGAZINE

10

Page 11: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

DESKTOP

Indienen van Feedback vanuit Web Access (Proces & Werking) Het Feedback proces is nu onderdeel van de Web Access. Vanuit deHome scherm van de Hosted TFS Team Project is deze optie zicht-baar. Het indienen van Feedback vanuit Web Access is erg eenvou-dig en werkt als volgt:

Fig. 4: Request Feedback sessie vanuit Web Access.

Met Request Feedback link, is het mogelijk om een nieuwe feedbacksessie te starten waarmee Feedback gegeven kan worden door klanten (Stakeholders) over alle onderdelen van het product waaraangewerkt wordt. De Stakeholders kunnen op deze manier op de hoogteblijven van de ontwikkelingen van het desbetreffende product/projecten kunnen tijdig hun mening geven of wijzigingen voorstellen als volgt:

Fig. 5: Request Feedback info wizard

Fig. 6: Requested Feedback sessie informatie waarop de meningvan Stakeholders nodig is

Wanneer men de benodigde informatie heeft ingevuld en op Senddrukt, komt deze Feedback Request als Work Item terug op de WorkItem Tab op de WebAccess Portal van de desbetreffende TeamProject. Zoals hieronder is weergegeven:

Fig. 7: Requested Feedback als Work Item type in Web Access

Deze actie wordt gevolgd door het verzenden van een E-mail naar depersonen (Stakeholders) die ingevuld zijn tijdens de Request Feed-back sessie en die deze Feedback moeten geven. De verzonden E-mail ziet er als volgt uit:

Fig. 8: Ontvangen Feedback Request E-mail

magazine voor software development 11

Fig. 3: Microsoft Feedback Client tool weergave voor TFS en TeamProject selectie

Page 12: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

DESKTOP

Middels de link in de E-mail, kan de Feedback Response gestart worden door de Microsoft Feedback Client Tool te starten (indien dezereeds is geïnstalleerd op de Client PC), anders wordt de gebruiker getracht om eerst de Microsoft Feedback Tool te installeren vanuit:http://go.microsoft.com/fwlink/?LinkId=230568 Wanneer deze al is geïnstalleerd op de Client PC, dan kan deze ge-start worden te klikken op de link: Start your feedback session. Mochtde link niet werken dan kan ook de url gekopieerd en geplakt wordenin een browser. In dat geval zal het volgende scherm wordt getoond :

Fig. 9: Feedback Link Validatie scherm

Door Allow te klikken, wordt de Visual Studio 11 Beta start schermals volgt getoond:

Fig. 10: Visual Studio 11 Beta start scherm bij Feedback Tool sessie

Hierna wordt de Feedback Client tool gestart waarin de initieel meegeleverde informatie vanuit de Feedback Request E-mail is mee-genomen. Deze ziet er als volgt uit (fig. 11):

Wanneer men Next klikt, wordt het volgende scherm getoond waarinalle bevindingen en de terugkoppeling van de stakeholders naar deFeedback verzoeker zijn opgenomen. Deze gegevens kunnen tekst,plaatjes en/of media zijn die helpen bij het verhelderen van de Feed-back.

Fig. 11: Feedback Client Start scherm met Feedback informatie link

NB: Met de rating indicatie kan men de tevredenheid van de feedbackaangeven!

Fig. 12: Feedback Client Provide Scherm voor Stakeholders Feedback

MAGAZINE

12

Page 13: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

DESKTOP

Met Next vanuit dit scherm kan er vervolgens naar de volgende stapin het Feedback proces gegaan worden als volgt:

Fig. 13: Submit Feedback Response scherm

Alle ingevoerde Feedback vanuit de stakeholders is hierin opgeno-men. Wanneer men Submit and Close klikt, wordt deze verzondennaar TFS Preview en wordt vervolgens ook zichtbaar als Work Itemin Web Access zoals hieronder is weergegeven.

Fig. 14: Submitted Feedback Response als Work Item in Web Access

Zoals je hierboven kunt zien, zijn zowel Feedback Request als Feed-back Response als twee afzonderlijke Work Items weergegeven. Ikadviseer om de Feedback Request te associëren in een Parent/Child

relatie met de Work Item waarvoor de Feedback is gedaan.

Dit maakt het zoeken naar Feedback Request en Feedback Responsegemakkelijker. Dit vereenvoudigd het zoek mechanisme plus ook hetfeit dat je geen expliciete links hoeft te leggen voor alle Feedback Responses naar de desbetreffende Requirements (of User Stories).

Conclusie:De feedback tool is het eerste tool dat ik gezien heb (er kunnen anderen zijn die dat ook kunnen) en die ons in staat stelt om ons vanbetrouwbare gegevens van klanten te voorzien, ongeacht waar ze zijn.Scrum beoefenaars zeggen altijd dat teams moeten worden co-loca-ted met hun klanten, zodat ze direct feedback kunnen geven. Uiteraard is dit ons streven, maar in de praktijk is dat niet altijd moge-lijk. Dit tool kan erg goed helpen om de wensen van de klanten op dejuiste manier te implementeren zonder vertaalslag en/of verlies van in-formatie of het langdurige wachten op het beantwoorden van E-mails.

Het gemak van dit tool geef ons het gevoel dat we ten alle tijde naastde klant zetten en direct kunnen schakelen om de juiste dingen tedoen. Dit is een grote en waardevolle editie van de Visual Studio ALM-tools. •

Hassan Fadili

Hassan Fadili is werkzaam als Free -

lancer (ICT Consultants) Lead

Architect / Consultant en VS ALM

Consultant (MVP). Hassan is zeer

actief in de Community en mede

bestuurslid van DotNed(.NET & VS

ALM UG NL) en VS ALM Track

Owner. Hassan houdt zijn blog op:

http://hassanfad001.blogspot.com en te bereiken via: hassan.

[email protected], [email protected], hassanfad11@

hotmail.com en/of via Twitter op: @HassanFad

Noteer alvast in

uw agenda:

SDN Event

15 juni a.s.

Reehorst - Ede

magazine voor software development 13

Page 14: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

WEB

dency-tracking en de aangegeven bindings automatisch verzorgen.

ObservablesHet belangrijkste concept binnen Knockout zijn de zgn. observables(vergelijkbaar met INotifyPropertyChanged en INotifyCollectionChan-ged is Silverlight en WPF) . Door het aanmerken van properties van jemodel als observable zullen veranderingen in deze properties auto-matisch in de UI worden doorgevoerd indien er UI-elementen bestaandie tegen de bewuste properties zijn gebind.

Er bestaan binnen Knockout 3 typen observables1. Observable – Zorgt er voor dat het Framework reageert op wijzigenvan de waarde

2. Computed (voorheen DependentObservable)- Zorgt er voor dat hetFramework reageert op wijzigingen in (observable)properties waarde de computed property van afhankelijk is.

3. ObservableArray – Zorgt er voor dat het Framework reageert wanneer er wijzigingen optreden in de items van een collectie (toevoegen, verwijderen van items).

Zie listing 1 voor een voorbeeld van type 1 en 2

@*define your bindings*@<p>First name: <input data-bind="value: FirstName" /></p><p>Last name: <input data-bind="value: LastName" /></p><p><p>First name: <span data-bind="text: FirstName " /></p><p>Full name: <span data-bind="text: FullName" /></p>

<script type="text/javascript">//Define your modelfunction ViewModel(firstName, lastName) {

this.FirstName = ko.observable(firstName);this.LastName = ko.observable(lastName);this.FullName = ko.computed(function () {

return this.FirstName() + ' ' + this.LastName();}, this)

}var viewModel = new ViewModel('voornaam', 'achternaam');//instruct Knockout to bind your model to your UIko.applyBindings(viewModel);

</script>

Listing 1

In listing 1 kun je zien dat de FirstName- en LastName properties vanhet model zijn aangemerkt als Observable. Indien je in de textbox deFirstName wijzigt zal Knockout middels de bindings automatisch de

Een javascript implementatievan het MVVM-pattern metKnockout.js

Sinds Microsoft heeft besloten Knockout.js op te nemen in de MVC4.0 Developer Preview is de kans zeer groot dat we deze techniek inde nabije toekomst steeds vaker zullen tegenkomen. De hoogste tijddus voor een nadere kennismaking.

Het MVVM-patternHet MVVM (Model-View-ViewModel) is een pattern dat nauw verwantis aan het welbekende MVC pattern. Hierbij bestaat het Model uit jedomein-model, de view uit de UserInterface en het ViewModel uit delijm tussen die 2. Het ViewModel is verantwoordelijk voor het aanbie-den van het Model aan de View in een geschikte vorm en het afvan-gen van commands die door de UI worden geraised. Heel simpelgezegd kan het ViewModel gezien worden als een gespecialiseerdeController. (Zie figuur 1)

Fig. 1

Key-conceptsKnockout.js is een project oorspronkelijk ontwikkeld door Steve Sanderson van Microsoft. Hoewel hij werkzaam is voor Microsoft is,staat Knockout volledig los van Microsoft en is het geheel Open-Source. Knockout biedt de volgende voordelen:• Klein – de benodigde Javascript file is slecht 39kb in omvang (minified)

• Puur Javascript • Geschikt voor alle mainstream browsers (IE 6+, Firefox 2+, Chrome, Opera, Safari (desktop/mobile))

Door de inzet van de Library is het mogelijk je UI-elementen middelsdeclaratieve bindings te koppelen aan een (Javascript) model. Op hetmoment dat er in het model wijzigingen plaatsvinden die moeten resulteren in updates van de UI zal Knockout dat middels depen-

Diederik Tiemstra

Met de komst van Knockout.js is het mogelijk geworden om op eenvoudigere wijze dan in hetverleden middels JavaScript een volledig dynamische UI te creëren. Op de knockout.js website wordt het zelf omschreven als : “Simplify dynamic JavaScript UIs byapplying the Model-View-ViewModel (MVVM) pattern”

MAGAZINE

14

Page 15: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

WEB

inhoud van de 2 laatste span-elementen verversen. Hoewel dit voor-beeld op het eerste gezicht erg eenvoudig is, toont het wel de krachtvan het Framework. Wilde je voorheen hetzelfde gedrag implemente-ren moest dit bijv. middels jQuery (bijvoorbeeld door het toevoegenvan onChange-eventhandlers op de beide textboxen en het in deeventhandler updaten van het label met de volledige naam). In eendergelijk eenvoudig voorbeeld is dat nog makkelijk te doen maar alsde data en het scherm complexer worden wordt ook de oplossingmiddels jQuery moeilijker. Dit kan verduidelijkt worden door boven-staand voorbeeld uit te breiden met wat extra gedrag.

Stel: elk persoon kan een aantal vrienden hebben (max 5) waarbij voorelke afzonderlijke vriend ook de voornaam en achternaam aangepastmoet kunnen worden (en dus automatisch ook de (afgeleide) volledige naam). De belangrijkste wijziging zit hem in het ViewModelwaarbij het Person-object is uitgebreid met een array welke is aange-merkt als ObservableArray. Het gebruik van de ObservableArray werktop vergelijkbare manier als de “normale” Observables. Als er UI-ele-menten gebind zijn tegen een item in de collectie zal (het gedeelte van)de UI automatisch worden gerefreshed wanneer er een wijziging op-treedt in de desbetreffende collectie.

Belangrijk hierbij is wel dat Knockout alleen reageert op het wijzigen van de item-collectie (toevoegen/verwijderen van items).Wijzigen van properties van individuele items in de collectie worden alleen door het Framework gedetecteerd als deze properties als Observable zijn aangemerkt.

Ten slotte zijn er in het voorbeeld functies aan het ViewModel toegevoegd voor het toevoegen en verwijderen van vrienden en is ereen binding gedefinieerd die aangeeft hoe een vriend-object gerendered moet worden. Zie listing 2 voor de nieuwe code.

@*define your bindings*@<p>First name: <input data-bind="value: FirstName" /></p><p>Last name: <input data-bind="value: LastName" /></p><p>Full name: <span data-bind="text: FullName" /></p>@*Show number of friends*@<p>#Friends: <span data-bind="text: Friends().length" /></p>@*Allow maximum of 5 friends*@<p><button data-bind="click: AddFriend, text:'add newfriend', enable: Friends().length < 5" /></p><br>@*define how friends should be rendered*@<table data-bind="foreach: Friends">

<tr><td>First name: <input data-bind="value: FirstName"

/></td><td>Last name: <input data-bind="value: LastName"

/></td><td>Full name: <span data-bind="text: FullName"

/></td><td><button data-bind="click: function(){ $parent.De-

leteFriend($data) }, text:'delete'"/></td></tr>

</table><script type="text/javascript">

//Define your modelfunction Person(firstName, lastName) {

var self = this;self.FirstName = ko.observable(firstName);self.LastName = ko.observable(lastName);self.FullName = ko.computed(function () {

return self.FirstName() + ' ' + self.LastName();})//Functions for managing friendsself.Friends = ko.observableArray([]);self.AddFriend = function () {

self.Friends.push(new Person('new', 'friend'));};self.DeleteFriend = function (friend) {

self.Friends.remove(friend);};

}var viewModel = new Person('voornaam', 'achternaam');//instruct Knockout to bind your model to your UIko.applyBindings(viewModel);

</script>

Listing 2

Zoals je kunt zien zit al het gedrag voor het aansturen van de UI in hetmodel weggestopt. Als we bijvoorbeeld de binding van de toevoeg-knop bekijken maakt dat de voordelen van Knockout t.o.v. een oplossing middels jQuery meteen duidelijk. (zie listing 3)

<button data-bind="click: AddFriend, text:'add new friend',enable: Friends().length < 5" />

De knop wordt middels de binding gedisabled als het aantal vriendenin het model 5 bedraagt. En ook het label waarin het aantal vriendenvermeld staat wordt automatisch door Knockout bijgewerkt wanneerer items toegevoegd of verwijderd worden. Makkelijk toch? (MetjQuery zou je in een eventhandler de rijen in de tabel moeten tellen eno.b.v. de uitkomsten de knop moeten en-/disabelen en het label metaantal vrienden moeten updaten). Ook het toevoegen van een vriendbestaat simpelweg uit het aanroepen van de juiste functie op hetViewModel zonder dat je je hoeft te bekommeren om de UI.

Ook het aanpassen van de namen van de vrienden is kinderspel.Omdat deze properties ook als Observable zijn aangemerkt zal ook hetspan-element met de Full Name automatisch wijzigen. Knockouthoudt via de dependency-tracking intern bij van welke vriend de naamwordt gewijzigd. Kortom : de UI wordt volledig bepaald door de statevan het Model. Het enige dat je zelf moet doen is het implementerenvan alle logica in je ViewModel en het aangeven van de bindings.

Andere mogelijkhedenUiteraard biedt Knockout veel meer mogelijkheden dan wat hier bovenis geschetst. Er bestaan ondermeer mogelijkheden om:• Je eigen custom-bindings te schrijven• Automatisch (JSON) objecten te mappen naar “Observable” objecten

• Delen van je UI te definiëren middels templating• Unobtrusive event-handlers toe te voegenHoewel de ruimte te kort is om deze onderwerpen hier te beschrijvenzijn staat er op de Knockout.js website veel (duidelijke) informatie omtrent deze onderwerpen.

ConclusieMocht je een keer voor de uitdaging staan om een (complexe en) dynamische UI te moeten bouwen bekijk dan zeker eens de moge-lijkheden van KnockOut.js. Het scheelt je wellicht de moeite van hettoevoegen van een heleboel jQuery eventhandlers en het aansturenvan je UI o.b.v. de beschikbaarheid/het aantal andere UI elementenop je scherm. Voor meer informatie kan je o.a. op de volgende onderstaande sites terecht: http://knockoutjs.com/http://learn.knockoutjs.com/ •

Diederik Tiemstra

Diederik Tiemstra is werkzaam als

.NET Developer bij VXCompany.

Zijn belangrijkste specialisme is het

ontwikkelen van web applicaties op

het Microsoft Platform.

magazine voor software development 15

Page 16: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

Unividuals weet dat het als zelfstandige niet altijd makkelijk is om alleen te werken. Herken je je bijvoorbeeld in:

1. Grote organisaties willen liever niet met ‘eenpitters’ samen werken. Ze zijn op zoek naar een betrouwbare onderneming die zorgt voor continuïteit en kennisontwikkeling.

2. Alleen is maar alleen: kennisdelen is lastig, collega’s hebben is niet alleen gezellig maar ook goed voor de nodige inspiratie, maakt samenwerken mogelijk en vooral makkelijker.

Dat het anders kan, weet UnividualsUnividuals is een coöperatieve kennisorganisatie bestaande uit zelfstandig professionals. Wij brengen ondernemers samen. Bij Unividuals creëren en coördineren we kennis en zijn wij voor opdrachtgevers een betrouwbare partner.

Meer weten?Kijk op onze website: www.unividuals.nl of bel op 088-8648400

Unividuals

Postbus 176

1270 AD Huizen

088-8648400

[email protected]

www.unividuals.nl

Ben jij ondernemer en vakspecialist? En altijd op zoek naar nieuwe klanten, af en toe eenklankbord en kennisontwikkeling?

Kom dan naar de volgende Unividuals kennisbijeenkomst en laat je inspireren!

(advertorial)

Samenwerken is slimmer werken

Wil je meer weten over Unividuals?

Kom dan geheel vrijblijvend naar een van de informatie bijeenkomsten op dinsdag 22 mei of donderdag 7 juni 2012.

19.30 Peter Lammersma, founder Unividuals

19.50 Gastspreker

20.10 Lid Unividuals vertelt over voor-delen samenwerking Unividuals

20.30 Netwerkborrel

Meld je nu gratis aan op onze website. Hier tref je ook de meest actuele informatie.

Grote organisaties willen liever niet met 1.

werken. Herken je je bijvoorbeeld in:Unividuals weet dat het als zelfstandige niet altijd makkelijk is om alleen te

‘eenpitters’ Grote organisaties willen liever niet met

werken. Herken je je bijvoorbeeld in:Unividuals weet dat het als zelfstandige niet altijd makkelijk is om alleen te

samen werken. Ze ‘eenpitters’

Unividuals weet dat het als zelfstandige niet altijd makkelijk is om alleen te

coördineren we kennis en zijn wij voor opdrachtgevers een betrouwbare partner.professionals. Wij brengen ondernemers samen. Bij Unividuals creëren en Unividuals is een coöperatieve kennisorganisatie bestaande uit zelfstandig Dat het anders kan, w

mogelijk en vooral makkelijker.gezellig maar ook goed voor de nodige inspiratie, maakt samenwerken Alleen is maar alleen: kennisdelen is lastig, collega’s hebben is niet alleen2. en kennisontwikkeling.zijn op zoek naar een betrouwbare onderneming die zorgt voor continuïteit

coördineren we kennis en zijn wij voor opdrachtgevers een betrouwbare partner.professionals. Wij brengen ondernemers samen. Bij Unividuals creëren en Unividuals is een coöperatieve kennisorganisatie bestaande uit zelfstandig

vidualseet UniDat het anders kan, w

mogelijk en vooral makkelijker.gezellig maar ook goed voor de nodige inspiratie, maakt samenwerken Alleen is maar alleen: kennisdelen is lastig, collega’s hebben is niet alleenen kennisontwikkeling.zijn op zoek naar een betrouwbare onderneming die zorgt voor continuïteit

coördineren we kennis en zijn wij voor opdrachtgevers een betrouwbare partner.professionals. Wij brengen ondernemers samen. Bij Unividuals creëren en Unividuals is een coöperatieve kennisorganisatie bestaande uit zelfstandig

gezellig maar ook goed voor de nodige inspiratie, maakt samenwerken Alleen is maar alleen: kennisdelen is lastig, collega’s hebben is niet alleen

zijn op zoek naar een betrouwbare onderneming die zorgt voor continuïteit

coördineren we kennis en zijn wij voor opdrachtgevers een betrouwbare partner.

zijn op zoek naar een betrouwbare onderneming die zorgt voor continuïteit

1270 AD Huizen

Postbus 176

Unividuals

Kijk op onze website:en?etMeer w

www.unividuals.nl

[email protected]

088-8648400

of bel op l.unividuals.n wwwKijk op onze website:

088-8648400 of bel op

Page 17: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

GENERAL

At one time two colleagues and I were working on an estimate for abid for a software development project. Now the three of us together,despite the fact that this occurred long time ago, had quite some yearsof experience in the field. So you would reckon we could come upwith a decent estimate. And we did. In fact, we created two estima-tes. One by counting screens, based on a point scale and a real-lifevelocity. A very popular and suitable technique as we were buildingdesktop applications. Next to that we created a work breakdownstructure. Using both techniques we estimated ALL the work in theproject, not just coding or coding and testing. Not much to our surprise the results from both estimates were comparable. Happy andconfident with the result, we presented our estimates to the accountmanager in charge.

It was at this particular point in time, at that very instant, that my faithand trust in our industry vanished into thin air, not to return again. Noteven more than glancing at the work we’d invested in our estimates,the account manager merely looked at the end result and added 20%to the overall price for the project. For contingency, he claimed.Up to this deciding moment in my career I had never even heard of theword. Contingency. And still I refuse to stop and think what the impact of that little word is to this industry and probably others too. To sum it up, every confident estimate can be killed by (account) managers adding seemingly random percentages. Just because theydon’t trust your estimates. Or they still remember the court cases fromprevious projects. Frightening all together.Needless to say we lost thebid. Our competitors were less expensive.

History revisitedNow I wouldn’t write about this unfortunate event if I hadn’t met a similar situation only a few weeks ago. You might imagine we’ve learned a thing or two in the twenty five years since. Alas. We didn’t.And it’s industry wide I assume.

With a small team we had worked on an estimate for re-engineeringa client/server desktop application to a .Net web application. We estimated based on smart use case points, a technique that we haveused and refined over the years. A reliable estimation technique. Theestimate resulted in just under 500 smart use case points, which is ameasure for the size and complexity of the system. Given the fact thatwe have executed multiple similar projects successfully we were ableto establish that it takes about 8 hours per smart use case point to realize the software. And yes, we have actually gathered metrics!

These 8 hours include ALL work on the project, including project management, documentation, testing, setting up the development environment etc. Simple calculation tells us that we would need 4.000hours to do the project. So this was what we coughed up for the responsible account manager.

Without so much as a blink of the eye an email came back from theaccount manager stating that he added 20% to our estimate, and thathe would communicate this new number to the client. Leaving us witha lot of questions of course.So the interesting question is: where does the 20% come from? You would expect that it originated from having evaluated softwaredevelopment projects for years and years, and comparing original estimates in those projects with the final outcome – given the fact thatrequirements change, teams change and technology changes. But tobe quite honest, unfortunately I suspect this is not case. There’s butonly a few organizations that actually measure like this. I assume. Andthen even if he had done that, would it be exactly 20%? Why not 17.6?Or 23.17? Exactly 20%? Or maybe the account manager know his statistics. Statistics claim that developers estimate 20% too optimistic. As we developers are optimists. But this was a team estimate including all work on the smart use case on the backlog.

Yesterday’s weatherTo cut to the chase, if a team estimates the amount of work in a project, especially on a relative scale, as an account manager this iswhat you should believe, as it is the best estimate available. This isthe yesterday’s weather principle. The best way to predict today’s we-ather, is to look at the weather from the day before. No more, no less.

Adding 20% – or 10% or 15% – just as a rule of thumb is not basedon any real-life experience. In my opinion such actions show that theaccount manager puts no trust in his own people, in his own organi-zation. This would be similar to saying that if it was 10 degrees yesterday, we’ll just state that it will be 7 degrees today, without havinglooked at the weather forecast.

Restore trustSo what’s the message here? Please dear account managers, putsome trust in the people who try to create as estimate as accurate asthey can. Don’t add 20%, or 10% for that matter, just based on gutfeeling. And more important, dear software developing organizations,start measuring your projects! Gather metrics so future estimates become much more accurate and realistic, and future project proposals and project will be less off target than so many projects I witness. And on the fly restore some of the trust so many peoplehave lost in our industry. Let’s learn. •

It must have been about twenty five years ago. I was working for a large international consultancy firm.One of the reliable ones. The ones that you would think that had everything worked out. But I guess thiswas merely the product of my imagination.

How to kill your estimates

Sander Hoogendoorn

magazine voor software development 17

Page 18: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

CLOUD Marcel Meijer

Als je vervolgens de gebouwde Windows Azure applicatie ook daad-werkelijk in de Cloud gaat laten draaien zijn er een aantal aha momenten. Het is wel gewoon handig om de website ook als SSL tebehandelen. Hieronder een opsomming.

De Windows Identity Foundation (WIF) runtime.Op de standaard Windows Azure instances is de WIF runtime nietaanwezig. Uit verschillende discussie die ik gevolgd heb en eigen ervaring, blijkt dat een simpel ‘copy local’ van de WIF assembly (Windows.Identity.dll) niet voldoende. Je zult echt de WIF runtime moeten mee installeren met de installatie van de Windows Azure webapplicatie.

Dat is relatief eenvoudig. Met behulp van het startup task mechanismevan Windows Azure kun je een batch file af starten en daarmee deruntime installeren. Deze runtime is te downloaden van http://www.microsoft.com/en-us/download/details.aspx?id=17331. Er is zoweleen x86 als x64 versie beschikbaar. De x64 heb je nodig voor het deployen naar Windows Azure. Afhankelijk van de gekozen OS Family (Windows 2008 of Windows 2008 R2) heb je de 6.0 of de 6.1nodig. Ontwikkel je lokaal op Windows 7 of Windows 2008 R2 danheb je ook 6.1 nodig.

In de ServiceDefinition.csdef van de WebRole voeg je het volgendestuk toe.

<Startup>

<Task commandLine="startup.cmd"

executionContext="elevated"

taskType="simple">

</Task>

</Startup>

Aan het webproject voeg je dan een file met de naam startup.cmdtoe. Het makkelijkst is dat om in de root te doen. Anders moet je in destap hierboven ook het path aangeven.De startup.cmd bevat dan:

REM WIF assembly

sc config wuauserv start= demand

Als je gebruik gaat maken van de Access Control Service (ACS) op het Windows Azure platform,dan zijn daar voldoende website te vinden met een keurig stappenplan. Bijvoorbeeld hier(http://msdn.microsoft.com/en-us/IdentityTrainingCourse_WIFonWAZLab2010). Hoewel er behoorlijk geconfigureerd moet worden, zowel in de applicatie als op de ACS website, is hetgoed te doen.

Windows Azure + WIF +Windows Azure AccessControl (ACS)

wusa.exe "%~dp0Windows6.1-KB974405-x64.msu" /quiet /norestart

rem wusa.exe "%~dp0Windows6.0-KB974405-x64.msu" /quiet /no-

restart

sc config wuauserv start= disabled

Bij het deployen van de applicatie wordt in een van de stappen ook destartup task uitgevoerd.

Multiple instancesZoals bekend moet je op Windows Azure om aan de SLA te voldoenin elk geval 2 instanties van je Role starten. Van Windows Azure ACSkrijg je een cookie. Deze cookie wordt geencryptd en gedecryptd.

Deze versleuteling vindt plaats met de machine-sleutel van de instan-tie waar je zat. Maar op de andere instantie is de machine-sleutel na-tuurlijk anders en dan kan het cookie niet gelezen worden door eenandere instantie.

De oplossing is dan ook vrij simpel, zorg ervoor dat de versleutelingplaats vind met voor alle machines een gelijke sleutel. Ik heb voor mijndomein een SSL certificaat gekocht en deze kan ik daar mooi voorgebruiken. Om dit goed te laten verlopen moet je in de Global.asax.csde FederatedAuthentication.ServiceConfigurationCreated methodetoevoegen.

protected void Application_Start()

{

AreaRegistration.RegisterAllAreas();

FederatedAuthentication.ServiceConfiguration

Created +=

OnServiceConfigurationCreated;

}

void OnServiceConfigurationCreated(object sender,

ServiceConfigurationCreatedEventArgs e)

{

// Use the <serviceCertificate> to protect the

cookies

// that are sent to the client.

// so multiple roles do the same.

MAGAZINE

18

Page 19: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

CLOUD

// if (e.ServiceConfiguration.ServiceCertificate

== null)

// return;

Trace.WriteLine("ServiceCertif: ",

e.ServiceConfiguration.ServiceCertificate.Thumbprint);

List<CookieTransform> sessionTransforms =

new List<CookieTransform>(

new CookieTransform[] {

new DeflateCookieTransform(),

new RsaEncryptionCookieTransform(

e.ServiceConfiguration.Service-

Certificate),

new RsaSignatureCookieTransform(

e.ServiceConfiguration.Service-

Certificate)

}

);

SessionSecurityTokenHandler sessionHandler =

new SessionSecurityTokenHandler(

sessionTransforms.AsReadOnly());

e.ServiceConfiguration.SecurityTokenHandlers.Ad-

dOrReplace(

sessionHandler);

}

RealmOp mijn demo site (https://cloudtest.marcelmeijer.net) zijn alle pagina’s zichtbaar zonder in te loggen, maar mag je secret page pasbenaderen na inloggen. In de default situatie na het doorlopen van dewizard zullen alle pagina’s niet benaderbaar zijn zonder in te loggen.Ik heb daarom dit gedeelte in de web.config uit gecommentarieerd.

<system.web>

<!—

<authorization>

<deny users="?" />

</authorization>

-->

Op de ACS portal heb ik de return URL laten verwijzen naar de paginadie bij mij geheim is.

Dat is deze pagina in de app.

ACS implementeren is eigenlijk heel makkelijk, maar toch weer heellastig. Er zijn veel knoppen waar je aan moet draaien om het goed telaten werken.

Ander dingetje wat je je moet realiseren. Het Access Control mecha-nisme zoals Windows Azure die aanbiedt bestaat voor het grootstegedeelte uit alleen de authenticatie. Weet je het nog Authenticatie, benjij degene die je zegt dat je bent; Autorisatie, wat mag jij of welke rollen heb jij op deze website / webapplicatie. Wat je met ACS uit handen geeft is de authenticatie. Door middel van de login/passwordbij een van de Identity providers.

De autorisatie moet je zelf uitwerken in je eigen website of webappli-catie. De claims die je van de identity providers terugkrijgt zijn tokens(alleen FaceBook), e-mail adressen (niet bij Windows Live), Name (nietbij Windows Live) en een nameidentifier. De nameidentifier kun je welgebruiken als key voor je rollen toekenningen systeem. En zoals jevoorgaande leest, wil je bij Windows Live zelf vragen om e-mail adresen name (of je gaat met de nameidentifier zelf te raden bij WindowsLive wat natuurlijk ook kan). •

Marcel Meijer

Al meer dan 15 jaar begeeft deze 42

jarige zich in de wereld van de ICT.

Op dit moment houdt hij zich voor-

namelijk bezig met Azure, Cloud,

C#, Software Ontwikkeling, Archi-

tectuur in het algemeen en Wind-

ows Phone 7. Ook is hij bezig met Biztalk en Sharepoint.

Hij werkt als Senior Architect bij VX Company. In zijn vrije tijd is hij

.NET track owner, eindredacteur en bestuurslid van de SDN.

Binnen de SDN is hij verantwoordelijk voor het regelen van

sprekers voor de SDN Events (SDE), het regelen/redigeren van

artikelen voor het SDN Magazine, mede verantwoordelijk voor de

eindredactie van de hardcopy en digitale magazines en de inhoud

van de SDN Conferences. Op 1 oktober 2010 werd hij MVP.

magazine voor software development 19

TIP:

Tips Windows Phone platformhttp://thewp7dev.wordpress.com/ en http://dotnetbyexample.blogspot.com/ zijntwee blogs, waar je terecht kunt voor interes-sante en praktische programmeer tips voor hetWindows Phone platform. Een aanrader als jeinfo zoekt. Beide bloggers zijn nooit te beroerdom je mail te beantwoorden.

Page 20: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

MOBILE Patrick Gilhuijs

Wat is een background agent?Een background agent in WP7 is een assembly die onderdeel is vanje applicatie maar die onafhankelijk van je applicatie uitgevoerd wordt.Het zijn twee aparte processen. Per applicatie is maximaal één back-ground agent toegestaan en wanneer deze actief is mag hij niet meerdan 6 of 15 Mb aan geheugen gebruiken, afhankelijk van het typeagent. Wanneer het geheugengebruik over deze limiet gaat, zal deagent per direct gestopt en afgebroken worden. In de praktijk blijktdat je behoorlijk wat moeite moet doen om aan deze regel te blijvenvoldoen. In een voorbeeld verderop in dit artikel laat ik hier meer vanzien.

Typen agentsVan een background agent zijn er drie verschillende typen. - Audio playback agent (15 Mb geheugenlimiet)- Audio streaming agent (15 Mb geheugenlimiet)- Scheduled Task agent (6 Mb geheugenlimiet)

Audio agents kunnen gebruikt worden voor het afspelen van audio opde achtergrond. Het verschil tussen deze twee is dat de playbackagent muziek lokaal vanaf het apparaat afspeelt en dat de streamingagent een audio stream af kan spelen van bijvoorbeeld een website.De Scheduled Task agent zal in dit artikel verder uitgediept worden.Het is goed om te beseffen dat het draaien van een applicatie terwijlje telefoon gelockt is, oftewel ‘run under lockscreen’ niet hetzelfde isals gebruikmaken van een background agent. ‘Run under lockscreen’betekent dat je applicatie niet in een dormant of tombstoned staat te-recht komt, maar gewoon actief blijft. Een typische toepassing hiervooris bijvoorbeeld het tracken van GPS data gedurende een bepaaldeperiode. Een agent is geen app, maar een proces op de achtergrond.

TasksNaast background agents heeft een WP7 app de notie van tasks. Toenik zelf de eerste keer in aanraking kwam met agents en tasks was hetvoor mij niet helemaal helder wat nu het verschil is tussen deze tweeen hoe ze samenwerken. Ook in de documentatie worden de namendoor elkaar gebruikt maar wordt vaak hetzelfde bedoeld.

Background Agents met Windows Phone 7Met de Mango release is er aan Windows Phone 7 een krachtig feature toegevoegd, namelijkmultitasking. Of in dit geval beter gezegd: het kunnen uitvoeren van werk op de achtergrond.Om dit mogelijk te maken is het concept van background agents geïntroduceerd. Deze agentskunnen taken op de achtergrond uitvoeren zonder dat de gebruiker daar op hoeft te wachtenen zonder dat zelfs de applicatie op de voorgrond actief hoeft te zijn. Ideaal voor bijvoorbeeldhet synchroniseren van data of het afspelen van muziek. Ook zou je data afkomstig van een re-mote server kunnen cachen zodat er dan ook met de applicatie kan worden gewerkt zonder dater een netwerkverbinding aanwezig is. De grote vraag is: hoe kun je als ontwikkelaar gebruikmaken van deze nieuwe functionaliteit? In dit artikel wil ik laten zien hoe background agentswerken in WP7. Ik beschrijf wat een background agent is, wat deze voor je kan betekenen enwaar je op moet letten als je er één implementeert. Wat mag wel en wat mag niet? Laat ik bijhet begin beginnen.

In Figuur 1 zie je een visuele weergave van de samenhang.

Figuur 1: Tasks en Agents

De tasks kunnen met de ScheduledActionService worden geagen-deerd zodat ze op bepaalde momenten worden uitgevoerd. Het uit-voeren wordt gedaan door de background agent, zoals we later zullenzien. Een task op zichzelf is eigenlijk niet meer dan een geagendeerditem met een type, een naam, interval en een verloopdatum. Meta-data eigenlijk dus. De task zelf bevat namelijk geen functionaliteit en iseen sealed class, overerven en uitbreiden is dus niet mogelijk. Uitein-delijk is het de agent aan wie een betreffende task aangeboden wordt.Deze kan dan op basis van type en naam van de task de juiste dingen gaan uitvoeren. En het type van de task bepaalt ook de restricties die op het moment van uitvoeren gelden.

MAGAZINE

20

Page 21: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

MOBILE

Soorten TasksEr is een tweetal soorten tasks in WP7. De Periodic en de ResourceIntensive task. Zie Figuur 2 voor het objectmodel. Beiden leiden af vanScheduled Task die op zijn beurt weer afgeleid is van Scheduled -Action. De twee tasks bieden zelf geen extra functionaliteit, hun typeis hun bestaansrecht in feite. De Scheduled Notification class en de afgeleiden daarvan zijn toegevoegd in de afbeelding voor de volledig-heid.

Figuur 2: Soorten tasks

Laten we eerst eens kijken naar de Periodic task. Deze wordt eens inde 30 minuten uitgevoerd. Je hebt geen invloed op het precieze moment van uitvoeren, dat bepaalt het OS. Volgens de documentatiezou het OS vanuit energiezuinigheidsoverwegingen zelfs kunnen be-sluiten om bepaalde agents om de 10 minuten uit te voeren. Het doelvan deze soort is om met een regelmatig interval kleine taken uit tevoeren die, per keer dat deze uitgevoerd worden, niet meer dan 25 seconden mogen duren. Als dat toch langer duurt, zal ook hier de taakafgebroken worden.

De andere soort task is de ResourceIntensive task. Zoals zijn naam aldoet vermoeden, is deze bedoeld om lange operaties uit te voerenzoals bijvoorbeeld het downloaden en lokaal cachen van data vanafeen server. Vanwege de aard van de task, is het dan ook toegestaandat hij langer mag doen over zijn werk dan zijn Periodic tegenhanger,namelijk 10 minuten. Echter zijn er wel een aantal condities waaraanvoldaan moet zijn voordat überhaupt de task uitgevoerd zal worden.Deze condities zijn:- Je device moet op een stroombron aangesloten zijn.- Je device moet een wifi verbinding hebben, of verbonden zijn met een netwerk via de PC

- De batterijlading moet minstens 90% zijn- Het lockscreen moet actief zijn- Er mag geen actief telefoongesprek zijn- Tijdens het uitvoeren van een task mag er niet overgeschakeld worden van wifi naar bijvoorbeeld een 3G verbinding

Mocht tijdens uitvoering van de task aan één van bovenstaande condities niet meer worden voldaan dan zal op dat moment meteende task beëindigd worden. Als we deze regels allemaal bij elkaar optellen, dan betekent dit dus eigenlijk dat deze soort task alleen uitgevoerd kan worden als de telefoon niet gebruikt wordt. Stel dat degebruiker van de telefoon niet de beschikking heeft over een wifi

verbinding, dan zou het kunnen zijn dat de background agent nooitaan zijn werk toekomt. Kritieke functionaliteit van de applicatie moetdus niet in een dergelijke agent geïmplementeerd worden, of er zaleen alternatief in de app zelf moeten worden ingebouwd om dezefunctie op te vangen.

Voor de tasks geldt dat ze verlopen na veertien dagen. Dat houdt inde praktijk in dat, wanneer de applicatie gedurende en na die periodeniet gebruikt wordt, er dus geen background agent meer geactiveerdzal worden totdat deze weer opnieuw gescheduled wordt. Wanneereen agent twee maal gecrasht is wordt deze ook uit het schedule verwijderd.

Geen restricties in debug modusAl deze restricties gelden niet wanneer de applicatie in debug modusdraait. Ook zal je er dan zelf voor moeten zorgen dat de betreffendetask ‘gescheduled’ wordt. Dit kun je doen met behulp van de classScheduledActionService. Deze heeft een LaunchForTest methode dieje kunt aanroepen waarna een task die matcht met de meegegevengeactiveerd zal worden. Om er voor te zorgen dat deze methode alleen aangeroepen wordt tijdens het debuggen is het aan te raden ereen #if/#endif conditie omheen te zetten, zie Listing 1.

#if DEBUG

ScheduledActionService.LaunchForTest("MyTaskName",

TimeSpan.FromS-

econds(10));

#endif

Listing 1: ScheduledActionService.LaunchForTest

Dit zou je bijvoorbeeld in de constructor van de App class kunnenplaatsen in het bestand App.xaml.cs of in je agent, zodat deze elkekeer weer opnieuw gestart zal worden.

Wanneer je deze code in een release versie draait op je device zal detask gewoon uitgevoerd worden! De aanroep wordt dus niet onder-schept. Zeer waarschijnlijk zal de applicatie niet door de marketplacecertificering komen wanneer er handmatig een task geactiveerd wordt,ik heb het echter niet uitgeprobeerd.

Hoe maak ik een background agent?Nu we wat nader kennis hebben gemaakt met een background agentgaan we eens kijken hoe je een agent kunt maken. We gebruiken hiervoor Visual Studio 2010 maken door aan een Windows Phone 7solution in Visual Studio 2010 een background agent project toe tevoegen, zie Figuur 3:

Figuur 3: Windows Phone Background agent project toevoegen

Periodic en Resource Intensive Tasks

magazine voor software development 21

Page 22: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

MOBILE

MAGAZINE

22

In de WMAppManifest.xml van je applicatie zal automatisch door Visual Studio ook een referentie naar deze backgroundagent opgenomen worden, zie Figuur 4. Wanneer je je agent hernoemt zulje zelf de manifest file bij moeten werken om het weer te laten werken.

Fig. 4: WMAppManifest.xml

In het background agent project genereert Visual Studio meteen eenScheduledAgent class voor je uit. Deze class bevat één methode diegebruikt wordt door de SchedulerService om de agent te vertellen dathij aan het werk moet. Deze methode is OnInvoke(...). Zie Listing 2voor het code voorbeeld.

/// <summary>Agent that runs a scheduled task</summary>

/// <param name="task">The invoked task</param>

/// <remarks>

/// This method is called when a periodic or resource inten-

sive

/// task is invoked

/// </remarks>

protected override void OnInvoke(ScheduledTask task)

{

try

{

//Do work

NotifyComplete();

}

Listing 2: Scheduled Agent

Deze OnInvoke methode verwacht een task object van het type ScheduledTask. We weten nu dat dit de base class is voor de PeriodicTask en de ResourceIntensiveTask. Wanneer door de applicatie bijvoorbeeld zowel een periodic als een resource intensivetask gescheduled zijn, zullen beide tasks op dezelfde manier via dezemethode worden aangeboden. De agent moet dan bepalen wat ermoet gebeuren voor welke task, er mag immers maar één backgroundagent per applicatie aanwezig zijn. Het OS garandeert dat er maar ééninstantie van de agent op een moment in de tijd actief is.

Wanneer het werk afgerond is, moet NotifyComplete() aangeroepenworden om de runtime er van te verwittigen dat het werk klaar is.Mocht er wat fout gaan dan moet Abort() worden aangeroepen. Ditzal er voor zorgen dat de IsScheduled property op false gezet wordt.De foreground applicatie kan hiermee controleren of Abort() aangeroepen is en dat de task weer opnieuw gescheduled dient teworden.

Schedulen van de agent / taskOm er voor te zorgen dat de agent ook daadwerkelijk aangeroepenwordt moeten er één of meerdere tasks gescheduled worden. Dat kanop de manier zoals te zien in Listing 3.

bool agentsAreEnabled = true;

PeriodicTask periodicTask = new PeriodicTask("MyPeriodic-

Task");

// Place the call to Add in a try block in case the

// user has disabled agents.

try

{

var task = ScheduledActionService.Find(periodicTask.Name);

if (task == null)

{

ScheduledActionService.Add(periodicTask);

}

}

catch (InvalidOperationException exception)

{

if (exception.Message

.Contains("BNS Error: The action is disabled"))

{

MessageBox.Show("You have disabled background" +

"agents for this application.");

agentsAreEnabled = false;

}

}

catch (SchedulerServiceException)

{

// No user action required.

}

Listing 3: Registreren van een task

Zoals je in de code kunt zien is er geen manier om te achterhalen ofde gebruiker het uitvoeren van background agents heeft disabled in desettings. Door de aanroep van de Add methode op de ScheduledActionService binnen een try catch te plaatsen kun je achterhalen ofdit het geval is en een passende melding geven naar de gebruiker metde mogelijkheid om die melding voortaan te onderdrukken. Naar mijn mening verdient dit geen schoonheidsprijs, maar dit is hoe het volgens de documentatie zou moeten. Deze code zou je typisch in de Application_Launching of Application_Activating eventhandlers van deApp class kunnen plaatsen. Het is niet toegestaan om meer dan éénperiodic task of meer dan één resource intensive task aan de ScheduledActionService toe te voegen. Een combinatie van de tweetypes mag dus wel, maar niet meer dan dat.

In feite is hiermee de basis gelegd om een scheduled backgroundagent te maken. Laten we eens verder gaan met wat specifieke zakenuit de praktijk waar je mogelijk tegenaan kunt lopen.

Cachen van data in een background agentVoor een interne applicatie die we binnen ons bedrijf gebruiken voorhet kunnen bekijken van informatie van multitrack / multisessie seminars e.d. wilde ik een proof of concept uitvoeren om te kijken ofik de sessiedata van zo’n conferentie lokaal zou kunnen cachen. Een typische klus die een agent voor me kan opknappen. Om deze caching functionaliteit te realiseren had ik een simpel datamodel gemaakt met één tabel genaamd Session met daarin naam, beschrijving, tijd, locatie, etc. Gebruikmakend van de DataContextclass kan ik een database creëren op het apparaat wanneer deze nogniet bestaat en eventueel al initieel vullen met data, zie Listing 4.

// Create the database if it does not exist.

using (MyDataContext db =

new MyDataContext("Data Source=isostore:/EventData-

base.sdf"))

{

if (db.DatabaseExists() == false)

{

// Create the local database.

db.CreateDatabase();

Page 23: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

MOBILE

magazine voor software development 23

// Prepopulate the sessions table

db.Sessions.InsertOnSubmit(new Session {Name = "Ses-

sion1"});

db.Sessions.InsertOnSubmit(new Session {Name = "Ses-

sion2"});

db.Sessions.InsertOnSubmit(new Session {Name = "Ses-

sion3"});

// Save sessions to the database.

db.SubmitChanges();

}

}

Listing 4: Database aanmaken

Maar wat doet bijvoorbeeld zo’n datacontext met het geheugen -gebruik van de agent? Valt dat binnen de marge van 6 Mb? Dit zijnzaken die wel onderzocht moeten worden tijdens het bouwen van eenagent. Want dat zal waarschijnlijk de eerste restrictie zijn waar tegen-aan gelopen wordt. Tijdens het debuggen zul je niks van die restrictiemerken, maar je kunt wel inzichtelijk maken wat het geheugengebruikop een bepaald moment is, wat de limiet is en het grootste aantalbytes dat op een bepaald moment nodig was. Dit kunnen we doenmet de DeviceStatus class. Deze heeft een drietal properties waar-mee je het geheugengebruik inzichtelijk kunt maken. - DeviceStatus.ApplicationMemoryUsageLimit- DeviceStatus.ApplicationCurrentMemoryUsage - DeviceStatus.ApplicationPeakMemoryUsage

Laten we dit eens toepassen en zien wat er allemaal gebeurt in eenagent. Zie Listing 5.

protected override void OnInvoke(ScheduledTask task)

{

try

{

Debug.WriteLine("Current application memory limit: {0}",

DeviceStatus.ApplicationMemoryUsageLi-

mit);

Debug.WriteLine("Start of OnInvoke --- " +

"Current application memory usage: {0}",

DeviceStatus.ApplicationCurrentMemoryU-

sage);

using (var ctx =

new SessionsDataContext(DataAccess.Constants.DbConnec-

tionString))

{

Debug.WriteLine("DataContext created --- " +

"Current application memory usage:

{0}",

DeviceStatus.ApplicationCurrentMemory-

Usage);

ctx.ObjectTrackingEnabled = false;

var result = ctx.Sessions.Max(s => s.SessionId);

Debug.WriteLine("Determine max Sessions Id ---" +

"Current application memory usage:

{0}",

DeviceStatus.ApplicationCurrentMemory-

Usage);

}

Debug.WriteLine("Current application memory peak usage:

{0}",

DeviceStatus.ApplicationPeakMemoryU-

sage);

NotifyComplete();

}

catch (Exception)

{

Abort();

}

}

Listing 5: Geheugengebruik in een agent

In deze code vraag ik het huidige aantal bytes op dat de agent in beslag neemt op het moment dat de OnInvoke is aangeroepen, vervolgens creëer ik een DataContext object en schrijf weer het huidigegeheugengebruik naar het output window, hetzelfde voor het opvragen van het hoogste session id. De tekst in Listing 6 toont de inhoud van het output window na het uitvoeren van de OnInvoke methode.

Current application memory limit: 6291456

Start of OnInvoke --- Current application memory usage:

3657728

'Background Task' (Managed): Loaded

'Microsoft.Phone.Data.Internal.dll'

DataContext created --- Current application memory usage:

4530176

'Background Task' (Managed): Loaded 'System.Xml.Linq.dll'

'Background Task' (Managed): Loaded 'Unmanaged Memory

Stream'

Determine max Sessions Id --- Current application memory

usage: 6004736

Current application memory peak usage: 6017024

Listing 6: Geheugengebruik inzichtelijk

De limiet geeft een getal weer van 6291456, dat overeenkomt met ongeveer zes megabyte, zoals ook door de documentatie wordt aangegeven. Op het moment dat de OnInvoke method is gestart is erongeveer een ruime drie en een halve megabyte aan geheugen gealloceerd. Vervolgens zien we dat er een assembly ingeladen wordt,deze wordt geladen vanwege de DataContext die we willen gaan gebruiken. Als de DataContext is geïnstantieerd, zitten we al op zo’nvier en een halve megabyte. Na het bepalen van het hoogste sessionid, waarvoor System.Xml.Linq.dll ingeladen wordt, zit het gealloceerdegeheugen zo’n beetje tegen de grens van wat mag aan. Dit is toch alredelijk stevig te noemen. Wanneer ik twee overbodige assembliesweghaal uit mijn references (System.Net.dll en System.Xml.dll) scheeltdat 4 Kb. Wanneer ik het statement ctx.Sessions.Max(...) vervang dooreen foreach loop waarin ik zelf het hoogste id opzoek scheelt dat nogeens 147 Kb...! Bij elkaar dus zo’n 150 Kb die ik heb kunnen uitsparen. Dat lijkt niet veel maar bij een limiet van zes megabyte helpen alle beetjes. Nu zou je kunnen denken, gebruik hier dan een resource intensive task voor. Maar voor dat type geldt dezelfde geheugenlimiet, dus dat helpt niet. Alleen de tijdslimiet is groter.

Bovenstaand voorbeeld laat zien hoe voorzichtig je moet zijn met hetschrijven van code in een background agent. Elk statement moet je opeen weegschaal leggen en kijken wat het voor een effect heeft op jeagent. Dit wijst erop dat je in een background agent niet al te zwaretaken kunt doen, ongeacht het type task. Het datacontext object in ditvoorbeeld is nog heel summier, een tweede tabel erbij in (alleen dedeclaratie) betekent weer 32Kb minder aan besteedbaar geheugen.

Memory gebruik analyseren loont de moeite

Page 24: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

MOBILE

MAGAZINE

24

Het is dus zaak bij het maken van een background agent heel goedop de 6 Mb restrictie te blijven letten en dit te meten en te testen in jeapplicatie. Anders zal de agent in de praktijk regelmatig gestopt worden en niet zijn werk kunnen doen, wat natuurlijk niet de opzet vaneen agent is.

Een andere toepassing van een background agent: updaten vaneen live tileEen background agent levert het ideale mechanisme om een live tilete updaten. Laten we eens bekijken hoe dit werkt. De standaard tilevan de applicatie is altijd aanwezig. Ongeacht of deze aan het start-scherm gepind is of niet. Deze kan ook niet vanuit code verwijderdworden. Om een referentie naar deze tile te krijgen kunnen we gebruiken maken van de ShellTile api. Door ShellTile.ActiveTiles te bevragen kunnen we bij alle tiles die bij je applicatie horen. De eerstetile is altijd de standaard live tile. Wanneer deze niet gepind is zullen updates van deze tile niet zichtbaar zijn. Om een tile te updaten of eensecondary tile te maken, moeten we gebruik maken van de klasseStandardTileData, zie Figuur 5.

De Title, Count en BackgroundImage properties zijn properties die vantoepassing zijn op de voorkant van de tile, de anderen worden getoond op de achterkant. Wanneer er geen van de Back... proper-ties ingevuld worden zal de tile niet omdraaien. Listing 7 laat zien hoede application tile geüpdatet kan worden.

var applicationTile = ShellTile.ActiveTiles.FirstOrDefault();

if (applicationTile != null)

{

var tiledata = new StandardTileData

{

Count = 2,

BackgroundImage = new Uri("UpdatedBackground.png",

UriKind.Relative),

Title = "My Updated Title",

BackContent = "My back content",

BackTitle = "My back Title"

BackBackgroundImage =

new Uri("UpdatedBackBackground.png",

UriKind.Relative),

};

applicationTile.Update(tiledata);

}

Listing 7: Aanpassen van de application tile

Er is ook nog een manier om een secondary tile te creëren. Alleen kandit niet vanuit een background agent, aangezien deze op de achtergrond draait. Wanneer je dit probeert zal er een InvalidOperati-onException optreden. Hoe je dat doet, zie je in Listing 8.

var secondaryTiledata = new StandardTileData

{

BackContent = "Using Background agents",

BackTitle = "Background agent",

BackBackgroundImage = new Uri("BackgroundTile.png", Uri-

Kind.Relative),

BackgroundImage = new Uri("Background.png", UriKind.Re-

lative),

Title = "Foreground Title"

};

var secondaryTile= ShellTile.ActiveTiles.FirstOrDefault(x =>

x.NavigationUri.OriginalString.Contains("MyId=5"));

if (secondaryTile== null)

{

ShellTile.Create(new Uri("/Views/Details.xaml?MyId=5",

UriKind.Relative),

secondaryTiledata);

}

Listing 8: Creeren van een secondary tile

ConclusieHet background agent fenomeen in Windows Phone 7 is een mooiconcept. Het gevaar dat in zo’n techniek schuilt is dat de batterijduurvan een telefoon flink verkort zou kunnen worden. Maar de ontwikkelaars van Microsoft hebben door de nodige kaders te stellenhet risico geminimaliseerd. Aan de ontwikkelaar de taak om hier opeen goede manier mee om te gaan. We hebben gezien welke back-ground agents er zijn en wat de tasks en agents met elkaar te makenhebben. Ook hebben we geleerd wat de restricties zijn waar rekeningmee moet worden gehouden tijdens het ontwerp en de implementa-tie van een applicatie met een background agent. Het programmeer-model is rechtlijnig en niet moeilijk te begrijpen, het zijn eerder allezaken er omheen waar goed over nagedacht moet worden. Hopelijkkun je nu na het lezen van dit artikel zelf aan de slag!

Background agents for windows phonehttp://msdn.microsoft.com/en-us/library/hh202961(v=vs.92).aspx

Unsupported APIs for background agentshttp://msdn.microsoft.com/en-us/library/hh202962(v=vs.92).aspx

How to: Disable Features of an Application for a 256-MB Devicehttp://msdn.microsoft.com/en-us/library/hh855083(v=vs.92).aspx •

Patrick Gilhuijs

Patrick Gilhuijs werkt als lead deve-

loper voor het Professional Devel-

opment Centre bij Info Support b.v.

Hij heeft meer dan 10 jaar ervaring

in de ICT en houdt zich voorname-

lijk bezig met Microsoft technologie.

Patrick interesseert zich o.a. voor

mobile development voor Windows

Phone 7 en iOS.

Page 26: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

DELPHI Cary Jensen

Some of you might be aware that I have written several papers aboutLiveBindings for Embarcadero, one of which is almost 50 pages inlength. I have also recorded an hour long Webinar, as well as five short5-10 minute videos on LiveBindings. You can find links to these articles and videos at the following URL:

http://www.Embarcadero.com/livebindings

I am providing you with this link so that you will have access to all ofthe material that I have produced on LiveBindings since XE2 shipped.I have spent considerable time getting my head around LiveBindings,and what I have learned has really opened my eyes. I am seeing themin a different light, and I am going to share these impressions with youin this article.

At the same time, I want you to know that this is a new and original article that I've written specifically for the Software Development Network. I hope that it answers some of the remaining questions thatyou have about LiveBindings, and raises even more.

Understanding Binding ScopeAt the end of my last article on LiveBindings I promised that I wouldreturn to the issue of scope. This is appropriate because scope is suchan essential part of getting LiveBindings to do for you the things thatyou want.

Scope relates to the expression engine, which is the mechanism thatevaluates string expressions at runtime, resolving those expressions toa value. That value may either be a value type or a reference type, de-pending on the nature of the expression. In this respect, scope spe-cifically refers to what can be referenced by the expression engine.

When you are using LiveBinding components, such as BindExpressions and BindLinks, those components place any registered custom methods within the expression engine's scope, making it possible to call those custom methods in your expressions.By comparison, if you use the TBindings class, which is found in the System.Bindings.Helper unit, you will need to add custom methods tothe scope explicitly.

An example of this, which is based upon code that Embarcadero engineer Jim Tierney wrote for one of his Code Rage 6 presentations,demonstrates how registered custom methods are added to an emptyscope, and then used to evaluate a string expression that containsboth string literals and a numeric literal.

procedure TForm1.ExpressionWithCustomMethodsBtnClick(Sender:

TObject);

var

i: Integer;

Scope: IScope;

Expression: TBindingExpression;

ValueInt: IValue;

Value: TValue;

begin

Scope := TDictionaryScope.Create;

Scope := TNestedScope.Create(Scope, TBindingMethodsFac-

tory.GetMethodScope());

Expression :=

TBindings.CreateExpression(Scope, '"5 x " + ToStr(5) + "

= 25"');

ValueInt := Expression.Evaluate;

Value := ValueInt.GetValue;

ShowMessage(Value.ToString);

end;

The execution of this code results in the following dialog box.

Fig. 1: An expression evaluated by the expression engine. The custom methods needed to be added to the scope explicitly in the absence of LiveBinding components.

When the expression engine is called directly there is only one scope,the scope associated with the expression being evaluated. When Live-Bindings are involved, there are usually two scopes: the input scopeand the output scope. The input scope defines the objects and custom methods that are visible to the expression engine for the expression that is being evaluated to a value. This scope is essentiallythe equivalent of the scope involved when you evaluate an expressiondirectly using the expression engine.

The output scope defines the object and output converters that areused to assign the result of the input expression evaluation to a property of an object in the output scope. From what I can tell, it would

LiveBindings: Taking Another LookThis is the third and final installment in this series of LiveBindings articles. In the first two articlesI introduced LiveBindings and discussed their basic, design-time configuration. In this article I will discuss scope, runtime code, LiveBindings with side-effects, LiveBinding limitations, andgeneral guidelines for LiveBinding usage.

MAGAZINE

26

Page 27: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

DELPHI

be unusual to invoke methods of an object in the output scope by wayof the output expression (I am not even sure that doing so is possible).However, assigning the value of the input scope expression to a property of an object in the output scope is certainly in order. In fact,it can be particularly interesting when the property that is assigned toperforms side effects, although those side effects are often limited to the internal data of the object in the output scope.

Object, Properties, and MethodsThe critical aspect of scope is that it places the properties and methods of the objects in scope within reach of the expression engine. For example, when an object is within the input scope, its properties can be included in the input expression, which gives theLiveBinding using that expression to ability to synchronize an object inthe output scope (the object to which the evaluated expression will beassigned) with the input expression. This is the original intent of LiveBindings, and it is essential for FireMonkey data-awareness.

Fortunately for us, and here is where it starts to get interesting, LiveBindings are far more capable than simple property binding. Whatisn't immediately obvious is that the methods of objects within scopeare also callable by the expression engine. This means that the valuesreturned by those methods, when those methods return a value, canalso used when evaluating the value that will be bound to the propertyof the output object. This goes way beyond simple property binding,permitting complex conversions, and more importantly, side effects.Compared to the side effects that are typical of property assignment,side effects performed by expressions called by the expression engine may be capable of synchronizing many objects, even thoseoutside the scope of the LiveBinding itself.

Here is how this can work. In many cases, the form on which an object is placed can be accessed from a LiveBinding by using theOwner property of the object in scope. This reference can then beused to execute a method on the form from the LiveBinding. This method can operate on any object within its scope. And here I amusing the term scope in the traditional sense: the visibility of symbolsat the point of code execution. In other words, the reach of a LiveBinding can quickly expand to that of the compiled code of yourapplication.

Fig. 2: A LiveBinding that extends its reach beyond its immediateinput scope

Here is a simple example from my white paper Understanding LiveBindings in RAD Studio (this white paper is available at the URLI listed at the beginning of this article). The following figure displays theproperties of a BindExpression LiveBinding attached to an Action of anActionList. This Action is employed by two Buttons on a form, butcould have been used by any number of user interface components.

The Action serves as both the input scope and the output scope. TheControlExpression, the output expression, is the Caption of the Action. The input expression uses the Owner property of the Action toinvoke a method of the form called OpenCDS, to which a property ofthe input expression, the Caption property of the Action, is passed.Here is the OpenCDS method implementation.

function TForm1.OpenCDS(Open: Boolean): string;

begin

if Open then

begin

ClientDataSet1.Open;

ClientDataSet1.LogChanges := False;

exit('Close');

end

else

begin

ClientDataSet1.SaveToFile;

ClientDataSet1.Close;

exit('Open');

end;

end;

The effect of this method is to open and close a ClientDataSet, whichin turn toggles the caption of the two buttons that are bound to thisAction. This is a simple, though interesting use of a LiveBinding sideeffect.

Here is another example. The following form contains two Edits thatare synchronized using a BindExprItem LiveBinding.

Fig. 3: A form whose functionality is performed entirely by a managed LiveBinding, and its one, simple Notify method invocation.

As you enter dollars into one Edit, the corresponding value in euros appears in the other, and visa versa. Here is the Object Inspector displaying the format expression that performs the euro to dollar conversion.

The reference to Converter in the ControlExpression is an instance ofthe TConverter class, an instance of which is created in the OnCreateevent handler of the form. Listing 1 includes the simple TConverterclass in its entirety.

magazine voor software development 27

Page 28: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

DELPHI

Fig. 4: A format expression that converts euros to dollars, by callingthe ConvertToEuros method of an object associated with the formon which the LiveBinding bound Edit appears.

unit converteru;

interface

uses System.SysUtils, System.Classes;

type

TConvertor = class(TComponent)

private

function GetEuroConversion: Extended;

function GetDollarConversion: Extended;

public

{ Public declarations }

function ConvertToDollars(const Value: string): String;

function ConvertToEuros(const Value: string): String;

property EuroConversion: Extended read GetEuroConversion;

property DollarConversion: Extended read GetDollarConver-

sion;

end;

implementation

function TConvertor.ConvertToDollars(const Value: string):

string;

var

f: Extended;

begin

Result := '';

if TryStrToFloat(Value, f) then

begin

Result := FloatToStr(f * DollarConversion);

end;

end;

function TConvertor.ConvertToEuros(const Value: string):

string;

var

f: Extended;

begin

Result := '';

if TryStrToFloat(Value, f) then

begin

Result := FloatToStr(f * EuroConversion) ;

end;

end;

function TConvertor.GetDollarConversion: Extended;

begin

Result := 1 / EuroConversion;

end;

function TConvertor.GetEuroConversion: Extended;

begin

//In a real world example, this value would

//be obtained from a Web service or other source.

Result := 0.762

end;

end.

Listing 1: The TConverter class and implementation

I find this very exciting, and I hope that you do, too. What this code demonstrates is that your LiveBinding scope can easily reach well beyond the boundaries of the object in the input scope. I'll talk a littlemore about this later in this article.

When are LiveBinding Expressions Evaluated?LiveBinding expression evaluation is a particularly interesting issue,and one that I imagine will become more flexible in future versions ofLiveBindings. Managed LiveBindings are activated when they are created if their AutoActive property is set to True, the default. Otherwise, they become active when their Active property is set toTrue. In any case, when the managed LiveBinding becomes active theexpression engine evaluates the associated expressions and performsthe configured assignment.

For example, the expression shown in Figure 2 executes when theform on which the Action appears is created. In fact, the initial Caption of the Action is Close, which causes the expression to attempt to close the ClientDataSet (which does nothing since it is already closed, but that is not a problem), and then sets the captionto Open, which in turn sets the captions of both of the bound Buttonsto Open. There is no way to avoid this first execution, though in the fu-ture I hope that we can avoid this by setting a not-yet implementedproperty that permits a LiveBinding to be activated without the initial,automatic evaluation.

Unmanaged LiveBindings are activated by their BindScope (such asa BindScopeDB). When the BindScope is activated, it activates everyLiveBinding that uses it, in turn, causing each of the associated expressions to be evaluated. This too, cannot be avoided at present,but once again, it does not appear to be a big issue.

This automatic evaluation when a LiveBinding is activated leads to some interesting behavior. This is especially true with respect to managed LiveBindings whose AutoActivate properties are set to True,since this activation occurs very early in the life cycle of a form.

Here is an example that demonstrates the issue. Consider the classesand their method implementations shown in Listing 2. I can use thischain of classes to execute the methods of TMyClassC from a LiveBinding that has the Form in its input scope.

unit mainformu;

interface

uses

Winapi.Windows, Winapi.Messages, System.SysUtils,

System.Variants,

System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms,

MAGAZINE

Unmanaged LiveBindings are activated by their BindScope

28

Page 29: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

DELPHI

Vcl.Dialogs,

Data.Bind.EngExt, Vcl.Bind.DBEngExt, System.Rtti,

Vcl.StdCtrls,

System.Bindings.Outputs, Vcl.Bind.Editors, Data.Bind.Com-

ponents;

type

TMyClassC = class(TComponent)

private

FMyName: string;

public

function GetMyName: String;

class function AClassMethod: string;

constructor Create(AOwner: TComponent); override;

end;

TMyClassB = class(TComponent)

private

FMyClassC: TMyClassC;

public

constructor Create(AOwner: TComponent); override;

property MyClassC: TMyClassC read FMyClassC;

end;

TMyClassA = class(TComponent)

strict private

FMyClassB: TMyClassB;

public

constructor Create(AOwner: TComponent); override;

property MyClassB: TMyClassB read FMyClassB;

end;

TForm1 = class(TForm)

Label1: TLabel;

BindingsList1: TBindingsList;

BindExpressionLabel11: TBindExpression;

Label2: TLabel;

BindExpressionLabel21: TBindExpression;

procedure Button1Click(Sender: TObject);

procedure FormCreate(Sender: TObject);

private

FMyClassA: TMyClassA;

public

constructor Create(AOwner: TComponent); override;

property MyClassA: TMyClassA read FMyClassA;

end;

var

Form1: TForm1;

implementation

{$R *.dfm}

constructor TForm1.Create(AOwner: TComponent);

begin

inherited;

FMyClassA := TMyClassA.Create(Self);

BindExpressionLabel11.Active := True;

end;

procedure TForm1.FormCreate(Sender: TObject);

begin

BindExpressionLabel11.Active := True;

end;

constructor TMyClassA.Create(AOwner: TComponent);

begin

inherited;

FMyClassB := TMyClassB.Create(Self);

end;

constructor TMyClassB.Create(AOwner: TComponent);

begin

inherited;

FMyClassC := TMyClassC.Create(Self);

end;

class function TMyClassC.AClassMethod: string;

begin

Result := 'This string is returned by a class function';

end;

constructor TMyClassC.Create(AOwner: TComponent);

begin

inherited;

FMyName := 'Here I am, ' + Self.ClassName;

end;

function TMyClassC.GetMyName: String;

begin

result := FMyName;

end;

end.

Listing 2

There are two LiveBindings on this form, both of which are managedLiveBindings, but for this example, I am only interested in their initialevaluation, which is why there are no calls to Notify in this code.One of these LiveBindings has its AutoActivate property set to False,and the other to True. Here is the BindExpression associated with thefirst LiveBinding.

Fig. 5: A LiveBinding whose AutoActivate property is set to False.

Fig. 6: A LiveBinding whose AutoActivate property is set to True.

magazine voor software development 29

Page 30: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

DELPHI

The primary difference between these two LiveBindings relates to themethods that the LiveBindings can touch when they are initially madeactive. The LiveBinding whose AutoActivate property is False has itsActive property set to True from the form's OnCreate event handler.This LiveBinding can call instance methods of TMyClassC when it isfirst activated. By comparison, the second LiveBinding, whose expression is evaluated in the very early stages of the form's creation(which occurs well before OnCreate is invoked) can only call class methods of TMyClassC, since an instance of TMyClassC is not yetavailable when this LiveBinding becomes active.

Figure 7 depicts how this form looks as it is currently configured. If wethen set the AutoActivate property of the LiveBinding whose expression is shown in Figure 5 to True, and run the project again, thecall to GetMyName will fail, and the expression will return a null value,as shown in Figure 8.

Fig. 7: Two LiveBinding, which are evaluated only once, assign texttwo two Label that appear on the form

Fig. 8: What the form in Figure 7 looks like if the LiveBinding expression in Figure 5 is auto activated.

Is this a big problem. Not really. For example, the BindExprItem usedto implement the dollar/euro conversion example shown in figure 3 isan auto activated LiveBinding, and both of the conversion expressionsare evaluated during the initialization of the form, even though theTConverter class has not yet been created. The result is that the eva-luation of the instance methods ConvertToEuros and ConvertToDollarsboth return null, and a blank value is assigned to the two Edits. If wewanted the form to be created with initial values in either of the Edits,we would have had to activate the BindExprItem within the form's OnCreate event handler (or some similar, post creation method).

LiveBinding LimitationsRAD Studio XE2 added a number of significant features, including 64-bit compilation, cross-platform compilation, support for iOS, a remarkable new component library (FireMonkey), LiveBindings, andmore. Of all of these features, LiveBindings have probably generatedthe most controversy among developers. Most of these complaints are well-deserved, but not all. Since I havespent a considerable time working with LiveBindings, I'd like to takethe opportunity to address these issues. The most common complaintis that LiveBindings don't add anything new to what we can alreadydo with RAD Studio. Furthermore, those things that they do are morecomplex than the alternatives already available to us. I completely disagree. How LiveBindings work is fundamentally diffe-rent than anything RAD Studio has supported in the past. Further-

more, LiveBindings are more complicated than alternative approachesto the extent that we have very little experience working in this declarative manner.

LiveBindings are evaluated at runtime, and can perform this evaluationon strings that do not exist until right before the evaluation is performed. This is novel in RAD Studio, and opens the doors to ope-rations that would previously be unthinkable. If you then consider thatthe side effects that LiveBindings can perform can have a very broadimpact on the execution environment, you start to see the power thatthey enable. That having been said, I agree that most all of the remai-ning complaints are valid, and will require the attention of Embarcaderoif LiveBindings are to mature into the indispensable feature that theycan be. Foremost of these complaints is that there is poor design timesupport for debugging and evaluating LiveBindings. Indeed, a bug inone of your LiveBinding expressions can require that you systemati-cally disable each LiveBinding, one by one, in order to find which oneis misbehaving, after which you still have to figure out what's wrongwith the offending expression. We are going to need better tools towrite and test our expressions as we go forward.

Also, there are some real limits as to which objects can be bound usingunmanaged LiveBindings. For example, it is currently very difficult touse LiveBindings to bind a TList and a StringGrid. This too is a limitation that needs to be addressed.Fortunately, Embarcadero is aware of the complaints, and is listening.They see LiveBindings as a critical part of their FireMonkey infrastruc-ture as it goes forward, and is committed to improving LiveBindings insubsequent releases. (And this applies to the VCL as well.) In the meantime, we, as a community, need to share with Embarcadero how we'dlike to use LiveBindings, as well as what we need LiveBindings to do.

Guidelines for Using LiveBindingsBecause LiveBindings are so new, and so different, they have beenhard to understand. For the longest time I've been looking for that application of a LiveBinding that would really open my eyes to theirtrue potential. It was only after a lot of thought and playing around thatit finally hit me, and the Action example that I described earlier in thisarticle was the result. Sure, that was a simple example, but it was aprofoundly different way of approaching a problem. Instead of writingcode that reacts to a user's interaction, and responds by manipulatingobjects, a string expression is evaluated at runtime in response to achange in state, and side effects produce addition, complementarychanges.

Yeah, that's taking it a bit far, as the Action example is a simple one.But it is a start, and when that example finally hit me I had a hard timesleeping for several days. I keep on thinking of more examples, wherechanges to objects produce effects that reach well beyond the simplesynchronization of one property with another. If the current limitationsof this first release of LiveBindings can be addressed, I think we will seea new paradigm for building interfaces, one that is especially well suited for the "rich GUI interfaces" that we hear so much about thesedays. What's better is that it will be in our favorite development environment, one that can produce native executables on a widerange of platforms. So, even though LiveBindings are relatively new, Ioffer this humble set of rough guidelines for their usage.• LiveBindings are not a replacement for traditional event handlers.Do not try to replace event handlers with LiveBindings, unless LiveBindings provide a better solution

• LiveBindings are not a replacement for sound object oriented programming techniques. For example, implementing side effectswithin an object through property accessor methods may be more appropriate than implementing the same behavior using LiveBindings.

• Don't force the use of LiveBindings. In other words, don't use

MAGAZINE

30

Page 31: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

DELPHI

magazine voor software development 31

LiveBindings just so you can say that you've used them. Use themwhere they make sense. Coming to a better understanding of wherethey are appropriate, however, will take time. LiveBindings are new,and their application will become clearer as we get more familiarwith their utility.

• Limit the number of LiveBindings that you use on a single form. LiveBindings are slow, compared to compiled code. The overuse ofLiveBindings can introduce significant performance issues. Forexample, don't use a LiveBinding to assign a value to a propertywhen design time assignment is sufficient. That's just not a gooduse of a LiveBinding.

SummaryLiveBindings are one of RAD Studio's powerful new features, and areessential for providing data-awareness in FireMonkey application. Theyalso provide a flexible, declarative, runtime mechanism for acting uponobjects in response to changes in state. And although there are clearlimitations in this initial release, LiveBindings introduce promising andexciting new possibilities with respect to user interface design. •

Cary Jensen

Cary Jensen is the bestselling

author of more than 20 books on

software development, including

Delphi in Depth: ClientDataSets,

and winner of the 2002 and 2003

Delphi Informant Reader's Choice

Award for Best Training. A frequent

speaker at conferences, workshops, and seminars throughout

much of the world, he is widely regarded for his self-effacing

humor and practical approaches to complex issues. Cary's com-

pany Web site is at: http://www.JensenDataSystems.com. Cary

has a Ph.D. from Rice University in Human Factors Psychology,

specializing in human-computer interaction.

Als je de Website start in VS11, dan verschijnt er in de taskbar een LocalSTS tool. En op jewebsite zal het Login con-trol keurig de naam latenzien uit het derde tabblad.

Als je kiest voor de Wind-ows Azure ACS omge-ving. Dan geeft je de ACSaccount gegevens op (na-mespace en managementkey). Vervolgens selecteerje welke Identity providersvoor jouw applicatie rele-vant zullen zijn. NB dezemoet je wel eerst zelf heb-ben toegevoegd op deACS administration page.Nadat je OK geklikt hebt,ratelt er iets en zul je ziendat de web.config ineensallerlei verwijzingen naar jeACS bevat. En als je runt,krijg je wat je verwacht.

Op de ACS management portal zijn ook automatisch een aantal zakenaangepast en toegevoegd. Deze opzet maakt het gebruik van WIF enACS een stuk eenvoudiger. •

Visual Studio 11 Beta en WindowsIdentity FoundationMet het uitkomen van Visual Studio 11 Beta is er ook een update gekomen van de Windows Identity Foundation (WIF) tools. De precieze details kun je natuurlijk beter verteld krijgen door Kap-tein Identity (Vittorio Bertocci). Voor de Cloud cover aflevering ziehttp://blogs.msdn.com/b/vbertocci/archive/2012/03/16/the-wif-tools-for-visual-studio-11-beta-on-cloudcover.aspx

In de huidige opzet van WIF en de Windows Azure Access ControlService (ACS) komt het gebruik vooral neer op heel veel configurerenen draaien aan allerlei knoppen was. Met de nieuwe WIF tools is dezeconfiguratie een stuk eenvoudigere geworden.

In het context menu van een Webproject zit nu een menu item ‘Iden-tity and Access’. Het startpunt om de Access control van je Websitein te regelen. Na de keuze verschijnt er een scherm met een beperktaantal keuzes. Zo kun je kiezen voor een local development STS,ADFS2 of ACS. Op de twee andere tabbladen kun je dan de settingsdoen, die voor de gekozen provider van belang zijn. De inhoud vandeze tabbladen is context gevoelig. Als je de local development STS kiest en je gaat naar het derde tabblad, dan zie je daar de waarden die de STS terug geeft aan je

applicatie. Nu kun je je Website betertesten met de verschillende claims.

Page 32: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

CLOUD Edwin van Wijk

relayed communicatie is dat bij brokered communicatie de verzen-der(s) en ontvanger(s) niet tegelijkertijd online hoeven te zijn. Er wordteen pull model gehanteerd voor de ontvanger (zie figuur 2). In dit artikel zal ik alleen brokered communicatie behandelen.

Fig. 2: Brokered communicatie

Servicebus namespaceOm gebruik te kunnen maken van de servicebus, moeten we eersteen servicebus namespace creëren. Op de Azure Management Portal is een onderdeel “Service Bus, Access Control & Caching” aanwezig waar een nieuwe namespace kan worden toegevoegd. Bijhet creëren van de nieuwe namespace kunnen een aantal zaken worden geconfigureerd. Uiteraard kan hier de naam worden opgege-ven. Als de naam reeds bestaat, zal dit worden aangegeven en moeteen andere unieke naam worden gespecificeerd. Naast de naam kanook de regio en de Azure subscription waaronder de namespace moetworden gecreëerd worden gespecificeerd (dit laatste is echter alleenvan belang wanneer met het Live! ID waarmee is ingelogd meerderesubscriptions kunnen worden beheerd). Zie figuur 3 voor een voor-beeld van het dialoog waarmee een nieuwe namespace kan worden gecreëerd.

Messaging patterns metAzure Servicebus Binnen gedistribueerde systemen komen we regelmatig verschillende messaging patterns tegen. Vaakmoet er veel zelf gebouwd en geconfigureerd worden om deze patterns te kunnen ondersteunen. In ditartikel beschrijf ik eerst de standaard functionaliteit voor het verzenden en ontvangen van berichten overde servicebus, inclusief eenvoudige codevoorbeelden. Daarna beschrijf ik aan de hand van praktijk-voorbeelden hoe deze functionaliteit kan worden benut om verschillende messaging patterns te realiseren. Als laatste beschrijf ik additionele servicebus features die gebruikt kunnen worden om complexere messaging patterns te realiseren of de implementatie te optimaliseren.

De Azure Service BusDe Azure Servicebus biedt functionaliteit om applicaties met elkaar telaten communiceren over het Internet. Dit is ook mogelijk als de applicaties achter een firewall of een NAT router draaien. Er moetenwel een aantal uitgaande poorten worden geopend op de firewall,maar dat levert over het algemeen minder problemen op dan een inkomende poort openen. Het principe dat hierbij wordt gehanteerd isdat zowel de ontvangende als de verzendende kant een uitgaandeconnectie opent naar de servicebus zodra ze worden gestart. De servicebus zorgt ervoor dat berichten die worden verzonden bij dejuiste partij worden afgeleverd.

De servicebus biedt 2 manieren van communiceren: “relayed” en “brokered”. Bij relayed communcatie moeten zowel de verzender alsde ontvanger tegelijkertijd online zijn (zie figuur 1). Hierbij wordt ookde mogelijkheid geboden dat de applicaties na initieel via de service-bus te hebben gecommuniceerd, rechtstreeks met elkaar gaan communiceren. Dit wordt “Hybrid mode” genoemd. Hierbij wordt eenmechanisme genaamd “NAT Probing” gebuikt. Relayed communica-tie wordt ondersteund sinds de eerste versie van de servicebus.

Fig. 1: Relayed communicatie

Met de introductie van Queues en Topics in de servicebus, is ook brokered communicatie mogelijk geworden. Het grote verschil met

MAGAZINE

32

Page 33: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

CLOUD

Fig. 3: Creëren service bus namespace

Access Control ServiceDe servicebus wordt standaard beveiligd middels de Access ControlService (ACS). Wanneer een nieuwe servicebus namespace wordtgecreëerd via de Management Portal, wordt automatisch de ACS geconfigureerd voor deze namespace. De ACS is een onderdeel vanAzure dat authenticatie en autorisatie van partijen kan verzorgen. Ikga in dit artikel niet in detail op de ACS in, maar in het kort werkt hetals volgt. Een gebruiker (of applicatie) authentiseert zich bij de ACS. Ditkan op verschillende manieren, bijvoorbeeld door in te loggen met eenLive! ID of met een Google account (dit worden “identity providers”genoemd). Maar dit kan ook door een bepaalde gebruikersnaam eneen bijbehorende geheime sleutel naar de ACS te sturen. Als de ge-bruiker succesvol is geauthentiseerd, zal de ACS vervolgens een tokengenereren met een aantal claims op basis waarvan de applicatie kanbepalen welke operaties door de desbetreffende gebruiker mogenworden uitgevoerd. Met elk verzoek naar de applicatie die wordt beveiligd middels de ACS, wordt vervolgens het token meegestuurd.

Zoals gezegd, wordt bij het creëren van een nieuwe servicebus namespace via de Management Portal automatisch de ACS geconfi-gureerd voor deze namespace. Er wordt een gebruiker (“issuer”) aangemaakt en een bijbehorende geheime sleutel (“issuer secret”) gegenereerd. We zullen later zien hoe we vanuit code de issuer en degeheime sleutel kunnen specificeren als we gebruikmaken van de servicebus. De issuer die standaard wordt aangemaakt is “owner” ende bijbehorende geheime sleutel is op de vragen via de Azure Management Portal.

De servicebus herkent 3 verschillende claims die kunnen worden uitgedeeld door de ACS: Send om berichten te mogen sturen via deservicebus, Listen om berichten te mogen ophalen uit de servicebusen Manage om servicebus entiteiten te mogen creëren, verwijderen,enzovoorts. Wanneer wordt ingelogd met de issuer “owner”, wordenal deze claims door de ACS toegevoegd aan het token. Deze gebrui-ker mag dus alles binnen de servicebus namespace. Het is mogelijkom de ACS zelf te configureren en nieuwe gebruikers toe te voegenmet een specifieke set van claims. Zo is het bijvoorbeeld mogelijk omeen gebruiker te definiëren die alleen berichten kan verzenden naarde servicebus en een andere gebruiker die alleen kan ontvangen vande servicebus.

Azure SDKWanneer je aan de slag wilt gaan met de servicebus, heb je de Wind-ows Azure SDK nodig. Deze is te downloaden van de Windows Azurewebsite (http://www.windowsazure.com/nl-nl/develop/net). Deze SDKbevat alle benodigde classes en tools voor Visual Studio om Windows Azure applicaties te bouwen.

RESTEen subset van de functionaliteit van de servicebus is ook te gebruiken via REST. Dat betekent dat via de servicebus berichten kunnen worden uitgewisseld tussen verschillende platformen. Denkdaarbij aan Java, PHP, enzovoorts. In principe kan elk platform dat de

mogelijkheid heeft om te communiceren via het HTTP protocol dusgebruikmaken van de servicebus. Ik zal het gebruik van de servicebusvia REST in dit artikel niet verder behandelen. In de MSDN is een beschrijving te vinden van de REST API’s die worden aangebodendoor de servicebus.

QueuesQueues topics en subscriptions zijn de features van de servicebus diezorgen voor de loskoppeling in de tijd tussen het verzenden en ontvangen van berichten. Ik behandel eerst de queues. Een service-bus queue gedraagt zich in principe als een traditionele queue: eenverzender plaatst berichten in de queue en de ontvanger leest de be-richten uit de queue (zie figuur 4). Er kunnen meerdere verzenders en/ of meerdere ontvangers zijn voor een queue. Een queue wordt ge-ïdentificeerd door een unieke queuenaam binnen de servicebus namespace.

Fig. 4: Azure Service Bus Queues

Een queue creërenAls we gebruik willen maken van een queue, zullen we deze eerstmoeten creëren in onze namespace. Dit is o.a. mogelijk via de Azuremanagement portal, maar kan ook vanuit code. De servicebus biedteen management API aan waarmee de entiteiten binnen de service-bus kunnen worden beheerd. Voor het gebruik van deze API wordenclasses geleverd in de Azure SDK. In codevoorbeeld 1 zien we o.a.hoe een queue wordt gecreëerd. De classes die in dit voorbeeld worden gebruikt zijn allemaal onderdeel van de Azure SDK in de namespace Microsoft.ServiceBus. Om deze te kunnen gebruikenmoet een referentie gezet worden naar de assemblies: Microsoft.ServiceBus en System.Runtime.Serialization (beide aanwezig in deGAC).

using Microsoft.ServiceBus;

string sbNamespace = "sdnasb";

string sbIssuer = "owner";

string sbIssuerSecret = "0bfu$c@t3d";

string queueName = "SampleQueue";

// maak namespace uri

Uri uri = ServiceBusEnvironment.CreateServiceUri(

"sb", sbNamespace, string.Empty);

// maak credentials

TokenProvider credentials =

TokenProvider.CreateSharedSecretTokenProvider(

sbIssuer, sbIssuerSecret);

// maak queue (als deze nog niet bestaat)

NamespaceManager nsManager =

new NamespaceManager(uri, credentials);

if (!nsManager.QueueExists(queueName))

{

nsManager.CreateQueue(queueName);

}

Codevoorbeeld 1: Creëren van een queue

magazine voor software development 33

Page 34: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

CLOUD

Als we door codevoorbeeld 1 heen lopen, zien we dat eerst de Urivoor onze servicebus namespace wordt gecreëerd met behulp vande ServiceBusEnvironment.CreateSericeURI helper. Vervolgens wordteen TokenProvider gecreëerd om ons te kunnen authentiseren bij deACS. We moeten hierbij de issuer (zoals eerder beschreven is dit standaard “owner”) en de bijbehorende geheime sleutel meegeven.Met de URI en de TokenProvider wordt vervolgens een Namespace-Manager gecreëerd. Deze manager kan worden gebruikt voor het beheren van de namespace. In het voorbeeld is te zien hoe de ma-nager wordt gebruikt om te controleren of de queue reeds bestaat en- indien niet aanwezig - de queue aan te maken. Nu we een queuehebben gecreëerd in onze servicebus namespace kunnen we dezegaan gebruiken om te communiceren.

Het aanmaken van een URI en een TokenProvider is iets dat we altijdzullen moeten doen als we iets met queues of topics willen gaan doen.In de volgende codevoorbeelden zal ik deze code weglaten om ruimtete besparen.

Berichten verzenden naar een queueOm berichten te kunnen versturen naar de servicebus, hebben weeen soort “proxy” nodig die voor ons de berichten waarin we onzedata stoppen op de juiste manier naar de servicebus kan verzenden.In codevoorbeeld 2 is te zien hoe een bericht wordt verzonden naareen queue. Eerst wordt een MessagingFactory gecreëerd. Hier moe-ten we weer de URI van de servicebus namespace en de credentialsvoor de ACS meegeven. Vervolgens creëren we m.b.v. deze factoryeen QueueClient (de “proxy”), waarbij we de naam van de queue specificeren. Nu kunnen we het bericht dat we willen verzenden gaansamenstellen. Een bericht dat we verzenden naar of ophalen uit deservicebus middels brokered communicatie, wordt in .NET gerepre-senteerd door de BrokeredMessage class uit de SDK. In codevoor-beeld 2 zien we hoe een bericht wordt gemaakt dat een order moetvoorstellen.

// maak een queueclient

MessagingFactory messagingFactory =

MessagingFactory.Create(uri, credentials);

QueueClient qClient =

messagingFactory.CreateQueueClient(queueName);

// maak een bericht

BrokeredMessage order = new BrokeredMessage()

{

MessageId = Guid.NewGuid().ToString("N")

};

order.Properties["CustomerId"] = "20111203006";

order.Properties["ProductId"] = "AX781-11-2";

order.Properties["Amount"] = 4;

order.Properties["OrderDate"] = DateTime.Now;

// verstuur het bericht

qClient.Send(order);

Codevoorbeeld 2: Verzenden van een bericht naar een queue

Een bericht heeft een aantal standaard eigenschappen, waaronderhet unieke MessageId. In tabel 1 zijn alle eigenschappen van de BrokeredMessage class genoemd. Een aantal zullen we in dit artikelook gebruiken.

Tabel 1: Eigenschappen van een BrokeredMessage

Naast deze standaard eigenschappen kunnen we ook zelf applicatiespecifieke eigenschappen toevoegen via de Properties eigenschap.In codevoorbeeld 2 wordt op deze manier een aantal eigenschappenvan de order toegevoegd. We zullen later zien dat we de standaard enapplicatie specifieke eigenschappen van het bericht kunnen gebruiken voor het routeren van het berichtenverkeer binnen de servicebus. In codevoorbeeld 2 zien we vervolgens dat het bericht viade QueueClient wordt verzonden. Het bericht staat nu klaar in onzequeue om opgehaald te worden.

Berichten ophalen uit een queueIn codevoorbeeld 3 zien we hoe een bericht uit de queue wordt gelezen. Voor het communiceren met onze queue creëren we wederom een QueueClient instantie. In dit geval geven we bij hierbijeen additionele parameter mee van het type ReceiveMode. Met dezeparameter kunnen we specificeren of we een bericht dat we uit dequeue lezen direct uit de queue wordt verwijderd of niet. In het voorbeeld kiezen we voor de optie om het bericht direct na het opha-len te verwijderen (ReceiveMode.ReceiveAndDelete). Ik kom later nogop de ReceiveMode terug. Vervolgens kijken we of er een bericht in dequeue aanwezig is door de Receive operatie aan te roepen op deQueueClient. Hierbij geven we aan dat we maximaal 5 seconden willen wachten op een bericht. Als binnen deze periode geen berichtin de queue aanwezig is, zal de methode retourneren met de waardenull. Als dit niet het geval is, hebben we een bericht opgehaald uit dequeue en hebben we deze als een BrokeredMessage instantie in handen. Via de eigenschappen van het bericht kunnen we vervolgensde informatie van de Order lezen en in codevoorbeeld 3 is te zien datdeze als voorbeeld worden afgedrukt op het scherm. Het resultaat iste zien in figuur 5.

// maak een queueclient

MessagingFactory messagingFactory =

MessagingFactory.Create(uri, credentials);

QueueClient qClient =

messagingFactory.CreateQueueClient(queueName,

ReceiveMode.ReceiveAndDelete);

// ontvang een bericht

BrokeredMessage receivedOrder =

qClient.Receive(TimeSpan.FromSeconds(5));

if (receivedOrder != null)

{

Console.WriteLine("Order received");

Console.WriteLine("Customer ID : {0}",

receivedOrder.Properties["CustomerId"].ToString());

Console.WriteLine("Product ID : {0}",

MAGAZINE

34

Page 35: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

CLOUD

receivedOrder.Properties["ProductId"].ToString());

Console.WriteLine("Amount : {0}",

receivedOrder.Properties["Amount"].ToString());

Console.WriteLine("Order Date : {0}",

receivedOrder.Properties["Orderdate"].ToString());

}

Codevoorbeeld 3: Ontvangen van een bericht uit een queue

Fig. 5: Eigenschappen van een bericht dat is opgehaald uit eenqueue

Message BodyNaast de eigenschappen die we kunnen specificeren op een BrokeredMessage, kan deze tevens een body bevatten. In de bodykunnen we een object stoppen, zolang het maar serializable is. Deverzender en ontvanger zullen dan moeten afspreken hoe de inhoudvan de body moet worden geïnterpreteerd. Hiervoor kan eventueel deContentType eigenschap van de BrokeredMessage worden gebruikt.Ik laat in dit artikel de body buiten beschouwing en focus alleen op deeigenschappen. Per applicatie moet bekeken worden of het gebruikvan de body noodzakelijk is of dat men met de eigenschappen uit devoeten kan.

Locking mechanismeIn codevoorbeeld 3 hebben we gezien dat bij het aanmaken van eenQueueClient is gespecificeerd dat een bericht dat is opgehaald uit dequeue automatisch moet worden verwijderd uit de queue (middels ReceiveMode.ReceiveAndDelete). Naast ReceiveAndDelete kan ookPeekLock mode worden gebruikt. De queue biedt in dat geval eensoort automatisch retry mechanisme. Op een bericht dat met PeekLock mode wordt opgepakt, wordt in de queue een lock op hetbericht gelegd zodat het niet door een andere ontvanger kan wordenopgepakt. Zodra de ontvanger het bericht heeft verwerkt, markeertdeze het bericht als zodanig door op het bericht de Complete methode aan te roepen. Het bericht wordt vervolgens uit de queueverwijderd. Als de ontvanger om wat voor reden dan ook het berichtniet kan verwerken, dan kan de ontvanger het bericht als het ware afkeuren middels de Abandon methode op het bericht. De lock op hetbericht wordt dan opgeheven en het bericht komt opnieuw beschikbaar in de queue om opnieuw opgepakt te worden.

Een lock op een bericht kan ook op een andere manier worden opgeheven. Een van de configureerbare eigenschappen van eenqueue, is namelijk de standaard lock timeout voor berichten. Als eenbericht met een lock in de queue niet binnen deze timeout wordt gemarkeerd als verwerkt of afgekeurd, wordt de lock automatisch opgeheven en komt het bericht opnieuw beschikbaar in de queue. De lock timeout is standaard 1 minuut. Met dit mechanisme moet welrekening gehouden worden aan de ontvangende kant, omdat de kansbestaat dat berichten meerdere keren worden verwerkt als de verwerking niet binnen 1 minuut kan worden afgerond. Daarnaastmoet rekening gehouden worden met een oneindige loop als een bericht telkens wordt afgekeurd door de ontvangende partij en opnieuw in de queue verschijnt. We zullen later zien hoe we dergelijke

problemen kunnen oplossen met de dead-letter queue feature die deservicebus hiervoor biedt.

TTLEen configureerbare eigenschap van de queue is de periode dat eenbericht in de queue beschikbaar is (time-to-live of TTL). Zodra dezeTTL periode verstrijkt voor een bericht in de queue, wordt het verwij-derd. Bij het plaatsen van een bericht in de queue kan voor dat specifieke bericht een afwijkende TTL worden gespecificeerd. Als deTTL van het bericht groter is dan de standaard TTL geconfigureerd opde queue, dan zal de laatste gebruikt worden. De standaard TTL opde queue is nagenoeg oneindig.

Topics en subscriptionsNaast queues biedt de servicebus ook topics en subscriptions. Eentopic kan net als een queue gebruikt worden om berichten naartoe testuren. Echter, om berichten die naar een topic zijn gestuurd te kunnen ontvangen, moet een subscription worden geregistreerd bijhet desbetreffende topic (zie figuur 6). Een bericht dat binnenkomt opeen topic, wordt dan doorgestuurd naar de subscription. Zodra berichten in een subscription zijn geplaatst, gedraagt de subscriptionzich verder eigenlijk exact als een queue waar we de berichten vervolgens uit kunnen lezen.

Fig. 6: Topics en subscriptions

Met topics en subscriptions kan dus een publish / subscribe mecha-nisme worden gerealiseerd, waarbij de partij die een bericht publiceertniet hoeft te weten hoe veel en welke afnemers er zijn van het bericht.Belangrijk om hierbij op te merken is dat berichten alleen worden verstuurd naar subscriptions die zijn geregistreerd bij het binnenko-men van een bericht in het topic. Wanneer een subscription wordt toegevoegd op een topic, worden berichten die eerder al naar hettopic zijn verzonden dus niet opgepakt door de subscription.

Berichten verzenden naar een topicHet creëren van een topic en het verzenden van berichten naar hettopic, gaat in principe op dezelfde manier als bij een queue. In code-voorbeeld 4 is te zien hoe een topic wordt gecreëerd en een berichtwordt verzonden. Zoals gezegd is in het codevoorbeeld (en alle volgende codevoorbeelden) het voorbereidende werk zoals het aanmaken van de Uri, de TokenProvider en de NamespaceManagerweggelaten. Dit is namelijk identiek aan codevoorbeeld 1.

string topicName = "SampleTopic";

if (!nsManager.TopicExists(topicName))

{

nsManager.CreateTopic(topicName);

}

// maak een topicclient

MessagingFactory messagingFactory =

MessagingFactory.Create(uri, credentials);

magazine voor software development 35

Lock Timeout is standaard 1 minuut

Page 36: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

CLOUD

TopicClient topicClient =

messagingFactory.CreateTopicClient(topicName);

// maak een bericht

BrokeredMessage order = new BrokeredMessage()

{

MessageId = Guid.NewGuid().ToString("N")

};

order.Properties["CustomerId"] = "20111203006";

order.Properties["ProductId"] = "AX781-11-2";

order.Properties["Amount"] = 4;

order.Properties["OrderDate"] = DateTime.Now;

// verstuur het bericht

topicClient.Send(order);

Codevoorbeeld 4: Sturen van een bericht naar een topic

Berichten ontvangen van een subscriptionHet creëren van een subscription voor een topic en het lezen van berichten uit een subscription, gaat in principe op dezelfde manier alsbij een queue. In codevoorbeeld 5 is te zien hoe een subscriptionwordt gecreëerd voor het topic dat in codevoorbeeld 4 is gecreëerden middels de SubscriptionClient een bericht uit het subscription wordtgelezen.

string topic = "SampleTopic";

string sub = "SampleSubscription";

// maak een subscription

if (!nsManager.SubscriptionExists(topic, sub))

{

nsManager.CreateSubscription(topic, sub);

}

// maak een subscriptionclient

MessagingFactory messagingFactory =

MessagingFactory.Create(uri, credentials);

SubscriptionClient subClient =

messagingFactory.CreateSubscriptionClient(topic, sub,

ReceiveMode.ReceiveAndDelete);

// ontvang een bericht

BrokeredMessage receivedOrder =

subClient.Receive(TimeSpan.FromSeconds(5));

Codevoorbeeld 5: Ontvangen van een bericht uit een subscription

Gebruik van filtersElke subscription heeft een filter op basis waarvan wordt bepaald ofhet bericht dat naar het topic is gestuurd moet worden opgepakt. Alshet filter een match oplevert, wordt een kopie van het bericht in de bijbehorende subscription geplaatst. Als we de code in codevoorbeeld5 bekijken, zien we dat er geen filter wordt gespecificeerd bij hetcreëren van de subscription. In dat geval worden alle berichten dienaar het topic worden gestuurd waar de subscription bij hoort, automatisch in de subscription geplaatst. Dit komt omdat als er geenfilter wordt gespecificeerd, standaard een TrueFilter wordt toegevoegdaan de subscription. Dit is een speciaal type filter dat altijd een matchoplevert.

Als we alleen geïnteresseerd zijn in bepaalde berichten, kunnen we bijde creatie van de subscription een filter specificeren. Een filter wordtgespecificeerd in SQL’92 syntax waarbinnen alleen gebruik kan worden gemaakt van de eigenschappen van een bericht (dus niet de

body). In codevoorbeeld 6 is te zien dat een subscription wordt gecreëerd, die alleen Order berichten ontvangt waarbij meer dan 10items worden besteld.

// maak een subscription

if (!nsManager.SubscriptionExists(topic, sub))

{

SqlFilter orderFilter =

new SqlFilter("Amount > 10");

nsManager.CreateSubscription(topic, sub, orderFilter);

}

Codevoorbeeld 6: Specificeren van een filter op een subscription

Het is overigens mogelijk om meerdere filters per subscription te specificeren. Dit kunnen er maximaal 2000 zijn! Dit kan ook nog nadatde subscription is gecreëerd. Voor elk filter dat een match oplevert,zal een kopie van het bericht in de subscription worden geplaatst.

Messaging patternsNu we de basisfunctionaliteit van queues & topics hebben gezien,wordt het tijd om te zien hoe we deze zaken kunnen toepassen omverschillende messaging patterns te realiseren.

Load levelingHet eerste pattern dat ik wil behandelen is “Load leveling”. In figuur 7is een schematisch overzicht van een systeem weergegeven. We zienhier aan de linker zijde een web-shop die 24x7 beschikbaar is voorhet verzamelen van orders. Deze orders moeten verwerkt worden opeen andere locatie door een back-end systeem. Nu is het probleem indit scenario dat de web-shop 24x7 in de lucht is, maar de back-endeen legacy systeem is dat traag werkt en niet altijd online is. Het gevolg is dat er time-outs ontstaan omdat de orders niet snel genoegof helemaal niet kunnen worden verwerkt.

Fig. 7: Load leveling scenario

Voor dit scenario kunnen we natuurlijk perfect de servicebus inzetten.Doordat het een cloud dienst is, vormt het feit dat het hier 2 verschil-lende fysieke locaties betreft geen probleem. Daarnaast worden berichten (orders) in de queue bewaard totdat de back-end beschik-baar is en tijd heeft om ze op te pakken in zijn eigen tempo. De loadop de back-end wordt op die manier genivelleerd en ontstaat er eenloskoppeling in de tijd tussen het ontvangen van de order in de web-shop en het verwerken ervan in de back-end. Dit is in figuur 8schematisch weergegeven.

Fig. 8: Load leveling met de servicebus

MAGAZINE

36

Page 37: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

CLOUD

De implementatie van dit scenario m.b.v. de servicebus is het aanmaken van een queue waar de web-shop de orders in plaatst ende back-end kant die de orders uit de queue leest en verwerkt. Wehebben in de voorgaande codevoorbeelden reeds gezien hoe dat erin code uitziet.

Load balancingHet kan natuurlijk ook zo zijn dat in de back-end meerdere systemenzijn neergezet voor het verwerken van de stroom van orders. In datgeval zou het mooi zijn als de load automatisch over de verschillendeback-end systemen wordt verdeeld. Dit wordt “load balancing” genoemd. Dat is in figuur 9 schematisch weergegeven. Qua implementatie m.b.v. de servicebus verandert er eigenlijk niets, be-halve dat er meerdere ontvangers uit dezelfde queue lezen. De ser-vicebus zorgt ervoor dat elk bericht maar door maximaal 1 ontvangerwordt verwerkt. Hier kan ook eventueel het eerder genoemde lockingmechanisme gebruikt worden om er voor te zorgen dat als een ontvanger uitvalt tijdens het verwerken van het bericht, het bericht automatisch weer in de queue beschikbaar komt zodat een andereontvanger het bericht op kan pakken.

Fig. 9: Load balancing met de servicebus

Multi-castingMulti-casting is het automatisch versturen van een enkel bericht naarmeerdere ontvangers. In figuur 10 is een schematisch overzicht vaneen systeem getoond waarin dit een rol speelt. Met dit systeem kunnen nieuwe beleidsregels uitgerold worden binnen de multi national.De nieuwe regels worden op het hoofdkantoor ingevoerd. Vervolgens moeten de regels gepubliceerd worden naar de kantorenop verschillende locaties in de wereld.

Fig. 10: Multi-casting scenario

Om dit scenario te kunnen realiseren, zetten we de topics en subscriptions van de servicebus in. We creëren een topic waar hethoofdkantoor berichten met de nieuwe beleidsregels naartoe kan sturen. Vervolgens creëren we voor elk kantoor een subscription op dittopic.

Fig. 11: Multi-casting met de servicebus

De verschillende kantoren lezen de berichten uit hun eigen subscrip-tion en verwerken die. Dit is schematisch weergegeven in figuur 11.

PartitioningPartitioning is een bijzondere vorm van multi-casting. Hierbij wordt eenbericht dat wordt gepubliceerd niet automatisch naar alle ontvangersverzonden, maar afhankelijk van de inhoud naar specifieke ontvan-gers. In figuur 12 zien we een schematisch overzicht van een systeemwaarin dit een rol speelt. Er is een centrale meldkamer waar allerleimeldingen van calamiteiten worden geregistreerd. Op het moment datbij de meldkamer een calamiteit is geregistreerd in het systeem, is hetvan belang dat de informatie bij de juiste regio terechtkomt.

Fig. 12: Partitioning scenario

Dit scenario wordt een identieke manier geïmplementeerd m.b.v. deservicebus als bij multi-casting. Echter nu wordt elke subscription diespecifiek voor een bepaalde regio wordt gecreëerd, voorzien van eenfilter. In elk bericht dat de meldkamer verstuurt, is een eigenschap“Regio” opgenomen. Het filter bepaalt op basis van deze eigenschapvoor welke regio het bericht is. Dit is schematisch weergegeven in figuur 13.

Fig. 13: Partitioning met de servicebus

Request responseTot nu toe hebben we eigenlijk alleen communicatie 1 kant op gezien.Maar in de praktijk komt het uiteraard ook vaak voor dat een bepaaldevraag wordt gesteld en dat er een antwoord moet worden terug -gestuurd. Omdat de verzender en ontvanger bij brokered communi-catie losgekoppeld zijn wat betreft connectie en tijdstip, moet er eenmanier zijn om het antwoord op een bepaalde vraag bij de juiste verzender te krijgen. Hiervoor biedt de servicebus correlation.

Bij het request-response pattern, stuurt de verzender een bericht meteen vraag naar een queue. Dit bericht is door de verzender voorzienvan een uniek kenmerk om later te kunnen bepalen bij welke vraageen binnengekomen antwoord hoort. Vervolgens gaat de verzenderin een voor hem specifieke reply-queue controleren op nieuwe berichten. De ontvanger haalt het bericht met de vraag uit de queueen stuurt het antwoord naar de reply-queue van de verzender, voorzien van het unieke kenmerk van de vraag. Zodra een bericht methet antwoord in de reply-queue van de verzender is geplaatst, haaltdeze het antwoord op en handelt het verder af. Dit is schematisch

magazine voor software development 37

Page 38: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

CLOUD

weergegeven in figuur 14. De BrokeredMessage class heeft een aan-tal eigenschappen om dit scenario te ondersteunen. De CorrelationIdeigenschap kan gebruikt worden om een vraag een uniek kenmerkmee te geven. De ReplyTo eigenschap kan gebruikt worden om dequeue te specificeren waar de ontvanger het antwoord naartoe moetsturen. Deze manier van correlation wordt “message correlation” genoemd.

Fig. 14: Message correlation

Een andere manier die de servicebus ondersteunt is “subscription correlation”. Hierbij wordt de vraag wederom naar een queue gestuurd, maar het antwoord wordt naar een topic gestuurd. Dit reply-topic kan hergebruikt worden door meerdere verzenders. Elkeverzender creëert namelijk per vraag een subscription op dit reply-topic. Deze subscription wordt voorzien van een CorrelationFilter. Een CorrelationFilter is een speciaal filter waarbij we het uniekecorrelation id van de vraag kunnen specificeren. Dit filter zal automa-tisch een match opleveren met een bericht dat het desbetreffendeCorrelationId bevat. Op die manier komt het antwoord op een vraagin de specifieke subscription voor deze vraag terecht. Dit mechanismeis schematisch weergegeven in figuur 15. Het is ook mogelijk dat deverzender 1 subscription op het reply-topic registreert met voor elkevraag een apart CorrelationFilter.

Fig. 15: Subscription correlation

Ondersteunende featuresWe hebben nu een aantal eenvoudige messaging patterns gezien diewe prima met de standaard features van queues, topics en subscrip-tions kunnen implementeren. Maar naast de standaard features biedtde servicebus ook additionele features die gebruikt kunnen wordenom complexere messaging patterns te realiseren of de implementatiete optimaliseren.

SessionsWanneer er meerdere ontvangers zijn voor een queue of subscription,dan is het soms van belang de berichten logisch gegroepeerd worden

Fig. 16: Servicebus sessions

opgepakt. Een voorbeeld is het versturen van een groot bestand via de servicebus door het op te knippen in kleinere stukken en op diemanier te verzenden. Het is dan wel van belang dat wanneer een ontvanger het eerste deel van het bestand oppakt, deze ontvangerook de bijbehorende delen oppakt om zo het bestand volledig op tekunnen bouwen. Dit is schematisch weergegeven in figuur 16. Om ditte realiseren maken we gebruik van servicebus sessions.

Een servicebus bericht (BrokeredMessage) heeft een standaard eigenschap “SessionId”. Wanneer we een aantal berichten hebbendie logisch gegroepeerd moeten worden, dan geven we deze berichten allemaal hetzelfde session id. Bij het creëren van de queueof subscription moeten we aangeven dat we sessions willen gebruikenmiddels de RequiresSession eigenschap. In codevoorbeeld 7 is te zienhoe een queue moet worden gecreëerd die met sessions werkt. Bij hetcreëren van een queue hebben we de mogelijkheid om alleen de naamvan de queue te specificeren of een QueueDescription instantie. Via deQueueDescription kunnen we talloze eigenschappen van de queueconfigureren, waaronder de RequiresSession eigenschap. Het verzenden van berichten gaat vervolgens op de manier die we reedshebben gezien.

// maak queue (als deze nog niet bestaat)

if (!nsManager.QueueExists(queueName))

{

QueueDescription desc =

new QueueDescription(queueName)

{

RequiresSession = true

};

nsManager.CreateQueue(desc);

}

Codevoorbeeld 7: Queue met sessions

Aan de ontvangende kant moeten we berichten anders gaan oppakken. Eerst moeten we aangeven dat we een session willen ontvangen. Dit kan een specifieke session zijn (op basis van een session id) of een willekeurige nieuwe session die in de queue aanwezig is. Het oppakken van een session gaat via de Accept -MessageSession methode van de QueueClient. Deze methode leverten MessageSession instantie op. Hiermee kunnen we berichten uit dequeue gaan lezen. Zodra de ontvanger een session heeft geaccep-teerd, zal er als het ware een soort filter op de queue ontstaan. Alleenberichten die een session id hebben dat overeenkomt met het sessionid dat de ontvanger heeft geaccepteerd, zullen in de queue zichtbaarworden voor deze ontvanger. Overige ontvangers zullen de berichtenmet dat session id juist niet meer zien in de queue. Deze situatie blijftzo totdat alle berichten van de session zijn ontvangen en de ontvanger een nieuwe session accepteert. De verzender en ontvangerzullen een manier moeten afspreken waarop wordt aangeduid dat eensession compleet is. Een eigenschap EindeSessie of iets dergelijks ophet bericht plaatsen is bijvoorbeeld een optie. In codevoorbeeld 8 iseen voorbeeld te zien van een ontvanger die met sessies werkt. Hierworden in een loopje de berichten van een session opgehaald. Heteinde van de session wordt aangeduid middels de eigenschap SessionComplete.

// accepteer een sessie

MessageSession session =

qClient.AcceptMessageSession();

// ontvang alle berichten van de sessie

while (true)

{

BrokeredMessage part =

MAGAZINE

38

Page 39: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

CLOUD

session.Receive(TimeSpan.FromSeconds(5));

if (part != null)

{

Console.Write(

part.Properties["Data"].ToString());

if (part.Properties.ContainsKey("SessionComplete")

&& (bool)part.Properties["SessionComplete"] == true)

{

break;

}

}

}

Codevoorbeeld 8: Ontvangen uit een queue met sessions

Sessions kunnen ook gebruikt worden met topics en subscriptions. Bij het creëren van het topic moet RequiresSession worden gespecificeerd en de SubscriptionClient heeft een AcceptMessage-Session methode.

Dead-letteringBij het verwerken van berichten kan er natuurlijk altijd iets mis gaan.Zoals reeds eerder besproken bij het locking mechanisme, kan hetvoorkomen dat een bericht dat is opgehaald niet kan worden verwerkt.Als in dat geval gebruikgemaakt wordt van de PeekLock mode, komthet bericht weer terug in de queue. Dit kan leiden tot een oneindigeloop. Onder andere om dit tegen te gaan biedt de servicebus dead-lettering. Zowel queues als subscriptions kunnen worden voorzien vaneen dead-letter queue (zie figuur 17). Wanneer een bericht niet ver-werkt kan worden, kan het in de dead-letter queue worden geplaatst.Dit kan expliciet gedaan worden door de ontvanger, maar kan ook automatisch door de servicebus infrastructuur geregeld worden. In het eerste geval heeft de ontvanger de mogelijkheid om op een ontvangen bericht de methode DeadLetter aan te roepen.

Fig. 17: Dead-letter queues

De servicebus kan op verschillende manieren besluiten om een bericht in de dead-letter queue te plaatsen. Elk bericht heeft een read-only DeliveryCount eigenschap. Hierin wordt door de infrastructuur automatisch bijgehouden hoe vaak een bericht is opgehaald door een ontvanger. Bij het creëren van een queue kanworden gespecificeerd na hoeveel keer opgehaald te zijn een berichtin de dead-letter queue moet worden geplaatst. Dit kan worden gespecificeerd middels de MaxDeliveryCount eigenschap van deQueueDescription (zie codevoorbeeld 9).

nsManager.CreateQueue(new QueueDescription(queueName)

{

MaxDeliveryCount = 5

});

Codevoorbeeld 9: Dead-letter een bericht op basis van Delivery-Count

Een bericht kan ook automatisch in de dead-letter queue worden geplaatst als de geldigheid verstrijkt. Zoals eerder besproken, heeftelk bericht in een queue een bepaalde time-to-live (TTL). Als bij hetcreëren van de queue de eigenschap EnableDeadLetteringOnMessageExpiration wordt gezet, dan worden berichten die langer in dequeue staan dan hun TTL, automatisch in de dead-letter queue geplaatst (zie codevoorbeeld 10).

nsManager.CreateQueue(new QueueDescription(queueName)

{

EnableDeadLetteringOnMessageExpiration = true

});

Codevoorbeeld 10: Dead-letter een bericht op basis van TTL

De laatste situatie die de infrastructuur kan doen besluiten om een bericht in de dead-letter queue te plaatsen, is als er een fout zit in defilterexpressie van een SQL filter op een subscription. In codevoor-beeld 11 zien we een SQL filter waarbij de waarde van een berichtei-genschap van het type int, wordt vergeleken met een string. Op desubscription die wordt aangemaakt met dit filter, wordt ook de eigen-schap EnableDeadLetteringOnFilterEvaluationExceptions van de SubscriptionDescription gezet. Wanneer een bericht in deze subscription wordt geplaatst, zal er een exception optreden bij hetevalueren van de filterexpressie en zal het bericht in de dead-letterqueue worden geplaatst.

// ProductNr is van het type int

SqlFilter filter =

new SqlFilter("ProductNr = '187846'");

SubscriptionDescription desc =

new SubscriptionDescription(topic, sub)

{

EnableDeadLetteringOnFilterEvaluationExceptions

= true

};

nsManager.CreateSubscription(desc, filter);

Codevoorbeeld 11: Dead-letter een bericht bij een fout in het SQLfilter

In figuur 18 is een voorbeeld te zien van de output van een applicatiedie berichten uit de dead-letter queue leest en afdrukt.

Fig. 18: Berichten in de dead-letter queue

magazine voor software development 39

Deadletter queue verstoort het procesniet in geval van een fout situatie

Page 40: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

CLOUD

Hier is tevens te zien dat bij een bericht in een dead-letter queue altijdeen reden en een omschrijving beschikbaar is om te achterhalenwaarom een bericht daar terecht is gekomen. Deze eigenschappenkunnen ook worden gespecificeerd door de ontvanger als deze eenbericht expliciet in de dead-letter queue plaatst.

Duplicate detectionEen handige ondersteunende feature van de servicebus is duplicatedetection. Hiermee kan een queue of topic zodanig worden ingestelddat wanneer een bericht binnenkomt dat in de afgelopen (configu-reerbare) periode reeds eerder is binnengekomen, het bericht automatisch wordt verwijderd. Dit is schematisch weergegeven in figuur 19. De servicebus herkent dubbele berichten op basis van het MessageId.

Fig. 19: Duplicate detection

Wanneer we duplicate detection willen gebruiken op een queue oftopic, moeten we dit bij het creëren aangeven middels de eigenschapRequiresDuplicateDetection. De periode waarbinnen op dubbele berichten moeten worden gecontroleerd, kan worden geconfigureerdmiddels de DuplicateDetectionHistoryTimeWindow eigenschap. In codevoorbeeld 12 is te zien hoe een queue met duplicate detectionwordt gecreëerd.

nsManager.CreateQueue(new QueueDescription(queueName)

{

RequiresDuplicateDetection = true,

DuplicateDetectionHistoryTimeWindow =

TimeSpan.FromMinutes(10)

});

Codevoorbeeld 12: Queue met duplicate detection creëren

Pre-fetchingEen manier om de performance en throughput van een systeem datgebruikmaakt van de servicebus te vergroten, is om gebruik te makenvan pre-fetching. Pre-fetching zorgt ervoor dat wanneer een ontvanger vraagt om een bericht uit een queue of subscription, er onderwater alvast een (instelbaar) aantal berichten naar deze ontvanger worden verstuurd. Deze worden vastgehouden in een lokalecache van de ontvanger. Het nadeel van pre-fetching is wel dat het ophalen van het eerste bericht wat langer duurt. Zodra de ontvangerhet eerste bericht heeft verwerkt en om een volgende bericht vraagt,wordt dit bericht uit de lokale cache gelezen. Deze werkwijze bespaartdus een roundtrip naar de servicebus. Dit mechanisme wordt volledigdoor de infrastructuur geregeld. Standaard is pre-fetching uitgeschakeld, maar de ontvanger kan middels de PrefetchCount eigenschap van de QueueClient of SubscriptionClient het aantal

berichten instellen dat moet worden vastgehouden in de lokale cache.Dit moet ingesteld worden voordat het eerste bericht wordt ontvangen.

Als men pre-fetching wil inzetten, moet wel goed gekeken wordennaar de performance karakteristieken van de ontvangende applica-tie(s). Pre-fetching heeft namelijk alleen zin als de verwerking van eenbericht snel kan. Dan heeft het namelijk een positief effect op dethroughput. Als de verwerking van een bericht veel tijd kost, dan levertpre-fetching veel minder voordeel op en kan zelfs tot problemen leiden.Als bijvoorbeeld gebruik wordt gemaakt van pre-fetching in combina-tie met het eerder besproken locking mechanisme, worden de opgehaalde berichten gelockt in de servicebus zodat ze niet door andere ontvangers kunnen worden opgepakt. Als de ontvanger een (of meerdere) bericht(en) niet binnen de lock time-out kan verwerken,worden de locks in de servicebus verwijderd. De desbetreffende berichten kunnen dan eventueel door andere ontvangers worden op-gepakt en verwerkt. De door de initiële ontvanger opgehaald berich-ten zijn echter nog wel gewoon aanwezig in de lokale cache. Wanneernu de initiële ontvanger een bericht uit de lokale cache oppakt en verwerkt, kan het zijn dat het bericht dubbel is verwerkt! Tevens zal,wanneer de initiële ontvanger het bericht gereed gaat melden (middels de Complete methode op het bericht), een exception optreden omdat de lock op het bericht reeds is opgeheven. Om dezeproblemen te voorkomen moet bij het gebruik van pre-fetching hetaantal te cachen berichten (PrefetchCount) altijd kleiner zijn dan hetaantal berichten dat de ontvanger kan verwerken binnen de ingesteldelock time-out.

ConclusieMet de Azure Service Bus biedt Microsoft een uitgebreide gereed-schapskist om relatief eenvoudig verschillende messaging patterns terealiseren. De belofte van Microsoft is dat deze functionaliteit ook standaard beschikbaar gaat komen op het Windows platform. Datzou betekenen dat de service bus in de toekomst ook gebruikt kangaan worden voor oplossingen die binnen het eigen bedrijfsnetwerkdraaien en geen gebruik (kunnen) maken van de “cloud”.

In dit artikel heb ik een aantal features van de servicebus laten zien. Dit is echter slechts een deel van de features en heb ik zeker niet alledetails geraakt. Op het Internet zijn talloze blogs en video’s te vindenmet veel uitleg en interessante voorbeelden. Ik adviseer dan ook iedereen die meer wil weten van de mogelijkheden van de Azure Servicebus om de Azure SDK te installeren en zelf aan de slag te gaan. •

Edwin van Wijk

Edwin van Wijk is sinds 1999 werk-

zaam in de IT en werkt als IT Archi-

tect bij Info Support, met als

specialisme het Microsoft platform.

Hij wordt hoofdzakelijk ingezet op

projecten bij klanten voor advies op

het gebied van architectuur en .NET

development. Daarnaast is hij vaak betrokken bij de invoering van

de Endeavour ontwikkelstraat van Info Support bij klanten. Edwin

is trekker van de Azure Platform focusgroup binnen het Info Sup-

port competence center voor Microsoft Application Development.

Zijn expertise ligt vooral op het gebied van: SOA, EAI, ESB, WCF,

WF, en het Windows Azure platform.

MAGAZINE

40

Prefetching heeft effect op deperformance

Page 41: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

Microsoft Private Cloud OplossingenLees meer op microsoft.nl/readynow

Page 42: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

GENERAL Dennis van der Stelt

Het is mogelijk dat binnen afzienbare tijd, opgedane kennis alweerachterhaald is. Denk bijvoorbeeld aan de WCF Web API, waarmeeservices gebaseerd op REST architectuur gebouwd konden worden.Dit is nu mogelijk met de ASP.NET Web API, waardoor de kennis vanuit WCF hierover overbodig is geworden. Ook het Azure platformlijkt zich sneller te bewegen dan iets wat Microsoft ooit heeft uitgebracht. Tijd die we steken in hoe je kwalitatief hoogwaardige software bouwt gaat echter nooit verloren.

Manier om de kwaliteit van software te verbeteren zijn onder andere deSOLID principles, verschillende design patterns, unit testing, architecturele stijlen, etc. Maar ook aan termen als ‘Loosely coupled’,‘Composition over inheritance’ en ‘Law of demeter’. Met voldoendekennis en de toepassing ervan levert dit een hogere kwaliteit op vansoftware, waardoor het eenvoudiger wordt om deze software te lezen,interpreteren en te wijzigen. En het lezen van code neemt onevenredig veel tijd in beslag als je kijkt naar hoeveel tijd het kost omcode te schrijven. Peter Hallam heeft na onderzoek geconcludeerddat ontwikkelaars 78% van de tijd besteden aan het lezen en verkrijgen van inzicht over code. Geen overbodige luxe om te strevennaar hoge kwaliteit en leesbaarheid ervan. In deze serie van artikelengaan we initieel specifiek op de SOLID principes in, maar de rodedraad blijft de kwaliteit van code, dan wel Clean Code, en zullen we

SOLIDDe ideeën achter de SOLID principes bestaan al langer, maar RobertC. Martin wordt gezien als de geestelijke vader, nadat hij ze zeer concreet heeft beschreven. SOLID is een acroniem wat als ezels-bruggetje kan worden gebruikt voor de volgende principes• Single Responsibility Principle• Open/Closed Principle• Liskov Substitution Principle• Interface Segregation Principle• Dependency Inversion PrincipleDeze principes helpen ons code te schrijven welke beter onderhoud-baar en uitbreidbaar is. Zoals altijd zijn het geen verplichtingen, maarwel een goed advies. Ze geven ook een naam aan een concept waarwe het over kunnen hebben met collega developers. En als we eenslecht gevoel hebben over code, zullen deze principes ons helpen het

Binnen het Microsoft development platform gaat de technologie ontzettend hard. Platforms enframework worden nieuw uitgebracht of krijgen grote vernieuwingen. Hoewel dit zeer interes-sante ontwikkelingen zijn, kost het ook veel tijd om hier voldoende aandacht aan te besteden.Zelden wordt tevergeefs kennis opgedaan over fundamentele zaken met betrekking tot kwaliteit van code. Dat is waar we het in een serie van artikelen over willen hebben. Laten webeginnen met het Single Responsibility Principle.

Code Quality: Single Responsibility Principle

probleem te benoemen. Ze kunnen ook helpen om problemen die wetegen komen te verhelpen en ervoor zorgen dat de uiteindelijke oplossing beter aanvoelt. Zodat deze aanvoelt als Clean Code.

Van al deze principes is het Single Responsibility Principle wellicht demeest eenvoudige. Maar daarnaast is het echter ook het meest misbruikte principe. Het principe luidt als volgt:

Er wordt wel eens gezegd dat de eerste regel met betrekking tot classes is dat deze klein moet zijn. De tweede hierop volgende is datze kleiner moeten zijn dan wat je net in gedachten had. Dit is eenvou-dig te realiseren met methodes, omdat je hiervan kunt definiëren hoeveel regels een methode maximaal mag bevatten. Veel bedrijvennemen dit als regel op in hun coding guidelines om developers hierinte sturen. Maar hoeveel regels mag een class dan bevatten? Wat wewel kunnen bepalen is dat een class maar een verantwoordelijkheidkan hebben. Als een class maar een verantwoordelijkheid heeft, kaner ook maar een reden zijn om deze te wijzigen.

Wellicht vragen we ons af waarom een class maar een reden kan heb-ben om te wijzigen. De reden is dat hoe meer verantwoordelijkhedeneen class heeft, des te groter is de kans dat deze gewijzigd moet worden in de toekomst. En hoe vaker een class wijzigt, des te groterwordt de kans dat bugs geïntroduceerd worden.

Facturen berekenen en opmaken

public class InvoiceCreator

{

public Invoice CreateInvoice(

int customerId,

int month,

int year)

{

var defaultPath =

ConfigurationManager.AppSettings[

"DefaultPathForInvoices"].ToString();

var db = new EntityModel();

var query = from c in db.Customers

Software Craftsmanship is really, really, ridiculously good looking code –Derek Zoolander

Er mag nooit meer dan een reden zijnom een class te wijzigen

MAGAZINE

42

Page 43: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

GENERAL

aanstuurt en de verschillende verantwoordelijke classes aanroept. In listing 2 zijn we hiermee begonnen en roepen we opnieuw de InvoiceCreator aan om een invoice aan te maken, waarna we eennieuwe class PdfCreator aanroepen om de PDF daadwerkelijk op diskop te slaan. Het proces wordt nu in de Program class aangestuurd,maar er wordt niet eerst informatie uit een datastore opgehaald. We hebben hier geprobeerd het principe ‘tell, don’t ask’ aan te hou-den. Alec Sharp heeft dit principe als eerste beschreven in “Smalltalkby Example”, waar hij aangeeft dat procedurele code informatie op-haalt om zelf beslissingen te nemen. Object georiënteerde code echter, vertelt objecten wat ze moeten doen en de beslissingen wor-den in deze objecten zelf genomen. Velen zeggen dat dit direct tegenhet Single Responsibility Principle in gaat, waardoor dit altijd een belangrijke afweging wordt. Zelf ben ik van mening dat het prima tecombineren is en we het beste van beiden kunnen kiezen. Laten weproberen dit aan te tonen.

public class InvoiceCreator

{

public Invoice CreateInvoice(int customerId,

int month, int year)

{

// No more EntityModel but a repository.

// What has changed? Think about this for

a moment.

CustomerRepository repository =

new CustomerRepository();

List<Order> orders =

repository.RetrieveOrders(year,

month);

CalculatorFactory factory = new Calcula-

torFactory();

InvoiceCalculator calculator =

factory.Create(customerId);

return calculator.Calculate(orders);

}

}

Listing-3

In listing-3 zien een nieuw proces ontstaan, namelijk het ophalen vande informatie uit de datastore door middel van een repository. Daarnawordt een factory class aangeroepen die we eerder niet gebruiktzagen worden. De verantwoordelijkheid van deze factory is de voordeze klant specifieke componenten te vinden, waarmee de factuurberekend wordt. Nadat de factory het object heeft geïnstantieerdwelke deze kennis heeft, vragen we dit object om daadwerkelijk het invoice object aan te maken en dit te retourneren.

De twee classes uit listing 2 en listing 3 sturen nu als het ware het proces, waarbij specifieke classes zaken uitvoeren zoals het bepalenwelke calculator gebruikt dient te worden, waarna de calculator uitgevoerd wordt met de informatie welke is opgehaald door een repository class. Als laatste hebben we de class welke de PDF daad-werkelijk opslaat. We hebben nu elke verantwoordelijkheid uitbesteedaan aparte classes. Terugkomend op het ‘tell, don’t ask’ principe, hebben we getracht in listing 2 niet alle acties en beslissingen naaronszelf toe te halen, maar dit uit te besteden aan de InvoiceCreator uitlisting 3. Het uiteindelijke class diagram ziet er dan uit zoals in afbeelding 1.

from o in c.Orders

where c.CustomerId ==

customerId

&& o.Month == month

&& o.Year == year

select ol;

Invoice invoice = Calculate(query);

SaveInvoiceAsPdf(invoice, defaultPath);

return invoice;

}

// ...

}

Listing-1

Een eenvoudig voorbeeld is bijvoorbeeld een class welke facturen berekend. Zoals we in listing 1 kunnen zien gebeuren daar een aantalzaken. Allereerst wordt er configuratie opgehaald. Daarna wordt hetEntityModel van Entity Framework geïnstantieerd, waarna een querywordt uitgevoerd op dit EntityModel. De volgende stap is dat er eenmethode wordt aangeroepen in dezelfde class, die we hebben weggelaten uit het voorbeeld, ten behoeve van leesbaarheid. In dezemethode wordt blijkbaar berekend wat er op de factuur moet komente staan. Als laatste wordt een PDF gegenereerd van de factuur endeze wordt opgeslagen op disk.

Theoretisch niet eens zulke slechte code. Als we naar het Single Responsibility Principle kijken, heeft deze class echter minimaal 4 verantwoordelijkheden. We lezen configuratie, praten met het Entity-Model, berekenen wat er gefactureerd moet worden en schrijven vaneen PDF naar disk. We zouden zelfs kunnen zeggen dat het instan-tiëren van het EntityModel en het opzetten van de query twee ver-schillende verantwoordelijkheden zijn. Als iets aan het model wijzigt, alsde opmaak van de PDF wijzigt, de manier van configuratie, dan moetdeze class gewijzigd worden.

class Program

{

static void Main(string[] args)

{

int customerId = 1337, year = 2012, month

= 4;

InvoiceCreator creator = new InvoiceCrea-

tor();

Invoice invoice =

creator.CreateInvoice(customerId, year,

month);

PdfCreator pdfCreator = new PdfCreator();

pdfCreator.CreatePdf(invoice);

}

}

Listing-2Als we dit opbreken en verspreiden over meerdere classes, komenwe vrij snel tot de conclusie dat er een class nodig is die het proces

Goede code heeft weinig verantwoordelijkheden

Tell, don’t Ask principe van Alex Sharp

magazine voor software development 43

Page 44: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

GENERAL

Let wel dat we nog maar een principe van de beschikbare SOLID principes hebben behandeld en dit nog niet de uiteindelijke code iszoals we die zouden willen hebben. Hier komen we echter in volgendeartikelen op terug.

Afbeelding 1

Reveal all intentionVoordat we listing 3 laten voor wat het is, willen we hier nog even opterug komen. Zoals reeds in commentaar is aangegeven, initialiserenwe in plaats van het EntityModel nu de repository, waarna we geenLINQ query zien maar de aanroep van een methode.

Het verschil is eigenlijk helemaal niet zo groot. Echter onze methodeop de repository verbergt de intentie van de vraag. De vraag die heelduidelijk terug kwam in de LINQ query. We hadden origineel wel eendependency op de class EntityModel, waar we nu een dependencyhebben op een class van onszelf. Maar als we deze dependency naarhet EntityModel zouden kunnen verwijderen, is het dan nog wel zoverkeerd om een LINQ query te gebruiken? LINQ zelf heeft namelijkniets met een specifieke data opslag of externe bron te maken. Iets omover na te denken.

Afbeelding 2

VerantwoordelijkhedenSoms is het lastig om verantwoordelijkheden te zien. Stel bijvoorbeeldde interface IModem uit afbeelding 1 voor. Wat is de verantwoorde-lijkheid van deze interface? Is het om de modem te laten werken, of is

het alles wat benodigd is om te communiceren met een anderemodem? Als we goed kijken, zien we methodes ten behoeve van hetopbouwen en afbreken van een connectie. Maar ook methodes omgegevens te verzenden en ontvangen. Als we dan naar afbeelding 2kijken, zien we dat we deze twee verantwoordelijkheden in twee verschillende interfaces hebben ondergebracht. Ze worden echter welin een class geïmplementeerd, maar in dit geval is dit omdat eenmodem een fysieke entiteit is en het hardware-matig niet anders ondergebracht zou kunnen worden.

Software welke met deze modem class communiceert, kan dat echter op basis van de twee interfaces doen. De code van deze software hoeft dus niet vervuilt te worden door ook verantwoordelijk-heden samen te voegen. Maar kan tegen hetzelfde object praten viade twee geïmplementeerde interfaces en daardoor de verantwoorde-lijke code die met een bepaalde interface communiceert, gescheidenhouden van code die tegen de andere interface communiceert.

Afbeelding 3

Een eenvoudig hulpmiddel om erachter te komen of we te veel verantwoordelijkheden in een specifieke class beleggen, is als het lastig is om een naam te bedenken. Kunnen we niet een eenduidigenaam bedenken, dan doet onze class waarschijnlijk al teveel. Weesniet bang dat we met meer classes ook meer complexiteit introduce-ren. Wellicht dat het eenvoudiger wordt de interactie tussen classes tezien, zodra een class diagram wordt gebruikt. Maar feit is dat het zelden tot nooit complexer wordt als we verantwoordelijkheden verspreiden over meerdere classes. Dit is ook de reden dat afbeelding1 is toegevoegd, zodat deze interactie tussen de classes uit listing 2en listing 3 duidelijker wordt.

Kleine methodesLaten we nog naar een laatste voorbeeld kijken. Omwille van hoe-veelheid aan regels code en leesbaarheid, zullen we niet classes alsvoorbeeld nemen, maar kleinere methodes. In listing 4 zien we eenmethode om een order te verwerken. Wederom zien we verschillendeverantwoordelijkheden in een en dezelfde methode. De order wordtgevalideerd, waarna de btw en de kosten voor het versturen wordenberekend. Als laatste wordt de order opgeslagen in de datastore. Metcommentaar geven we aan wat er exact gebeurd.

public void SubmitOrder(Order order)

{

// validate order

Bepaal goed wie of wat verantwoordelijk is, juist in code

MAGAZINE

44

Page 45: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

GENERAL

if (order.Products.Count == 0)

{

throw new

InvalidOperationException(

"Add products first!");

}

// calculate tax

order.Tax =

order.SubTotal * TAX_PERCENTAGE;

// calculate shipping

if (order.SubTotal < 25)

order.ShippingCharges = 5;

else

order.ShippingCharges = 10;

// submit order

_orderShipper.SubmitOrder(order);

}

Listing 4

Waarom gebruiken we eigenlijk commentaar in onze code als we ookmet behulp van namen in classes en methodes aan kunnen gevenwat er gebeurd? Als we bijvoorbeeld naar listing 5 kijken, zien we eenmethode die het proces stuurt. Het is bijzonder duidelijk wat hier gebeurd. Nogmaals, het voorbeeld is eenvoudig gehouden; normaalgesproken willen we de state van een object wat we meegeven nietwijzigen en geven we een nieuw resultaat terug. Voor nu is het voorbeeld duidelijk genoeg.

public void SubmitOrder(Order order)

{

ValidateOrder(order);

CalculateTax(order);

CalculateShipping(order);

ShipOrder(order);

}

Listing 5

Als we uiteindelijk naar listing 6 kijken, zien we de lange methode uitlisting 4 in verschillende nieuwe methodes uitgeschreven. Alle code isbeter onderhoudbaar en elke methode op zich heeft maar een redenom te wijzigen. Zoals gezegd zien we dit liever opgedeeld in meerdereclasses, maar is het ten behoeve van het voorbeeld eenvoudig gehouden.

private void ValidateOrder(Order order)

{

if (order.Products.Count == 0)

{

throw

new InvalidOperationException(

"Add products first!");

}

}

private void CalculateTax(Order order)

{

order.Tax = order.SubTotal * TAX_PERCENTAGE;

}

private void CalculateShipping(Order order)

{

if (order.SubTotal < 25)

Dennis van der Stelt

Dennis van der Stelt heeft meer dan

15 jaar ervaring als ontwikkelaar en

is momenteel als solution architect

werkzaam bij Tellus. Verschillende

architecturale stijlen zijn een grote

passie, alsook kwaliteit van soft-

ware. Een grote drijfveer is het ver-

spreiden van deze kennis aan

iedereen die het maar wil horen. Wil

je ervaringen delen of heb je vragen, dan is hij altijd bereikbaar via

[email protected] of via zijn weblog op http://blogging-

about.net/blogs/dennis/

order.ShippingCharges = 5;

else

order.ShippingCharges = 10;

}

private void ShipOrder(Order order)

{

_orderShipper.SubmitOrder(order);

}

Listing 6

ConclusieZoals in het begin van het artikel aangeven, is het Single Responsibility Principle het meest eenvoudig om te begrijpen, maarwaarschijnlijk het meest misbruikte principe. Kom je classes tegen vanhonderden, dan wel duizenden regels code en worden heel veel verantwoordelijkheden beschreven in elk van deze classes, dan moetdat een gevoel geven waarvan we weten dat er iets mis is. Gebruik refactoring gereedschap als CodeRush of Resharper om deze codeop te breken en te verdelen over het juiste aantal classes. Ontwikkelaars die unit tests schrijven zullen hier enorme voordelen vanondervinden, aangezien de code ook vele malen eenvoudiger testbaar wordt.

Genoeg redenen om het Single Responsibility Principle rigoureus toete passen in je eigen software. De voordelen worden zeer snel duidelijk. •

magazine voor software development 45

Voor ons magazine zijn we altijd opzoek naar interessante artikelen.Wat heb je ontdekt, waar heb je een mening over, waar heb je

ervaring mee opgedaan en waar wil je over vertellen?.

Neem contact op met de redactie [email protected]

Page 46: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

WEB

AJAX impliceert bijna dat je altijd online bent. Gedeeltes van de paginaworden geregeld bijgewerkt, al dan niet door acties van de gebruiker.Dat soort functionaliteit is lastig offline aan te bieden, omdat de servervrijwel altijd betrokken is bij deze functionaliteit. Sommige functionali-teit is echter ook offline aan te bieden, maar dit betekent wel dat jedaar rekening mee moet houden bij het ontwerp.

Chatty vs. Chunky interfacesIn een AJAX pagina is het over het algemeen zo dat telkens kleinestukjes van de pagina bijgewerkt worden. Een mooi voorbeeld hiervanis een cascading dropdown, een dropdownlist waarvan de mogelijkewaardes aangepast worden doordat de gebruiker een waarde kiestin een andere dropdownlist, zoals de modellen auto na het selecterenvan een specifiek merk. Omdat er telkens kleine onderdelen van eenpagina bijgewerkt worden zijn de webservices die hiervoor gebruiktworden “chatty”. Dat wil zeggen dat er veel kleine berichten over hetnetwerk gaan (er wordt veel gekwetterd). Het omgekeerde van “chatty”is “chunky”. Daarbij gaan juist enkele grote berichten over het netwerk(er worden veel monologen gehouden). De hamvraag is natuurlijk: watis beter? Het antwoord daarop hangt af van wat je belangrijk vindt.

Als het je gaat om responstijd (over het netwerk), dan is chatty beter,omdat er niet zoveel data tegelijk opgevraagd hoeft te worden. In hetvoorbeeld van de cascading dropdown zijn dit alleen de modellen autovan het geselecteerde merk. Dat gaat altijd sneller dan alle automer-ken met alle modellen in één keer downloaden. Als die allemaal binnen zijn is de responstijd echter beter, omdat er helemaal niet meerover het netwerk gegaan hoeft te worden. Daar komt bij dat de netwerkbelasting en de belasting van de server bij elkaar minder zwaaris, omdat er minder requests met de bijbehorende overhead gedaanmoeten worden. Voor schaalbaarheid zijn chunky interfaces beter.

Als je (delen van) je applicatie ook offline beschikbaar wilt maken zijnchatty interfaces vervelend. Niet alleen omdat je dan op allerlei plaat-sen geen interactie kunt hebben met de server, of daarvoor moet compenseren, maar ook omdat de user interface vaak nauw gekoppeld is aan de webservices en de data die ze terug leveren. Wathier ook een rol speelt is wat de AJAX services voor respons geven.Is dit HTML die ingeplakt moet worden, dan zijn de services niet loste zien van de user interface. Als je de services ook voor andere clientswil kunnen gebruiken, bijvoorbeeld voor een App op een tablet ofsmart phone, dan is het beter als alleen data over de lijn gaat. Als jedaarbij ook zorgt dat de data chunky is, kan de user interface zelf bepalen hoe de data weergegeven wordt.

Geschikt voor offline?Afgezien van of er sprake is van chatty of chunky services, zijn er uiteraard wel voorwaarden aan het offline beschikbaar kunnen stellenvan een (deel van) je applicatie. Een belangrijk aspect is dat het groot-ste deel van de data die je nodig hebt relatief statisch moet zijn. Datadie iedere 10 seconden wijzigt is offline nooit voldoende up-to-date.Zogenaamde referentiedata, zoals de automerken en modellen kun jeprima offline beschikbaar maken. Een ander aspect is dat je niet dehele database offline beschikbaar moet hoeven hebben. Dit kan betekenen dat iemand die offline gaat van te voren een keuze moetmaken. Een vertegenwoordiger moet dus bijvoorbeeld voordat hij oppad gaat de gegevens van de klanten “downloaden” waar hij op bezoek zal gaan. De orders die hij krijgt moeten vervolgens offline opgeslagen worden en aan het eind van de dag verwerkt worden. Ditimpliceert dat slechts een deel van je applicatie offline beschikbaarhoeft te zijn. Sterker nog, je kunt delen specifiek ontwerpen om offlinete werken, naast de online variant, zodat je data tijdelijk lokaal kuntopslaan en dan wanneer de gebruiker online is kunt verwerken. Offlinefunctionaliteit hoeft er vaak alleen voor te zorgen dat de gebruiker ietsop kan voeren wat later verder verwerkt kan worden. Dit kun je opslaanin HTML5 localStorage (zie http://diveintohtml5.info/storage.html). In localStorage kun je strings opslaan, maar met de simpele JavaScript extension in Listing 1 kun je daar ook geserialiseerde JSONobject in kwijt.

Storage.prototype.setObject = function(key, value) {this.setItem(key, JSON.stringify(value));

}

Storage.prototype.getObject = function (key) {var value = this.getItem(key);return value && JSON.parse(value);

}

Listing 1: JavaScript extension voor JSON in localStorage.

localStorage werkt zo’n beetje in alle gangbare browsers. Offline Apps(zie http://diveintohtml5.info/offline.html) helaas in alles behalve… jeraadt het al… Internet Explorer. Dat betekent nog steeds dat zo’n 2/3van de wereld het wel kan gebruiken en je kunt ook best tegen je klantzeggen dat als ze offline willen dat ze een andere browser moeten gebruiken.

Offline is belangrijkOffline functionaliteit is een van de belangrijkste onderdelen vanHTML5, omdat je voorheen Apps moest hebben om offline te kunnengaan. Dat is een van de killer features van Apps, maar Apps kun jemoeilijk cross-platform ontwikkelen. Voor veel applicaties zal HTML5offline apps daarom de oplossing zijn, tenzij de user interface echt bijzonder moet zijn. Kortom, als er een feature van HTML5 is waar jeje in moet verdiepen, dan is het offline wel. •

In de afgelopen jaren heeft AJAX een enorme vlucht genomen. Vrijwel elke nieuwe web applicatie heeft wel iets van AJAX functionaliteit. Logisch ook, want met AJAX wordt de user interface van je web applicatie veel vloeiender. AJAX vereist echter wel dat je altijd online bent,terwijl HTML5 ook faciliteiten biedt voor het offline kunnen gebruiken van een web applicatie. Dit lijkt in tegenspraak met AJAX.

Michiel van Otegem

Offline AJAX

Voor schaalbaarheid zijn chunky interfaces beter

MAGAZINE

46

Page 47: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

Ton Blankers

Landelijke incidenten met Cloud computinghebben recent voor onzekerheid gezorgd.Waarom zouden bedrijven hun systemen tochnaar de Cloud moeten brengen?

“De groei van Cloud computing blijft gehandhaafd, ondanks enkeleincidenten die misschien voor een vertraging van Cloud-gebruik zorgen. Cloud computing is een ideale oplossing die zorgt voor eenflinke kostenbesparing. En daar ontkomen bedrijven niet aan in de huidige economische situatie. Bedrijven maken dankzij Cloud computing efficiënter gebruik van resources en zijn in staat klantenmeer bij de bedrijfsvoering te betrekken.”

Applicaties in de Cloud vragen wel om onder-houd. Wat betekent Cloud computing voor hetbouwen en onderhouden van applicaties?

Bij Cloud Computing zie je dat zaken als beveiliging, integratie en 24/7beschikbaarheid een belangrijke rol spelen. Daarnaast moeten bedrij-ven vooral rekening houden met de wensen van de eindgebruiker. Endie wensen veranderen in de loop der tijd. Onderhoud betekentdaarom niet alleen veranderen, maar ook vernieuwen. De kern functionaliteit van de applicatie blijft grotendeels hetzelfde, maar deomliggende technologie verandert. Onderhoud is noodzakelijk. Onzeklanten willen zelf zo min mogelijk werk hebben aan technische veranderingen maar willen zich met name focussen op applicatie functionaliteit. Een tool als Uniface groeit met de veranderende technologieën mee en stelt de ontwikkelaar in staat om deze technologieën te gebruiken zonder daarbij de functionaliteit van de applicatie te hoeven aanpassen.

Voor welke uitdaging staan ontwikkelaars tegenwoordig?

Software ontwikkelaars worden voortdurend geconfronteerd metnieuwe technologieën. Hun kennis portfolio groeit dan ook voortdurend. Op hardware gebied verdwijnen systemen vaak na eenpaar jaar, maar op softwaregebied gebeurt dat veel minder snel. Regelmatig krijgen wij van klanten te horen dat ze behoefte hebbenaan een nieuwe generatie ontwikkelaars met kennis van technologieënzoals Cloud computing, aan de andere kant hebben ze juist de ervaring van de huidige generatie ontwikkelaars nodig om de bestaande systemen goed te laten functioneren. We zijn dan ookvoortdurend bezig om de ontwikkelomgeving aan te passen zodatmeerdere technologieën naast elkaar gebruikt kunnen worden en datsoftware componenten zowel voor Windows als voor Web applicatiesgebruikt kunnen worden.

Bouwen en onderhouden van applicaties in “de Cloud”

Hoe lang gaan applicaties in de Cloud mee,gelet op de snelle technologische ontwikkelin-gen?

“Wat ooit begon als een simpele ondersteunende applicatie is bij veelbedrijven uitgegroeid tot een systeem dat noodzakelijk is voor de bedrijfsvoering . Als onderhoud op deze systemen adequaat gebeurdgaan veel informatiesystemen langer mee dan initieel werd gedacht.Het maakt qua kosten natuurlijk een groot verschil of er 2 of 12 ontwikkelaars nodig zijn om een applicatie voor jaren te onderhouden.Bedrijven moeten daarnaast kiezen welke onderdelen van hun applicatie ze naar de Cloud willen brengen en bij welke Cloudproviderze dat willen doen. De Cloudprovider zorgt er dan voor dat de gebruikte technologie ondersteund is en het bedrijf heeft een kopzorgminder “Een modernisatie strategie die aangeeft hoe een bedrijf gefaseerd naar de Cloud overgaat is zeer aan te raden en zorgt ervoordat een applicatie nog langer meekan.” •

Meer informatie

Het van origine Amsterdamse bedrijf Uniface werd in 1995 overge-nomen door het Amerikaanse softwarebedrijf Compuware. Unifaceis vandaag de dag één van de productlijnen van Compuware enricht zich op het ontwikkelen van bedrijfsapplicaties met een hogeproductiviteit. Uniface applicaties zijn database en platform onafhankelijk. Voor meer informatie gaat u naar www.uniface.com

CLOUD

Ton Blankers

Ton Blankers werkt sinds 1991 bij

Compuware in verschillende techni-

sche en commerciele functies. Als

Client Manager van het ontwikkel

Lab van Uniface in Amsterdam

overlegt hij met grote klanten hoe zij

de nieuwste mogelijkheden van het

Uniface product optimaal kunnen

gebruiken en vertaalt hun verwach-

tingen over applicatie ontwikkeling naar toekomstige technische

mogelijkheden van het product.

magazine voor software development 47

Page 48: SDN magazine 113Nummer 113 mei 2012 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network ˆ7 ˙ ˘7 . .: #*.&’ ˚ 2 #, ’ ˇ 1˜/%#10 < Ò Bdinfb

Volgende maand werk jij bij Macaw

Wat doe jij volgende maand?

Senior .NET DeveloperArchitect

t doe jij vaW t doe jij v ende maand?olgt doe jij v ende maand?ende maand?

ectchitArSenior .NET De

ende maand wolgVelopervSenior .NET De

de maand w


Recommended