SOFTWARE DEVELOPMENT NETWORK
MAGAZINE ISSN: 2211-6486
IN DIT NUMMER O.A.: Full text search met Lucene op Azure < Async/await en het restaurantmodel <
Talking about Frames <
Continuous Deployment met TFS, Octopusdeploy en Azure < Application Insights for Visual Studio Online <
Nummer 121 juni 2014 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network
121
www.sdn.nl
Colofon Uitgave:
Software Development Network Tweeëntwintigste jaargang No. 121 • juni 2014
voorwoord
Bestuur van SDN:
Marcel Meijer, voorzitter Rob Suurland, penningmeester Remi Caron, secretaris
Redactie:
Beste SDN magazine lezer,
Marcel Meijer (
[email protected])
Aan dit magazine werd meegewerkt door:
Roel Hans Bethlehem, Bob Swart, Maarten van Stam, Arjen Bos, 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] Reclamebureau Bij Dageraad, Winterswijk www.bijdageraad.nl
©2014 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 bestuur en/of de redactie. Alle in dit magazine genoemde handelsmerken zijn het eigendom van hun respectievelijke eigenaren.
Microsoft Achmea
Onze ICT wereld is dat eigenlijk ook. Is de ene release geweest, dan staat de volgende op het punt het levenslicht te zien. Hebben we net de Build Conference gehad met de verschillende aankondigen, worden er in Teched Noord Amerika weer nieuwe aankondigingen gedaan. En als je dan denkt dat het even rustig is, dan komen Apple of Google of Delphi met hun Conferenties en hun nieuwtjes. Kortom ook dit is een aaneenschakeling van aankondigingen en nieuwe producten. Zeker nu we bijna allemaal gebruik maken van een Agile manier van werken, volgen de vernieuwingen elkaar nog sneller op. Hierdoor gaat de wereld sneller dan enige jaren geleden. Voor een jong vakgebied is dat best knap.
Vormgeving en opmaak:
Adverteerders
De Olympische spelen zijn inmiddels afgelopen, maar de Oranje gekte gaat de volgende fase in. Want de wereldkampioenschappen Voetbal beginnen zeer binnenkort in Brazilië. De tenniswedstrijden op Roland Garos en Wimbledon zijn voor ons Nederlanders in het verleden ook mooie toernooien geweest. Maar deze trekken naast het wereldkampioenschap Hockey in Den Haag, de Giro in Italië en de Tour de France toch minder bekijks en spreken minder tot de verbeelding dan het Voetbal. Als je het zo bekijkt is het een aaneenschakeling van sportevenementen voor elk wat wils.
Om bij te blijven en op de hoogte te blijven van de nieuwste ontwikkelingen proberen wij je met ons magazine volledig up-to-date te houden. Ook dit magazine staat weer boordevol met nuttig en bruikbare informatie. Onze auteurs hebben allemaal stuk voor stuk hun uiterste best gedaan om mooie, aansprekende en informerende artikelen te maken. Ik vind dat ze daarin zijn geslaagd. Zo hebben we artikelen over Async programmeren, Dynamic Frames met Delphi, het nieuwe Application Insights van Visual Studio Online, Column over Agile van Sander, Hoe nog beter te kunnen samenwerken door een stukje toegevoegde techniek, coolere website met HTML5, Column van Michiel over de Wolkenarchitect, Remote applications on Microsoft Azure, hoe Lucene te gebruiken op Azure, Delphi XE5, de combinatie van Continous deployment met TFS en Octopusdeploy en wat kleine nieuwtjes over het Microsoft Azure platform. Kortom een lekker dik nummer met mooie artikelen. Graag horen we welke artikelen jullie zelf zouden willen schrijven. Er zit een auteur in ons allemaal. Veel leesplezier en mail ons jullie vragen cq. opmerkingen. Groeten, Marcel
2 40
Eindredacteur Magazine en Voorzitter SDN •
Adverteren? Informatie over adverteren en de advertentietarieven kunt u vinden op www.sdn.nl onder de rubriek Magazine.
magazine voor software development 3
Agenda 2014 • 6 juni 2014 SDN event 2 • 22 augustus 2014 SDN magazine 122 • 8-9 september 2014 SDC/SDE+ • 27-31 oktober 2014 Teched (Barcelona) • 14 november 2014 SDN magazine 123 • medio december 2014 SDN event 3
Inhoud 03
Marcel Meijer
04 04 05
Voorwoord
Inhoudsopgave Agenda
Roy de Boer en Freek Paans
10
Full text search met Lucene op Azure
Working software over proce$$es and fools
Sander Hoogendoorn
13
Delphi REST Client Components
Bob Swart
16
Async/await en het restaurantmodel
Piet Amersfoort
20
Cary Jensen
Talking about Frames
24
Applicatiestack opnieuw uitvinden met HTML5
26
Continuous Deployment met TFS, Octopusdeploy en Azure
Niels Bergsma Eric Tummers
31
Michiel van Otegem
Wolkenarchitect
32
Reach further by developing collaboratively
34
Application Insights for Visual Studio Online
38
Microsoft Azure Remote Apps
Isak Edblad
Hassan Fadili Marcel Meijer
CLOUD
Roy de Boer en Freek Paans
Full text search met Lucene op Azure Lucene is een full text search engine, oorspronkelijk geschreven in Java. Het biedt mogelijkheden om grote hoeveelheden tekst efficiënt te doorzoeken. In dit artikel beschrijven we onze ervaringen met het inzetten van Lucene.NET (een populaire .NET port van Lucene) binnen een Azure-omgeving, de cloud-oplossing van Microsoft. Azure stelt namelijk een aantal specifieke eisen aan de architectuur van een applicatie, die ook van invloed zijn op de Lucene implementatie. We stellen daartoe een dergelijke architectuur voor en onderzoeken een aantal karakteristieken hiervan. Bij dit artikel hoort een voorbeeldproject, waarin we de publieke domein boeken van gutenberg.org doorzoekbaar maken. In dit voorbeeldproject passen we de voorgestelde architectuur toe. Daarnaast kan dit project ook als basis dienen om zelf verder met Lucene op Azure te experimenteren. Het project is te vinden op https://github.com/infi-nl/lucene-azure. We zullen nu beginnen met een korte review van de Lucene API, waarna we ingaan op de Azure-specifieke uitdagingen. Vervolgens tonen we een mogelijke implementatie en sluiten af met een analyse van de operationele karakteristieken van die implementatie. Lucene Vroeger was het gebruikelijk om informatie te zoeken aan de hand van sleutelwoorden in een kaartenbak. Dit was beter dan niets, maar met de komst van zoekmachines is het gebruikelijk geworden om informatie te zoeken op basis van willekeurige tekstfragmenten. Dit concept staat bekend als full text search. Mocht je zelf full text search willen aanbieden om applicatie-specifieke informatie doorzoekbaar te maken, dan bieden veel databases daar standaard mogelijkheden voor. Als die mogelijkheid er echter niet is, zoals in Azure SQL Database, dan bestaan er ook externe componenten die dit kunnen, zoals Lucene. Dit is een populaire keuze voor Java-projecten, en wordt onder andere gebruikt door Solr en ElasticSearch. Daarnaast is het project inmiddels ook naar .NET geport, deze port gebruiken we voor dit artikel. Lucene Document Waar binnen een relationele database een record de kleinste eenheid van opslag is, is dat binnen Lucene een Document. Dit is een datastructuur waarmee je de te doorzoeken data in één of meerdere velden kunt onderbrengen. Naast deze zelf te definiëren velden, houdt Lucene ook een intern ID bij voor elk document. Dit ID zullen we later terugzien bij het ophalen van resultaten. Zo maken we in het voorbeeldproject per boek een document aan, met daarin de volgende velden: Gutenberg ID, titel, publicatiedatum op Gutenberg, taal, auteur en de volledige tekst van het boek. Dit maakt het mogelijk om bijvoorbeeld specifiek op Gutenberg ID of taal te zoeken.
IndexReader en IndexWriter Lucene slaat alle documenten op in de zogenoemde index. Net als bij bijvoorbeeld een relationele database zorgt de index ervoor dat er efficiënt gezocht kan worden. Het uitlezen van en wegschrijven naar deze index wordt respectievelijk door de classes IndexReader en IndexWriter verzorgd. Deze classes zijn ontworpen met multithreaded applicaties in het achterhoofd: een enkele instantie kan worden gedeeld tussen alle threads binnen de applicatie zonder dat je zelf voor synchronisatie hoeft te zorgen. In verband met performance en geheugengebruik wordt geadviseerd om met één instantie per applicatie te werken. In ieder geval kan de fysieke index maar door één IndexWriter tegelijkertijd worden bewerkt. In het algemeen is de geïndexeerde informatie, en zo ook de Lucene index, aan verandering onderhevig. IndexReader detecteert wijzigingen niet automatisch. De wijzigingen worden pas zichtbaar na het aanmaken van een nieuwe instantie. Hoe we hier mee omgaan, laten we verderop in het artikel ook zien. Query en IndexSearcher Zoekopdrachten binnen Lucene worden gëencapsuleerd in een Query object. Een dergelijk object is op meerdere manieren te verkrijgen, bijvoorbeeld via de QueryParser class die een tekstuele query zoals titel:max AND auteur: mult* vertaalt naar een Query. Maar er is bijvoorbeeld ook de TermQuery. De Query kan vervolgens door de Search methode van de class IndexSearcher worden uitgevoerd. Dit levert een op relevantie gesorteerde lijst met Lucene Document ID’s op. IndexSearcher is net als IndexReader en IndexWriter threadsafe, waardoor één instantie per applicatie voldoende is. Directory Toegang tot de fysieke index wordt geregeld door implementaties van de abstract class Directory, zoals bijvoorbeeld FSDirectory of RAMDirectory (die de index respectievelijk op het filesystem of in RAM opslaan). Tot zover de review van de Lucene API. We gaan nu verder in op de Azure-specifieke uitdagingen.
magazine voor software development 5
CLOUD
Uitdagingen op Azure Om Lucene te gebruiken op Azure moet je rekening houden met een aantal uitgangspunten van Azure: • In een Azure-omgeving moet je elk logisch onderdeel van je systeem op minimaal twee nodes draaien om aanspraak te kunnen maken op de SLA van 99.95% beschikbaarheid. Zo zul je minimaal twee nodes van je web- of worker-roles nodig hebben. • Binnen de Azure-rollen heb je te maken met een transient harddisk. Dat wil zeggen dat bestanden die je wegschrijft op het lokale filesystem niet durable zijn; als Azure de node re-imaged krijg je weer een “kaal” filesystem. Aangezien Azure dit op willekeurige tijden doet, moet je hier rekening mee houden bij het ontwikkelen van je applicatie. Voor het gebruik van Lucene heeft dit een aantal implicaties. Een request als GET /Search?q=foo+bar komt namelijk op een willekeurige web-node uit. De node in kwestie zal toegang moeten hebben tot de fysieke index om het request af te kunnen handelen. In een dergelijke multi-node situatie zijn er twee voor de hand liggende opties voor de locatie van de index: ofwel het lokale filesystem, ofwel een shared storage, in het geval van Azure bijvoorbeeld de Windows Azure Blob Storage. De oplossing met het lokale filesystem is vrij complex omdat je zelf de index op de diverse nodes gesynchroniseerd moet houden. Je loopt dan al snel tegen situaties aan waar je gebruik moet maken van gedistribueerde transacties om de indices consistent te houden. Een ander probleem is het initialiseren van een kale node, bijvoorbeeld omdat een node wordt toegevoegd, of een bestaande node opnieuw wordt ge-imaged. In dergelijke situaties moet je de index herbouwen, wat afhankelijk van de grootte een tijdrovende klus kan zijn. We hebben daarom gekozen voor de oplossing waar we de index delen via een shared storage. Hierbij zullen de indices wel altijd in-sync zijn. Er kleeft echter ook een nadeel aan: elke node moet updates kunnen doorvoeren op de index, terwijl er maar één actieve Index Writer kan zijn. In principe regelt Lucene deze synchronisatie zelf via locking, maar nodes moeten hierdoor op elkaar wachten. Hierdoor kunnen de responsetijden oplopen en kunnen er uiteindelijk zelfs time-outs optreden.
In dit schema valt op dat er twee Indexer nodes zijn (waar het Indexer proces op draait), dit is nodig vanwege de Azure SLA voorwaarden. We leggen later uit hoe we zorgen dat er slechts één actief is. We zullen nu de geschetste architectuur verder uitwerken en onderzoeken. Implementatie Er zijn twee aspecten waar een wezenlijk verschil ontstaat tussen deze architectuur en een single-node situatie: het doorvoeren van updates en het verversen van de IndexReader. Omdat ons artikel specifiek gaat over Lucene op Azure zullen we deze aspecten verder uitdiepen. Index updates Een update op de index bestaat uit twee stappen: allereerst wordt de gewenste update gequeued door een web-node, waarna hij wordt gedequeued en aan de index wordt toegevoegd door het Indexer proces. Het queuen gebeurt, in pseudocode, als volgt: Book book = …; Queue queue = …; queue.Enqueue(Serialize(book));
Dit probleem is op te lossen door één proces aan te wijzen dat alle writes doet. Andere nodes geven dan hun gewenste wijzigingen door aan dit proces. In onze implementatie noemen we dit proces de Indexer, en communiceren we de updates via een queue. Nadeel van deze oplossing is wel dat je eventual consistency introduceert: na een write zal het even duren voordat deze zichtbaar is op elke node. De tijd tussen het doorgeven van een wijziging en het daadwerkelijk zichtbaar worden op een web-node noemen we de update-latency.
Het verwerken van de update ziet er dan zo uit: IndexWriter writer = …; Queue queue = …; Message message = queue.Dequeue(); Book book = Deserialize(message.Body); writer.AddDocument(ToLuceneDocument(book));
Een ander probleem is dat de index niet op het lokale filesystem leeft en de daarom benodigde netwerktoegang tot de shared storage extra latency zal opleveren. Dit probleem zou je kunnen verzachten door de index lokaal te cachen. Lucene leent zich hier goed voor omdat updates incrementeel te downloaden zijn. Beide oplossingen voor de genoemde problemen worden geïmplementeerd door de vrij beschikbare component AzureDirectory (http://azuredirectory.codeplex.com). Dit is een implementatie van de Lucene Directory die de index opslaat op de Blob Storage. Bovendien wordt de index ook in een cache op het lokale filesystem bijgehouden. Een complete oplossing zou er dan zo uit kunnen zien:
6
MAGAZINE
writer.Commit(); message.Complete(); De call naar Message.Complete wordt gedaan omdat er gewerkt wordt met een peek-lock pattern. Dit voorkomt verlies van berichten bij fouten tijdens de verwerking. Het is dan wel belangrijk om Message.Complete pas na writer.Commit aan te roepen. Azure Service Bus Queues biedt deze peek-lock semantiek en gebruiken we dan ook in onze implementatie. De API’s van Lucene en de Service Bus bieden beide mogelijkheden tot batchverwerking. Wanneer er meerdere berichten beschikbaar zijn
CLOUD
in de queue kunnen deze in één keer worden verwerkt. Zoals we straks laten zien heeft dit invloed op de performance. De batch size noemen we B. Dat ziet er dan zo uit: IndexWriter writer = …; Queue queue = …; int batchsize = …; Message[] messages = queue.ReceiveBatch(batchsize); foreach (var message in messages) { AddMessageToIndex(writer, message); } writer.Commit(); queue.CompleteBatch(messages); Bij het bepalen van de batch size kijken we naar de verwerkingssnelheid van de Indexer en naar de update-latency :
function GetIndexWriter() { Directory directory = Ö; while (true) { try { return new IndexWriter (directory); } catch (LockObtainFailedException) { Sleep(Ö); } } } De LockObtainFailedException treedt op wanneer een Indexer-node al een IndexWriter open heeft op de index. Met deze constructie kan er dus altijd maar één Indexer-node berichten verwerken. Verversen van de IndexReader Voor het lezen van de index implementeren we een IndexReader singleton: class IndexReaderSingleton { static _indexReader = new IndexReader(..) static GetInstance() { return _indexReader; } }
We zien dat een batch size van minder dan B=200 berichten de verwerkingssnelheid beperkt. Voor batch sizes groter dan 200 neemt de verwerkingssnelheid niet meer toe. De optimale verwerkingssnelheid is dus te bereiken door de batch size op minimaal B=200 berichten te stellen.
Als er updates plaatsvinden op de index worden deze pas zichtbaar als we een nieuwe IndexReader openen. We hebben voor een strategie gekozen waarbij de IndexReader periodiek, dus elke x seconden, opnieuw geopend wordt. Dit zorgt er dus voor dat we elke x seconden een verse IndexReader hebben. We noemen die periode de verversperiode R. Het verversen gaat dan als volgt: class IndexReaderSingleton { … static Refresh() { _indexReader = new IndexReader(…); } } Schedule.Every(x seconden, IndexReaderSingleton.Refresh) We hebben voor de overzichtelijkheid synchronisatie- en lockingoverwegingen buiten beschouwing gelaten.
We hebben ook gekeken hoe de update-latency zich bij verschillende aanvoersnelheden v (updates per seconde) gedraagt: We zien dat er voor batch sizes groter dan 175 berichten geen significant verschil in update-latency is bij deze aanvoersnelheden. We zien ook dat rond de 100 updates per seconde verzadiging van de queue plaatsvindt en dat de latencies daardoor oplopen. Dit strookt met de observaties met betrekking tot de verwerkingssnelheid. Een laatste overweging bij implementatie is de Azure SLA: het proces dat schrijft zal ook dubbel uitgevoerd moeten worden, maar er mag slechts één IndexWriter tegelijkertijd actief zijn. Dit lossen we op door het synchronisatiemechanisme van Lucene te gebruiken:
Een nadeel van deze oplossing is dat we steeds een compleet nieuwe IndexReader openen, wat potentieel duur is. We benutten daarom de Reopen()-methode van de IndexReader, deze methode vult de door de huidige IndexReader geladen data aan met nieuw beschikbare informatie. class IndexReaderSingleton { static Refresh() { _indexReader = _indexReader.Reopen(); } } Voor het uitvoeren van zoekopdrachten hebben we tot slot de IndexSearcher nodig. Deze heeft een afhankelijkheid op de IndexReader en daarom laten we de lifecycle van de IndexSearcher samenlopen met die van de IndexReader.
magazine voor software development 7
CLOUD
class IndexSearcherSingleton { static _indexReader = new IndexReader(Ö) static indexSearcher = new IndexSearcher(_indexReader); static Refresh() { IndexReader newReader = _indexReader.Reopen(); if (newReader == _indexReader) { return; } _indexReader = newReader; indexSearcher = new IndexSearcher(_indexReader) } static GetInstance() { return _indexSearcher; } }
We maken hierbij gebruik van het feit dat _indexReader.Reopen zichzelf teruggeeft als de index onveranderd is. Een zoekopdracht neemt dan de volgende vorm aan: IndexSearcher indexSearcher = IndexSearcherSingleton.GetInstance(); string userQuery = …; Query query = new QueryParser(…).parse(userQuery); TopDocs topDocs = indexSearcher.Search(query, …); TopDocs bevat dan de lijst met de meest relevante Lucene Document ID’s. Dan moeten we nog een keuze maken voor de waarde van de verversperiode R. Om dit te bepalen bekijken we hoe de updatelatency hierdoor beïnvloed wordt bij verschillende aanvoersnelheden v.
We zien dat de verversperiode geen significante invloed heeft op de hoeveelheid gedownloade data. Overigens zijn de duidelijke stappen in de grafiek toe te schrijven aan het index merge proces van Lucene. Dit proces optimaliseert de fysieke index door onder andere data samen te voegen. Deze samengevoegde data staat dan niet in de cache, en moet dus in zijn geheel gedownload worden. De initiële download is 465 MB, wat ruwweg overeenkomt met de grootte van de index op de Blob Storage, 425 MB. Er blijkt dus dat een verversperiode van 2500 ms voor alle onderzochte aanvoersnelheden resulteert in een update-latency van lager dan 4 seconden. Daarbij levert dit ten opzichte van langere verversperiodes geen groot verschil op in traffic naar de Blob Storage. We hebben echter het gebruik van systeemresources niet gemeten en kunnen ons voorstellen dat er problemen kunnen ontstaan bij korte verversperiodes, vooral wanneer je het opruimen van de IndexReader en IndexSearcher overlaat aan de garbage collector. Dit lichten we hieronder verder toe. Dispose versus GC In bovenstaande implementatie laten we het opruimen van de oude IndexReader en IndexSearcher over aan de garbage collector.Dit kan ervoor zorgen dat sommige resources (zoals files) onnodig lang geopend blijven. Als dit een probleem blijkt kun je ervoor kiezen om de Dispose()-methodes van IndexSearcher en IndexReader aan te roepen na gebruik. Pas echter op: meerdere threads kunnen een reference hebben naar deze objecten en Dispose() mag pas aangeroepen worden nadat alle threads hebben aangegeven klaar te zijn met hun reference. Een methode om dit te doen is het gebruik van reference counting. Een mogelijke implementatie hiervan tonen we in het voorbeeldproject. Operationele karakteristieken Als laatste zijn we geïnteresseerd in de operationele eigenschappen van deze oplossing. We kijken daarvoor naar enkele omgevingsparameters: wat is de invloed van het aantal gebruikers op de zoeksnelheid, en wat is de invloed van het aantal documenten op de update-latency.
We zien dat de aanvoersnelheid in de gevallen v=0, v=10, v=20 updates per seconde geen significante invloed heeft op de updatelatency bij verschillende verversperiodes. Voor een aanvoersnelheid van v=50 updates per seconde zie je een hogere latency voor verversperiodes kleiner dan 2000 ms, dan voor 2500 ms. We hebben dit verder niet onderzocht. Daarnaast zien we dat de update-latency in de overige gevallen lineair schaalt met de verversperiode. Een tweede overweging is de interactie met de Blob Storage. We hebben daarom gemeten hoeveel data er vanaf de Blob Storage gedownload wordt per web-node, uitgezet tegen de tijd. Tijdens deze meting was de aanvoersnelheid 75 updates per seconde:
8
MAGAZINE
CLOUD
We hebben gemeten hoe de zoekperformance schaalt met het aantal zoekende gebruikers (gesimuleerd met meerdere threads) bij twee verschillende indexgroottes N (aantal documenten in de index). We doen dit door te zoeken op willekeurige zoektermen en de 10 meest relevante resultaten op te vragen: We zien dat een concurrency tot 25 threads per node in beide gevallen een zoeklatency van minder dan 100 ms oplevert. Bij 100.000 documenten is er nog ruimte voor hogere concurrency bij gelijke zoeklatency. Voor 1.000.000 documenten is dit echter niet het geval; daar loopt de zoeklatency snel op. Het aantal concurrent zoekopdrachten dat je per node kunt bedienen wordt dus beperkt door de indexgrootte.
Dit hebben we verder niet onderzocht. De updatedoorvoersnelheid van 100 updates per seconde is in onze gevallen toereikend geweest. We hebben daarom niet onderzocht of we deze nog hoger konden krijgen. De Indexer lijkt wel moeilijker uit te schalen omdat er maar één Indexer actief kan zijn. Deze eigenschappen maken dat wij Lucene een geschikte oplossing vinden voor het aanbieden van full text search in een Azure-omgeving. In de praktijk zetten wij de geschetste oplossing met succes in binnen meerdere projecten. We zijn hierbij niet tegen grote verrassingen aangelopen en zullen Lucene blijven overwegen voor nieuwe projecten. •
Roy de Boer
Tenslotte onderzoeken we hoe de update-latency zich gedraagt bij verschillende indexgroottes. Hiertoe meten we de update-latency als functie van het aantal documenten in de index N, bij verschillende aanvoersnelheden v.
Roy de Boer (
[email protected]) is één van de oprichters van Infi. Naast een voorliefde voor C#, en de oneindige tocht naar elegant softwareontwerp, is hij ook nogal enthousiast over OS X en FreeBSD.
Freek Paans Freek Paans (
[email protected]) werkt als technisch directeur bij Infi. Hij houdt zich voornamelijk bezig met het optimaliseren van het softwareontwikkeltraject binnen Infi, maar typt ook nog actief mee aan verschillende projecten. Verder vindt hij het leuk om na te denken over vrijwel elk vraagstuk in de softwareontwikkeling: van low-level performancewerk tot teamorganisatie tot conceptontwikkeling. Freek is ook te vinden op twitter onder @FreekPaans.
Het blijkt dat het aantal documenten in de index geen significante invloed heeft op de update-latency. Daarnaast is de gemeten ondergrens van de update-latency 2.0 s. Conclusie We hebben de Lucene API in het kort geïntroduceerd en de problemen om deze op Azure in te zetten uiteengezet. Vervolgens hebben we een architectuur die deze problemen oplost voorgesteld en de karakteristieken hiervan doorgemeten. We hebben de volgende observaties gedaan voor een implementatie die gebruik maakt van Azure Service Bus voor queueing en Azure Blob Storage voor persistent storage voor de index: • De zoeklatency is bij indices tot 1.000.000 documenten en een concurrency van 25 threads minder dan 100 ms. • De indexgrootte heeft een duidelijke invloed op de zoeklatency: grote indices hebben in het algemeen een hogere latency en beperken bovendien de concurrency per node ten opzicht van kleinere indices. • De indexgrootte heeft geen significante invloed op de updatelatency. • We kunnen tot 100 updates per seconde op de index doorvoeren, hiervoor is wel een batch size van minimaal 200 berichten vereist. • Bij een verversperiode van 2.5 s zien we een update-latency van 4 seconden. • De traffic van de Blob Storage wordt niet significant beïnvloed door de verversperiode. Lucene op Azure is daarmee binnen onze projecten een schaalbare oplossing gebleken. Binnen een node vinden wij de performance van Lucene acceptabel en je ziet bovendien ook lineair gedrag bij het bijschakelen van web-nodes. Uiteindelijk zal de Blob Storage waar de index op staat mogelijk een bottleneck worden.
1
We gebruiken in de metingen documenten tussen de 0 en 3 kb. Mocht je meer vragen hebben over de meetmethode dan kun je deze per mail aan ons stellen.
TIP:
Downloaden SDN Magazines Op de site van SDN vind je niet alleen een archief van alle magazines, het is ook mogelijk om de magazines te downloaden: www.sdn.nl/magazine.
magazine voor software development 9
GENERAL
Sander Hoogendoorn
Working software over proce$$es and fools Quite frequently people in agile (and non-agile) projects or at conferences and workshops come up to me and ask me what tooling they should use. “Which online agile dashboard tooling do you recommend us?”, “What is the best code repository?” or even “We are doing a Scrum project. Are we allowed to use a UML modeling tools such as Enterprise Architect in Scrum?” In all situations, I reply using the all-time favorite Scrum Master - which I’m not and never will be - response: it depends. Not because I don’t know much about agile tooling, but because there’s many different sides to the subject. To be honest, in my opinion, the discussion around agile tooling is expanding faster than the universe. Agile hippies and Scrumdamentalists First of all, there are groups in the agile community - if there ever was a single one - with highly idealistic attitudes, where people have this almost John Lennon-esque view of how agile will make the world a better place and will bring world peace at last. This is a world where all tools are considered evil, and are comparable to releasing drones in Afghanistan. A world where using tools feels cheating. These agile hippies as I refer to them rely heavily on the left side of the Agile Manifesto. This is where “Working software over comprehensive documentation” turns into “No, we do not document in agile projects,” and where “Individuals and interaction over processes and tools” become “No, you’re not allowed to use a modeling tool in an agile project.” To me, although this is an interesting view, it is also a rather naïve way of looking at the world of agile.
Next, there are what I refer to as the Scrumdamentalists. With the rising popularity of agile and agile approaches such as Scrum and now Agility Path - basically Scrum but with the word “enterprise” added to the names of all the roles and deliverables - many newbies have enrolled in Scrum Mastery; well-willing people with brand new
10
MAGAZINE
certificates but hardly any real-life experience in agile projects. Scrumdamentalists will follow the Scrum Guide, which they consider to be their bible, quite literally. Now the Scrum Guide is an interesting read as it comes to tooling, as it hardly discusses tooling. The Scrum Guide does not refer to unit testing frameworks, or how to set up your dashboard, or even where to store your user stories. In fact, the Scrum Guide does not even mention user stories. At all. The agile suits On the other, total opposite side of the spectrum, we find the vendors. Agile is more and more becoming a vehicle to make money. We already had a plethora of monopolized certification programs - or scams if you wish - to make money from, but more recently we are seeing that agile principles and techniques are penetrating board rooms of large enterprises. Hence the sudden need from agile methodologists to quickly come up with enterprise agile approaches. Think Disciplined Agile Delivery, SAFe and Agility Path - which, with the risk of being called blasphemous, you could describe as the Scrum Guide with the word enterprise taped to it. And when there’s enterprises involved, there’s tools to be sold, and there’s money to be made. So the vendors, which I refer to as the agile suits, enter the agile arena as well. Some vendors are achieving this by displaying agile street credibility, such as Atlassian, who print tshirts for nerds -yes, which I do wear – and send funny videos on how to pair program out on YouTube.
GENERAL
As you can imagine this strategy goes down quite well with the agile hippies. Other vendors such as IBM Rational, have long established board room credibility, and have found ways to sell their often quite expensive and extensive tool sets to CTO’s and CIO’s. Tools that are often not specifically targeted at agile, but have been lying around on shelves anyway. A company I know just bought around a million dollars’ worth of tooling on a large vendor’s application lifecycle management platform to run their enterprise agile projects. Same ball game, different strategies. Fuzzy But let’s be honest, besides these somewhat black-and-white views on the world, it is virtually impossible or at least undesirable to run an agile software development project without tools. If you are trying to organize your rehousing using agile techniques - which I did once -just using post-its on the kitchen door can be enough tooling, but not when you’re delivering working software. For instance, there seems to be little debate about using a development environment. Think Visual Studio, Eclipse, IntelliJ. And although I’ve seen passionate discussion between developers about which development environment to use, nobody will dispute that you need one. But after that, it gets fuzzier. When discussing agile tooling there is a wide variety of categories to consider. Are you discussing Scrum Boards, Kanban Boards, agile dashboards or Task Boards for instance? Most co-located teams use post-its on the wall, but distributed teams are going to have to rely on something more electronically organized boards. But then what? Mingle? Trello? Speedbird9? Jira Agile?
If you’re a two man co-located team, post-its on the wall will do fine, and you can easily produce your burn-down chart on a piece of paper or an Excel spread sheet. If you are an international trading company that develops new software around the clock with a highly distributed team of for example requirements people in Singapore and New York, analysts in Stockholm, developers in Poland, and testers in Germany, as I’ve seen recently, you might best consider using a complete application lifecycle management platform. At last, some guidelines I do feel sorry if you hoped that this article would present you with the out-of-the-box right tool choice for your project. I am unable to make such recommendation. Your project can and is very likely very different from mine. It might have a different number of teams, a different number of people, different technology, and a different geographical distribution of people. There is no one-size-fits-all agile tool set, as there is no one-size-fits-all agile process. However, I do want to leave you with some practical guidelines when it comes to choosing a specific tool set for your project. So here they are: • Start minimal. Always start with the minimal set of tools that will do the work for your current situation. It is always easier to add tools later, then to have to remove tools which you’ve been using for half a year just because they didn’t add much value. • 3M. If you are a co-located team that is not re-building the entire application landscape of a large insurance company, my favorite 3M tooling will do the job nicely: start with post-its on the wall.
On my current project we have set up a special room with projector and comfy seats just for doing demo’s and retrospectives. Oh, and for doing modeling sessions, because we are using a modeling tool for use cases and domain modeling – Enterprise Architect in this particular case. So can you use modeling tools in agile projects? Well, I think you can. If you really need it. I wouldn’t recommend setting up a modeling environment such as Enterprise Architect for a six week mobile project, but if you intend to rebuild all administrative systems of let’s say an insurance company, a modeling environment is indispensable. And what about bug tracking? We do need tools for that, right? Should we use Basecamp? Or should we use Jira instead? Recently I visited a project where the tester explained that whenever he found a bug on a feature he was testing, he created an issue in Jira. The developer then could pick it up from Jira, and work on it. Sounds reasonable right? It’s just that in this project both the tester and the developer are always working on the same feature, and they are literately sitting back-to-back in the office. And what about bug tracking? Management reporting? Tools for unit testing? Integration testing? Continuous integration? Continuous delivery? Are you getting on the continuous delivery train? There are even so many categories of tools, that it’s almost impossible to name them all. If you had enough time, you could probably create a short list for each of the categories, but then again, every project if different, so the requirements for tools in each project is likely different too. YAGNI This is where, as often, the YAGNI acronym comes in handy. You Ain’t Gonna Need It. You will need to pick the right tools for the right job. If you’re just hanging up a picture on the wall, a hammer and nail will probably do the trick, but if you’re totally reconstructing your kitchen from the ground up, you will definitively need other heavier equipment. Software development is not much different when it comes to tooling.
• Track your items. But, always start with tracking the progress of your work items from day one in the project, whether these are user stories, features, smart use cases, chores, bugs or whatever you’re doing. This way you at least have data on your project from the start, and you can start counting and measuring at any point in time, which you will want eventually. • Yes, Excel. As developers, you might have a big grudge against Microsoft Excel (probably because it’s the favorite tool for project managers), but I’ve seen many projects that have used a single (not a hard disk full of them) spread sheet successfully to keep track of everything you will need to know in your project. Think of burn-down or burn-up charts, retrospective outcomes, velocity numbers and current work item statuses. • Only add when needed. When starting with a minimal set of tools in your project, for some reason, at some point in time, you will realize that some element of your work could be optimized by using a tool. Usually you start to realize this during a sprint´s retrospective. Only now figure out what you’ve been missing, identify the minimal set of requirements for a-tool-to-add, and then simply choose the cheapest and best fitted product to add to your eco-system. And this tool doesn’t have to be the absolute best or most bling-bling
magazine voor software development 11
GENERAL
rich tool you can find on the planet. Just keep it simple. • Don’t get religious. Many people in the Scrum community feel that it is mandatory to use user stories as their unit of work. However, if you consider the Scrum Guide, the phrase user story does not even appear in it. With tooling, it’s not much different. I’ve had many discussions with people who feel very religious about one tool or another. Jira is a good example. There’s nothing wrong with Jira, but it is by far to be considered mandatory in Scrum projects. Nor is it mandatory to even use an online issue tracking tool. Especially when the whole team is in the same room. • Agile tools don’t exist. Also, don’t let others judge which tools you can or cannot use in your agile project. Or even worse, which tools are agile or are not agile. In my humble opinion, there’s no such thing as an agile tool. Tools are either fitted to your project, or are not fitted. I’ve been using UML modeling tools and model driven development tools successfully in many agile projects, despite the fact that some zealots think it is not agile to use such tools. • No free lunch. There’s no such thing as a free lunch. Every tool comes with consequences. Post-its will eventually fall off the wall. Free online dashboard tools are often limited to a certain number of users, of are only available for free for a certain period of time. Frameworks will version. Make sure you realize the consequences. By default, any automated tool you add will create a (vendor) lock-in.
To wrap things up, I’m sorry that I’m unable to give you more concrete tooling recommendations. Every project is different, and agile is a sliding scale. Personally, I consider it wise to start small, and only add tools when the add value, instead of starting with a fully integrated application lifecycle management support eco-system. And at last, always keep in mind that a fool with a tool is still a fool. The same goes for agile fools with tools.
Sander Hoogendoorn Sander Hoogendoorn houdt zich in zijn rol als Principal Technology Officer bij Capgemini zich vooral bezig met de innovatie van software development. Sander is erkend global thought leader op het vlak van agile development bij Capgemini. Daarbij is hij onder meer verantwoordelijk voor Capgemini’s agile ontwikkelplatform, dat het Accelerated Delivery Platform (ADP) wordt genoemd.
Als je voorop wilt lopen in je vakgebied, sluit je je aan bij de SDN community! Als lid van het Software Development Network, kortweg het SDN, ben je op de hoogte van de nieuwste ontwikkelingen. Je maakt deel uit van een netwerk van professionele architecten, designers en ontwikkelaars die elkaar met raad en daad terzijde staan. Je kunt lid worden van het SDN op basis van een bedrijfs- of een persoonlijk lidmaatschap. Het belangrijkste verschil is dat bij een bedrijfslidmaatschap twee of meer personen recht hebben op gratis toegang tot bijeenkomsten en de SDN website, bij een persoonlijk lidmaatschap is dat één persoon.
De kosten voor een bedrijfslidmaatschap voor twee personen bedragen € 299,- per jaar. Uitbreiding kost € 99,- per persoon per jaar. Een persoonlijk lidmaatschap kost € 199,- per jaar. Bedragen zijn exclusief 21% BTW. (Bedrijfs)naam
:
T.a.v. Adres PC/Woonplaats Email adres Telefoonnr. Personen
(indien bedrijfsabonnement minimaal 2)
Een lidmaatschap wordt aangegaan voor tenminste één jaar en wordt zonder schriftelijke annulering automatisch met een jaar verlengd op 31 december. Facturering vindt plaats per kalenderjaar of een deel hiervan. Opzeggingen uitsluitend schriftelijk en tenminste zes weken voor het einde van het jaar. Datum
Handtekening
Verzend dit formulier naar het secretariaat van SDN: Postbus 506 7100 AM Winterswijk of mail naar
[email protected]
12
MAGAZINE
DELPHI
Bob Swart
Delphi REST Client Components Apart from the REST Debugger, covered in the previous issue of SDN Magazine, Delphi also contains a number of REST Client components: TRESTClient, TRESTRequest, TREST Response, and TRESTResponseDataSetAdapter, plus four REST authentication components: TSimpleAuthenticator, THTTPBasicAuthenticator, TOAuth1Authenticator, and TOAuth2Authenticator. All these new components can be found in the REST Client category of the Tool Palette:
REST Twitter Client The example of this article covers the implementation of a REST Twitter Client, connecting to our Twitter account, and being able to send new Tweets. All using the Delphi REST Client components, including one of the Authenticator components (the TOAuith1Authenticator). We start by going to the Twitter API website, were we need to register our application (or at least specify that an application will be accessing the Twitter API). The URL for this is https://apps.twitter.com/ and we must login with our normal Twitter account. Here, we can click on the "Create new App" button to create a new application that will be allowed to communicate with the Twitter API. In the new form, we must specify the details:
Fig. 1 The TRESTRequest is the component that makes the actual RESTRequest. It has a Client property (pointing to a TRESTClient) as well as a Response property (pointing to a TRESTResponse component, introduced shortly). Using the TRESTRequest component we can specify the Resource property as well as the Params TRESTRequestParameterList collection. The TRESTResponse component is the one that will receive the response of a connected TRESTRequest component in the Content property.
Fig. 2 In our case, I've specified a name of "Delphi Developer Days 2014 Demo" with a description of "Delphi Developer Days 2014 Demo for the RAD Development and REST Client Tools (REST Debugger) session". As website I've used my own URL at http://www.drbob42.com although I probably should have used http://www.DelphiDeveloperDays.com as well.
magazine voor software development 13
DELPHI
Now, click on "Create your Twitter Application", which will give you some more information, like the Access Level, etc. This is the page were we can find some of the initial keys for use with the OAuth authentication to ensure our application has the permission granted to use the Twitter API via REST.
Let's take a look at the response. Place a TRESTResponse component (and make sure TRESTRequest Response property points to TRESTResponse now). In de FormCreate, write the following:
RESTRequest.Execute; if RESTResponse.GetSimpleValue('oauth_token', LToken)then OAuth1Authenticator1.RequestToken := LToken; if RESTResponse.GetSimpleValue('oauth_token_secret', LToken) then OAuth1Authenticator1.RequestTokenSecret := LToken;
Add REST.Authenticator.OAuth.WebForm.Win to the uses clause, and as a result we will see a page where we need to login using out Twitter account, and click on the "Authorize App" button in order to get a PIN code that needs to be used in the next part of our application.
Fig. 3 Click on the "Manage API Keys" link to go to a screen with your API Key and API secret key values. You need to copy the API Key and API secret values, and place them in the comments in your Delphi REST Client project, so we can use them shortly. OAUTH In order to be allowed to access the Twitter API using REST, we need to use an OAuth1Authenticator component, so place one on the form. We must set three EndPoint properties to the specific URLs for retrieving the Access Token, the Request Token and for doing the actual Authentication. These properties can be specified in the Object Inspector as follows: AccessTokenEndpoint to https://api.twitter.com/oauth/access_token RequestTokenEndpoint to https://api.twitter.com/oauth/request_token AuthenticationEndpoint to https://api.twitter.com/oauth/authenticate Finally, we need to set the CallbackEndpoint property value to oob.
Fig. 4 To simplify things, I've written the FormCreate event handler that will perform the first two steps, as well as a FormShow that will be used to enter the PIN code (which cannot be copied over the clipboard, so I'm using a InputBox to ask the user to specify the PIN code manually.
Then, set the ConsumerKey and ConsumerSecret property values based on the values from your twitter registered page (the two values you just copied from the web browser).
uses REST.Types, REST.Authenticator.OAuth.WebForm.Win;
Now, we can place a TRESTClient component on the form (it will automatically connect its Authenticator property to the OAuth1Authentocator1 component). Set the BaseURL to the RequestTokenEndPoint, or https://api. twitter.com/oauth/request_token
procedure TFormMain.FormCreate(Sender: TObject); var wv: Tfrm_OAuthWebForm; LToken: String;
Then, place a TRESTRequest component on the form, and set the Method to mtPOST (was mtGET) Right-mouse click on RESTRequest and do Execute... This will give Response: 200 - HTTP/1.0 200 OK
begin RESTClient1.Authenticator := OAuth1Authenticator1; RESTRequest1.Client := RESTClient1; RESTRequest1.Response := RESTResponse1; OAuth1Authenticator1.RequestTokenEndpoint :=
14
MAGAZINE
DELPHI
'https://api.twitter.com/oauth/request_token'; OAuth1Authenticator1.AuthenticationEndpoint := 'https://api.twitter.com/oauth/authenticate'; OAuth1Authenticator1.AccessTokenEndpoint := 'https://api.twitter.com/oauth/access_token'; OAuth1Authenticator1.CallbackEndpoint := 'oob'; // get your consumer key & secret from https://api.twitter.com OAuth1Authenticator1.ConsumerKey := 'QjCB98tSX25CUpjDXLm3Sw'; OAuth1Authenticator1.ConsumerSecrect := 'J0fs8uaLcRCau8S1ujtG04jtkdOKNVwvSgFQfliTek8'; RESTClient1.BaseURL := OAuth1Authenticator1.RequestTokenEndpoint; RESTRequest1.Execute; if RESTResponse1.GetSimpleValue('oauth_token', LToken) then OAuth1Authenticator1.RequestToken := LToken; if RESTResponse1.GetSimpleValue('oauth_token_secret', LToken) then OAuth1Authenticator1.RequestTokenSecret := LToken; // Get the auth-verifier (PIN must be entered by the user!) wv := Tfrm_OAuthWebForm.Create(self); try wv.ShowModalWithURL(OAuth1Authenticator1.AuthenticationEndpoint + '?oauth_token=' + OAuth1Authenticator1.RequestToken); finally wv.Release; end; end; At this point, the OAuth Web Login page will be shown, where we need to log into our Twitter account, and click on the "Authorize App" button in order to get a PIN code. The next step, in the FormShow, will start by getting the PIN code (using the Clipboard, which works on some machines, or the InputBox method), and preparing the REST components so we can make a call to the Tweet API. procedure TFormMain.FormShow(Sender: TObject); const {$J+} Done: Boolean = False; var LToken: String; begin if not Done then begin Done := True; OAuth1Authenticator1.VerifierPIN := InputBox('PIN','PIN:',''); RESTClient1.BaseURL := OAuth1Authenticator1.AccessTokenEndpoint; RESTRequest1.Params.AddItem('oauth_verifier', OAuth1Authenticator1.VerifierPIN,
TRESTRequestParameterKind.pkGETorPOST, [TRESTRequestParameterOption.poDoNotEncode]); RESTRequest1.Execute; if RESTResponse1.GetSimpleValue('oauth_token', LToken) then OAuth1Authenticator1.AccessToken := LToken; if RESTResponse1.GetSimpleValue('oauth_token_secret', LToken) then OAuth1Authenticator1.AccessTokenSecret := LToken; /// now we should remove the request-token OAuth1Authenticator1.RequestToken := ''; OAuth1Authenticator1.RequestTokenSecret := ''; OAuth1Authenticator1.CallbackEndpoint := ''; end; end; Note that I'm using a typed constant called Done to ensure that the code inside the FormShow to include the PIN is executed only once, and not for each and every FormShow call. Finally, the code to send an actual tweet is done by sending a status update to the Twitter API, as follows: procedure TFormMain.Button2Click(Sender: TObject); begin RESTClient1.BaseURL := 'https://api.twitter.com'; RESTRequest1.Resource := '1.1/statuses/update.json'; RESTRequest1.Params.AddItem('status', edTweet.Text, TRESTRequestParameterKind.pkGETorPOST); RESTRequest1.Execute; end; Although it may take quite some code, the result is that our custom application can work with the Twitter API and send REST requests using the Delphi REST Client components. •
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.
magazine voor software development 15
.NET
Piet Amersfoort
Async/await en het restaurantmodel Async/await is de belangrijkste uitbreiding van C# in versie 5.0. Deze uitbreiding is toegevoegd om asynchroon programmeren te vereenvoudigen. Het aantal regels code wordt bij toepassing van async/await verminderd en de kans op fouten wordt kleiner. Maar het is ook een extra abstractie laag. Een programmeertaal is per definitie een abstractie die het manipuleren van nullen en enen vereenvoudigd. Maar abstractie op abstractie kan het zicht op wat er werkelijk gebeurt vertroebelen. Hierdoor wordt programmeren gereduceerd tot het toepassen van recepten. Bij problemen is het dan niet meer mogelijk zorgvuldige analyses te maken en uiteindelijk de juiste oplossing te kiezen. Om beter inzicht te krijgen in deze abstracties, zullen we naar de bedrijfsvoering van een restaurant kijken en deze vergelijken met de ontwikkeling van asynchroon programmeren in C#. We kunnen dan iets beter begrijpen op welke wijze async/await problemen voor ons oplost. Simpel voorbeeld van async/await Stel dat we WPF-applicatie willen ontwikkelen die onder andere een window bevat met daarop een invoerveld, een button en een label. Als de gebruiker een priemgetal invoert en op de button klikt, verschijnt op het label de tekst: het ingevoerde getal is een priemgetal. Als er iets anders wordt ingevoerd, verschijnt er een andere tekst. private void Button_Click(object sender, RoutedEventArgs e) { Resultaat.Content = IsPriemWrapper(InputText.Text); } private string IsPriemWrapper(string inputText) { long getal; bool isGetal = long.TryParse( inputText, out getal); if (isGetal) { return IsPriem(getal) ? inputText + " is een priemgetal" : inputText + " is niet een priemgetal"; } return inputText + " is niet een getal"; } private bool IsPriem(long getal) { for (var i = 2; i < getal; ++i) { if (getal % i == 0) return false; }
16
MAGAZINE
return true; } Listing 1: Is een getal een priemgetal? (synchrone versie) Als er kleine getallen worden ingevoerd, dan verschijnt de tekst bijna direct. Bij grote getallen, bijvoorbeeld 756771235126757131, duurt de berekening veel langer. Tijdens de berekening kan de gebruiker de applicatie niet meer gebruiken, het scherm is bevroren. Bij Windows desktop applicaties is dit gedrag niet fraai, voor Silverlight en Windows Store Apps is dit gedrag niet acceptabel. De killer feature van versie 5.0 van C# is async/await. Het is aan de taal toegevoegd om asynchroon programmeren voor ontwikkelaars makkelijker te maken. Dus laten we het nieuwe async/await-recept gebruiken: • maak van de langzame functie een functie die een Task
oplevert, in ons geval een Task<string>. • Roep deze functie aan met await. • Maak de UI-functie async. Nu is de aanroep van de functie asynchroon geworden. Als de gebruiker op de knop heeft geklikt, dan blijft de applicatie reageren. private async void Button_Click( object sender, RoutedEventArgs e) { Resultaat.Content = await IsPriemWrapperAsync( InputText.Text); } private Task<string> IsPriemWrapperAsync( string inputText) {
.NET
return Task.Run(() => IsPriemWrapper(inputText)); } Listing 2: De aanpassingen om een asynchrone versie van de functie te maken Door deze simpele aanpassing voldoet het programma aan onze eisen en is de code ook te gebruiken in bijvoorbeeld een Windows Store App. Onder de C#-motorkap is veel complexe software verstopt. Het verbergen van complexiteit is in het algemeen een goede zaak. Als we een auto besturen, is het niet noodzakelijk dat we alle details van de werking van de automotor kennen. Het is zelfs aan te raden om tijdens het rijden hierover niet te veel na te denken. Maar, om met Einstein te spreken, maak het simpel, maar niet te simpel. Als onze software complexe scenario’s moet ondersteunen, dan is het goed om te weten wat er zich onder de motorkap bevindt. We gaan daarom asynchroon programmeren beschrijven door deze te vergelijken met de bedrijfsvoering van een restaurant. Restaurant 0.0 We hebben de gehele dag achter het toetsenbord doorgebracht en hebben trek in een stukje pizza. We gaan naar Pizzeria Francesco. In deze zaak werkt Francesco en hij is de eigenaar, de ober en de kok. Hij is de enige medewerker. We bestellen een pizza en een flesje wijn Fonterutoli Chianti Classico uit 2005. Francesco begint aan de voorbereidingen van de pizza en gaat in de wijnkelder op zoek naar de gevraagde wijn. Hij komt niet meer terug. Na een uur wachten vertrekken we maar. De werkwijze van dit restaurant is te vergelijken met de manier waarop de eerste pc’s werkten. Alle opdrachten worden in de gevraagde volgorde uitgevoerd. Als er één of meerdere opdrachten tussen zitten die lang duren, dan kan de gebruiker verder niets meer doen. En als opdrachten zelfs oneindig lang duren en dus geen resultaat opleveren, dan is er geen manier om het programma te stoppen en door te gaan met andere opdrachten. De enige optie is dan de computer uit te zetten, vervolgens weer aan te zetten en nieuwe opdrachten te starten. Ditmaal zonder de opdracht die het probleem heeft veroorzaakt. Restaurant 1.0 We waren niet de enige klanten van het restaurant die problemen hebben gehad. Meerdere klanten zijn boos weggelopen en de zaak was bijna failliet. Francesco heeft daarom een nieuwe manier van werken bedacht. Hij schrijft de opdrachten op kaartjes die hij bundelt met een touwtje. Hij werkt vijf minuten aan het eerste stapeltje met opdrachten, dan gaat de wekker. Hij stopt met zijn werk en pakt het volgende stapeltje en gaat verder met de opdrachten van het nieuwe stapeltje. Na vijf minuten gaat de wekker weer en gaat Francesco verder met de volgende stapel opdrachten. Als hij vijf minuten aan de opdrachten van het laatste stapeltje heeft gewerkt, gaat hij met de opdrachten van de eerste stapel verder. Deze manier van werken is minder efficiënt, omdat Francesco om de vijf minuten van stapel moet wisselen. Als hij een pizza aan het bakken is, moet hij daarmee stoppen en met een andere opdracht verder gaan, bijvoorbeeld het serveren van wijn. Hij moet zich hiervoor omkleden, kokskleding uit, oberkleding aan en verder met de volgende opdracht. Maar het originele probleem is wel opgelost. Als Francesco aan het zoeken is naar een fles wijn die hij moeilijk of niet kan vinden, dan gaan de andere opdrachten door en krijgen uiteindelijk alle gasten eten geserveerd. Dit is de wijze waarop single core Windows pc’s werken. Threads zijn setjes instructies die bij elkaar horen, per thread worden de instructies
uitgevoerd. Als er meerdere threads zijn aangemaakt, worden deze semi-parallel uitgevoerd. Elke thread krijgt geregeld de tijd om een gedeelte van zijn instructies uit te voeren. In .NET 1.0 is het mogelijk zelf nieuwe threads aan te maken. Deze kunnen worden gestart, waarna de opdrachten semi-parallel worden uitgevoerd. Een nadeel van deze wijze van werken is al genoemd. Het wisselen van thread’s kost veel tijd en is daardoor inefficiënt. Er zijn meer nadelen, het aanmaken van nieuwe threads is duur. In termen van het restaurantmodel, het kost Francesco veel tijd en energie om een nieuwe stapel opdrachten aan te maken. Hij moet op zoek naar een nieuwe stapel lege kaartjes, de instructies opschrijven en ze daarna bundelen. Dan moet hij een nieuw stukje touw zoeken en dit door de bundel met opdrachten rijgen. Er is nog een overeenkomst tussen het werk in het restaurant en de meeste Windowsapplicaties. Als Francesco een opdracht moet uitvoeren waarbij er contact is met de gasten, dan zal hij dit als ober moeten doen en niet als kok. Windows Forms en WPF applicaties vereisen het gebruik van STAThreadAttribute. STA is de afkorting van single-threaded apartment. Er mogen wel meerdere threads gebruikt worden in de applicatie, maar er is maar één UI-thread en het is de taak van deze thread de UI aan te passen. Tegen sluitingstijd zijn er nog stapeltjes met opdrachten waaraan gewerkt wordt. Sommige van deze opdrachten kunnen direct gestopt worden, bijvoorbeeld het afbakken van stokbrood voor nieuwe gasten. Andere opdrachten moeten wel worden afgemaakt, bijvoorbeeld de vuile borden in de vaatwasmachine zetten en de machine aanzetten voor het weggaan. Daarom heeft Francesco twee kleuren touwtjes, zwart en rood. Stapels met het zwarte touwtje mogen worden gestopt en stapels met een rood touwtje moeten worden afgemaakt, voordat de zaak kan worden afgesloten. Zo zijn er ook twee soorten threads, background threads en foreground threads. Anders dan de naam suggereert heeft het onderscheid niets te maken met de UI. Het enige verschil is de wijze van stoppen, voor de rest zijn ze identiek. Als een applicatie wordt gestopt, worden de background threads direct gestopt. De foreground threads moeten eerst hun werk afmaken. Call-backs Francesco wacht ook veel, ondanks dat hij het razend druk heeft. Hij stopt het eten in de oven en dan wacht hij de resterende vijf minuten. Daarna gaat hij door met de andere stapeltjes opdrachten. Daarna is weer het stapeltje met het eten in de oven aan de beurt. Dan wacht hij weer vijf minuten en gaat daarna weer door met zijn andere werk. Hij denkt: “dat moet anders kunnen”. Als hij nu eens twee stapeltjes met opdrachten maakt: één stapeltje met opdrachten tot het eten in de oven gaat en één stapeltje met opdrachten voor als het eten in de oven klaar is. Hij kan dan eerst de voorbereiding uitvoeren, vervolgens het eten in de oven zetten en de stapel met de vervolgopdrachten op een speciale plaats leggen. Nu hoeft hij niet meer nodeloos te wachten. Als het eten in de oven klaar is, gaat hij verder met de klaargelegde stapel vervolgopdrachten. .NET bevat sinds versie 1.0 classes die het BeginInvoke/EndInvokdepattern implementeren. Dit wordt het Asynchronous Programming Model (APM) genoemd. Als voorbeeld bekijken we de opdracht om in een groot tekstbestand op een netwerklocatie te controleren of er een bepaald woord in voorkomt. Deze opdracht kan synchroon worden uitgevoerd, maar dan moeten we net als Francesco nodeloos wachten totdat alle gegevens zijn verplaatst naar onze pc. Als we deze opdracht asynchroon uitvoeren, kunnen we de controle en de presentatie van het resultaat in een functie vastleggen. Deze functie wordt een call-back-functie genoemd. De functie wordt aangeroepen als de voorgaande activiteiten zijn uitgevoerd.
magazine voor software development 17
.NET
Als we de BeginRead/EndRead methodes van de Stream class gebruiken, kunnen we de BeginRead gebruiken om de informatie te verzamelen en de EndRead om de controle uit te voeren en het resultaat te presenteren. We wachten dan niet actief op het resultaat van de lees- en controleactie, maar we vertellen wat er met het resultaat moet gebeuren en vertrouwen erop dat dit uiteindelijk door een andere thread zal worden uitgevoerd en het resultaat ook zal worden getoond. Bij asynchroon programmeren zijn er drie soorten opdrachten. Opdrachten die voornamelijk door de hoofd processor (CPU) worden uitgevoerd. Deze opdrachten worden CPU bound genoemd en kunnen verder worden verdeeld in kortlopende en langlopende opdrachten. Opdrachten die lang duren worden long running operations genoemd. Het eerste voorbeeld, de bepaling of een getal een priemgetal is, is een voorbeeld van een kortlopende opdracht bij kleine invoerwaarden en een langlopende berekening bij grote waarden. Daarnaast zijn er de opdrachten die hoofdzakelijk niet door de hoofd processor worden uitgevoerd. Deze worden I/O bound opdrachten genoemd. Voorbeelden hiervan zijn lees- en schrijfopdrachten naar de harddisk en netwerkcommunicatie. Elk soort opdracht vereist een andere benadering. Kortlopende opdrachten kunnen beter synchroon worden uitgevoerd, langlopende opdrachten kunnen het beste op een andere thread dan de UI-thread worden uitgevoerd en I/O bound taken kunnen het beste worden gesplitst in deeltaken. Door ons tijdens het programmeren bewust te zijn van dit onderscheid, kunnen we altijd de juiste oplossing kiezen. Voorbereiding Het aanmaken van threads is duur. Franseco moet op zoek naar nieuwe kaartjes, een pen, touw, etc.. En altijd op momenten dat hij zijn tijd wel beter kan gebruiken, want de nieuwe gasten komen binnen, moeten naar hun tafel worden gebracht, de pizza’s moeten worden gebakken. Daarom heeft Francesco bedacht dat het handig zou zijn als hij al stapeltjes met kaarten heeft klaarliggen. En hij heeft ook bedacht dat het misschien verstandig zou zijn om de stapeltjes waar hij mee klaar is niet in de vuilnisbak te gooien, maar her te gebruiken. Hij is daarom naar de Makro gegaan en heeft daar een doos opschrijfboekjes gekocht, zodat hij de opdrachten kan vastleggen. In .NET 1.0 is het idee van Francesco geïmplementeerd. Het heet de threadpool. Als de applicatie wordt opgestart, dan worden er al enkele threads aangemaakt. Deze doen nog niets, maar als het nodig is kunnen ze aan het werk. Door de statische methode ThreadPool.QueueUserWorkItem worden ze in de wachtrij gezet om te worden uitgevoerd door de threads. Als laatste heeft Francesco bedacht dat het aantal stapeltjes met opdrachten waaraan hij gelijktijdig werkt, moet worden beperkt. Hij gaat pas aan de slag met een nieuwe stapel als hij een andere stapel met opdrachten heeft afgehandeld. Dit heeft diverse voordelen, onder andere dat als mensen besteld hebben, zij relatief snel eten op tafel krijgen. Aan de stapels met opdrachten die in behandeling zijn wordt relatief vaak gewerkt. Ook de threadpool heeft een beperkte capaciteit. Alle opdrachten worden wel aangenomen (QueUserWorkItem), maar wanneer er daadwerkelijk gestart wordt met de uitvoering van de opdracht, wordt onder andere bepaald door het aantal WorkItems waar al aan wordt gewerkt. Restaurant 2.0 Soms weet Franseco tijdens het voorbereiden van zijn opdrachten nog niet wat er moet gebeuren als het eten uit de oven komt. Dan is het misschien voldoende om het eten uit de oven te halen en te laten weten dat het klaar is. Dan kan hij daarna bepalen wat er met het eten moet gebeuren.
18
MAGAZINE
In versie 2.0 van .NET komt er een tweede asynchroon pattern bij. Dit heet Event-based Asynchronous Pattern (EAP). In plaats van een callback is er een event. Alle methodes die geïnteresseerd zijn in het event kunnen hierop reageren. Daarnaast was er nog het probleem dat de UI door de juiste thread moet worden geüpdatet. Dat werd in .NET 2.0 versimpeld door helper-class de SynchronizationContext te implementeren. In termen van het restaurantmodel, de SynchronizationContext onthoudt in welke stapel de klantcontacten zich bevinden, en weet als er informatie beschikbaar komt, hoe deze moet worden doorgespeeld naar de klanten. De SynchronizationContext bezit een Post-methode en accepteert een callback. Restaurant 3.0 Francesco heeft zijn restaurant steeds beter onder controle. Het aantal klanten groeit elk jaar. Ook stijgt elk jaar de productiviteit van Francesco. Door harder te werken kan hij de groei in zijn eentje bijbenen. Echter op een dag is de rek eruit. Aan het eind van de avond heeft hij het zo warm en is hij zo vermoeid, dat hij naar de dokter gaat. Van de dokter moet hij het rustiger aan gaan doen. De dokter stelt voor dat hij een medewerker aanneemt. Op deze wijze kan zijn restaurant doorgroeien. Zijn manier van werken met de stapeltjes opdrachten maakt dit al mogelijk. Taken opsplitsen is nu nog belangrijker. Door deze te splitsen kan het werk worden verdeeld en sneller worden uitgevoerd. Ook de CPU’s in onze pc’s zijn door de jaren heen steeds sneller geworden. Maar door de processoren sneller te maken, worden deze ook warmer en uiteindelijk worden ze te warm. Dus het sneller maken van de procesoren is gestopt. In plaats daarvan worden nu in een pc meerdere CPU’s geplaatst. De noodzaak om het werk eerlijk te verdelen over de CPU’s vereist dat bij het ontwikkelen van software opdrachten worden gesplitst, zodat elke CPU kan bijdragen aan het uitvoeren van de opdrachten. Restaurant 4.0 Nu Francesco meerdere medewerkers heeft, is het dus noodzakelijk het werk beter te verdelen. Om dit efficiënter te laten werken, heeft hij een pc aangeschaft. Hierin kan hij de stapeltjes met opdrachten vastleggen en beheren. Hij heeft een abstractie laag toegevoegd. Francesco werkt niet meer met fysieke kaartjes, maar met een elektronische versie van de kaarten. In .NET 4.0 is de Task Pararlel liibrary (TPL) toegevoegd. Dit wordt gezien als een abstractie laag over de al aanwezige threads. Het abstractie moet asynchroon ontwikkelen gemakkelijker maken. Een taak die de TPL ons uit handen neemt, is nadenken over de vraag of we zelf een thread moeten maken of de theadpool-thread moeten gebruiken. De TPL regelt dit voor ons. Waar blijft het eten? Als we voor een theatervoorstelling nog iets willen eten in Restaurant Francesco, dan moeten we op tijd eten geserveerd krijgen en op tijd vertrekken om niets van de voorstelling te missen. Als er vlak voor het vertrek nog geen eten op tafel staat, willen we graag weten hoe lang het nog gaat duren. Als het antwoord is: ”het kan nog wel even duren” dan willen we de mogelijkheid hebben om onze bestelling te annuleren. Als we met een groep mensen in een restaurant uit eten zijn en iedereen heeft zijn eten opgediend gekregen op één persoon na, dan zullen we wachten met eten. Stel nu dat het eten van die persoon is aangebrand en in de vuilnisbak is verdwenen, dan willen we dit wel graag weten. Dan kunnen we het vervolg zelf bepalen. Dat we nog even wachten met eten of dat we alvast beginnen of dat we het eten op tafel verdelen.
.NET
Voor de service van restaurants is het essentieel dat bovenstaande processen goed worden ondersteund. In essentie bevatten deze processen de volgende elementen: • Prioriteiten (priority) • Voortgangsbewaking (progress reporting) • Foutafhandeling (exception handling) • Beëindigen (cancellation) • Vervolgacties of basis van status (callbacks en continuations) Deze elementen worden in de TPL geïmplementeerd. De TPL is een zeer uitgebreide bibliotheek. Helaas ontbreekt hier de ruimte om deze functionaliteit in detail te bespreken. Restaurant 5.0 Francesco is hard aan het werk in zijn restaurant en maakt inmiddels veelvuldig gebruik van het nieuwe systeem. Echter op dagen dat hij niet aanwezig is, wil hij wel dat de zaken doorlopen. De training van medewerkers kost veel tijd. Daarnaast vereist het werken met het systeem veel extra handelingen. Daarom verzucht Francesco weleens: kan het niet wat simpeler? Is het niet mogelijk te werken op een manier die lijkt op de oude eenvoudige manier van werken? We zijn aangekomen bij C# 5.0 met async/await. Aan het voorbeeld van het begin kunnen we zien dat asynchrone code lijkt op de originele synchrone code. Achter de schermen wordt er echter gewerkt met taken uit de TPL, threads uit de threadpool, de synchronisatie context en call-backs. De compiler vertaalt de relatief simpele code in een complexe state machine. Dit gebeurt allemaal om het asynchroon programmeren voor ons zo makkelijk mogelijk te maken.
Tot slot Dit artikel is een korte introductie van asynchroon ontwikkelen in C# en async/await. Dit kijkje in de keuken heeft hopelijk tot meer inzicht geleid en smaakt mogelijk naar meer. Ik verwijs om die reden graag naar enkele van de vele boeken waarin veel dieper op de materie wordt ingegaan: • Bart de Smet - C# 5.0 Unleashed • Joseph Albahari, Ben Albahari - C# 5.0 in a Nutshell • Richard Blewett, Andrew Clymer- Pro Asynchronous Programming with .NET • John Skeet - C# in Depth, Third Edition •
Piet Amersfoort Piet Amersfoort is zelfstandig consultant op het gebied van bedrijfsautomatisering. Hij is op zoek naar problemen die meer zijn dan een uitdaging. Microsoft-technologieën is één van zijn specialisme. Zijn blog is te vinden op: http://ps-a.blogspot.com/
Microsoft Azure Websites Backup Als je een Microsoft Azure Website hebt gemaakt, dan kun je deze nu ook regelmatig en automatisch laten backuppen. In deze backup routine kun je ook de bijbehorende database of linked resources meenemen. Dit maakt Microsoft Azure websites nog interessanter om te gebruiken.
magazine voor software development 19
DELPHI
Cary Jensen
Talking About Frames I like frames, and by frames, I mean instances of the TFrame class first introduced in Delphi 5. I use frames extensively in my applications, and I was very pleased to see frames added to the FireMonkey component library. In this article I want to share with you a couple of techniques that I have been using extensively in my applications. Of course, these techniques apply to frames. I will also share with you an observation about mobile development with Delphi, and will argue that frames solve one of the bigger issues that Delphi mobile developers have been commenting about. But first, let's start with a brief overview of frames. Frames in a Nutshell A frame is a type of module, much like a form or data module. Frames support a design surface for both visual and non-visual components, and in that way are similar to forms. (Data modules also support a design surface, but that design surface is limited to non-visual components.) From a user interface perspective, frames are significantly different from forms. Specifically, forms are intended to be used as a whole, defining a window or dialog box in your application. Frames, by comparison, are more like a fancy panel. Specifically, one or more frames can be placed onto a form, and frames can even be placed into other frames. In this way a frame acts like a compound component. That is, a component that exposes other components, both visual and nonvisual. Unlike a traditional compound component, however, frames permit the objects that have been placed into them to be selected and configured using the Object Inspector from the container in which the frame is placed. For example, I can create a frame that contains a DBGrid and a DataSource. Once I place that frame onto a form, I can still select the DataSource in the frame instance and set its DataSet property. Similarly, from the form on which this frame appears I can easily reach into the frame and change the position of the DBGrid, changing the position in just this one instance of the frame. Permitting the objects that are exposed by a compound component to be configured in this fashion would require custom code, and some of that could get quite complicated. There are two primary benefits of frames. The first is that, under certain circumstances, frames can dramatically reduce the amount of resources that need to be stored in a project. The second, and in most cases the more important benefit, is that frames permit you to visually create objects that can be easily reused and extended. To look at it another way, frames are building blocks for your user interface that can be easily configured at design time. Components that appear on your frame are available in each instance of the frame that you place, and the code defined for the frame is likewise present in each instance. As a result, frames are a powerful tool in an object-based design environment like Delphi, and an excellent source of code reuse.
20
MAGAZINE
Before I continue, let me acknowledge that it is also possible to make a form appear within another form, and a given form can consist of one or more embedded forms. However, doing so is a strictly runtime operation, and it requires several lines of code, at a minimum. You cannot place one form within another at design time. Furthermore, many of the features of a form, such as its OnClose event handler, are lost when placed on another form. As a result, using a form within a form more or less turns the form into a frame, but without the convenience of design time placement and configuration. Dynamically Created Frames In my brief introduction to frames I emphasized the benefits of the design time use of frames. And while those benefits are very real, they tend to make us forget that frames can play an important role in runtime code. In particular, I often find myself creating frames dynamically at runtime, and the results are something that would be difficult using any other technique. For example, I often have the need to create a calendar-like interface to represent date-related events, such as the daily schedules of work to be performed over the course of a month. In those cases, I create a frame that represents a day, and that frame is designed to display the schedule for a date. At runtime I create one instance of the frame for each day in the month, positioning the frame on the calendar based on its day of the month and day of the week. I might even make each instance of the frame responsible for loading the schedule for the particular date that it represents. Creating a calendar-like interface at design time cannot entirely capture the fluid nature of a calendar. For example, some months have more days than others, and one month (February) occasionally has an extra day, depending on the year. In addition, the first day of the month can potentially land on any day of the week. In other words, the layout of the calendar depends on which month and which year the calendar interface is representing. Dynamically-created frames provide an excellent, object-oriented solution to this interface problem. A calendar is really just one example of dynamic frames. Instead of calendar dates, I might create a frame that represents a team of employees. Since the total number of teams, and the specific employees that constitute each team, may vary from day to day, it is unreasonable to design an interface that displays all teams in advance. Here again, a query to a database can identify the number teams as
DELPHI
well as each team's members, and then one frame can be created for each team at runtime. I created a simple project that demonstrates the dynamic use of frames. This project queries one of the sample databases that ships with Delphi, and each frame is used to display the orders for a given year. I happen to use cloned ClientDataSet cursors in this example, but that is not an essential part of the demonstration. Instead of using a cloned ClientDataSet cursor to populate a given frame, I could have called a method of the frame designed to load the frame's data from some data source. This project is named DynamicFrames, and you can download it from the following URL: http://www.JensenDataSystems.com/DynamicFrames This project contains a single frame shown in Figure 1. This frame, named GridFrame, consists of a DBGrid and a DataSource, though your dynamic frames can contain any visual and non-visual components necessary to display the associated data.
Fig. 1: A frame that will be created dynamically The main form of this application is also terribly simple, consisting of some components for accessing the data and a FlowPanel that is aligned to client. Figure 2 shows this form in the designer.
SELECT extract(Year FROM o.SaleDate) AS SaleYear, c.Company, o.SaleDate, e.LastName AS SalesPerson FROM Orders o INNER JOIN Customer c ON c.CustNo = o.CustNo INNER JOIN Employee e ON e.EmpNo = o.EmpNo ORDER BY SaleYear The only runtime code in this project is that found on the OnCreate event handler for the main form. This code is shown here. procedure TForm1.FormCreate(Sender: TObject); var GridFrame: TGridFrame; Clone: TClientDataSet; Year: Integer; DBPos: Integer; DBParam: string; CurrentYear, LastYear: Integer; begin DBParam := 'Database=' + GetEnvironmentVariable('DEMOSDIR') + 'Data\dbdemos.gdb'; DBPos := FDConnection1.Params.IndexOfName ('Database'); if DBPos <> -1 then FDConnection1.Params.Delete(DBPos); FDConnection1.Params.Add(DBParam); ClientDataSet1.Open; CurrentYear := ClientDataSet1.FieldByName ('SaleYear').AsInteger; ClientDataSet1.Last; LastYear := ClientDataSet1.FieldByName ('SaleYear').AsInteger; ClientDataSet1.First; while CurrentYear <= LastYear do begin GridFrame := TGridFrame.Create(Self); GridFrame.Name := 'GridFrame' + IntToStr (CurrentYear); GridFrame.Parent := FlowPanel1; Clone := TClientDataSet.Create(GridFrame); Clone.CloneCursor(ClientDataSet1, True); Clone.IndexFieldNames := 'SaleYear'; Clone.SetRange([CurrentYear], [CurrentYear]); GridFrame.DataSource1.DataSet := Clone; inc(CurrentYear); end; end;
As you can see, once the ClientDataSet is populated with data, copies of the GridFrame are created, one for each year in the range returned by the query. Each frame is systematically associated with a different clone of the ClientDataSet, each clone being restricted to a particular date range. Fig. 2: The main form of the DynamicFrame project
Figure 3 shows how the main form looks when the application runs.
The ClientDataSet, DataSetProvider, FDQuery, and FDConnection components were configured at design time (for the most part. The FDConnection is partially configured in the OnCreate event handler). For example, the SQL found in the FDQuery contains the following code:
This is a simple example, by design. Nonetheless, it demonstrates the power of dynamically created and configured frames.
magazine voor software development 21
DELPHI
Fig. 3: Dynamically created frames populate a FlowPanel A few comments are in order before leaving this example. The use of a FlowPanel in this project was a convenience, since the FlowPanel actively creates the layout. An alternative is to create the frames parented to a scrollbox, or some other container. It would even be acceptable to place all of the dynamically created frames in a single default position, and then order them using a method similar to this one here. procedure PositionFramesInContainer(Container: TWinControl; Stack: Boolean = False; Horizontal: Boolean = False); var FH, FW: Integer; CW: Integer; CurrTop, CurrLeft: Integer; i: Integer; begin //Initialize FW. This is used as a flag to get the size of one of the frames FW := 0; //Make the frames invisible for i := 0 to Container.ControlCount - 1 do begin if Container.Controls[i] is TCustomFrame then begin if FW = 0 then begin FH := TCustomFrame(Container.Controls[i]).Height; FW := TCustomFrame(Container.Controls[i]).Width; end; Container.Controls[i].Visible := False; //Reset their position Container.Controls[i].Top := 0; Container.Controls[i].Left := 0; end; end; CW := Container.Width; CurrTop := 0;
22
MAGAZINE
CurrLeft := 0; if (FW > CW) or Stack then begin //Stack'em up if Horizontal then begin for i := 0 to Container.ControlCount - 1 do if Container.Controls[i] is TCustomFrame then begin with TCustomFrame(Container.Controls[i]) do begin Top := 0; Left := CurrLeft; CurrLeft := CurrLeft + FW + 1; end; end; end else for i := 0 to Container.ControlCount - 1 do if Container.Controls[i] is TCustomFrame then begin with TCustomFrame(Container.Controls[i]) do begin Top := CurrTop; Left := 0; CurrTop := CurrTop + FH + 1; end; end; end else begin //Lay'em out for i := 0 to Container.ControlCount - 1 do if Container.Controls[i] is TCustomFrame then begin with TCustomFrame(Container.Controls[i]) do begin Top := CurrTop; Left := CurrLeft; //Update CurrLeft CurrLeft := CurrLeft + FW + 1; //Is there room for a new frame? if (CurrLeft + FW + 1) > CW then
DELPHI
Fig. 4: The Visual LiveBindings Designer for a mobile application with two TabItems
begin //No, reset CurrLeft and advance CurrTop CurrLeft := 0; CurrTop := CurrTop + FH + 1; end end; end; end; //Make the frames visible again for i := 0 to Container.ControlCount - 1 do if Container.Controls[i] is TCustomFrame then Container.Controls[i].Visible := True; end;
Frames and Mobile Development Unless you have been sleeping under a rock you already know that Delphi can create native executables for both iOS and Android mobile devices. These applications must be created using FireMonkey, since FireMonkey is Delphi's cross-platform component library. When using FireMonkey, most developers make use of LiveBindings and the Visual LiveBindings Designer to enable data awareness in the visual controls. Unfortunately, the evolving best practices for mobile application design in Delphi has relied on applications based on a single form where a TabControl containing two or more TabItems defines the various screens (page) of the application. Indeed, most of Delphi's mobile wizards in the Object Repository create just such an interface. The problem with this is that all of the visual controls in the application end up being owned by the single form. As a result, the Visual LiveBindings Designer becomes incredibly cluttered. This can be seen in Figure 4, which depicts the Visual LiveBindings Designer for an applications that contains two TabItems and their associated visual controls.
Unfortunately, a two-page mobile application is uncommon. Most mobile applications will have many more pages (TabItems), and the problem of clutter in the Visual LiveBindings Designer can get completely out of hand. Sure, the layers feature of the Visual LiveBindings Designer is there to help, but the problem is real. How can we solve this problem? With frames, of course. Instead of placing your visual controls on a TabItem, place them instead on a frame. Each frame is its own module, and it owns the controls that appear upon it. As a result, when a given frame is displayed in the designer, the Visual LiveBindings Designer will display only the components on that frame. Granted, the one form of your application on which the TabControl appears will display all of the objects from all of the frames placed on the individual TabItems within the Visual LiveBindings Designer when the form itself is selected in the designer, so the clutter still exists. But you will not really care. As long as you can configure LiveBindings at the Frame level, you will use the Visual LiveBindings Designer only with individual frames, in which case only the components on the selected frame will be visible. •
Cary Jensen Cary Jensen is Chief Technology Officer of Jensen Data Systems. Since 1988 he has built and deployed database applications in a wide range of industries. Cary is an Embarcadero MVP, a best selling author of more than 20 books on software development, and holds a Ph.D. in Engineering Psychology, specializing in humancomputer interaction. Each spring Cary and fellow Embarcadero MVP Bob (Dr.Bob) Swart present the annual Delphi Developer Days tours. Learn more at www.DelphiDeveloperDays.com.
magazine voor software development 23
HTML
Niels Bergsma
Applicatiestack opnieuw uitvinden met HTML5 Tegenwoordig worden steeds meer webapplicaties grotendeels met client-side technologieën gerealiseerd. Waarom, wat zijn de voordelen en waar moet je op letten? Waarom Om maar met de belangrijkste vraag te beginnen: waarom? Omdat het kan! Door de nieuwe mogelijkheden van HTML5 en een scala aan bibliotheken is het niet meer nodig alles op de server uit te voeren. Zaken zoals het renderen van html, het toetsen van invoer en toepassen van restricties zijn uitermate geschikt om op de client (de browser) af te handelen. Dat scheelt een hoop rekenwerk aan de serverkant, minimaliseert netwerkverkeer en verlaagt reactietijd, wat uiteindelijk ten goede komt aan de gebruikerservaring. Het is niet ondenkbaar om een applicatie enkel met html en javascript te realiseren, waarbij de server alleen als opslagmechanisme of communicatiebrug dient. De applicatiestack opnieuw verdelen In een traditionele webapplicatie, ontworpen met een drielagenarchitectuur (figuur 1), worden alle lagen afgehandeld op de server. De client weergeeft de uitvoer (html), die hij van de server ontvangt en communiceert terug op basis van events. Dit model is vergelijkbaar met de allereerste terminal-computers.
Fig. 1: drielagenmodel Sinds de introductie Web 2.0 (2001), waarbij er onderwater data wordt opgehaald met AJAX, voegen we langzaam maar zeker steeds meer logica aan de client-side toe. De logica maakt dus een verschuiving van server naar client. De laatste jaren heeft die verschuiving zich voortgezet en is het niet ongewoon geworden om de UI-laag en deels van de business logica-laag te implementeren aan de client-side. Voorbeeld 1: een applicatie met aan de client-side alle lagen, waarbij storage als transparent proxy is geïmplementeerd. De applicatie kan volledig offline werken. Wanneer er een internetverbinding beschikbaar is, worden modificaties gesynchroniseerd. Op de server
24
MAGAZINE
worden alle gegevens gecontroleerd en opgeslagen in een gemeenschappelijke opslag. Voorbeeld 2: een applicatie met aan de client-side de user interface en deels van de business logica geïmplementeerd. De applicatie is opgebouwd uit sjablonen en componenten, die eenmalig worden opgehaald. Alleen voor data wordt de server geraadpleegd. Eenvoudige invoervalidaties vinden lokaal plaats, de complexere logica op de server. Welke logica je waar implementeert hangt sterk af van de situatie. Van invloed is: - De gevoeligheid van de data - De geldigheidsduur van de data - Het gebruikersgedrag (nieuwe bezoekers versus terugkerende bezoekers) - Het soort omgeving (intranet versus internet) - De algehele complexiteit van het probleemdomein
Een gouden regel is om bedrijfsgeheimen nooit prijs te geven en dat je niets of niemand kan vertrouwen. Client-side code is eenvoudig in te zien en te manipuleren. Bedrijfsspecifieke en belangrijke algoritmes moet je niet vrijgeven. Stuur nooit meer gegevens terug naar de client, dan dat de gebruiker mag zien. Neem aan dat er gesjoemeld gaat worden met data. Stel de geldigheid van data nogmaals vast op de server. Naar mijn inziens is er geen typische of ultieme architectuur. De verdeling van lagen hangt af van je wensen-en-eisenpakket. Realiseer echter dat alles wat op de client wordt afgehandeld, niet meer door de server gedaan hoeft te worden. Dit resulteert doorgaans in een betere scheiding van lagen en componenten. De API die de data beschikbaar stelt is herbruikbaar, voor bijvoorbeeld een App of
HTML
externe partijen. Het vereenvoudigd de cacheability en beveiliging, omdat je op dit dataniveau bepaalt, in plaats van paginaniveau. De ontwikkeling van client- en server-side kan worden opgesplitst. Wanneer er is afgesproken hoe de twee met elkaar communiceren, uitgedrukt in een (restful) API, kunnen beiden onafhankelijk van elkaar evolueren. Datzelfde argument geldt ook voor schalen. Het wordt eenvoudiger om technieken zoals partitioneren toe te passen. HTML5 Van origine is html bedacht om documenten weer te geven, waarbij maar beperkte interactie nodig was. In opvolgende versies zijn er steeds meer mogelijkheden toegevoegd om de interactie met het document verbeteren. In de meest recente versie (HTML5) zijn met name mogelijkheden toegevoegd voor het realiseren van webapplicaties:
tegenstelling tot bijvoorbeeld shared state). Conclusie Met HTML5 kan je werk van de server naar de client verschuiven, wat ten goede komt aan de performance en user experience. Technisch zijn er weinig beperkingen waar een stuk code wordt uitgevoerd. Waar en wanneer hangt af van de data en het gebruik. Het loont om hier goed over na denken en een strategie te kiezen. Een voorbeeld Om de bovenstaande ideeën en concepten wat concreter te maken, heb ik een voorbeeld uitgewerkt. Dit voorbeeld laat onder andere zien hoe je modulariteit, offline-mogelijkheden en het drielaagsmodel aan de client-side kan toepassen. Je kan het voorbeelden downloaden van Github http://bit.ly/1jQP2XO •
Application cache Application cache stelt je in staat een lijst op te geven met bestanden die beschikbaar moeten zijn wanneer er geen internetverbinding is. Ook kan je fallback opgeven wanneer een bestand of een groep bestanden niet benaderbaar is. Web storage Web storage is een key-value database, waarbij zowel de key-, als de value-waarde een string is. Per domein kan je maximaal 5MB opslaan. Web works Web works zijn de threads van javascript. Je start een web worker met een verwijzing naar het uit te voeren javascript-bestand. Communicatie met de web worker gaat middels message passing (in
Niels Bergsma
Niels Bergsma is als architect al ruim 9 jaar werkzaam bij Reflex Online B.V. Hij verdiept zich in modelleren & schalen van applicaties en het maximaliseren van user experience. Hij is te bereiken via LinkedIn of [email protected]
SDN > Update
Azure Websites staging Een ontwikkeltraject van software bestaat altijd uit een stuk design, bouw, testen en deployment. Of je dit nu agile of niet doet, de stappen komen altijd terug. Voor de verschillende onderdelen heb je ook verschillende omgevingen. Bouwen doe je op een development omgeving en vaak lokaal. Testen doe je op een Testomgeving en deze staat meestal centraal. Op Productie wordt alleen maar gedeployed en hebben de vorige stappen gevalideerd dat de software werkt en goed is. Soms bevat een deployments (productie of test maakt niet zo uit) procesjes om de omgeving voor te verwarmen. Bijvoorbeeld de
eerste call naar een website duurt meestal iets langer op een vers geinstalleerde omgeving. Niet zo gek er moeten allerlei zaken gecached worden en opgestart. Maar als je een nieuwe versie gepubliceerd hebt, dan merken je productie gebruikers deze vertraging. Niet fijn en zeker in onze snelle maatschappij waar we bijna niet meer willen wachten niet handig.
Dan zou het handig zijn om alvast een deployment te doen, de boel op te warmen en deze dan beschikbaar te stellen aan je gebruikers.
Bij Microsoft Azure Cloud Services deden we dat door de staging omgeving gebruiken. Op deze Staging omgeving kon je dan alles even aanraken en zorgen dat de eerste vertraging uit de lucht is. Daarna kon je met een Swap Staging naar Productie brengen..
Bij Microsoft Azure websites was de Staging omgeving er niet. Maar sinds kort bestaat dit ook voor de Websites. Scherm technisch ziet het er iets anders uit, maar werkt ongeveer gelijk. De Staging omgeving is er niet standaard en moet je zelf toevoegen.En wil je Staging Productie maken, dan gaat het net zo eenvoudig.
magazine voor software development 25
DEPLOYMENT
Eric Tummers
Continuous Deployment met TFS, Octopusdeploy en Azure Het opzetten van continuous deployement kost wat tijd, maar de winst die het oplevert aan het einde van het traject is de moeite waard. In dit artikel loods ik je stapsgewijs door de inrichting van een octopus deploy omgeving. Hiervoor maak ik gebruik van Team Foundation Service en Windows Azure. Alles wat je nodig hebt is een Windows Live Id en wat tijd. Voorbereiding Ik ga ervan uit dat je een Windows Live Id hebt. Hiermee kun je een gratis (proef) abonnement bij Windows Azure nemen op http:// windowsazure.com. Daarna download je de software van http://octopusdeploy.com (octopus server, octopus tentacle en commandline, 64 bit indien van toepassing) Vraag ook alvast een trial licentie aan voor octopus server. Als laatste vraag je een gratis (proef) abonnement bij Visual Studio Online aan op http://visualstudio.com. Voor dit artikel gebruik ik een nieuw Windows Live Id en alle gratis varianten van de hierboven beschreven services en software. Als je al een service hebt aangeschaft, kan die natuurlijk ook gebruikt worden.
Via Remote Desktop maak ik een verbinding. Als eerste open ik de poorten 80 en 10943 ook in de Windows Firewall. Via Copy-and-Paste breng ik de installatie bestanden naar de Remote Desktop. Daarna voer ik de installatie van octopus server uit. De installatie bestaat uit het accepteren van de licentie en het kiezen van een installatie locatie. Na de octopus server installatie start de configuratie. Bij de licentie vraag plak ik de ontvangen xml uit de email met de trial licentie. De rest van de wizard wijst zich vanzelf.
Octopusdeploy server Als eerste richt ik de octopus server in. Dit doe ik in een Windows Azure Virtual Machine. Virtual Machine Ik log in met mijn Windows Live Id op de Windows Azure Portal en maak een Virtual Machine aan. Gebruik FROM Gallery in plaats van de Quick Create. Bij het aanmaken zorg ik ervoor dat er endpoints voor poorten 80 en 10943 zijn. Op poort 80 host octopus server haar web portal en over poort 10943 maken de beheerde machines contact met de server.
Fig. 2: octopus server setup wizard Nu kan de Remote Desktop gesloten worden. Voor de rest van dit artikel gebruik ik de web portal die beschikbaar is op het Cloud Service adres van de zojuist aangemaakte Virtual Machine. Web portal Na inloggen op de web portal kom ik op het dashboard uit. Hierop worden de omgevingen en projecten weergegeven met de daarop geïnstalleerde releases. Het dashboard is nog leeg, omdat ik nog niets heb ingericht.
Fig. 1: octopus server virtual machine configuratie met endpoints voor HTTP en Tentacle 26
MAGAZINE
In environments maak ik de OTAP (ontwikkel, test, acceptatie en productie) omgevingen aan. Alleen de naam van de omgeving is nu
DEPLOYMENT
nodig, de overige velden mogen leeg blijven. Speciaal voor nieuwe machines maak ik een Parking omgeving aan, hierover straks meer. Zodra een machine onderdeel is van een omgeving wordt deze hier weergegeven.
Ik installeer de tentacle software. Ook dezeinstallatie bestaat uit het accepteren van de licentie en het kiezen van de installatie locatie. Na het installeren van de tentacle software start automatisch de tentacle manager om de tentacle te registreren. Deze manager sluit ik zonder de tentacle te configureren. Tijdens de configuratie wordt namelijk een unieke code gegenereerd waarmee de machine wordt geïdentificeerd door de octopus server. Als de image deze code bevat zijn de VM’s niet van elkaar te onderscheiden. Verderop in dit artikel geef ik een eenvoudiger stappenplan die geen gebruik maakt van een image. Microsoft bied een mogelijkheid om na de provisioning fase van een nieuwe VM een script uit te voeren. Dit is de fase nadat het systeem is ingericht voor de nieuwe hardware en voor de laatste keer herstart. Het script moet SetupComplete2.cmd heten en in de folder c:\windows\oem komen te staan. In dit script configureer ik de tentacle, zodat een unieke code wordt gegenereerd en de tentacle zich registreert bij mijn octopus server in de parking omgeving als webserver.
Fig. 3: octopus server web portal met de lege environments Onder projects maak ik een project “Company website” aan. Opnieuw is alleen even de naam belangrijk, de overige velden laat ik leeg. Een project is de kapstok voor een release. De stappen van een release definieer je in Process en in Variables staan de variabelen zoals locaties, connectionstrings en applicationsettings. Na de eerste build van mijn project zal ik het release proces inrichten. In mijn profile staat de API key waarmee ik acties kan uitvoeren vanaf de commandline. Deze noteer ik want deze heb ik later nodig om vanuit mijn CI build de deployment uit te voeren. Maar ook om de machines zichzelf te laten registreren bij mijn octopus server. Mijn screenshots zijn van versie 2.1.3, inmiddels is API een apart tabblad geworden.
ECHO SetupComplete2.cmd BEGIN >> %windir%\Panther\WaSetup.log REM register tentacle CD "C:\Program Files\Octopus Deploy\Tentacle" Tentacle.exe create-instance --instance="Tentacle" --config="C:\Octopus\Tentacle\Tentacle.config" --console Tentacle.exe new-certificate --instance="Tentacle" -if-blank --console Tentacle.exe configure --instance="Tentacle" -home="C:\Octopus" --app="C:\Octopus\Applications" --console Tentacle.exe register-with --instance "Tentacle" -server "http://octopusdemo3.cloudapp.net" --apiKey="API-LTV8SYHODOMA12WUVDGACY2MU" --environment "Parking" --role "Webserver" --comms-style TentacleActive -console Tentacle.exe service --instance="Tentacle" --install --start --console ECHO SetupComplete2.cmd END >> %windir%\Panther\WaSetup.log Listing 1: Configuratie en registratie van tentacle na provisioning Sysprep en nieuwe VM’s Nu mijn machine ingericht is zoals ik wil, start ik sysprep en kies voor Out-of-Box Experience, Generalize en Quit.
Fig. 4: octopus server web portal profile met API key Machines De machines in OTAP worden ook Windows Azure Virtual Machines. Hierbij is het handig om een image te maken van een ingerichte omgeving om daarmee de VM’s aan te maken. Ik maak een nieuwe VM aan en maak verbinding via Remote Desktop. Dan installeer ik Application Server, Web Server (IIS) en SQL Server 2012 Express LocalDb. Deze software heb ik nodig om de Company Website te hosten. Tentacle Om een deployment naar een machine te kunnen uitvoeren moet software aanwezig zijn op die machine. Deze software heet een tentacle. De octopusdeploy server communiceert met de tentacle om de software en installatie instructies erop te krijgen.
Fig. 5: sysprep Windows Azure Virtual Machine
magazine voor software development 27
DEPLOYMENT
Nadat sysprep klaar is sluit ik de Remote Desktop sessie. In de Windows Azure Portal stop ik de VM en kies ik Capture om een image aan te maken voor mijn standaard omgeving. Nadat het image is aangemaakt, creëer ik twee nieuwe VM’s op basis van dit image. Dit worden mijn ontwikkel en test omgevingen. Hiervoor browse ik in de Gallery voor My Images en kies ik mijn net aangemaakte image.
Fig. 6: My Images in de Virtual Machine Image gallery Zodra een VM de status running heeft, is die ook bekend in mijn octopusdeploy server. Hiervoor had ik het setupComplete2.cmd script aangemaakt. De machines verplaats ik naar de toepasselijke omgevingen: dev01 naar ontwikkel en tst01 naar test.
Octopack Voor deployment van de binaries maakt octopus gebruik van nuget. Een nuget is een zip bestand met een standaard indeling en onder andere een nuspec bestand. Dit nuspec bestand beschrijft de inhoud van de nuget. <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata> Company.Web Company web project 1.0.0.0 Eric Tummers Eric Tummers http://octopusdemo.net <projectUrl>https://octopusdemo.visualstudio.com <requireLicenseAcceptance>false <description>Company Website hosted on Azure This will be installed with Octopus deploy Listing 2: nuspec van Company Website Ik installeer octopack via de nuget package manager. Hiermee wordt een nuget van mijn project gemaakt tijdens de build. Nou moet ik nog een nuspec bestand toevoegen en dan is mijn Company Website klaar voor deployment. Via de commandline voer ik msbuild uit met parameters die ervoor zorgen dat de nuget naar octopus server gepusht wordt. Ik gebruik een apart build script om ook package restore uit te voeren. MSBUILD build.proj /p:RunOctoPack=true /p:OctoPackPublishPackageToHttp=http://octopusdemo3.cloudapp.net/n uget/packages /p:OctoPackPublishApiKey=API-LTV8SYHODOMA12WUVDGACY2MU Listing 3: MSBUILD commandline om project te builden en nuget naar octopus te pushen
Fig. 7: nieuwe machines dev01 en tst01 automatisch geregistreerd in Parking environment na provisioning van VM’s Eenvoudiger Het maken van een image met sysprep en registreren van een tentacle via een script is voor een eerste kennismaking mogelijk te complex. Door de configuratie met de tentacle manager uit te voeren kan ik de registratie van een enkele machine uitvoeren. Ik moet dan tijdens de wizard kiezen voor een “pulling tentacle” omdat die geen last heeft van loadbalancers of extra endpoints nodig heeft. Dit moet ik dan wel op iedere machine uitvoeren, maar is sneller aan te corrigeren dan een image. Ik laat het aan jou over welke aanpak je kiest. Visual Studio project In Visual Studio maak ik een leeg MVC project aan. Dit wordt de Company Website die ik met continuous deployment wil ontwikkelen. Ik voeg het toe aan sourcecontrol van mijn visualstudio.com team project.
28
MAGAZINE
Fig. 8: Company Website package in de octopus nuget feed Het commando heeft 3 extra parameters:
DEPLOYMENT
• RunOctoPack=true, hierdoor zal een nuget package worden aangemaakt via octopack, • OctoPackPublishPackageToHttp, hiermee wordt de nuget package naar octopus gepushed, • OctoPackPublishApiKey, dit is de API key van mijn octopus gebruiker Nadat de build en push klaar zijn, heb ik een nuget package op de octopus server staan. Via de octopus web portal, configuration > nuget kan ik deze opzoeken. Release Zoals eerder beschreven, definieer je een release met Process steps en Variables. De binaries van een project worden via nuget geïnstalleerd. Daarnaast is powershell een heel krachtig middel.
Bij Web Site Name geef ik “Default Web Site” op. Die is gekoppeld aan poort 80. Als Application Pool name gebruik ik “CompanyWebsite”. De Bindings laat ik op poort 80 staan. Authentication zet ik op Anonymous authentication, Windows authentication zet ik uit. Environments laat ik leeg. Hiermee kan een stap beperkt worden tot alleen die environments. Dit is handig als je bijvoorbeeld in productie geen data wil verwijderen. Met save sla ik de stap op. Run a powershell script De tweede stap is een powershell script waarmee ik de website warm draai. De eerste request voor een pagina kan lang duren, omdat het proces gestart moet worden, de pagina van disk geladen, net als alle plaatjes. Door de pagina op te vragen wordt dit al gedaan direct na het deployen en is deze direct beschikbaar voor de eerste bezoeker. Ik kies voor Run a powershell script bij het toevoegen van een stap. Als naam gebruik ik “Warm up Company Website” en de stap wordt uitgevoerd op de rol Webserver. Het script wordt uitgevoerd met administrative rights. Een Invoke-WebRequest is geen probleem, net als minder onschuldige Format-Volume. $client = new-object system.net.WebClient $null = $client.OpenRead('http://localhost') $client.Dispose() Listing 4: powershell om website op te starten Met save sla ik de stap op. Mijn release proces is nou beschreven.
Fig. 9: Type stappen in een release proces Het sturen van emails en handmatige tussenkomst zijn vooral bedoeld voor auditing. Windows Azure is vergelijkbaar met azure role deployment vanuit Visual Studio. FTP upload spreekt voor zich. Nu dat ik een nuget package op de octopus server heb geplaatst met het build commando, kan ik mijn release gaan definiëren. Ik kies voor Deploy a Nuget package als eerste stap om de website te deployen. Daarna voeg ik nog Run a PowerShell script toe om de website alvast een keer aan te roepen. Deploy a NuGet package Ik browse naar het release proces van het project. Daar voeg ik de eerste stap toe, Deploy a NuGet package. Ik kies een naam voor de stap en de rollen waarop deze stap uitgevoerd moet worden: Webserver. Deze stap zal dus op alle machines met de rol Webserver in de environment waarnaartoe ik deploy uitgevoerd worden. Bij een loadbalanced situatie zullen dit dus meerdere machines zijn. Ik gebruik de interne NuGet feed en geef mijn NuGet package ID op: Company.Web. Dit staat in mijn nuspec bestand. De volgende twee opties (Configuration variables en Configuration transforms) laat ik aangevinkt. Hiermee worden mijn configuratie bestanden aangepast met Variables die ik later nog zal definieren. Daarna klik ik op Configure features om nog meer acties in deze stap uit te kunnen voeren. Er moet namelijk nog een IIS website en applicationpool worden aangemaakt. Ik kies de feature “IIS web site and application pool” en Apply. Er is nou een sectie bijgekomen om de gekozen feature te configureren.
Fig. 10: Proces van stappen in octopus Variables Tijdens de deploy a nuget package stap worden alle configuratie bestanden gecontroleerd op applicationsettings en connectionstrings. De identificatie en vervangende waarde per omgeving geeft ik op in de Variables tab. Tijdens een release zal scope, in dit geval de environment waar de release naar is, bepalen welke waarde er voor de DefaultConnection in de config gezet wordt. De waarde van alle variabelen wordt vastgelegd in iedere release. CI Build Visual Studio online heeft een hosted build controller, waarmee ik een continuous integration build kan inrichten. In Visual Studio Team Explorer maak ik een nieuwe build definitie.
magazine voor software development 29
DEPLOYMENT
Als laatste moet ik de AssemblyVersion van het project een autonumber (1.0.*) geven. Het releasenummer komt door de commandline aanroep hierboven namelijk overeen met de AssemblyVersion. Het releasenummermoet uniek zijn. Nou heb ik mijn continuous deployment ingericht. Zodra iemand een code change naar source control pusht zal de CI Build uitgevoerd worden met een deployment van de laatste build als resultaat.
Fig. 11: DefaultConnection connectionstring voor verschillende environments De build moet de extra parameters die ik eerder via de commandline meegaf ook gaan gebruiken. Hiervoor heeft de template het veld MSBuild arguments.
Fig. 13: Continuous build in ontwikkel omgeving en stabiele release in test omgeving Promote Een release kan nu ook deployed worden naar de andere omgevingen. In octopus wordt dat promote genoemd. Ik open de release op de development omgeving door erop te klikken. Daarna kies ik promote rechts boven en deployment naar de test omgeving.
Fig. 12: Continuous integration met custom build script en msbuild arguments Octo commandline Om een nieuwe release te definieren voor de laatste build en die ook automatisch te deployen, moet ik het build script aanpassen. Met commandline tool octo.exe kan ik dit voor elkaar krijgen. Ik voeg de octo.exe toe aan de Custom Binaries folder in source control. Daardoor is het ook beschikbaar op de build controller. In het build script voeg ik een regel toe die de commandline aanroep uitvoert. <MSBuild Targets="Build" Projects="@(Solution)" Properties="$(ProjectProperties)" /> <Exec Command='"$(MSBuildThisFileDirectory)Custom Binaries\Octo.exe" create-release --server=http://octopusdemo3.cloudapp.net/api --project="Company Website" --deployto=Ontwikkel --apikey=API-LTV8SYHODOMA12WUVDGACY2MU' /> Listing 5: commandline aanroep in build om een release aan te maken op basis van de laatste gebouwde assemblies en die direct te deployen naar de ontwikkel omgeving
30
MAGAZINE
Conclusie In dit artikel heb ik je door de inrichting van continuous deployment met octopus geleidt. De Company Website wordt na iedere build naar de ontwikkel omgeving gedeployed. Van daar uit kan het test team een versie overzetten naar hun test omgeving. Als daar de duimen omhoog gaan kan besloten worden om de website door te zetten naar acceptatie en zelfs productie. Met behulp van octopus is het deployen van je project een stuk beter te managen. De uniforme aanpak over alle omgevingen en de centrale registratie maken een deployment een push-of-a-button in plaats van een lijst instructies waarvan je er altijd eentje vergeet. •
Eric Tummers Eric Tummers is werkzaam als technisch consultant bij Valid en richt zich op kwaliteit in software development. Denk hierbij aan unit testen, build en deployment processen. Bloggen doet Eric voornamelijk over zijn werk, maar af en toe komt een thuis project erop te staan, een productiviteit tip of een review. Als het maar bijdraagt aan het sociale internet. In 2014 hoopt Eric een groot Windows Azure project te mogen doen. Dan heeft hij genoeg om over te schrijven. Het eerste project dit jaar is met nServiceBus, Umbraco en Octopus deploy.
GENERAL
Michiel van Otegem
Wolkenarchitect De laatste tijd ben ik vooral bezig met applicaties migreren naar de cloud. Maakt mij dat een cloudarchitect? En wat is dat dan eigenlijk? Hoe verschilt een cloudarchitect van een "gewone" applicatiearchitect? Terwijl ik deze column schrijf ben ik eigenlijk met vakantie. De eerste dagen was deze vooral bewolkt en met af en toe een stevige stortbui, afgewisseld met druilerige regen. De dagen verloopen daardoor behoorlijk anders dan gepland. Mijn vakantie staat in die zin model voor redelijk wat cloudmigraties: torenhoge ambities die gaandeweg behoorlijk bijgesteld moeten worden. Nu is dat op mijn vakantie niet zo erg. Sterker nog, ik verander zelf graag tussendoor mijn plannen, om daarmee in te spelen op veranderende omstandigheden. Bij cloud-migratie levert dit echter vooral frustratie teweeg voor de betrokkenen. Blijft een project zitten met tegenslagen dan krijg je wat ik gisteren had: een brandalarm. Dat is dan ook weer mijn vakantie... never a dull moment. Hoewel het best schrikken is als rond middernacht het brandalarm af gaat en je op de 41e verdieping van het hotel zit. Vrouw en kinderen vlug in de kleren en de trap af (om bij de 15e verdieping te horen dat de brandweer het sein veilig gegeven heeft)..
On-premises omgevingen bestaan vaak uit high-end hardware met de snelste processoren en met een hoge mate van betrouwbaarheid Dat er zoveel mis gaat bij migratie naar de cloud (maar ook bij ontwikkeling van nieuwe cloudapplicaties) is veelal te wijten aan een gebrek aan inzicht in de verschillen tussen "reguliere" architectuur en cloudarchitectuur. Vandaag de dag zijn veel on-premises serveromgevingen gevirtualiseerd. Als gevolg daarvan hoeven we bij het bouwen van applicaties weinig rekening te houden met de hardware specificaties, deze kunnen we namelijk achteraf nog aanpassen om beter aan te sluiten bij het resource gebruik van de applicatie. On-premises omgevingen bestaan vaak uit high-end hardware met de snelste processoren en met een hoge mate van betrouwbaarheid. Voor het netwerk geldt dat we meestal gebruik kunnen maken van gigabit netwerken, firewalls en load balancers met allerlei toeters en bellen.
Clouds zijn juist niet gemaakt van high-end hardware Door Web Application Proxies en stateful load balancers hoeven we ons in on-premises situaties weinig te schenken aan (session) state en andere zaken die de schaalbaarheid ondermijnen.
Dat wordt immers opgelost door de infrastructuur. In de cloud liggen de zaken anders. De cloud is vooral gericht op het beperken van kosten. De meeste clouds zijn daarom juist niet gemaakt van high-end hardware, zowel qua betrouwbaarheid als snelheid van CPU en disk. Microsoft Azure gebruikt bijvoorbeeld standaard CPUs met een kloksnelheid van 1.6 GHz, behalve voor de allergrooste (en duurste) machines. Voor on-premises hardware is 3 GHz heel gewoon. Single-threaded operaties zullen daardoor in Azure aanzienlijk langzamer zijn en dienen dus vermeden te worden. Nu is dat niet heel erg, want doordat het einde van Moore's law in zicht is, was het al verstandig om parallel programmeren te leren. Voor bestaande applicaties ligt dit echter lastiger en dat is ook het geval als je third party componenten gebruikt. Hiet ligt wel een gevaar op de loer, want we weten eigenlijk al jaren dat we session state moeten vermijden, of in elk geval niet gebonden moeten maken aan een enkele machine... en toch doen we dat nog steeds. In Azure worden we hier ook keihard op afgestraft. Dat geldt overigens ook voor ontwikkelpraktijken die ervan uitgaan dat de applicatie lokaal draait. Over een gigabit netwerk is HTML van meerdere MBs geen probleem. Daar merk je eigenlijk weinig van. Dezelfde applicatie zal vanuit de cloud echter niet optimaal presteren. Een niet te onderschatten probleem is dat al deze relatief kleine technische obstakels voor de gebruiker moeilijk te begrijpen zijn. De gebruiker ziet alleen een verslechtering van de gebruikerservaring, terwijl het om een vertrouwde applicatie gaat. De conclusie dat de cloud niet werkt is dan ook snel getrokken. Als cloudarchitect is het misschien wel je belangrijkste taak om die conclusie te voorkomen en anders te weerleggen. Daarmee is cloudarchitectuur weldegelijk iets anders dan applicatiearchitectuur.
De conclusie dat de cloud niet werkt is dan ook snel getrokken Bij cloudarchitectuur zul je je meer moeten verdiepen in de infrastructuur die eronder zit en meer moeten doen op het gebied van vewachtingsmanagement. Zoals ik in een eerdere column ook al geschreven heb, zul je ook moeten zorgen dat je meer weet van alle diensten die het cloudplatform levert. Denk daarbij aan messaging, identity & access management, caching enzovoorts. •
magazine voor software development 31
WINDOWS
Isak Edblad
Reach further by developing collaboratively Visual Studio is a Microsoft desktop application that offers an integrated development environment for building, testing and debugging code. Basically, Visual Studio is the go-to tool when developing software for the Windows platform. As of late, developers all over the world are starting to expect a more flexible development environment in search for a liquid experience. And at the same time, outsourcing work is becoming more and more common. The main issue for Visual Studio developers working in distributed teams is the loss of basic yet essential functionalities, such as pair programming, collaborative code reviews or maybe cooperative merges to a repository. To advance, coworkers have been forced to write long and tangled emails or share their screens - leaving just one person in charge which makes collaboration difficult. Bigger companies can also run into problems with knowledge transfer and knowledge distribution. Especially when having spread out developers, even working in the same office building. VS Anywhere is a Visual Studio extension that confronts these limitations, creating a seamless collaboration and consistency that developers need. No more emails or screen sharing. Extending Visual Studio What VS Anywhere does is enable real time collaboration in Visual Studio, allowing developers to work in shared sessions from anywhere in the world. They can decide if they want to share specific project items, the full project or even a whole solution, and then collaborate as if side by side. Let´s look at an example that most developers are familiar with, the need of pair programming. Pair programming is a technique where two people are working on the same work station. One person is the driver and the other person is the observer; one person writes the code and the other person reviews each line of code to see possible bugs and to get an idea of the bigger picture. In the past, this technique required the driver and the observer to physically sit next to each other, but with VS Anywhere two developers can be working collaboratively, and in real time – no matter their location. John, for example, is working from the US while his colleague Jane is working from Spain. They both have the same shared solution opened inside Visual Studio, and they are viewing the same file.
Since they already have the same version of the specific project, John can simply share it through the VS Anywhere Control Center that shows up as soon as you are logged on, inside Visual Studio. John decides what people to invite, in this case Jane, and clicks Set up session.
John is going to take the role as the driver. For Jane to be able to follow his working context, she uses one of the features integrated through VS Anywhere: Follow a contact. As John is writing, Jane sees everything he does on her screen. If John would change files, or even create a new one, Jane would follow there as well.
Of course, this works both ways. When John feels ready, he can ask Jane to take over. It’s easy with the integrated chat, which can also be
32
MAGAZINE
WINDOWS
used for sending files or chatting in groups. And if they were to stop following, they could simply continue working on the same, or different, files inside the project.
The ability of follow each other’s code in real time eliminates the physical gap between individuals. Another VS Anywhere tool that could be used to enforce this process is the Highlight a contact functionality, meaning that all code written by a specific individual will be highlighted with a light background. And the same technique that was used in the example of remote pair programming could of course also be used in many other situations, for example when interviewing and testing out new hires for a company, or when conducting developer training sessions. Simplifying knowledge transfer One of the biggest struggles for distributed teams has been transferring knowledge from the experienced developer to newer coworkers. But with VS Anywhere, you can host moderated sessions, having several individuals following a driver (as in the pair programming example) at the same time.
To use this feature, all that you would need to do is check the Moderation box when inviting your colleagues to a collaborative session. As soon as they join your session, they will automatically be following your working context. For the developers to be able to make changes and contribute to the session, they will need to ask for permission from the host. If they try to edit something without permission, an error message appears. To give permissions, the host simply navigates to the VS Anywhere Control Center, opens the shared session and right clicks the person to take over. From the Control Center, you can also choose to Disable moderation of this session, allowing all people to make changes. The exact same way, you can restart the moderated session again, as long as you are the person hosting the session. Leaving the desktop to hit the web So what happens if Jane would need John to review some of her code, or do a quick session while he is not in the front of a computer? Don’t worry, with another of VS Anywhere’s unique features you can even do code reviews from mobile devices or tablets. It’s called the Web Workspace, and lifts Visual Studio off the desktop into the web.
Using the workspace, Jane can simply generate a URL address for the project she’s got opened in Visual Studio, and share the link with John. When he clicks the link, he gets access to all Jane’s opened Visual Studio files, directly from his web browser! As she is developing, he follows her working context, again in real time, but now even without having access to Visual Studio. Reaching your full potential A team is only as strong as its individuals. That is why it is important to recognize every developer, providing them with tools to reach their full potential.
Working with VS Anywhere, collaboration in real time will allow you to eliminate knowledge gaps by easily hosting training sessions, and quickly bring new collaborators up to speed. While overcoming geographical distances, you also make it possible for outsourced partners to pinpoint problems and solve them at a much faster pace. All this comes in the package of a clever Visual Studio extension. And while strengthening your team, you save your business both time and money. For more information and access to a free trial period of one month, visit https://vsanywhere.com. •
Isak Edblad Isak Edblad is a technology enthusiast that has spent his last years working with different start-up companies. When he's not writing articles, he enjoys web design and video production. And cookies.
magazine voor software development 33
ANALYSE
Hassan Fadili
Application Insights for Visual Studio Online
(Deel 1/2)
Microsoft streeft steeds meer naar volledige integratie van de Visual Studio Apllication LifeCycle Management Tools en Futures. Daarom is er een nieuwe fenomeen toegevoegd aan de Visual Studio Application Life Cycle Management suite. Dit Fenomeen heet “Application Insights” In dit eerst deel van dit artikel, zal ik eerst uitleggen wat “Application Insights” is en waarin dit kan helpen in het gehele Application Life Cycle Management flow om snel de monitoring en het gedrag van de applicaties en/of systemen snel in kaart te brengen. “Application Insights” is een monitoring mechanisme die toegevoegd is aan de Visual Studio Application Life Cycle Management Suite sinds de Visual Studio 2013 Release. Middels Application Insights, applicaties (Web, Windows, Web Services, Store apps etc.) kunnen gemonitord worden om meer te weten te komen over het gebruik, gedrag en de aanvullende informatie die belangrijker kunnen zijn om je applicatie / systeem te monitoren. Denk hierbij aan de volgende aspecten: • Gebruik van de applicatie. In dit geval worden de volgende applicatie types ondersteund om “Appllication Insights” te mogen gebruiken na de installatie van de vereiste “Application Insights SDK” te weten: - Beschikbaarheid van je Web Service (Availability_Synthetic Transactions) - Monitoren van performance de stabilitiet van je applicatie (Performance_Server Performance) - Het door kunnen zoeken in de diagnostics logs van je applicatie voor verdure onderzoek(Diagnostics_Search) - …etc.
Fig. 0: Application Insights toevoegen aan Windows Store App Project Overige Application Insights tools kunnen afhankelijk van de applicatie type via NuGet Package Install toegevoegd worden zoals hieronder is weergegeven:
De bovenstaande onderdelen van de “Application Insights” worden verder toegelicht door de bijbehorende schema’s. Om gebruik van de Application Insights te mogen maken, dient de benodigde software ““Application Insights SDK” hiervoor geïnstalleerd te worden op je machine. Daarna zal wanneer je een nieuwe applicatie maakt bijvoorbeeld een Windows Store Applicatie, gevraagd worden of “Application Insights” toegevoegd kan worden aan deze applicatie zoals hieronder is weergegeven:
Fig. 1: Application Insights SDK – Tools via NuGet Package Install Wanneer de benodigde SDK’s voor de desbetreffende Applicatie geïnstalleerd zijn, kun je vanaf dat moment gebruik maken van de “Application Insights” voor dat applicatie. De portal dashboard hiervoor ziet er als volgt uit in Visual Studio Online (VSO)
34
MAGAZINE
ANALYSE Afhankelijk van de gekozen optie (Yes of No), wordt wel/niet naar meer informatie gevraagd. In geval van Yes, deze flow wordt als volgt afgehandeld:
Fig. 2: Application Insights Dashboard in Visual Studio Online Fig. 5: Applicatie Specifieke informatie voor Application Insights Vanaf dit punt, weet Application Insights welke informatie van belang is voor het monitoren van de desbetreffende applicatie. Hierdoor worden de Juiste instructies gegeven voor betere monitoring. Door de naam van je applicatie op te geven en op Create te klikken, dienen zowel de ApplicationInsights.config en Microsoft Monitoring Agent gedownload te worden. Met een klik op “Click here to show instructions” link, wordt het volgende scherm getoond:
Fig. 2A: Application Insights Dashboard Overview in Visual Studio Online Vanuit deze Dashboard, kan de desbetreffende applicatie toegevoegd worden waarvoor Application Insighs voor gebruikt kan worden door op Add Application aan de rechter bovenkant van dit scherm te klikken zoals hier is weergegeven: Fig. 6: Applicatie instructies afhankelijk van de applicatie type Wanneer alle installatie en configuratie werk gereed is, is de applicatie in kwestie klaar om gebruik te maken van Application Insights zoals hier onder is weergegeven:
Fig. 3: Add Application aan Application Insights Dashboard Wanneer men Add application klikt, wordt het volgende scherm getoond waarmee de informatie specifiek over de applicatie ingevuld kan worden om betere monitoring te kunnen waarborgen. Dit proces ziet er als volgt uit: Fig.7: Application Insights – Availability_ Synthetic Monitors Om het gebruik van de applicatie te kunnen monitoren, dient eerst de applicatie type en de URL opgegeven te worden als volgt:
Fig. 4: Add Application specific information to Application Insight
magazine voor software development 35
ANALYSE Voor het verkrijgen van de “Usage-Users” informatie, dient net als bij “Usage_Features” eerst de applicatie type aangegeven te worden waar vervolgens de onderstaande informatie (indien beschikbaar) getoond kan worden:
Fig.8: Application Insights – Performance_Server Performance
Fig.10: Application Insights – Diagnostics_Metrics
Fig.9: Application Insights – Usage_Features Wanneer de configuraties gereed zijn, worden de volgende gegevens (indien deze beschikbaar zijn) weergegeven zoals hieronder is afgebeeld:
Fig.10A: Application Insights – Diagnostics_Events
Fig.9A: Application Insights - Usage_Features
Fig.9B: ApplicationInsights-Usage_Users
36
MAGAZINE
Om verdere onderzoek te kunnen doen op je applicatie wanneer iets fout gaat, bidet Application Insights de mogelijkheid om te kunnen zoeken naar specifieke informatieve die kan leiden tot de beste resultaten om het probleem beter te kunne oplossen. Deze (Search) overzicht ziet er als volgt uit:
Fig.10B: Application Insights – Diagnostics_Search
ANALYSE Conclusie Waar voorheen gebruik wordt gemaakt van overige andere tools buiten Visual Studio Application Life Cycle Management Suite voor monitoring van de applicaties/ systemen, is Microsoft erin geslaagd om een volledige suite eromheen te bouwen namelijk Application Insights. Deze Application Insights bieden naast volledige integratie met de rest van Visual Studio Application Life Cycle Management suite ook meer toegevoegd waarde om snel de problemen te visualiseren en/of te verhelpen. Zo wordt de samenwerking tussen Development- en DevOps teams nog verder versterkt en verbeterd om uiteindelijk voor stabiele en kwalitatief hoogwaardig applicaties / systemen te implementeren en te beheren. Voor meer informatie over “Application Insights”, verwijs ik U graag naar de onderstaande links. Links Use Application Insights to find out what users are doing with your app http://www.visualstudio.com/en-us/get-started/get-usage-data-vs Application Insights Tools for Visual Studio http://visualstudiogallery.msdn.microsoft.com/82367b81-3f97-4de1bbf1-eaf52ddc635a Application Insights Dashboard inVisual Studio Online https://hassanfad11.visualstudio.com/_appanalytics/_overviews/das hboards?rs=true#dashboard=333a5917-1d4c-409e-93c37229553ee797
Organize your insights in dashboards http://msdn.microsoft.com/en-us/library/dn481097.aspx Customizing Application Insights in ApplicationInsights.config http://msdn.microsoft.com/en-us/library/dn550723.aspx //BUILD 2014/ Sessies over Application Insights: https://channel9.msdn.com/Events/Build/2014/3-592 https://channel9.msdn.com/Events/Build/2014/3-595 https://channel9.msdn.com/Events/Build/2014/3-596 https://channel9.msdn.com/Events/Build/2014/3-597 •
Hassan Fadili Hassan Fadili is werkzaam als Freelance Lead Architect / Consultant en VS ALM Consultant (MVP) voor zijn eigen bedrijf FadiliCT Consultancy (http://www.fadilict-consultancy.nl). 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: [email protected], [email protected], hassanfad11 @hotmail.com en/of via Twittop: @HassanFad
Visual Studio Online Organizational Account Om gebruik te maken van Visual Studio Online had je een Microsoft Account nodig. Het is nu ook mogelijk om een Visual Studio Online aan te maken met een Office 365 account.
Dat maakt Visual Studio Online beschikbaar en bereikbaar voor Business en Enterprise omgevingen.
Uiteraard kun je deze dan ook aan je Microsoft Azure subscription koppelen die gekoppeld is aan een Office 365 account.
magazine voor software development 37
AZURE
Marcel Meijer
Microsoft Azure Remote Apps Op het Microsoft Azure platform hebben we het altijd voor de 3 AAS-en: Infrastructure as a Service, Platform as a Service en Software as a Service. Elk heeft zijn eigen doel en plaats binnen iedere Enterprise. De eerste IAAS gaat over virtualisatie van computers in de vorm van Virtual Machines. Er zijn nog weinig bedrijven die gebruik maken van fysieke hardware voor een machine. Bij PAAS gaat het over virtualisatie van het hele platform. Voor de applicatie/developer is het geheel van onderliggende servers en hardware onzichtbaar. Ze hoeven daar ook niet van te weten, het platform garandeert de capaciteit en de beschikbaarheid. Bij SAAS is nog meer van het onderliggende platform complexiteit voor de gebruiker verborgen. Vaak zie je binnen Enterprises nog een ander level van Virtualisatie. Bij SAAS gaat het om applicaties die met web technologieën gemaakt zijn. Maar veel van onze LOB applicaties zijn niet gemaakt of geschikt voor Web. Bijvoorbeeld in een ERP omgeving is de applicatie voor de gebruiker een Fat Client. De functionaliteiten op de webportalen zijn (nog) niet voldoende om de Fat Client te doen vergeten. Nadeel van Fat Clients is dat deze het Client/Server principe volgen. En dus op de werkplek van de gebruiker installeerd moeten worden. Die levert voor de IT afdeling een behoorlijke beheerslast met zich mee. Om de beheerslast te verlagen zoeken de Enterprises hun heil in desktop virtualisatie oplossingen zoals Microsoft Enterprise Desktop Virtualization, Citrix of RES Workspace Virtualisatie maar er zijn nog meer oplossingen. Deze oplossingen hebben allemaal een Client app of omgeving nodig, deze maakt een koppeling met de server en draait daar de applicatie.
Een template met Windows Server 2012 R2 met Office.
Waarom zou zoiets niet ook kunnen op Microsoft Azure? Tuurlijk kan dat. We kunnen verschillende Virtual Machines inrichten en zo bijvoorbeeld een Remote Desktop server opzetten. Hiermee kunnen we dan applicaties virtualiseren. Super natuurlijk, maar dan moeten we deze omgeving zelf beheren. Nu is er op het Microsoft Azure platform Remote App in preview. Daarmee kunnen we gebruik maken van de ongekende mogelijkheden van de Cloud. Het beheer van de hardware wordt gedaan door Microsoft. Microsoft Azure is op een internet scale, dus connectivity en beschikbaarheid is ook gegarandeerd.
Op de Azure portal kun je de Remote App service aanmaken. Op dit moment kun je nog maar uit een Template kiezen. Uiteraard is het mogelijk om eigen templates te maken. Hiermee kunnen Corporate apps op deze wijze beschikbaar gesteld worden. Het is zelfs mogelijk om deze Remote Apps service via een secure VPN te koppelen aan het Enterprise network.
38
MAGAZINE
Als je dan naar de portal van de Remote App gaat (https:// w w w. re m o t e a p p . w i n d o w s azure.com/), dan zie je dat je een Client app moet installeren. Maak je niet ongerust, ondanks dat het om een preview gaat en het gebruik maakt van het Standaard Microsoft Remote Desktop protocol, is er voor elk platform een app aanwezig. Dus ook voor Android, iOS en MAC.
AZURE
Ik gebruik de Windows Remote Desktop Client. Na de installatie volg je een simpele wizard.
Na het doorlopen zie je onderstaande scherm voor je.
Als bewijs dat je daadwerkelijk een applicatie van een Server gebruikt, starten we de calculator. De about schermen laten zien van welk OS ze oorspronkelijk waren. Dit is een geweldige toevoeging aan het Microsoft Azure platform.
Dubbelklikken op de applicatie zorgt voor een dialoogje en uiteindelijk zal de gekozen applicatie geopend worden. In onderstaande voorbeeld is dat Word 2013.
In de taakbalk van Windows zie je dan een Remote Desktop toevoeging aan het applicatie icoontje. De gekozen template bevat naast Office 2013 ook de standaard Windows Server 2012 applicaties. Ook deze applicaties kun je beschikbaar stellen aan je gebruikers. Na het toevoegen zie je dat uiteraard op de Microsoft Azure portal, maar ook in de Remote Desktop app.
Een volgend scenario om de transformatie naar de Cloud mogelijk te maken is hiermee nu beschikbaar. •
Marcel Meijer Marcel Meijer werkt als Senior Solution Architect bij Prodware Benelux. In zijn vrije tijd is hij .NET track owner, eindredacteur en voorzitter van de SDN. Op dit moment houdt hij zich voornamelijk bezig met Azure, Cloud, C#, Software Ontwikkeling, Architectuur in het algemeen en Windows Phone. Op 1 oktober 2010 werd hij MVP.
magazine voor software development 39
Kunnen we jou de technologie van de grootste digitale verzekeraar van Nederland toevertrouwen?
Achmea heeft de ambitie om de meest vertrouwde verzekeraar te zijn. Daarbij speelt IT een cruciale rol. We zijn dan ook voortdurend op zoek naar ambitieuze IT’ers. Bijvoorbeeld IT’ers die gaan meewerken aan het implementeren van de infrastructuur binnen Achmea. Met hardware en virtuele machines van Atos richten we het Operating System in, waarna alle applicaties aan meerdere systemen worden gekoppeld. Zo bouwen we verder aan ons bedrijf als de grootste digitale verzekeraar en het vertrouwen van onze klanten. We bieden je een groot aantal opleidingen en doorgroeimogelijkheden. Meer weten? Kijk op werkenbijachmea.nl
IT VACATURES Senior SAP BI Consultant in Tilburg
›
WIJ STAAN VOOR GROTE IT-UITDAGINGEN
AV É R O A C H M E A
KUNNEN WE DIE JOU TOEVERTROUWEN?
Trainee Software Engineer ETL › in Apeldoorn
AGIS
CENTR A AL BEHEER ACHMEA FBTO INTERPOLIS Z I LV E R E N K R U I S A C H M E A
IT Infrastructuur Architect › in Amsterdam Bekijk alle vacatures op werkenbijachmea.nl