Faculteit Wetenschappen Departement Computerwetenschappen
Ontwerppatronen voor Ingebedde Systemen
door
Roos UWAERTS
Promotor :
Prof. dr. ir. E. STEEGMANS
Academiejaar 2010–2011
Proefschrift ingediend tot het behalen van de graad van Master in de informatica
c Copyright by K.U.Leuven
Zonder voorafgaande schriftelijke toestemming van zowel de promotor(en) als de auteur(s) ¨ is overnemen, kopieren, gebruiken of realiseren van deze uitgave of gedeelten ervan verboden. Voor aanvragen tot of informatie i.v.m. het overnemen en/of gebruik en/of realisatie van gedeelten uit deze publicatie, wendt u tot het Departement Computerwetenschappen, Celestijnenlaan 200A, 3001 Leuven, (016) 32 77 00 of via email:
[email protected]. Voorafgaande schriftelijke toestemming van de promotor(en) is eveneens vereist voor het aanwenden van de in dit afstudeerwerk beschreven (originele) methoden, producten en programma’s voor industrieel of commercieel nut en voor de inzending van deze publicatie ter deelname aan wetenschappelijke prijzen of wedstrijden.
Faculteit Wetenschappen Departement Computerwetenschappen Celestijnenlaan 200A 3001 Leuven (016) 32 77 00
K.U. Leuven Academiejaar 2010–2011
Voornaam en naam student : Roos Uwaerts Titel : Ontwerppatronen voor Ingebedde Systemen Engelse vertaling : Design Patterns for Embedded Systems Korte inhoud : Embedded systemen zijn overal. Hun ontwikkelingsproces is echter lang en duur. Deze thesis maakt een studie over hoe ontwerppatronen kunnen bijdragen in de ontwikkeling van embedded systemen en hoe ze een vereenvoudiging van het ontwerpproces inhouden. Er wordt onderzocht hoever het onderzoek naar embedded ontwerppatronen staat, welke ontwerppatronen werden ontwikkeld en hoe deze patronen kunnen worden gerangschikt. Ook wordt bekeken op welke manier ontwerppatronen in de industrie worden gebruikt. Hieruit blijkt dat patronen niet gestructureerd worden toegepast. Het tweede deel van de thesis richt zich op het ontwikkelen van een embedded toepassing, met behulp van ontwerppatronen. Het gebruik van executable UML als ontwikkelingsproces voor embedded systemen wordt hier eerst gevalueerd. Met executable UML wordt een embedded systeem ontworpen. Eerst worden geen ontwerppatronen gebruikt. Erna wordt hetzelfde systeem ontworpen, met gebruik van ontwerppatronen. Het verschil tussen het ontwerp van deze systemen wordt ¨ geevalueerd, waarbij het systeem waarbij ontwerppatronen werden gebruikt positief wordt beoordeeld.
Proefschrift ingediend tot het behalen van de graad van Master in de informatica Promotor : Prof. dr. ir. E. Steegmans Assessoren :
Dr. ir. D. Preuveneers Dr. Ir. J. Boydens (KHBO)
Begeleiders :
Dr. Ir. J. Boydens (KHBO) Ir. P. Cordemans (KHBO)
iv
Dankwoord Veel mensen hebben meegeholpen aan de totstandkoming van deze masterproef. In deze paragraaf wil ik hen bedanken voor hun steun, inzet en vertrouwen. Eerst en vooral zou ik graag mijn promotor, Prof. Dr. Ir. Eric Steegmans willen bedanken voor zijn uitstekende begeleiding tijdens het uitvoeren van deze masterproef. Zijn inzicht en kritische benadering hebben een duidelijke meerwaarde betekend. Ook wil ik mijn begeleiders Jeroen Boydens en Piet Cordemans bedanken, bij wie ik steeds terecht kon met mijn vele vragen. Ik bedank ook de mensen van E.D.&A., in het bijzonder Patrik Smout, voor het toelaten van de case study in hun bedrijf en alle hulp die ze mij daarbij geboden hebben. Daarnaast wil ik mijn familie bedanken. Zonder hun steun, zowel moreel als financieel, was de realisatie van deze masterproef niet mogelijk geweest. Ook voor het nalezen en verbeteren van de tekst kon ik steeds op hen rekenen. In het bijzonder bedank ik mijn vriend, Kristof, voor zijn onuitputtelijke geduld. Nog vele anderen uit mijn omgeving verdienen mijn dank voor de steun, interesse, hulp en suggesties die ze geboden hebben bij het maken van deze masterproef.
v
Inhoudsopgave Dankwoord
v
Inleiding
1
I
4
Onderzoek naar ontwerppatronen
1 Theoretische studie 1.1 Onderzoek naar embedded ontwerppatronen . . . . . . . . . . . . . . . . . . ¨ patronen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.1 Industriele 1.1.2 Theoretische patronen . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Onderzoek naar Model-Driven Architecture(MDA) voor embedded systemen 1.3 Besluit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ¨ gevalstudie 2 Industriele 2.1 Inleiding . . . . . . . . . . . . . . . . . 2.2 Voorstelling van de gevalstudie . . . . 2.3 Het eerste project . . . . . . . . . . . 2.3.1 Analyse van ontwerppatronen . 2.3.2 Toegevoegde ontwerppatronen 2.4 Het tweede project . . . . . . . . . . . 2.4.1 Analyse van ontwerppatronen . 2.4.2 Toegevoegde patronen . . . . 2.5 Besluit . . . . . . . . . . . . . . . . . .
II
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
Toepassing van ontwerppatronen
3 Executable UML 3.1 Wat is executable UML . . . 3.2 Proces van executable UML 3.2.1 Analyse . . . . . . . 3.2.2 Ontwerp . . . . . . . 3.2.3 Testen . . . . . . . . 3.2.4 Implementatie . . . 3.3 Tools voor executable UML 3.4 Besluit . . . . . . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
5 5 6 6 9 9 10 10 10 11 11 13 15 15 17 19
21 . . . . . . . .
. . . . . . . .
vi
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
22 22 24 24 27 29 31 31 32
INHOUDSOPGAVE
vii
4 Gevalstudie: zonder ontwerppatronen 4.1 Opzet van de gevalstudie . . . . . . . . . . . . . 4.2 Uitwerking van de gevalstudie in executable UML 4.2.1 Analyse . . . . . . . . . . . . . . . . . . . 4.2.2 Testen . . . . . . . . . . . . . . . . . . . . 4.2.3 Ontwerp . . . . . . . . . . . . . . . . . . . 4.2.4 Implementatie . . . . . . . . . . . . . . . 4.3 Besluit . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
33 33 34 34 37 39 41 41
5 Gevalstudie: met ontwerppatronen 5.1 Inleiding . . . . . . . . . . . . . . 5.2 Toepassing van de patronen . . . 5.2.1 Analysefase . . . . . . . . 5.2.2 Testfase . . . . . . . . . . 5.2.3 Ontwerpfase . . . . . . . 5.2.4 Implementatie . . . . . . 5.2.5 Evaluatie . . . . . . . . . 5.3 Besluit . . . . . . . . . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
46 46 46 46 46 46 52 52 52
Besluit
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
63
Lijst van figuren 1.1 Structuur van het Virtual Machine patroon . . . . . . . . . . . . . . . . . . . . 1.2 Toepassing van het Recursive Containment patroon . . . . . . . . . . . . . .
7 8
2.1 2.2 2.3 2.4 2.5
Klassendiagram met verduidelijking van de lagen . . . . . . . . . . . . . . . Toepassing van het 5-layered patroon . . . . . . . . . . . . . . . . . . . . . Klassendiagram met verduidelijking van het recursive containment patroon Klassendiagram en interactiediagram voor de veranderingen . . . . . . . . Klassendiagram en interactiediagram na de veranderingen . . . . . . . . .
. . . . .
14 14 15 18 19
3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8
Domeingrafiek van de online boekenwinkel . . . . . . . . . . . . . . . . . . . Domeinmissieverklaring van het domein Web GUI . . . . . . . . . . . . . . . Use cases van de online boekenwinkel . . . . . . . . . . . . . . . . . . . . . . Activiteitsdiagram van de online boekenwinkel . . . . . . . . . . . . . . . . . . Klassendiagram voor het ordering domein van de online boekenwinkel . . . . Toestandsdiagram voor de ShoppingCart klasse van de online boekenwinkel Sequentiediagram van de acties in het ShoppingCart-toestandsdiagram . . . Beschrijving van de testen van de use case ’Order Books’ van de online boekenwinkel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
25 26 26 27 28 29 30
4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8
Domeingrafiek van het thermometer voorbeeld . . . . . . . . . . . . Domeinmodel van het TemperatureSensor domein . . . . . . . . . . Use cases van het thermometer voorbeeld . . . . . . . . . . . . . . Activiteitsdiagram van het thermometer voorbeeld . . . . . . . . . . Toestandsdiagram voor de eerste test van de use case start reading Klassendiagram van het temperatuursensordomein . . . . . . . . . . Toestandsdiagram van de loggerklasse . . . . . . . . . . . . . . . . Toestandsdiagram van de timerklasse . . . . . . . . . . . . . . . . .
34 36 37 39 41 43 44 45
5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 5.10
Analysemodellen van het thermometervoorbeeld . . . . . . . . . . . . . . . . Klassendiagram met het Interruptpatroon . . . . . . . . . . . . . . . . . . . . Toestandsdiagram van de loggerklasse na toepassing van het interruptpatroon Toestandsdiagram van de timerklasse na toepassing van het interruptpatroon Klassendiagram met het Pool Allocationpatroon . . . . . . . . . . . . . . . . . Toestandsdiagram van de loggerklasse met het Pool Allocation patroon . . . Klassendiagram na toepassing van het Criticcal Section patroon . . . . . . . Toestandsdiagram van de loggerklasse met het Pool Allocation patroon . . . Klassendiagram na toepassing van het recursive containment patroon . . . . Klassendiagram na toepassing van het layered patroon . . . . . . . . . . . .
viii
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
30
54 55 56 57 58 59 60 61 61 62
Lijst van tabellen 3.1 Vergelijking tussen de actie-specifieke taal en Java . . . . . . . . . . . . . . .
29
4.1 4.2 4.3 4.4 4.5
. . . . .
35 38 38 39 40
5.1 Testen voor de use cases Start Reading, Process Daily Results en Request Statistic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
47
Beschrijving van de verschillende domeinen . . Tekstuele beschrijving van de use cases . . . . Testen voor de use case Start Reading . . . . Testen voor de use case Process Daily Results Testen voor de use case Request Statictic . . .
ix
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
Inleiding Deze thesis onderzoekt het gebruik van ontwerppatronen tijdens het ontwerp van embedded systemen. Ook het principe van model-driven ontwerp wordt onderzocht in het licht van embedded systemen. Embedded Systemen Ingebedde of embedded systemen zijn niet weg te denken uit de huidige samenleving. Denk aan keukenapparaten, auto’s, televisietoestellen... Embedded systemen onderscheiden zich van gewone softwaresystemen, door hun beperkingen in bijvoorbeeld geheugen en rekenvermogen. Tevens blijven veel systemen oneindig lang doorlopen waardoor er extra aandacht moet besteed worden aan het vermijden van gefragmenteerd geheugen. Al dit soort beperkingen zorgen ervoor dat het ontwikkelingsproces meestal lang is en duur. ´ van de eerste systemen dat als embedded beschouwd kan worden, was de Apollo Een Guidance Computer in het Apollo-project [24] in het begin van de jaren zestig. Sindsdien zijn de prijzen voor componenten spectaculair gedaald en de capaciteit van het geheugen en rekenvermogen drastisch gestegen waardoor het aantal toepassingen van embedded systemen sterk toenam. Embedded systemen worden gebruikt in situaties waar voorheen het gebruik van een computer zelfs niet eens werd overwogen [24]. Ontwerppatronen Ontwerppatronen zijn vooral gekend in standaard softwareontwerp. Eric Gamma en de Gang of Four hebben met het boek Design Patterns [10] het gebruik van ontwerppatronen tot een standaard gemaakt in het ontwerp van grote softwaresystemen. Omdat embedded systemen op andere vlakken problemen ondervinden dan standaard softwaresystemen, helpen de standaard ontwerppatronen slechts in beperkte gevallen en kunnen embedded systemen niet profiteren van deze vooruitgang. Embedded systemen ondervinden bijvoorbeeld problemen op het vlak van taakbeheer. Hiervoor biedt Gamma geen patronen aan. Er zijn echter wel specifieke patronen ontwikkeld voor embedded systemen die dit probleem wel aanpakken. Andersom biedt Gamma het State patroon aan, waarmee een object anders kan reageren naarmate in welke toestand het zich bevindt. Enkel in grotere embedded systemen is het nuttig dit patroon te gebruiken (indien het nodig is). In kleinere systemen geeft dit patroon te veel overhead, omdat het geheugen hier te beperkt is. Model-driven architecure Model-Driven Architecture (MDA), in 2001 door de Object Management Group gedefinieerd, is een recente techniek om het ontwikkelingsproces van software te structureren. Het ontwerpproces bestaat uit het maken van drie verschillende modellen: het platformonafhankelijk model, het platform-specifiek model en een platform-definitie model. Deze 1
INLEIDING modellen worden achtereenvolgens opgesteld. Het platform-onafhankelijke model bevat het ontwerp van het systeem, waarbij niet wordt ingegaan op platform-specifieke eigenschappen, zoals programmeertaal-specifieke datatypes of hardware gerelateerde operaties. Het platform-definitie model definieert de regels waarmee een platform-onafhankelijk model kan omgevormd worden tot een platform-specifiek model. Het platform-specifieke model tenslotte, is de vertaling van het platform-onafhankelijke model naar de gekozen programmeertaal en hardware. In de praktijk wordt het platform-definitie model meestal aangeboden door de tools die gebruikt worden voor model-driven design. Het platform-specifiek model kan dus, met behulp van een tool, automatisch worden gegenereerd. MDA biedt ook voor embedded systemen een manier van ontwerpen. Verschillende toonaangevende organisaties vermeldden MDA reeds als veelbelovend voor de embedded industrie. Doelstellingen en aanpak Het doel van deze thesis is, nagaan in welke mate specifieke ontwerppatronen voor embedded systemen bestaan en hoe ze bijdragen tot een vereenvoudiging van het embedded ontwikkelingsproces. • Eerst wordt een algemeen onderzoek verricht naar ontwerppatronen die specifiek werden ontworpen voor embedded systemen. Er wordt onderzocht of en welke patronen reeds ontwikkeld werden en in welke context deze patronen dan gebruikt worden (architectuur van het systeem, implementatie,...). Dan wordt nagegaan of er een opdeling van de bestaande patronen kan gemaakt worden. • Wanneer over ontwerppatronen wordt gesproken, wordt meestal ook een ontwerpmethode vermeld. In het geval van embedded systemen, is er een nieuwe tendens om model-driven ontwerp toe te passen. Er wordt ook onderzocht in hoeverre deze tendens zich heeft vertaald in onderzoek naar model-driven ontwerp van embedded systemen. Executable UML is een vorm van UML waarbij een manier is toegevoegd om acties van modellen te specificeren. Het is een manier om model-driven ontwerp toe te passen. Er wordt nagegaan in welke mate het executable UML-proces geschikt zou kunnen zijn voor het ontwerpen van embedded systemen. • Wanneer het theoretische onderzoek naar patronen is afgerond, wordt een industrieel onderzoek verricht. Er wordt bekeken welke ontwerppatronen men in de praktijk toepast en of deze patronen volgens een bepaalde methode worden toegepast. Er wordt nagegaan of een bepaalde soort patronen vaker of minder vaak wordt toegepast dan een andere soort. Ook in verband met model-driven ontwerp wordt gekeken of deze of ¨ gevalstudie werd in het een andere ontwerpmethode wordt toegepast. De industriele bedrijf E.D.&A. gevoerd. ¨ implementatie, wordt • Na het theoretische onderzoek en de studie van de industriele nagegaan op welke manier model-driven ontwerp en ontwerppatronen kunnen worden toegepast bij het ontwerp van embedded systemen. Hiervoor wordt een evaluatie gemaakt van het executable UML-proces in het kader van embedded systemen. Deze evaluatie wordt in de praktijk gezet door het toepassen van dit proces op een nog te ontwerpen embedded systeem. Het ontwerp wordt eerst zonder ontwerppatronen gemaakt waarna een evaluatie van het executable UML-proces wordt gemaakt. • Tenslotte wordt hetzelfde systeem volgens hetzelfde proces ontworpen, maar met het gebruik van geschikte ontwerppatronen. Hier wordt aangetoond hoe het ontwerp van
2
INLEIDING een embedded systeem kan vereenvoudigd worden door de toepassing van de ontwerppatronen. Overzicht van de tekst De thesis bestaat uit twee grote delen. Het eerste deel bevat het onderzoek naar de ontwikkeling en het gebruik van ontwerppatronen. In hoofdstuk 1 wordt nagegaan welk onderzoek er reeds is verricht naar het gebruik van ontwerppatronen in het ontwerp van embedded systemen. Hoofdstuk 2 bekijkt in welke mate ontwerppatronen reeds gebruikt worden in een ¨ context. industriele Het tweede deel van de tekst beschrijft hoe ontwerppatronen kunnen worden gebruikt in het ontwerp van een embedded systeem. In dit deel wordt een nieuw systeem ontworpen aan de hand van het executable UML-proces. Hoofdstuk 3 geeft een introductie tot het gebruik van executable UML om model-driven ontwerp toe te passen. Hoofdstuk 4 en 5 passen dit proces toe op de nieuwe toepassing, respectievelijk zonder en met toepassing van ontwerppatronen.
3
Deel I
Onderzoek naar ontwerppatronen
4
Hoofdstuk 1
Theoretische studie van ontwerppatronen voor embedded systemen In dit hoofdstuk wordt een theoretische studie gemaakt van embedded ontwerppatronen. Eerst wordt onderzocht waarin ontwerppatronen voor embedded systemen verschillen van ontwerppatronen voor standaard softwaresystemen. Daarna worden de ontwerppatronen onderverdeeld in verschillende groepen volgens hun eigenschappen. Tenslotte wordt ingegaan op het gebruik van model-driven ontwerp bij embedded systemen.
1.1
Onderzoek naar embedded ontwerppatronen
Embedded systemen verschillen van gewone computersystemen op verschillende vlakken. ´ algemene taak. Ze hebben vaak Embedded systemen zijn klein en slechts gericht op e´ en beperkt geheugen en rekenvermogen. Embedded real-time systemen hebben nog striktere vereisten. Zij moeten binnen een bepaalde tijdspanne een cruciale taak uitvoeren. Ook in hun ontwerpproces verschillen embedded systemen van gewone softwaresystemen. Wanneer een embedded systeem wordt ontwikkeld, moet hierbij ook rekening gehouden worden met eventueel reeds bestaande of nog te ontwerpen hardware. In beide gevallen gelden er strikte beperkingen voor de software. Het aanpassen van embedded hardware na softwareontwikkeling is doorgaans duur of onmogelijk, waardoor men moet proberen de software volledig te modelleren vooraleer over te gaan tot realisatie. Daarom is het ontwikkelingsproces van een embedded systeem relatief veel langer dan het ontwikkelingsproces van een gewoon softwaresysteem. Het systeem kan niet meer worden aangepast, dus mogen er geen fouten optreden, de software moet stabiel zijn en uitvoerig worden getest. Ondanks al deze vereisten wordt de ontwikkeling van embedded systemen vaak nog ongestructureerd aangepakt. De programmeur houdt weinig rekening met uitbreidbaarheid en ¨ is. Enige strucleesbaarheid van de code, meestal is de enige vereiste dat de code efficient tuur en methodiek aanbrengen in het ontwerpproces is nochtans niet moeilijk met behulp van ontwerppatronen, zij zorgen voor een overzichtelijke code en voor een gemakkelijke manier om veelvoorkomende problemen op te lossen. Wanneer over ontwerppatronen gesproken wordt, heeft men het meestal over de patronen voor grote softwaresystemen. Het werk van Erich Gamma en de Gang of Four, in het bijzonder hun boek over ontwerppatronen [10] heeft hierbij een grote rol gespeeld. Men vergeet doorgaans dat ontwerppatronen ook gebruikt kunnen worden in (eerder kleinere) embedded systemen. Ook hier kunnen ontwerppatronen een verschil maken, ze helpen 5
HOOFDSTUK 1. THEORETISCHE STUDIE om de structuur van een programma duidelijker te maken. Ook veelvoorkomende problemen, zoals het plannen van taken (scheduling), beheer van het (beperkte) geheugen en de toegang tot resources, kunnen worden aangepakt met behulp van ontwerppatronen. Het gebruik van ontwerppatronen is een manier om stabiele code te verzekeren. Ontwerppatronen, zoals beschreven in [10], geven een beschrijving van een manier om een veelvoorkomend probleem op te lossen. Bij embedded systemen komen de meeste problemen voor daar waar ze zich onderscheiden van gewone computersystemen. Hierdoor zijn patronen voor gewone computersystemen slechts beperkt van toepassing en dit enkel op grotere embedded systemen. Ontwerppatronen voor embedded systemen spitsen zich dan ook toe op deze specifieke problemen. Mijn onderzoek naar ontwerppatronen voor embedded systemen toont dat deze kunnen ¨ ontwerppatronen, ontwikkeld voor worden opgesplitst in twee grote groepen: de industriele een bepaalde hardware, en de puur theoretische ontwerppatronen, die door de programmeur worden aangepast aan de vereisten van de hardware.
1.1.1
Industri¨ ele patronen
¨ ontwerppatronen werden door hardware verkopers ontwikkeld om de speciDe industriele fieke problemen van embedded systemen op de door hen verkochte hardware op te lossen. Zo biedt Intel verschillende patronen aan om te helpen bij het ontwerp op zijn processoren. Op zijn website [19] toont Intel hoe deze patronen kunnen worden toegepast op elke hardware. Later werd academisch onderzoek verricht naar ontwerppatronen op specifiek hardware. Zo beschrijft Michael Pont in zijn boek Patterns for Embedded and Time-Triggered Systems [21] en later in een artikel [17] enkele ontwerppatronen die specifiek ontworpen zijn voor de 8051 microcontrollers. Deze patronen zijn meestal gebaseerd op de theoretische patronen, die verder worden besproken, maar uitgewerkt op die specifieke hardware. De programmeur moet enkel de code toepassen in zijn systeem om het patroon te gebruiken. Tenslotte bieden ook verkopers van ontwikkelingstools ontwerppatronen aan voor de hardware die zij ondersteunen. Deze patronen zijn beschreven binnen de context van hun ontwikkelingstool. Zo biedt het bedrijf EventHelix enkele ontwerppatronen aan voor hun ontwikkelingstool EventStudio [9].
1.1.2
Theoretische patronen
Theoretische patronen zijn patronen die onafhankelijk van de hardwareconfiguratie kunnen gebruikt worden. Zij geven een algemene oplossing van het probleem, de eigenlijke implementatie op de hardware wordt aan de programmeur overgelaten. Zo zijn deze patronen op grote schaal bruikbaar. Het boek Real-Time design patterns van Bruce Powel Douglass [4] geeft een volledig overzicht van deze patronen. Patronen die door andere auteurs werden ontwikkeld, zijn steeds terug te brengen tot een patroon uit het boek van Douglass. Zo stellen Corsaro en Schmidt in hun paper Virtual Component a Design Pattern for Memory Constrained Embedded Applications [1] het Virtual Component patroon voor, een patroon waarmee het systeem wordt opgebouwd uit verschillende componenten, sommige reeds bestaand, andere nieuw. Dit patroon komt overeen met het Component-based patroon uit het boek van Douglass. Soundararajan en Brennan ontwikkelden dan weer een patroon in hun paper A Proxy Design Pattern to Support Real-Time Distributed Control System Benchmarking [22] dat beschrijft hoe client-server communicatie kan worden geregeld. Het boek van Douglass beschrijft hetzelfde patroon onder de dezelfde naam: het proxy patroon. Wanneer de patronen van naderbij worden onderzocht, blijkt dat de theoretische patronen in twee groepen
6
HOOFDSTUK 1. THEORETISCHE STUDIE
7
kunnen worden opgedeeld: de architecturale patronen en de gedragspatronen. De patronen die verder in deze tekst als voorbeeld worden aangehaald, komen allemaal uit het boek van Douglass. Ook de figuren zijn over genomen uit dat boek. Architecturale patronen Architecturale patronen richten zich op de structuur van het programma. Zij zorgen voor de uitbreidbaarheid en het overzicht, maar ook voor de draagbaarheid naar andere platformen. Voorbeelden van deze architecturale patronen zijn het virtual machine patroon en het recursive containment patroon. Het virtual machine patroon zorgt ervoor dat een systeem gemakkelijk kan ge¨ımplementeerd worden op hardware. Figuur 1.1 toont de structuur van dit patroon. De applicatie wordt zo gemaakt dat ze enkel instructies van de virtuele machine gebruikt. De virtuele machine vertaalt op haar beurt die instructies naar de concrete instructies van de hardware. Wanneer er van hardware wordt gewisseld, moet enkel de virtuele machine aangepast worden. Wanneer er verschillende applicaties op dezelfde hardware gebruik maken van deze virtuele machine, kunnen ze alle op andere hardware gedraaid worden, enkel door die ene virtuele machine aan te passen.
Figuur 1.1: Structuur van het Virtual Machine patroon Het recursive containment patroon is een voorbeeld van een architecturaal patroon waarbij de software wordt opgedeeld volgens functionaliteit. Op deze manier wordt het onderscheid tussen de verschillende functies van het programma behouden en kunnen later eventueel functies worden toegevoegd of verwijderd zonder de volledige code te moeten
HOOFDSTUK 1. THEORETISCHE STUDIE aanpassen. Het patroon is recursief, dit wil zeggen dat elke functionaliteit is opgedeeld in deelfunctionaliteiten die op hun beurt ook kunnen opgedeeld worden. Zo wordt elke basisfunctionaliteit apart behandeld waardoor een eventuele wijziging geen grote veranderingen teweegbrengt. Een toepassingsvoorbeeld van het recursive containment patroon is te vinden in figuur 1.2.
Figuur 1.2: Toepassing van het Recursive Containment patroon ¨ verbetering beDe voorbeelden tonen aan dat de architecturale patronen een essentiele tekenen wanneer het programma achteraf wordt uitgebreid of gewijzigd. Ze betekenen ook een grote meerwaarde wanneer er met verschillende mensen aan een programma wordt gewerkt: het ontwerp en ook de code zijn overzichtelijker. Door eerst een model te maken van het systeem wordt een structuur vastgelegd die belangrijk is voor het verdere ontwikkelingsproces. Gedragspatronen Waar architeturale patronen een oplossing bieden voor de softwarestructuur, richten gedragspatronen zich op de specifieke implementatie van veelvoorkomende problemen, zoals bijvoorbeeld taakbeheer, geheugenbeheer en resourcebeheer binnen de vereisten en beperkingen van het systeem. Zo kan voor het taakbeheer van een systeem beroep gedaan worden op verschillende patronen, onder andere het cyclic executive patroon, het interrupt patroon en het static priority patroon. Afhankelijk van de vereisten van het programma kan dan een geschikte oplossing worden gekozen. Zo is een vereiste bij het cyclic executive patroon dat er geen taken zijn die prioriteit hebben over andere en dat alle taken telkens in dezelfde volgorde worden uitgevoerd. Wanneer taken wel prioriteiten hebben, kan het static priority patroon worden gebruikt, dat bij het plannen van de taken rekening houdt met hun prioriteit. Wanneer taken met een hogere prioriteit taken met een lagere prioriteit moeten kunnen onderbreken, wordt het interrupt patroon gebruikt.
8
HOOFDSTUK 1. THEORETISCHE STUDIE Daar waar de architecturale patronen zijn ontwikkeld uit best practices, zijn de gedragspatronen meer een theoretische weergave ervan, zonder er veel aan te veranderen. De gedragspatronen geven letterlijk weer wat waar ge¨ımplementeerd moet worden terwijl de architecturale patronen eerder een omschrijving geven van de verschillende mogelijkheden. De invulling ervan hangt voor een stuk van de interpretatie van de ontwerper af.
1.2
Onderzoek naar Model-Driven Architecture(MDA) voor embedded systemen
Wanneer over ontwerppatronen wordt gesproken, heeft men het meestal ook over een ont¨ de revue zijn werpproces. Daar waar in het algemene softwareontwerp veel methodologieen gepasseerd, blijft het ontwerpen van embedded systemen eerder een zaak van de programmeur. Deze schrijft zo snel mogelijk werkende code, ongeacht of deze code gestructureerd of uitbreidbaar is. Het besef groeit echter dat er ook voor embedded softwareontwerp een gestructureerde ontwerpmethode moet gezocht worden. Verschillende gespecialiseerde organisaties zoals EETimes [7], embedded.com [8] en het Belgische DSP Valley [5] hebben al artikels gepubliceerd en conferenties georganiseerd omtrent model-driven ontwerp. Onderzoek wijst uit dat model-driven ontwerp een goede keuze is voor embedded systemen. Zo ontwikkelden Ito en Matsuura in hun paper Model driven development for embedded systems [12] een embedded systeem door het model-driven principe toe te passen. Wanneer men embedded systemen wil ontwerpen volgens het model-driven principe is dat het moeilijk is een platform-onafhankelijk model te maken dat ook nog rekening houdt met de hardware. Het Deense technologisch instituut ontwikkelde hiervoor een eigen ontwerptool, Rhapsody [2], die dit probleem zou moeten oplossen. Daarenboven laat de tool ook het gebruik van ontwerppatronen toe. Hoofdstuk 3 gaat verder in op het toepassen van de model-driven principes op embedded systemen.
1.3
Besluit
Wanneer het gebruik van ontwerppatronen bij embedded systemen wordt bekeken, blijkt dat er reeds veel onderzoek naar werd gedaan. Er kan een onderscheid gemaakt worden tussen ¨ patropatronen die specifiek voor een bepaalde hardware werden ontwikkeld, de industriele ¨ nen, en de theoretische patronen die een algemene methode voorstellen. Op de industriele patronen ga ik niet verder in. De theoretische patronen zijn op hun beurt op te delen in architecturale patronen, die de structuur van een systeem vastleggen, en de gedragspatronen, die de werking van het systeem modelleren. Aangezien dit onderzoek vooral in de academische wereld werd gevoerd, onderzoekt het volgende hoofdstuk in welke mate dit onderzoek door de industrie werd opgepikt.
9
Hoofdstuk 2
Patronen voor embedded systemen in een industri¨ ele omgeving 2.1
Inleiding
In de academische wereld is reeds veel onderzoek naar ontwerppatronen voor embedded systemen gebeurd. In dit hoofdstuk gaan we na in welke mate dit onderzoek effect heeft gehad in de industrie. Er wordt onderzocht in welke mate ontwerppatronen worden gebruikt door programmeurs en op welk vlak ze deze gebruiken. Deze gevalstudie wordt gemaakt in samenwerking met het bedrijf E.D.&A. [6]. Dit bedrijf is gespecialiseerd in ontwerp en fabricatie van op maat gemaakte applicaties. E.D.&A. zegt geen ontwerppatronen te gebruiken. Zij maken geen ontwerp, maar programmeren rechtstreeks de gewenste functionaliteit in C. Ze zochten een betere oplossing naar uitbreidbaarheid en hergebruik van code toe en keken hiervoor richting ontwerppatronen. Bij gevolg is dit een ideale gevalstudie om te zien in hoeverre de ontwerppatronen aanleunen bij de praktijken in de professionele wereld en of toepassing ervan inderdaad leidt tot een robuustere, aanpasbare architectuur.
2.2
Voorstelling van de gevalstudie
In deze gevalstudie wordt de code van twee kleinere applicaties geanalyseerd. Tijdens deze analyse wordt gekeken welke patronen reeds gebruikt worden en hoe deze toegepast worden. Er wordt ook gekeken waar nieuwe ontwerppatronen kunnen worden toegepast. Na de analyse worden, waar mogelijk, die ontwerppatronen toegepast in de code. Na de toepas¨ sing wordt geevalueerd of deze verandering ook voordelig is. Het eerste project is een eenvoudig programma, dat slechts enkele functionaliteiten aanbiedt. Het tweede project is een groter programma. Het is geen werkend programma, maar een toepassing waarop een klant een eigen applicatie kan bouwen. Er worden verschillende functionaliteiten aangeboden. Omdat de informatie over de toepassingen vertrouwelijk is, worden geen details over de werking van het project gegeven. Wanneer toepassingen van ontwerppatronen worden ge¨ıllustreerd, wordt dit slechts voor een deel van het project gedaan.
10
¨ HOOFDSTUK 2. INDUSTRIELE GEVALSTUDIE
2.3
Het eerste project
Het project is een relatief eenvoudig programma, bestaande uit een lus die een aantal threads na elkaar uitvoert. Per functionaliteit is er een managerklasse aanwezig die de instructies verdeelt en doorgeeft aan de klassen die in verbinding staan met de hardware. Er wordt eveneens een eenvoudige gebruikersinterface aangeboden. Het is een programma dat, eens opgestart, jaren moet runnen, zonder dat er geheugen gereset wordt.
2.3.1
Analyse van ontwerppatronen
Uit de eerste analyse bleek dat de ontwerppatronen die in aanmerking kwamen voor het project reeds allemaal werden toegepast. Hieronder volgt een lijst van de gebruikte patronen en hoe ze werden toegepast. De beschrijving van elk patroon kan worden teruggevonden in het boek Real-time design patterns van Bruce Powel Douglass [4]. Layered patroon Beschrijving van het patroon Het programma wordt onderverdeeld in verschillende niveaus van abstractie. Zo wordt de eigenlijke implementatie van de functionaliteiten van het programma gescheiden van de delegatie van de opdrachten en verloopt de werking van het programma transparanter. In samenwerking met het recursive containment patroon (zie verder) levert dit zeer gestructureerde code die gemakkelijk uitbreidbaar is. Toepassing van het patroon Er zijn drie niveaus van abstractie in dit programma: op het hoogste niveau liggen de mainklasse en de algemene managerklasse die de ordening ¨ van de taken en de coordinatie verzorgen. Op het middelste niveau bevinden zich de managerklassen die de oproepen naar de juiste klasse in de onderste laag doorsturen. Op het laatste niveau liggen de klassen die de technische implementatie verzorgen. Conclusie De klassen zijn ge¨ımplementeerd zoals het hoort op hun niveau van abstractie. Ook wordt op basis van de namen van de klassen een onderscheid gemaakt tussen de verschillende lagen. De klassen van de middelste laag hebben immers het suffix “Manager”gekregen. Zie ook sectie 2.3.2 waarin de toegevoegde patronen worden beschreven. 5-Layered patroon Beschrijving van het patroon Wanneer een programma op basis van abstractie wordt opgedeeld, zoals in het vorige patroon, zal de onderste laag (minst abstract) groot zijn, omdat een embedded systeem vooral is afgestemd op de hardware. Met dit patroon wordt er een onderscheid gemaakt binnen deze laag, die het gemakkelijker maakt componenten te herkennen, met het oog op eventuele latere uitbreiding. De klassen worden opgedeeld in ¨ volgende categorieen: • Application: De klassen die typisch zijn voor deze applicatie en dus, in tegenstelling tot ¨ niet in andere programma’s zullen voorkomen. klassen in de andere categorieen, • User interface: Bevat alle elementen die nodig zijn voor de user interface. • Communication: Alle klassen die communicatie met andere systemen regelen.
11
¨ HOOFDSTUK 2. INDUSTRIELE GEVALSTUDIE • Abstract OS: Zorgt voor een laag tussen het programma en het onderliggende OS, zodat enkel deze instructies moeten worden aangepast bij verandering van OS. • Abstract Hardware: In deze laag bevinden zich de klassen die de randapparaten voorstellen, zoals sensors, interfaces en drivers. Toepassing van het patroon De functionaliteit van de 5 verschillende lagen wordt door verschillende klassen ge¨ımplementeerd. Er is geen klasse die functies van twee lagen combineert. Conclusie Weerom wordt de functionaliteit verdeeld en wordt dit patroon in principe toegepast, maar dit is niet duidelijk wanneer je de code bekijkt. Een onderverdeling zou hier het verschil kunnen maken. Zie ook sectie 2.3.2 waarin de toegevoegde patronen worden beschreven. Recursive containment patroon Beschrijving van het patroon Scheidt de verschillende functionaliteiten van het programma op verschillende niveaus. Toepassing van het patroon Op het hoogste niveau wordt het programma als geheel aangeboden. Op een lager niveau zijn er per functionaliteit manager-klassen (bv. TODO). Elk van deze manager-klassen is een interface waarlangs die bepaalde functionaliteit wordt opgeroepen. De oproep wordt dan doorgegeven door de manager naar de klasse die die bepaalde functionaliteit zal uitvoeren. Op het laagste niveau bevinden zich de afzonderlijke klassen. Deze bieden elk een eigen deel van de functionaliteit van hun manager-klasse aan. Interactie die de functionaliteit van de manager overschrijdt loopt via de manager. Andere interacties tussen klassen verlopen zonder tussenkomst van de manager. Conclusie Dit patroon is zeer nuttig wanneer men verschillende functionaliteiten wil aanbieden. Wanneer later de code wordt uitgebreid met een nieuwe functionaliteit, volstaat het om (in dit geval) een nieuwe manager-klasse te maken die met de andere managerklassen communiceert. De implementaties op lager niveau moeten niet worden aangepast. Ook hier is een indeling van de klassen gewenst (zie ook conclusie van het gelaagd patroon). Zij het op basis van de naam, of door indeling in folders. Dit komt de leesbaarheid van het programma ten goede en zal bij eventuele uitbreiding van pas komen. Zie ook sectie 2.3.2 waarin de toegevoegde patronen worden beschreven. Static allocation patroon Beschrijving van het patroon Omdat allocatie van dynamisch geheugen voorzichtig moet worden aangepakt (met gevaar voor geheugenfragmentatie en het niet vrijgeven van geheugen), wordt dit vermeden waar mogelijk. Alle variabelen die nodig zijn om het programma te runnen, worden bij de start aangemaakt en niet meer verwijderd. Dit wordt typisch gebruikt in systemen waarbij de geheugencapaciteit in het slechtste geval niet veel verschilt van de gemiddelde geheugencapaciteit en waar het dus geen overhead geeft om geheugen te alloceren voor geheugengebruik in het slechtste geval.
12
¨ HOOFDSTUK 2. INDUSTRIELE GEVALSTUDIE Toepassing van het patroon Alle variabelen die nodig zijn, worden bij initialisatie van alle managerklassen gealloceerd. Zo worden in de mainmethode, voordat de lus begint (zie volgend patroon), de initmethode van alle managerklassen opgeroepen. Deze methoden zorgen voor de initialisatie van alle nodige variabelen. Ook worden de variabelen niet verwijderd. Conclusie In dit programma is het een goede keuze om dit patroon te gebruiken. Dynamische geheugenallocatie is hier niet nodig. Aangezien het programma moet blijven runnen gedurende verschillende jaren, is het ook niet wenselijk dat er zich geheugenfragmentatie voordoet. Cyclic executive patroon Beschrijving van het patroon Dit is een eenvoudig taakbeheerpatroon, dat een set onafhankelijke taken na elkaar uitvoert en dan van voorafaan begint. Toepassing van het patroon De mainklasse bestaat uit een oneindige lus die achtereenvolgens de managers hun taken laat uitvoeren. Bij elke taak wordt gekeken naar de parameters die gezet zijn. Indien deze aanduiden dat een bepaalde actie moet worden gedaan, wordt deze uitgevoerd, anders wordt deze actie overgeslagen. Taken worden dus niet onderbroken. De enige reden waardoor de acties zouden moeten onderbroken worden, is wanneer er een fout zou optreden. Echter, de lus is zo kort dat de fout wellicht meteen wordt afgehandeld als deze zich voordoet. Conclusie Deze manier van taakbeheer is ideaal voor een programma als dit. Met weinig geheugen ter beschikking, is een real-time besturingssysteem (RTOS) niet mogelijk. De functionaliteit van het programma is ook zo klein dat een RTOS overbodig is. In het boek van Douglass staan enkele vereisten waaraan een programma moet voldoen, zodat het cyclic ¨ executive patroon de efficientste oplossing is. Dit programma voldoet aan al deze vereisten: het aantal taken dat wordt uitgevoerd is constant gedurende de hele run-time, de tijd dat een taak nodig heeft om uitgevoerd te worden is constant, de taken zijn onafhankelijk van elkaar, de taken hebben het gebruik van eventuele resources afgerond wanneer ze de controle terug geven aan de mainklasse en de volgorde waarin de taken worden uitgevoerd voldoet in alle situaties.
2.3.2
Toegevoegde ontwerppatronen
In de vorige sectie werdt het project geanalyseerd en werden de verschillende ontwerppatronen ge¨ıdentificeerd. In dit deel, bekijken we welke patronen nog kunnen toegevoegd worden om de applicatie beter te maken. Ook de patronen die slechts gedeeltelijk werden toegepast, worden hier verder ge¨ımplementeerd. Layered patroon Toepassing van het patroon Om dit patroon toe te passen, moeten er geen codeveranderingen gebeuren. Wel heb ik een klassendiagram gemaakt dat de verschillende interacties tussen de klassen duidelijk maakt. Door het klassendiagram te structureren, worden de niveaus van abstractie meteen duidelijk (zie figuur 2.1).
13
¨ HOOFDSTUK 2. INDUSTRIELE GEVALSTUDIE
Figuur 2.1: Klassendiagram met verduidelijking van de lagen
5-Layered patroon Toepassing van het patroon De toepassing van dit patroon gebeurde ook reeds in de code (zie sectie 2.3.1) maar is niet meteen duidelijk te zien in de code. In onderstaand diagram wordt aangetoond hoe de verschillende klassen in het 5-gelaagd patroon passen. In dit geval wordt er geen real-time besturingssysteem gebruikt. De klassen in de abstractOS laag zijn hier klassen die ondersteuning bieden die normaal door het besturingssysteem zou worden gegeven. Figuur 2.2 toont de toepassing van dit patroon. Er worden enkel de klassen weergegeven die het voorbeeld illustreren. Het overzicht van de klassen is niet volledig.
Figuur 2.2: Toepassing van het 5-layered patroon Wanneer het recursive contaiment patroon ook wordt toegepast (zie volgende sectie), zal een deel van deze klassen reeds per functionaliteit worden ingedeeld (onder andere de abstract hardware-laag). Deze hoeven dus niet onmiddellijk volgens deze indeling worden weergegeven. Wel is het praktisch om de user interfacelaag en OS-laag apart weer te geven. Recursive containment patroon Toepassing van het patroon Wanneer we het recursive containment patroon volledig willen toepassen, delen we de klassen in volgens functionaliteit. Omdat eveneens het gelaagd patroon wordt gebruikt, heeft elke functionaliteit een managerklasse die delegeert naar de onderliggende klassen. Dit wordt weergegeven in figuur 2.3, gebaseerd op het klassendiagram. Conform het recursive containment patroon, kan een functionaliteit (licht grijze vakken) verder onderverdeeld worden in subfunctionaliteiten (donker grijze vakken). Dit gebeurt hier
14
¨ HOOFDSTUK 2. INDUSTRIELE GEVALSTUDIE
Figuur 2.3: Klassendiagram met verduidelijking van het recursive containment patroon
ook, de klassen implementeren elk een deel van de functionaliteit die op zichzelf staat. Omdat deze subfunctionaliteit per klasse wordt ge¨ımplementeerd, is het onderscheid op dat niveau duidelijk. Ik heb enkel de klassen onderverdeeld op basis van de hoofdfunctionaliteit waartoe ze behoren. Conclusie Wanneer ik de klassen onderverdeel volgens functionaliteit, verandert dit niets ¨ en gebruikt evenveel geheugen. Het is echaan de code. Het programma blijft even efficient ter veel duidelijker welke klassen welke functionaliteit hebben en dit maakt het programma gemakkelijker aanpasbaar en uitbreidbaar.
2.4
Het tweede project
Dit project is geen afgewerkte applicatie, maar een ondersteunende structuur waarop de klant een applicatie kan bouwen. Er wordt onder meer een embedded besturingssysteem aangeboden om het taakbeheer en geheugenallocatie te doen. Dit real-time besturingssysteem bestaat reeds, de overige functies werden door E.D.&A. toegevoegd.
2.4.1
Analyse van ontwerppatronen
Er werden reeds een aantal patronen gebruikt, zowel in het RTOS als in de rest van de applicatie. De volledige beschrijving van de patronen kan weer gevonden worden in het boek van Bruce Powel Douglass [4]. Enkel de patronen nuttig voor de code van E.D&A. worden beschreven, patronen gebruikt in het besturingssysteem niet. Layered patroon Beschrijving van het patroon Het programma wordt onderverdeeld in verschillende niveaus van abstractie. Zo wordt de eigenlijke implementatie van de functionaliteiten van het programma gescheiden van de delegatie van de opdrachten en verloopt de werking van het programma transparanter. Toepassing van het patroon Dit programma is een ondersteunende structuur waarop applicaties worden gebouwd. Het gehele programma is dus de onderste laag uit het gelaagd patroon. Meer abstracte lagen worden door de bovenliggende applicatie ge¨ımplementeerd.
15
¨ HOOFDSTUK 2. INDUSTRIELE GEVALSTUDIE 5-layered patroon Beschrijving van het patroon Wanneer een programma op basis van abstractie wordt opgedeeld, zoals in het gelaagd patroon, zal de onderste (minst abstracte) laag groot zijn, omdat een embedded systeem vooral is afgestemd op de hardware. Met dit patroon wordt er een onderscheid gemaakt binnen deze laag die het gemakkelijker maakt componenten te herkennen, met het oog op eventuele latere uitbreiding. ¨ De klassen worden opgedeeld in volgende categorieen: • Application: De klassen die typisch zijn voor deze applicatie en dus, in tegenstelling tot ¨ niet in andere programma’s zullen voorkomen. klassen in de andere categorieen, • User interface: Bevat alle elementen die nodig zijn voor de user interface. • Communication: Alle klassen die communicatie met andere systemen regelen. • Abstract OS: Zorgt voor een laag tussen het programma en het onderliggende OS, zodat enkel deze instructies moeten worden aangepast bij verandering van OS. • Abstract Hardware: In deze laag bevinden zich de klassen die de randapparaten voorstellen, zoals sensors, interfaces en drivers. Toepassing van het patroon Hier is de onderste laag het volledige programma. Dit ¨ of lagen. Enkel de programma kan worden opgedeeld in de bovenstaande vijf categorieen application-laag is nog niet aanwezig omdat de specifieke applicatie niet aanwezig is. Net zoals in het eerste project is de functionaliteit goed verdeeld, maar ontbreekt de zichtbare verdeling (bv door gebruik van mappen of naamgeving). Een gedeelte van de code is wel onderverdeeld, de code voor het OS staat in een aparte map en de klassen die de drivers voor in- en output bevatten, kregen het prefix “Io -”. Conclusie Net zoals in het eerste project is het belangrijk om de onderverdeling duidelijk weer te geven. Een consistente weergave is ook gewenst (mappen of naamgeving). Dit komt de uitbreidbaarheid en leesbaarheid ten goede. Recursive contaiment patroon Beschrijving van het patroon Scheidt de verschillende functionaliteiten van het programma op verschillende niveau’s. ´ laag van abstractie Toepassing van het patroon Omdat het programma slechts e´ en weergeeft, is de indeling volgens functionaliteit al deels gegeven door het 5-gelaagd patroon. Deze indeling is niet recursief. In het besturingssysteem zien we wel een weergave van het recursive containment patroon: als we het besturingssysteem zien als de hoofdfunctionaliteit, dan wordt deze op een lager niveau opgedeeld in de enkele deelfunctionaliteiten zoals geheugenbeheer, taakbeheer, etc. De onderverdeling in deelfunctionaliteiten wordt hier duidelijk gemaakt door de naamgeving. Conclusie Het recursive containment patroon wordt gebruikt in het besturingssysteem, maar niet in het programma omdat dit slechts een deel van de uiteindelijke applicatie zal zijn. Toepassing van dit patroon op de code geschreven door E.D.&A. is niet nuttig.
16
¨ HOOFDSTUK 2. INDUSTRIELE GEVALSTUDIE Watchdog patroon Beschrijving van het patroon Om corruptie van de gegevens tegen te gaan, wordt bij gebruik ervan de waakhond (watchdog) ingeschakeld die een check doet van de gebruikte gegevens. Toepassing van het patroon Volledig conform het patroon wordt een bericht naar de waakhond gestuurd. De waakhond gaat dan na of er een fout is gebeurd. In dit systeem wordt niet gekeken naar het moment waarop het bericht naar de waakhond wordt gestuurd. Conclusie Het waakhondpatroon is een eenvoudig, lichtgewicht patroon dat een eenvoudige controle uitvoert op berekende gegevens. Het patroon werd hier toegepast, zoals beschreven in het boek.
2.4.2
Toegevoegde patronen
In de vorige sectie werdt het project geanalyseerd en werden de verschillende ontwerppatronen ge¨ıdentificeerd. In dit deel, bekijken we welke patronen nog kunnen toegevoegd worden om de applicatie beter te maken. Ook de patronen die slechts gedeeltelijk werden toegepast, worden hier verder ge¨ımplementeerd. Guarded call patroon Beschrijving van het patroon Om ervoor te zorgen dat resources door verschillende taken kunnen worden gebruikt, wordt met behulp van dit patroon een interface voor deze resource voorzien. Elke methode die de resource gebruikt, doet dit via deze interface. Zo kan de toegang tot de resource gecontroleerd worden en wordt een deadlock vermeden. Toepassing van het patroon Het patroon wordt toegepast op de “Spi1-resource. Deze resource wordt gebruikt door een “Display-klasse en een “Flash-klasse. Eerst wordt een test geschreven die de oproepen naar de “Display-klasse test. Dan wordt de interface voor de “Spi1-resource gemaakt. In deze interface komen alle methoden die gebruik maken van de “Spi1-resource. Dit blijken enkel methoden uit de “Display- en de “Flash-klasse te zijn. Alle betreffende omroepen worden langs de interface omgeleid. Tenslotte wordt de bovenstaande test opnieuw uitgevoerd om eventuele veranderingen te meten. Een grafisch overzicht van de veranderingen is te vinden in figuren 2.4 en 2.5. Hier is telkens een eenvoudig klassendiagram te zien en een interactiediagram dat de oproepen illustreert. Figuur 2.4 toont de situatie voor de veranderingen, figuur 2.5 toont welke veranderingen werden gedaan. ¨ Conclusie De applicatie loopt niet efficienter, oproepen naar de resource worden immers omgeleid via de interface. Wel zal het gebruik van resources in principe veiliger gebeuren. Alle toegang vanuit andere threads tot de resource verloopt via de interface en verloopt dus gecontroleerd. In dit geval heeft het gebruik van dit patroon weinig meerwaarde voor de applicatie. De applicatie werd in de programmeertaal C geschreven. Deze taal is procedure-gericht en er is dus geen verschil tussen de oproep naar de methode van de interface of wanneer de
17
¨ HOOFDSTUK 2. INDUSTRIELE GEVALSTUDIE
(a) Klassendiagram
(b) Interactiediagram
Figuur 2.4: Klassendiagram en interactiediagram voor de veranderingen methode in de server rechtstreeks wordt opgeroepen. Wanneer de taal C++ zou gebruikt worden, zou dit patroon wel nut hebben, omdat dan de methoden van de server kunnen worden afgeschermd van andere threads, wat de veiligheid van de applicatie bevorderdt. Component based architecture Beschrijving van het patroon Door een onderscheid te maken tussen de verschillende functionaliteiten van de applicatie en deze los van elkaar te ontwerpen, kunnen een aantal herbruikbare ’componenten’ worden gemaakt. Deze kunnen dan later in andere applicaties die dezelfde functionaliteit vereisen gebruikt worden. Toepassing van het patroon Door de verschillende klassen die de functionaliteit implementeren te verschuilen achter een publieke interface, kan deze groep klassen als een component worden beschouwd. De component kan dan gecompileerd worden bijgehouden en gebruikt wanneer nodig. Zo kan een applicatie worden opgebouwd uit verschillende componenten, waarbij enkel de tussenlaag nog ge¨ımplementeerd moet worden. De applicatie is reeds opgedeeld in verschillende functionaliteiten (zie ook het recursive containment patroon). Omdat de applicatie is geschreven in C, is de interfacelaag niet nodig zolang de aangeboden methoden publiek zijn. De hardwarelaag kan nog verder worden opgedeeld in componenten. Het is echter moeilijk om in bestaande code dit patroon toe te passen. Alle code moet immers herschreven worden. Alle oproepen tussen componenten moeten veranderd worden naar een oproep naar de interface van een component. Omdat het moeilijk te traceren is waar een methode wordt opgeroepen en omdat het moeilijk is de volledige applicatie te herschrijven, werd enkel een virtuele wijziging gemaakt in de diagrammen. Enkel de componenten OS, HAL en Modbus bestonden voordien.
18
¨ HOOFDSTUK 2. INDUSTRIELE GEVALSTUDIE
(a) Klassendiagram
(b) Interactiediagram
Figuur 2.5: Klassendiagram en interactiediagram na de veranderingen Conclusie Dit patroon laat toe om gestructureerd software te ontwerpen aan de hand van bestaande componenten en nieuw geschreven code. Op deze manier kan er een grote bibliotheek met componenten gemaakt worden, waaruit de nodige functionaliteiten gekozen kunnen worden bij een nieuw project.
2.5
Besluit
Omdat patronen gebaseerd zijn op best practices, worden de meeste patronen reeds (gedeeltelijk) intu¨ıtief toegepast. Ze worden echter niet gestructureerd gebruikt, waardoor hun nut vaak verloren gaat (zie bv. het recursive containment patroon). Wanneer patronen volledig worden toegepast, komt dit de leesbaarheid en uitbreidbaarheid van de code ten goede. In een klein project als het eerste zijn de veranderingen nauwelijks merkbaar. Wanneer dit project zou worden uitgebreid, zullen de veranderingen dit wel significant gemakkelijker maken. Er is een onderscheid te merken tussen de toepassing van architecturale en gedragspatronen. Architecturale patronen worden toegepast in die zin dat de implementatie van de klassen voldoet aan het patroon. De schikking van de code en naamgeving van de bestanden gebeurt niet volgens het patroon, waardoor de code onoverzichtelijk wordt. Wanneer deze patronen volledig worden toegepast, zijn de programma’s overzichtelijker en dus ook ¨ beter uitbreidbaar. Deze aanpassingen veranderen niets aan de efficientie van de code of aan het geheugengebruik, maar zorgen vooral voor een gestructureerde code die gemakkelijker leesbaar is voor andere programmeurs en op die manier is gestructureerd dat hergebruik en uitbreidingen van de code veel gemakkelijker gaan. Een reden waarom deze patronen gedeeltelijk of niet worden toegepast kan zijn dat er in de embedded industrie minder toegespitst wordt op niet-functionele vereisten zoals uitbreidbaarheid. Gedragspatronen (bv waakhondpatroon of statische allocatiepatroon), worden wel vol-
19
¨ HOOFDSTUK 2. INDUSTRIELE GEVALSTUDIE ledig toegepast. Dat is logisch aangezien deze patronen het dichtst aanleunen bij de best practices in de industrie. Ook is dit logisch omdat in de industrie veeleer gefocust wordt op de functionele vereisten van een programma.
20
Deel II
Toepassing van ontwerppatronen
21
Hoofdstuk 3
Executable UML Een manier om softwareontwerp te structureren is executable UML. Executable UML is op UML gebaseerd en beschrijft een proces om software te ontwerpen conform met het modeldriven engineering concept. Eerst wordt een algemene uitleg gegeven over executable UML. Daarna wordt er dieper ingegaan op het proces dat executable UML beschrijft. Tenslotte volgt er kort een beschrijving van verschillende tools die kunnen gebruikt worden in het modelleringsproces.
3.1
Wat is executable UML
Model-Driven Engineering (MDE) is een recente techniek om het ontwikkelingsproces van software te structureren. Een onderscheid wordt gemaakt tussen onder andere de techniek van model-driven architecture (MDA) en model-driven design (MDD). Model-driven architecture werd door de Object Management Group (OMG) [11] gedefinieerd in 2001. Modeldriven design is een vorm van model-driven architecture, waarbij de focus versmald wordt, zodat het model meer gedetailleerd kan gemaakt worden. Voor embedded systemen wordt vooral deze techniek gebruikt, aangezien embedded systemen nooit heel uitgebreid zullen zijn, in vergelijking met gewone softwaresystemen. Bij model-driven design worden drie verschillende modellen gedefinieerd: het platformonafhankelijk model (platform independent model of PIM), het platform-specifiek model (platform specific model of PSM) en een platform-definitie model (platform definition model of PDM). Het platform-onafhankelijke model bevat het ontwerp van het systeem, waarbij niet wordt ingegaan op platform-specifieke eigenschappen, zoals programmeertaal-specifieke datatypes of hardware gerelateerde operaties. Het platform-definitie model definieert de regels waarmee een platform-onafhankelijk model kan omgevormd worden tot een platformspecifiek model. Het platform-specifieke model tenslotte, is de vertaling van het platformonafhankelijke model naar de gekozen programmeertaal en hardware. In de praktijk wordt het platform-definitie model meestal aangeboden door de tools die gebruikt worden voor model-driven design. Het platform-specifiek model kan dus, met behulp van een tool, automatisch worden gegenereerd. Het modelleren van het platform-specifiek model wordt meestal in een modellering-taal zoals UML gedaan. Om model-driven design in de praktijk toe te passen is er echter meer ¨ nodig dan enkel een manier om modellen te definieren, zoals aangeboden door UML. Ook het gedrag van deze modellen moet gemodelleerd kunnen worden. Het antwoord op deze ´ manier om vereiste is executable UML, of kortweg xUML. Executable UML is slechts e´ en model-driven design toe te passen. Er zijn nog verschillende andere methoden. Hier wordt gekozen om executable UML verder uit te diepen in verband met embedded systemen. 22
HOOFDSTUK 3. EXECUTABLE UML
Executable UML is een afleiding van de UML standaard, waarbij ook een actie-specifieke taal (Action Specific Language) wordt gedefinieerd. In principe zijn alle modellen die UML definieert ook mogelijk in executable UML. Executable UML legt de focus echter op slechts een paar van die diagrammen door deze op te nemen in zijn ontwiklleingsproces. Omdat UML voorlopig nog geen notatie voor acties in modellen bevat, voegt executable UML voor de beschrijving van acties een taal toe, een actie-specifieke taal. De invulling van deze taal wordt niet gedefinieerd door executable UML. De meeste tools voor ontwerp van executable UML diagrammen hebben een eigen vorm van de actie-specifieke taal ontwikkeld. Zo wordt in het boek van Stephen Mellor en Marc Balcer, Executable UML: a foundation for model-driven architecture [16] de BridgePoint Object Action Language gebruikt die de tool BridgePoint [14] aanbiedt. Onafhankelijk van welke programmeertaal of welk platform later gebruikt zal worden, wordt met deze actie-specifieke taal state acties, operaties en interacties tussen klassen weergegeven. Ook kunnen bijkomende mapping-regels worden gespecificeerd in deze taal, waardoor de transformatie van platform-onafhankelijk model naar platform-afhankelijk model automatisch kan gegenereerd worden [15]. Deze nieuwe taal werd opgesteld om een hoger niveau van abstractie te bekomen dan wanneer een programmeertaal zoals Java of C++ gebruikt wordt. De vraag kan echter gesteld worden of dit in de praktijk ook effectief zo is. De actie-specifieke taal biedt alle typische operaties aan die kunnen worden teruggevonden in imperatieve talen, zoals conditionele uitdrukkingen, iteratieve uitdrukkingen en recursie. Er zijn echter geen grote verschillen in de ondersteuning van deze concepten in vergelijking met standaard programmeertalen zoals Java of C++. De actie-specifieke taal biedt geen meerwaarde op vlak van het modelleren van gedrag van klassen. Hierbij moet wel vermeld worden dat deze conclusie wordt getrokken op basis van de BridgePoint Object Action Language die gebruikt wordt in het boek van Mellor [16]. Zoals eerder vermeld, werd de acie-specifieke taal aan executable UML toegevoegd om het gedrag van de verschillende objecten te modelleren, wat in standaard UML niet mogelijk was. UML biedt echter wel sequentiediagrammen aan, die interacties in en tussen klassen kunnen modelleren. Executable UML gaat hier niet op in om het gedrag van de klassen te modelleren, maar vermelt sequentiediagrammen wel als een hulp bij het begrijpen van de werking van het systeem. Daar waar UML een standaard is voor modellen, gaat executable UML verder en stelt ook een proces voor om software te ontwerpen. Op dit proces wordt verder ingegaan in paragraaf 3.2. Ook bij de ontwikkeling van embedded systemen bestaat de tendens om model-driven design steeds vaker toe te passen. Op gespecialiseerde websites verschijnen steeds meer artikels die deze manier van ontwikkelen aanprijzen. Veel van deze artikels beschrijven ook een manier om model driven design toegankelijk te maken voor embedded systeemontwerp. Model driven design is voor embedded systemen zeer interessant, omdat op deze manier de werking van de software op alle mogelijke manieren getest kan worden, voordat de hardware moet worden gemaakt. Hierdoor wordt het ontwikkelingsproces voor embedded systemen gereduceerd in kosten en uiteindelijk ook in tijd, aangezien het aanpassen van de hardware veel intensiever is als een aanpassing van de software. Omdat er een model opgemaakt wordt voor het systeem, zal het systeem ook toegankelijker zijn naar eventuele latere uitbreiding of aanpassing. Typisch aan model-driven design voor embedded systemen is dat ook voor de hardware componenten een model wordt opgesteld. Op deze manier wordt het hele systeem gemodelleerd en getest, waardoor eventuele beslissingen over de hardware kunnen aangepast worden. Omdat model-driven design voor embedded systemen een logische stap is, zou executa-
23
HOOFDSTUK 3. EXECUTABLE UML ble UML ook voor embedded systemen toepasbaar moeten zijn. Op niveau van de software, is dit geen probleem. Pas wanneer ook de hardware componenten moeten gemodelleerd worden, zal executable UML beperkingen hebben. Denk hierbij aan timers, threads, sensors,... Executable UML zal steeds met eigen code moeten worden aangevuld, wil men een embedded systeem ontwerpen.
3.2
Proces van executable UML
Het executableUML-proces bestaat uit verschillende fasen. In elke fase wordt een model gebouwd. Op dit model wordt verder gebouwd in de volgende fase. Normaal wordt over verschillende fasen ge¨ıtereerd om zo een volledig model te bekomen. Het hele executableUMLproces wordt uitgelegd in het boek van Stephen Mellor en Marc Balcer, Executable UML: a foundation for model-driven architecture [16]. Zij beschrijven elk model in detail en alle aspecten ervan. Het proces wordt hier kort beschreven om de gevalstudie die in het volgende hoofdtuk wordt beschreven gemakkelijk te volgen. Alle voorbeelden zijn ook overgenomen uit het boek van Mellor en Balcer. Hoewel dit niet wordt vermeld in het boek van Mellor, kan het executableUML-proces in vier verschillende fasen worden opgedeeld. Deze fasen komen overeen met de fasen in het standaard software ontwerp. De eerste fase is de analysefase. In deze fase worden de vereisten van het systeem gezocht en gedocumenteerd. De tweede fase is die van het ontwerp en de derde fase is de testfase. Deze twee fasen lopen door elkaar in die zin dat eerst de testen worden opgesteld. Telkens wanneer een deel van het ontwerp klaar is, worden de testen uitgevoerd om na te gaan of het ontwerp correct is. In de laatste fase wordt de implementatie van het systeem uitgevoerd.
3.2.1
Analyse
De eerste fase van het executabeUML-proces is de analysefase. In deze fase wordt nagegaan in welke context het systeem zal werken, waaruit een domeingrafiek wordt opgesteld. Vervolgens zullen de vereisten van het systeem worden opgesteld in de vorm van use cases. Tenslotte duidt een activiteitsdiagram aan hoe het systeem zal werken. Domeingrafiek In de eerste stap van de analyse wordt nagegaan in welke verschillende domeinen de applicatie zich bevindt. Mellor spreekt hier over een domeingrafiek (domain chart) [16, p. 36]. Deze domeingrafiek verschilt echter van het domeinmodel dat doorgaans in software ontwerp wordt gebruikt. Het domeinmodel dat in standaard software ontwerp voorkomt, is een representatie van de elementen in de echte wereld, die relevant zijn voor de ontwikkeling van het systeem. Hier worden ook de relaties tussen de elementen, hun attributen en eventuele beperkingen in weergegeven [23]. ¨ hypothetische of abstracte wereld Executable UML definieert een domein als een reele, die autonoom is en een aantal entiteiten bevat [16, p. 30]. Deze definitie verschilt niet veel van de definitie die doorgaans gehanteerd wordt. Het verschil ligt in het feit dat een domein in executable UML minder breed wordt gezien als in standaard softwareontwerp. Wanneer men bijvoorbeeld een domeinmodel wil maken van een online boekenwinkel, dan zal in standaard softwareontwerp het domein dat van de boekenwinkel zijn. Dit domein bevat dan boeken, bestellingen en leveringen. Wanneer van deze online boekenwinkel een domeingrafiek in executable UML wordt gemaakt, zal men de inventaris en de bestellingen als een apart domein bekijken. Figuur 3.1
24
HOOFDSTUK 3. EXECUTABLE UML
Figuur 3.1: Domeingrafiek van de online boekenwinkel
toont de domeingrafiek van het voorbeeld van de online boekenwinkel. De domeinen die de annotatie realized hebben, zijn domeinen die reeds bestaan. Een ander belangrijk verschil tussen domeingrafieken en domeinmodellen is het feit dat domeingrafieken ook softwareelementen bevatten, daar waar een domeinmodel enkel elementen uit de echte wereld bevat. In het voorbeeld in figuur 3.1 zijn onder andere het modelcompilerdomein, het HTML-domein en het XML-domein hier een voorbeeld van. Men kan zich dan de vraag stellen in welke mate dit model past in het concept van het platform-onafhankelijk model uit model-driven ontwerp, aangezien in deze domeingrafiek ook de programmeertalen worden vermeld. Het is een goed idee om de analysefase los van het model-driven proces te zien. In deze fase worden de vereisten van het systeem opgesteld. Het is onvermijdelijk, zeker bij embedded systemen, dat enkele van deze vereisten met hardware te maken zullen hebben. We kunnen er vanuit gaan dat het echte platformonafhankelijke model pas in de ontwerpfase wordt ontworpen, hoewel dit niet wordt vermeld in het boek van Mellor. De relaties tussen de domeinen in executable UML noemt men bruggen (Bridges). Een brug geeft aan wat een domein veronderstelt en wat het andere domein als vereiste moet ´ richting. Zo duidt de brug tussen het domein zien. Deze interactie is telkens slechts in e´ en Web GUI en het domein Web Server aan dat de Web GUI veronderstelt dat alle communicatie tussen deze domeinen over veilige kanalen gebeurt. Het is aan het domein Web Server om hiervoor te zorgen. De beschrijving van de bruggen gebeurt in de domeinmissieverklaring (Domain Mission Statement) van een domein. Figuur 3.2 toont de domeinmissieverklaring van het domein Web GUI. Het is interessant op te merken dat, met deze benadering van domeinen, er geen gedetailleerde analyse van de domeinen gebeurt. Een domeinmodel zoals gebruikt in standaard softwareontwerp, biedt een steun bij bijvoorbeeld het ontwerp van het klassendiagram. Deze steun valt weg wanneer de stappen van het executable UML-ontwerpproces gevolgd worden. Het zou geen slecht idee zijn om elk domein verder uit te werken met een domeinmodel.
25
HOOFDSTUK 3. EXECUTABLE UML
Figuur 3.2: Domeinmissieverklaring van het domein Web GUI
Use cases Een tweede deel van de analyse bestaat uit het identificeren van de use cases. Use cases worden in executable UML op dezelfde manier gedefinieerd als in standaard softwareontwerp. Een use case specificeert een interactie tussen een actor en het systeem. Use cases in executable UML hebben alle eigenschappen die ze in standaard softwareontwerp hebben. Figuur 3.3 toont de use cases voor het online boekenwinkelvoorbeeld.
Figuur 3.3: Use cases van de online boekenwinkel
Activiteitsdiagram Het laatste deel van de analyse bestaat uit het maken van een activiteitsdiagram (activity diagram). Dit diagram is een aanvulling op de use cases en toont het typische verloop van het systeem. Figuur 3.4 toont een activiteitsdiagram van de online boekenwinkel.
26
HOOFDSTUK 3. EXECUTABLE UML
Figuur 3.4: Activiteitsdiagram van de online boekenwinkel
3.2.2
Ontwerp
De tweede fase van het executable UML-ontwikkelingsproces, is de ontwerpfase. In deze fase worden de vereisten die in de vorige fase werden ge¨ıdentificeerd, omgezet in een abstract ontwerp van het systeem. Wanneer we de analogie met model-driven design volgen, wordt in deze fase het platform-onafhankelijke model gemaakt. In de vorige fase werden de verschillende domeinen ge¨ıdentificeerd. In deze fase wordt voor elk domein afzonderlijk een ontwerp gemaakt. Elke stap van deze fase wordt voor elk domein afzonderlijk doorlopen. In deze fase wordt voor elk domein een klassendiagram opgesteld. Dit klassendiagram duidt de structuur van de software aan. Na de identificatie van de verschillende klassen wordt voor elke klasse een toestandsdiagram opgesteld. Het ontwerp van een softwaresysteem is een iteratief gebeuren. Elke stap van de ontwerpfase wordt verschillende keren herhaald tot het model volledig is. Zoals eerder aangehaald, loopt de testfase gelijk met de ontwerpfase. Om de duidelijkheid te behouden wordt eerst deze fase volledig besproken en wordt verder de testfase uitgelegd. Klassendiagram Eerst wordt een klassendiagram gemaakt dat de verschillende attributen en operaties van de klassen uitwerkt. In dit klassendiagram worden ook de relaties tussen de verschillende klassen aangegeven (zoals overerving en associaties).
27
HOOFDSTUK 3. EXECUTABLE UML Het klassendiagram in executable UML wordt op dezelfde manier gemaakt als bij standaard software ontwerp. Figuur 3.5 toont het klassendiagram voor het ordering domein.
Figuur 3.5: Klassendiagram voor het ordering domein van de online boekenwinkel
Toestandsdiagram Nadat het klassendiagram is voltooid, wordt voor elke klasse een toestandsdiagram (state diagram) ontworpen. Dit toestandsdiagram bevat in elke toestand een beschrijving van wat de klasse doet in die toestand. Deze beschrijving wordt gegeven in de actie-specifieke taal die eerder werd vermeld. Figuur 3.6 bevat het toestandsdiagram voor de klasse ShoppingCart uit het klassendiagram van het orderingdomein. Op deze figuur is de beschrijving van een toestand in de actie-specifieke taal van de tool BridgePoint weergegeven. Uit het voorbeeld blijkt dat de taal die hier gebruikt wordt niet meer abstract is dan Java of C++, zoals wel door executable UML vooropgesteld. Figuur 3.1 toont een vergelijking tussen de actie-specifieke taal en Java. Voor de vergelijking worden de acties uit het toe-
28
HOOFDSTUK 3. EXECUTABLE UML
29
Figuur 3.6: Toestandsdiagram voor de ShoppingCart klasse van de online boekenwinkel
standsdiagram voor de ShoppingCart gebruikt. De actie-specifieke taal heeft geen meerwaarde tegenover het gebruik van Java of C++ in het toestandsdiagram, zo blijkt. Wanneer een actie-specifieke taal wordt gebruikt die meer abstract is dan Java of C++, zou de meerwaarde van executable UML duidelijker zijn. Tenslotte kan nog anagetoond worden dat de beschrijving van de activiteiten van klassen ¨ ook met een sequentiediagram kan, zonder extra taal te definieren. Figuur 3.7 toont het sequentiediagram van de acties uit het ShoppingCart-toestandsdiagram.
3.2.3
Testen
Wanneer de analyse voltooid is, worden testen ge¨ıdentificeerd. In de eerste plaats wordt per use case een aantal testen gemaakt, unittesten genaamd. Deze testen gaan alle mogeBP Object Specification Language generate addSelection( productID:rcvd evt.productID, quantity:rcvd evt.quantity) to self; create object instance newSelection of ProductSelection;
Java addSelection( rcvd evt.productID, rcvd evt.quantity); ProductSelection newSelection = new ProductSelection();
Tabel 3.1: Vergelijking tussen de actie-specifieke taal en Java
HOOFDSTUK 3. EXECUTABLE UML
Figuur 3.7: Sequentiediagram van de acties in het ShoppingCart-toestandsdiagram
lijkheden van de use case na en testen het systeem onder alle voorwaarden. Er wordt ook getest wat er gebeurt wanneer er niet aan de precondities werd voldaan. Deze testen worden meestal in textuele vorm opgesteld, zie figuur 3.8. Wanneer de testen zijn ge¨ıdentificeerd, worden ze in het model ge¨ıntegreerd in de vorm van toestandsdiagrammen. In elke toestand bevatten ze, net zoals de toestandsdiagrammen van het ontwerp, een beschrijving van de acties in de betreffende actie-specifieke taal.
Figuur 3.8: Beschrijving van de testen van de use case ’Order Books’ van de online boekenwinkel De testen worden opgesteld zodra de use cases ge¨ıdenficeerd zijn. Tijdens de ontwerpfase worden de testen uitgevoerd, om na te gaan of het ontwerp aan alle vereisten voldoet, in alle omstandigheden. Zolang niet alle testen slagen, gaat de iteratie over beide fasen door. Naast de unittesten, worden ook globale testen opgesteld, die nagaan of de combinatie van verschillende use cases geen problemen oplevert. Deze testen worden in executable UML systeemtesten genoemd. Deze testen zijn een combinatie van de unit testen en hebben extra specificatie over hoe er met de uitslag van de test van de ene use case invoer van de volgende use case gegenereerd kan worden. Systeemtesten worden gebaseerd op het activiteitsdiagram. Het activiteitsdiagram legt de werking van het systeem vast. Een systeemtest gaat na of het systeem werkt zoals vastgelegd. In een ideale wereld worden zowel de unit testen als de systeemtesten automatisch
30
HOOFDSTUK 3. EXECUTABLE UML
31
gegenereerd en uitgevoerd. Voorlopig is dit nog niet mogelijk met de bestaande tools.
3.2.4
Implementatie
De laatste fase van het ontwerpproces in executable UML is de implementatie van het systeem. Deze fase wordt uitgevoerd wanneer alle testen in de testfase slagen en wanneer het ontwerp volledig is. Ideaal in de wereld van executable UML is weer dat de generatie van code automatisch gebeurt. Tot op zekere hoogte kunnen de meeste huidige tools code genereren. Meestal zal de programmeur echter zelf nog steeds code moeten aanvullen of aanpassen. Bijvoorbeeld de hardware-specifieke code bij embedded systemen kan een codegenerator niet zelf genereren.
3.3
Tools voor executable UML
Hier volgt een korte beschrijving van enkele tools die ontwerp met executable UML toelaten. Een eerste tool die beschreven wordt, is een tool die ontworpen is voor ontwerp met executable UML, namelijk BridgePoint. Een andere tool is Visual Paradigm, een tool voor standaar UML ontwerp. BridgePoint BridgePoint [3] is een tool die is ontworpen voor ontwerp met executable UML. Deze tool biedt alle mogelijkheden om de verschillende diagrammen te ontwerpen ¨ en te verifieren. Ook automatische codegeneratie naar Java of C/C++ is mogelijk. BridgePoint heeft een eigen actie-specifieke taal ontwikkeld, namelijk de BridgePoint Object Action Language. Ondanks dat deze tool wordt aangeraden door het boek van Mellor en Balcer en de bewering dat zij BridgePoint hebben gebruikt voor de gevalstudie die zij aanhalen in hun boek, is het moeilijk om de verschillende ontwikkelingsstappen van executable UML te volgen in de tool. Ook in het leren van de actie-specifieke taal die BridgePoint definieert, moet tijd en moeite gestoken worden. Het leren van deze nieuwe taal lijkt niet nuttig, aangezien deze taal niet meer abstract is dan Java, C++ of een andere reeds gekende taal. Op zich is het geen moeilijke taal, wanneer ze gekend is, zal ze gemakkelijk te gebruiken zijn. Er is echter weinig ondersteuning te vinden om de taal te leren, afgezien van de referentiegids die BridgePoint aanbiedt. De vraag is of iemand die reeds Java en C++ kent deze nieuwe taal zal willen leren alleen om met deze tool te kunnen werken, ook al biedt ze geen meerwaarde. Visual Paradigm Visual Paradigm [20] is een tool voor het modelleren van standaard UML. Aangezien executable UML een afleiding is van UML, is het in principe ook mogelijk om executable UML te modelleren in Visual Paradigm. Visual Paradigm zal wel geen ondersteuning geven in het executable UML-proces, daar waar BridgePoint dat wel doet, onder andere door de specifieke diagrammen van het executableUMLproces in die volgorde aan te bieden. ¨ Een ander nadeel van Visual Paradigm is dat het geen manier geeft tot het verifieren van de modellen. De verificatie, toch een belangrijk aspect van het executable UMl-proces, moet manueel gedaan worden. Codegeneratie gebeurt wel in Visual Paradigm, maar deze code is niet volledig. De implementatie van de klasse-specifieke activiteiten moet de programmeur zelf doen, omdat Visual Paradigm geen rekening houdt met de invulling van het toestandsdiagram.
HOOFDSTUK 3. EXECUTABLE UML Het voordeel van het gebruik van Visual Paradigm is dat er geen nieuwe programmeertaal moet geleerd worden. Men kan gewoon C++ of Java gebruiken bij het invullen van de toestandsdiagrammen.
3.4
Besluit
Executable UML is een afleiding van UML, aangevuld met een manier om acties te beschrijven, namelijk een actie-specifieke taal. Dit maakt executable UML uiterst geschikt om het model-driven design proces te volgen. Er zijn echter nog wat verbeteringen nodig om de taal een meerwaarde te laten hebben bij gebruik in de industrie. Zo is de actie-specifieke taal die nu in de tools gebruikt wordt niet meer abstract dan een bestaande programmeertaal zoals Java of C++. De nieuwe taal leren om executable UML toe te kunnen passen zal geen extra meerwaarde opleveren. Ook is het niet duidelijk of de analysefase, waarin onder andere de domeingrafiek wordt gemaakt, deel uitmaakt van het platform-onafhankelijke model. Het lijkt van niet, omdat in deze domeingrafiek ook over de implementatie-specifieke aspecten van het systeem wordt gesproken. De analysefase wordt dus best afzonderlijk van het model-driven ontwerpproces gezien. De meeste tools die executable UML ondersteunen, bieden codegeneratie aan. Deze code is echter niet volledig en zal door de programmeur nog moeten worden aangepast. Ook de automatische verificatie van de modellen is in de meeste tools nog niet vanzelfsprekend. Het is ook zeer de vraag of automatische verificatie en generatie ooit zal gerealiseerd worden. Tenslotte nog een evaluatie van executable UML in het licht van embedded en real-time systemen. Executable UML kan gebruikt worden voor het ontwerpen van embedded systemen. Het ontwerp zal echter niet volledig in executable UML kunnen worden gemaakt. Een embedded systeem is afhankelijk van de hardware waarop het draait. Een model van deze hardware moet dus ook in het ontwerp worden opgenomen. Hiervoor is in executable UML geen ruimte. Andere aspecten die belangrijk zijn bij het ontwerp van embedded systemen zijn geheugengebruik en rekencapaciteit. Hiermee wordt bij automatische codegeneratie geen rekening gehouden. Automatisch gegenereerde code is doorgaans groot en minder ¨ dan code geschreven door een ervaren embedded programmeur. In het volgende efficient hoofdstuk wordt het gebruik van executable UML bij het ontwerpen van een embedded systeem ge¨ıllustreerd aan de hand van een gevalstudie. Het hoofdstuk erna bespreekt dezelfde gevalstudie, maar met gebruik van embedded ontwerppatronen.
32
Hoofdstuk 4
Gevalstudie: zonder ontwerppatronen ¨ We hebben reeds gezien dat ontwerppatronen nog niet ingeburgerd zijn in het industriele ontwerpproces (zie hoofdstuk 2). In dit en volgend hoofdstuk proberen we door middel van ¨ ontwerp. een kleine gevalstudie aan te tonen hoe patronen kunnen bijdragen tot een efficient Tegelijk wordt de gevalstudie ontworpen volgens het executable UML-proces (zie hoofdstuk 3). Op deze manier worden de stappen van het executable UML-proces aangetoond en wordt het principe van executable UML in het licht van embedded systemen gedetailleerd besproken. Omdat de tools voor ontwerp van executable UML slechts als demo beschikbaar zijn voor studenten en er dus geen gebruik kan gemaakt worden van hun volledige functionaliteit, opteer ik ervoor om de diagrammen te tekenen in het programma Visual Paradigm. Als actiespecifieke taal wordt een pseudotaal, gebaseerd op C++ gebruikt. Het is weinig zinvol hier een volledige beschrijving van de acties in C++ te doen, want er gebeurt geen codegeneratie van de toestandsdiagrammen. Aangezien het doel van deze gevalstudie is na te gaan in welke mate executable UML geschikt is voor embedded ontwerp, levert dit geen problemen op. In dit hoofdstuk wordt de gevalstudie besproken zonder het gebruik van ontwerppatronen.
4.1
Opzet van de gevalstudie
Het probleem dat in deze gevalstudie zal worden uitgewerkt, is dat van een elektronische thermometer. Deze thermometer meet de temperatuur telkens na een bepaald interval. De gebruiker kan statistieken opvragen over de laatste metingen. Na het verloop van een dag worden de resultaten van die dag geanalyseerd en opgeslagen. Het voorbeeld zal uitgewerkt worden op het EasyARM-bordje van MicroElektronica [18]. Er wordt voor een bestaande hardware gekozen, enerzijds omdat het voorbeeld zo op bestaande hardware kan getest worden. Anderzijds biedt executable UML geen mogelijkheid om de hardware te modelleren. Door bestaande hardware te gebruiken, kan het executable UML proces toch worden toegepast op embedded systemen. De hardware kan dan als een gerealiseerd domein beschouwd worden en vereisten opleggen aan de rest van het systeem. Het easyARM-bord bevat een MCU met een LPC2148 ARM chip, een on-board programmeerunit, een grafische display en een digitale thermometer. Dit voorbeeld werd zo gekozen omdat het op vlak van geheugengebruik en planning van de verschillende taken keuzes vereist. Ook op vlak van ontwerppatronen kunnen hier interessante keuzes gemaakt worden. 33
HOOFDSTUK 4. GEVALSTUDIE: ZONDER ONTWERPPATRONEN
4.2
Uitwerking van de gevalstudie in executable UML
In deze sectie wordt het executable UML proces toegepast op het voorbeeld beschreven in ¨ sectie 4.1. De verschillende fasen worden uitgelegd en geevalueerd in het kader van de embedded toepassing. Zoals in het hoofdstuk over executable UML beschreven, wordt eerst een analyse van het probleem gemaakt. Na deze analyse worden testen opgesteld en wordt het ontwerp gemaakt. Tenslotte wordt de toepassing ge¨ımplementeerd.
4.2.1
Analyse
Tijdens de analysefase wordt eerst een domeingrafiek gemaakt. Daarna worden de use cases ge¨ıdentificeerd. Tenslotte wordt een activiteitsdiagram opgesteld om de werking va het systeem te illustreren. Zoals in het vorige hoofdstuk reeds vermeld, moet de analysefase los van het modeldriven proces worden gezien. Er wordt dus nagegaan wat de verschillende vereisten zijn, zowel voor de software als voor de hardware. Omdat de hardware reeds gerealiseerd is, wordt de software afhankelijk van de hardware. Dit wordt in de analysefase beschreven. De modellen uit deze fase bevatten dus concepten zowel uit de software als de hardware. Domeingrafiek Voor de analyse van het probleem worden de verschillende domeinen ge¨ıdentificeerd waarin de thermometer zich bevindt. We vinden hier de drie domeinen, namelijk temperatuursensor, hardware en modelcompiler. Figuur 4.1 laat zien hoe deze domeinen zich tot elkaar verhouden in een domeingrafiek. Tabel 4.1 geeft de beschrijving van de verschillende domeinen en hun bruggen. Een ’unallocated assumption’ is een assumptie die weergeeft welke veronderstellingen het domein maakt die niet via een brug worden overgebracht naar een ander domein. Een brug geeft aan wat een domein veronderstelt en wat het andere domein als vereiste ziet. De domeinen modelcompiler en hardware zijn reeds gerealiseerd. Het hardwaredomein is gerealiseerd omdat we een bestaand elektronicabordje gebruiken.
Figuur 4.1: Domeingrafiek van het thermometer voorbeeld
34
HOOFDSTUK 4. GEVALSTUDIE: ZONDER ONTWERPPATRONEN TemperatureSensor Mission Statement: Zorgt voor het verwerken van de metingen gedaan door de hardware. Unallocated Assumptions: De gebruiker kan uit een aantal mogelijke statistieken kiezen wanneer hij deze wil opvragen. Bridge to Hardware: De hardware sensor is steeds beschikbaar om metingen te doen. Bridge to Model Compiler : De compiler compileert de code naar de juiste bewerkingen voor de betreffende hardware. Hardware Mission Statement: Doet de temperatuur metingen en toont gegevens op het scherm. Unallocated Assumptions: / Bridge to Model Compiler : De compiler compileert de code naar de juiste bewerkingen voor de betreffende hardware. Model Compiler Mission Statement: Compileert het model naar code die compatibel is met de gekozen hardware. Unallocated Assumptions: / Tabel 4.1: Beschrijving van de verschillende domeinen Omdat deze domeinen zeer algemeen zijn, voegen we hier een uitgewerkt domeinmodel van het domein temperatuursensor toe. Dit wordt in het standaard proces van executable UML niet gedaan, maar wanneer in deze fase reeds over de elementen van elk domein wordt nagedacht, is het in het verdere ontwerp gemakkelijker om bijvoorbeeld de verschil¨ lende klassen te definieren. We stellen het domeinmodel van het domein temperatuursensor op. De andere domeinen zijn reeds gerealiseerd. Om het domeinmodel op te stellen, moeten nog enkele afwegingen gemaakt worden. Omdat we een embedded systeem ontwerpen, is het in deze fase reeds belangrijk rekening te houden met geheugengebruik en ¨ efficiente verwerking. Dit lijkt in tegenstelling tot het idee van model-driven ontwerp en het platform-onafhankelijk model. Zoals in het vorige hoofdstuk al aangehaald, moet de analysefase los gezien worden van het model-driven proces. Het is inderdaad nodig dat tijdens ¨ de anamysefase reeds wordt nagedacht over de niet-functionele vereisten zoals efficientie en geheugengebruik. Wanneer deze zaken pas zouden worden bekeken wanneer men met de implementatie begint(platform-afhankelijk model), zouden te veel veranderen aan het ontwerp om van model-driven ontwerp te kunnen spreken. • Hoe worden de metingen voorgesteld die de temperatuursensor doet en hoe stellen we de statistische waarden voor die op het einde van een dag gegenereerd worden? Hierbij moet rekening gehouden worden met het beperkte geheugen van de hardware. ´ lijst bij– Een eerste optie is dat we alle metingen en statistische waarden in e´ en houden. Hiervoor hebben we drie types statistische waarden nodig, namelijk een minimum, een maximum en een gemiddelde. Willen we met deze lijst kunnen werken, dan zullen de datatypes meer informatie moeten bevatten over welke waarden ze bevatten (is het een minimum, maximum, gemiddelde of een geme¨ geheugengebruik, aangezien er voor elke dag ten waarde). Dit is geen efficient drie verschillende statistische waarden in de lijst staan. – We kunnen de verschillende types ook in verschillende lijsten zetten. Dan zouden ¨ er vier verschillende lijsten worden bijgehouden. Dat is beter voor de efficientie ¨ verdeelt. van de berekeningen, maar het geheugen wordt minder efficient
35
HOOFDSTUK 4. GEVALSTUDIE: ZONDER ONTWERPPATRONEN
36
Figuur 4.2: Domeinmodel van het TemperatureSensor domein
– Uiteindelijk kozen we voor de optie waar een statistische waarde drie waarden ´ dag. Er worden twee lijsbevat: het minimum, maximum en gemiddelde van e´ en ´ met de metingen van die dag, de andere met de statistische ten bijgehouden, e´ en ´ statistische waarden van de voorbije dagen. Voor elke dag zal er slechts e´ en waarde in de lijst staan, wat de lijst aanzienlijk korter maakt. • Hoe de tijdstippen en dagen worden voorgesteld? Omdat executable UML een platformonafhankelijk model maakt, kunnen we bij het modelleren geen gebruik maken van bestaande datatypes in een programmeertaal. We ontwerpen hiervoor een time-type. Dit type bevat het aantal milliseconden dat verstreken is sinds een bepaalde datum. Hieruit kan dan worden berekend welke dag en tijdstip het is. Ook zijn vergelijkingen tussen verschillende types gemakkelijk te maken. • De hardware kan een timer voorzien. Hiermee kan eveneens geen rekening worden gehouden in het platform-onafhankelijk model dat later wordt ontwikkeld. Daarom voorzien we een eigen timertype, dat later wordt gebruikt in het platform-onafhankelijke model. Dit timertype bevat een aantal milliseconden en telt af van dat aantal tot nul. ¨ mogelijk melden dat de tijd verstreken is en dat de log• Hoe kan de timer zo efficient ger in actie moet komen? Hiervoor gebruiken we een timervlag in de loggerklasse. Wanneer de timer afloopt, zet deze de vlag aan. De loggerklasse checkt op regelmatige tijdstippen de vlag. Wanneer de loggerklasse ontdekt dat de vlag aan staat, zal deze de betreffende acties uitvoeren en de vlag terug uit zetten. De timer wordt nadien opnieuw opgezet. Het domeinmodel wordt voorgesteld in figuur 4.2. Dit domein bevat een loggerklasse die de resultaten opvraagt en verwerkt. Een bijgehouden waarde wordt voorgesteld door de readingklasse. Een reading kan een pas gemeten waarde zijn, hier voorgesteld als een temperatuur. Een temperatuur heeft een waarde en een tijdstip. Een andere vorm van een reading is de statistische waarde, die berekend wordt op het einde van de dag. Deze
HOOFDSTUK 4. GEVALSTUDIE: ZONDER ONTWERPPATRONEN statistische waarde heeft een dag, een minimum, maximum en een gemiddelde van die dag. De logger heeft twee timers. De eerste timer geeft na een bepaald interval aan dat er een meting moet gedaan worden, deze meting gebeurt via de sensor. De tweede timer signaleert het einde van de dag, waarop de logger de resultaten van die dag verwerkt naar een statistische waarde. Use cases In de volgende stap worden de verschillende use cases gezocht. Voor de thermometer zijn er niet veel use cases, enkel de use case waar de gebruiker een statistiek kan opvragen. Bij real-time systemen is de timer echter ook een actor. In dit geval laat de timer weten wanneer het interval voor de volgende meting is verstreken. Een andere timer laat weten wanneer het einde van de dag is aangebroken, zodat de thermometer die gegevens van die dag kan verwerken. Figuur 4.3 toont de verschillende use cases.
Figuur 4.3: Use cases van het thermometer voorbeeld De use cases worden verder uitgewerkt in tabel 4.2. Van elke use case worden de vereisten gegeven en een beschrijving van het proces dat ze inhouden. Omdat er weinig interactie is tussen de actors en het systeem, zijn deze beschrijvingen slechts kort. Activiteitsdiagram Het verloop van het systeem wordt weergegeven in een activiteitsdiagram. Het activiteitsdiagram voor de thermometer bevindt zich in figuur 4.4. Vanuit de starttoestand wordt gewacht tot er ofwel een timervlag aangezet wordt, ofwel tot een gebruiker het systeem wil gebruiken. Wanneer een gebruiker een statistiek wil opvragen, zoekt het systeem die statistiek op en toont vervolgens het resultaat op het scherm. Daarna wacht het systeem weer af. Wanneer een timervlag aangezet wordt, zal het systeem de betreffende acties voor die timer uitvoeren en erna de timervlag terug opzetten. Een activiteitsdiagram wordt normaal over verschillende domeinen gemodelleerd. In dit voorbeeld loopt het activiteitsdiagram enkel over het temperatuursensordomein. Er is op de figuur dus geen onderscheid tussen domeinen te zien, zoals in het voorbeeld omtrent executable UML in hoofdstuk 3 wel te zien was.
4.2.2
Testen
Voordat we aan het ontwerp beginnen, identificeren we per use case enkele testen die de werking van het systeem nagaan.
37
HOOFDSTUK 4. GEVALSTUDIE: ZONDER ONTWERPPATRONEN Use Case: Start Reading Preconditions: / Postconditions: A new reading has been added to the list of readings 1. Timer signals to logger that period has expired. 2. Logger requests temperature from sensor. 3. Logger adds result to list of temperatures. Use Case: Process Daily Results Preconditions: / Postconditions: A new statistic value has been added to the list of statistical values 1. Timer signals to logger that period has expired. 2. Logger processes alle temperatures of that day. 3. Logger adds result to list of statistical values. Use Case: Request statistic Preconditions: / Postconditions: Required result is shown on screen 1. User selects getstatistic option. 2. User selects start of period. 3. User selects end of period. 4. User confirms. 5. System calculates required statistic and shows on screen. Tabel 4.2: Tekstuele beschrijving van de use cases Start Reading Test Begintoestand 1 T(20, 12:30), T(22, 13:00)
Invoer T(22, 13:30)
2
T(20, 14:00)
T(20, 12:30), T(22, 13:00), T(22, 13:30), max = 3
Gewenste uitvoer T(20, 12:30), T(22, 13:00), T(22, 13:30) T(22, 13:00), T(22, 13:30), T(20, 14:00)
Tabel 4.3: Testen voor de use case Start Reading Er wordt telkens aangegeven in welke beginsituatie het systeem zich bevindt. Het type T(temperatuur, tijdstip) geeft aan dat er een temperatuurgegevenstype aanwezig is. Het type S(minimum, maximum, gemiddelde, dag) geeft een statistische waarde aan. In tabel 4.3 worden de testgevallen voor de use case Start Reading tekstueel voorgesteld. In de eerste test wordt nagegaan of een gemeten waarde ook effectief aan de lijst van metingen wordt toegevoegd. De tweede test gaat na of, wanneer de lijst met metingen vol is, het oudste element wordt overschreven. Tabel 4.4 toont de testen voor de use case Process Daily Results. In de eerste test wordt met de metingen van die dag een nieuwe statistische waarde gemaakt, die toegevoegd wordt aan de lijst. In de tweede test wordt weer nagegaan of het oudste element van de lijst wordt overschreven wanneer de lijst vol is. De testen voor de use case Request Statistic worden opgesomd in tabel 4.5. De eerste test vraagt een minimum van dezelfde dag op, de tweede test vraagt een minimum van de voorbije dagen. De derde test vraagt een maximum op van een tijdspanne die zowel de huidige dag als de voorbije dagen bevat. Het maximum moet dus uit zowel temperatuurgegevenstypes als statistische waarden worden berekend. Deze testen worden in de vorm van een toestandsdiagram in het model ge¨ıntegreerd. Omdat de toestandsdiagrammen identiek zijn, op de gegevens in de tabellen vermeld na,
38
HOOFDSTUK 4. GEVALSTUDIE: ZONDER ONTWERPPATRONEN
39
Figuur 4.4: Activiteitsdiagram van het thermometer voorbeeld Process Daily Results Test Begintoestand 1 T(20, 12:30), T(22, 13:00), T (22, 13:30) S(18, 22, 20, 12/5/2011) 2
T(17, 12:30), T(22, 13:00), T (5, 13:30) S(18, 22, 20, 12/5/2011), S(20, 22, 21.3, 13/5/2011), max = 2
Gewenste uitvoer T(20, 12:30), T(22, 13:00), T (22, 13:30) S(18, 22, 20, 12/5/2011), S(20, 22, 21.3, 13/5/2011) T(20, 12:30), T(22, 13:00), T (22, 13:30) S(20, 22, 21.3, 13/5/2011), S(5, 22, 14.6, 14/5/2011)
Tabel 4.4: Testen voor de use case Process Daily Results wordt hier enkel het diagram voor de use case Start Reading, test 1 gegeven. Figuur 4.5 toont dit diagram. Omdat in dit voorbeeld de use cases onafhankelijk van elkaar worden uitgevoerd en geen gevolg zijn van elkaar, is een systeemtest hier niet van toepassing. In een groter systeem, waarbij bijvoorbeeld na het registreren van de temperatuur extra statistieken worden berekend en getoond, zou een systeemtest wel nut hebben. Dit kan ook worden afgeleid uit het activiteitsdiagram, waarin use cases naast elkaar worden uitgevoerd, in plaats van na elkaar.
4.2.3
Ontwerp
De volgende stap is het ontwerp zelf maken. Zoals eerder aangegeven, biedt executable UML geen functionaliteit om de hardware te modelleren, er wordt dus een bestaande hardware gebruikt, namelijk de EasyARM-ontwikkelingstool [18]. Dit ontwerp wordt per domein afgehandeld. Het modelcompilerdomein en het hardwaredomein bestaan reeds. Enkel het temperatuursensordomein moet nog gemodelleerd worden. Klassendiagram In eerste instantie identificeren we de verschillende klassen die nodig zijn. Omdat in de analysefase reeds een domeinmodel werd opgesteld, is dit redelijk eenvoudig. De verschillende klassen worden aan de hand van het domeinmodel ge¨ıdentificeerd. Voor elke klasse worden de verschillende attributen gezocht en de nodige operaties genoteerd. Figuur 4.6 toont het volledige klassendiagram van de thermometer. De loggerklasse bevat de centrale functionaliteit, deze klasse bevat de initialisatiemethoden en zorgt voor het
HOOFDSTUK 4. GEVALSTUDIE: ZONDER ONTWERPPATRONEN Request Statistic Test Begintoestand 1 2 3
T(20, 12:30), T(22, 13:00), T(22, 13:30) S(18, 22,20, 12/5/2011), S(20, 22, 13/5/2011) T(20, 12:30), T(22, 13:00), T(24, 13:30)
Invoer
21,3,
min(12:30, 13:00) min(12/5/2011, 13/5/2011) max(12/5/2011, 14/5/2011)
40
Gewenste uitvoer 20 20 24
S(18, 22, 20, 12/5/2011), S(20, 22, 213, 13/5/2011) Tabel 4.5: Testen voor de use case Request Statictic taakbeheer. De loggerklasse heeft daarnaast enkele methoden om minima, maxima en gemiddelden te berekenen uit zowel de lijst van statistische waarden als de lijst van metingen. Een laatste functionaliteit van de loggerklasse is dat deze klasse op het einde van de dag de metingen van die dag verwerkt. De timerklasse krijgt enkele methoden om op te starten, te stoppen en om de timer opnieuw in te stellen. De attributen ms set en ms left wijzen op het aantal milliseconden dat initieel wordt ingesteld en het aantal milliseconden dat de timer nog moet aftellen. De temperatuursensorklasse zorgt voor de communicatie met de sensor van de hardware. De gebruikersinterfaceklasse zorgt voor de communicatie met de gebruikersinterface van de hardware (knoppen en lcd scherm). Tenslotte wordt nog een tijdsgegevenstype voorzien. Dit type bevat het aantal milliseconden dat sinds een bepaald tijdstip is verstreken. En biedt het systeem de kans om verschillende tijdstippen met elkaar te vergelijken. Toestandsdiagrammen De werking van elke klasse wordt verder toegelicht in de toestandsdiagrammen. Er wordt enkel van de loggerklasse en van de timerklasse een toestandsdiagram gemaakt. De andere klassen hebben geen veranderende toestand, waardoor een toestandsdiagram geen extra informatie biedt. Het eerste diagram (figuur 4.7) laat de verschillende toestanden van de loggerklasse zien. Initieel zit de loggerklasse in een wachtcyclus. Wanneer een timer zijn timervlag aan zet, zal de loggerklasse naar de overeenkomstige toestand gaan en daar de betreffende acties uitvoeren. Een andere mogelijkheid is dat de gebruiker een statistiek opvraagt. Dit wordt in het diagram aangeduid met de term ’userinput’. Het tweede diagram (figuur 4.8) toont het toestandsdiagram van de timerklasse. De timer bevindt zich in de initialisatietoestand totdat hij gestart wordt. Op dat moment wordt er afgeteld van het ingestelde aantal milliseconden naar nul. Wanneer de timer nul bereikt, gaat hij naar de volgende toestand, de ’succesfull end’-toestand waarin de loggerklasse wordt ¨ toestand. Wanneer de timer om een verwittigd. Daarna wordt teruggekeerd naar de initiele reden wordt onderbroken, wordt er geen signaal naar de loggerklasse gestuurd. De timer ¨ toestand. Hoewel de ’unsuccesfull end’-toestand geen imgaat gewoon terug naar de initiele ¨ toestand, wordt hier toch een aparte plementatie heeft naast het doorsturen naar de initiele toestand voorzien. Bij eventuele uitbreiding kan hier bijvoorbeeld een foutboodschap worden gestuurd. Wanneer het ontwerp klaar is, zou het geen inconsistenties met de testgevallen mogen tonen. In dit model is aan alle testgevallen voldaan.
HOOFDSTUK 4. GEVALSTUDIE: ZONDER ONTWERPPATRONEN
Figuur 4.5: Toestandsdiagram voor de eerste test van de use case start reading
4.2.4
Implementatie
De implementatie gebeurt in dit voorbeeld manueel. Visual Paradigm heeft een codegenerator, die de code genereert van de informatie in de klassendiagrammen. Deze generatie ¨ levert echter zeer uitgebreide, inefficiente code op. Om met het beperkte geheugen en rekencapaciteit te kunnen werken, moet de code manueel worden herschreven. Een voorbeeld ¨ van deze inefficiente code is dat voor elk attribuut van de klassen een get- en set-methode wordt gegenereerd. Dit is bij grotere systemen veiliger, maar bij embedded systemen zorgen ¨ deze methoden enkel voor vermindering van rekeneficientie. Bij ontwikkeling van embedded systemen zullen deze meestal omzeild worden om het veranderen van attributen snel en ¨ te laten gebeuren. efficient Het implementeren zelf is echter geen ingewikkeld karwei. Alle acties van de klassen worden reeds vermeld in de toestandsdiagrammen. Er moet enkel een vertaling van de pseudo code naar C++ gemaakt worden. Enkel de specifieke hardware-commando’s, zoals het inlezen van de temperatuur door de sensor en het tonen van gegevens op de display, moeten nog worden opgezocht. Het compileren van deze code gebeurt met de Keil-compiler [13] voor ARM.
4.3
Besluit
Wanneer executable UML wordt toegepast om een embedded systeem te ontwerpen, stoten we op enkele tekortkomingen. Zo is er geen functionaliteit voorzien voor het modelleren van hardware, dit zal de programmeur uiteindelijk zelf moeten doen.
41
HOOFDSTUK 4. GEVALSTUDIE: ZONDER ONTWERPPATRONEN Executable UML stelt enkel voor om een domeingrafiek op te stellen tijdens de analysefase. Het lijkt me echter ook aangeraden om evenseens van elke domein een domeinmodel op te stellen. Dit bespaart veel werk bij het opstellen van het ontwerp en biedt de ontwerper de kans om na te denken over het domein in een algemene, niet-technische context. Ook datatypes die door een programmeertaal worden aangeboden, zoals een datumtype, ontbreken en moeten zelf gemodelleerd worden. De automatische codegeneratie levert geen gebruiksklare code op, omdat alle operaties die verband houden met de hardware door de programmeur zelf moeten worden gemodelleerd. De code gegenereerd door een ¨ dan wanneer een ervaren programmeur deze automatische generator is ook minder efficient zelf zou schrijven. Zeker bij embedded systemen kan dit significante verschillen geven bij uitvoering van de code. Ook embedded principes zoals een timerklasse zijn moeilijk te modelleren in executable UML. In het volgende hoofdstuk wordt dezelfde gevalstudie uitgewerkt, met behulp van ontwerppatronen.
42
HOOFDSTUK 4. GEVALSTUDIE: ZONDER ONTWERPPATRONEN
Figuur 4.6: Klassendiagram van het temperatuursensordomein
43
HOOFDSTUK 4. GEVALSTUDIE: ZONDER ONTWERPPATRONEN
Figuur 4.7: Toestandsdiagram van de loggerklasse
44
HOOFDSTUK 4. GEVALSTUDIE: ZONDER ONTWERPPATRONEN
Figuur 4.8: Toestandsdiagram van de timerklasse
45
Hoofdstuk 5
Gevalstudie: met ontwerppatronen 5.1
Inleiding
In het vorige hoofdstuk zagen we hoe door toepassing van het executable UML-proces een embedded systeem werd ontworpen dat de temperatuur meet en de gebruiker enkele statistieken aanbiedt. In dit hoofdstuk wordt hetzelfde systeem ontworpen met behulp van ontwerppatronen. Hier wordt opnieuw het executable UML proces gevolgd, maar de focus ligt op het toepassing van de ontwerppatronen. Er wordt nagegaan hoe de toepassing van ontwerppatronen gebeurt, of deze een verschil maken bij het ontwerpen en of ze tenslotte een verbetering van het ontwerp inhouden.
5.2
Toepassing van de patronen
We passen het executable UML-proces opnieuw toe om een thermometer te maken. Nu gebruiken we echter ontwerppatronen om het ontwerp te structureren. Elke fase van het executable UML-proces wordt weer doorlopen: eerst de analysefase, daarna volgen de testen ontwerpfase en tenslotte wordt het systeem ge¨ımplementeerd. De bespreking van de analysefase en de testfase zijn slechts kort, aangezien het gebruik van ontwerppatronen hier geen veranderingen teweeg brengt.
5.2.1
Analysefase
De analyse van het systeem werd reeds in het vorige hoofdstuk gedaan. Daar werden domeingrafiek, domeinmodel, use cases en activiteitsdiagram gemaakt. Deze worden hier opnieuw getoond in figuur 5.1.
5.2.2
Testfase
Ook de testen zijn hetzelfde: ook al worden ontwerppatronen gebruikt, de werking van het systeem verandert niet. Er worden dan ook dezelfde resultaten verwacht. De testen worden hier opnieuw weergegeven in tabel 5.1.
5.2.3
Ontwerpfase
Het is in de ontwerpfase dat de ontwerppatronen worden toegepast. In deze fase wordt eerst nagegaan welke aspecten van embedded systemen een ontwerpprobleem oplevert. 46
HOOFDSTUK 5. GEVALSTUDIE: MET ONTWERPPATRONEN
Start Reading Test Begintoestand 1 T(20, 12:30), T(22, 13:00)
Invoer T(22, 13:30)
2
T(20, 14:00)
T(20, 12:30), T(22, 13:00), T(22, 13:30), max = 3
Process Daily Results Test Begintoestand 1 T(20, 12:30), T(22, 13:00), T (22, 13:30) S(18, 22, 20, 12/5/2011) 2
T(17, 12:30), T(22, 13:00), T (5, 13:30) S(18, 22, 20, 12/5/2011), S(20, 22, 21.3, 13/5/2011), max = 2
3
T(20, 12:30), T(22, 13:00), T(22, 13:30) S(18, 22,20, 12/5/2011), S(20, 22, 13/5/2011) T(20, 12:30), T(22, 13:00), T(24, 13:30)
Gewenste uitvoer T(20, 12:30), T(22, 13:00), T(22, 13:30) T(22, 13:00), T(22, 13:30), T(20, 14:00)
Gewenste uitvoer T(20, 12:30), T(22, 13:00), T (22, 13:30) S(18, 22, 20, 12/5/2011), S(20, 22, 21.3, 13/5/2011) T(20, 12:30), T(22, 13:00), T (22, 13:30) S(20, 22, 21.3, 13/5/2011), S(5, 22, 14.6, 14/5/2011)
Request Statistic Test Begintoestand 1 2
47
Invoer
21,3,
min(12:30, 13:00) min(12/5/2011, 13/5/2011) max(12/5/2011, 14/5/2011)
Gewenste uitvoer 20 20 24
S(18, 22, 20, 12/5/2011), S(20, 22, 213, 13/5/2011) Tabel 5.1: Testen voor de use cases Start Reading, Process Daily Results en Request Statistic
HOOFDSTUK 5. GEVALSTUDIE: MET ONTWERPPATRONEN Voor deze problemen wordt dan een ontwerppatroon gezocht dat het probleem het beste oplost, rekening houdend met de vereisten en beperkingen van het systeem. De beschrijvingen van de patronen worden hier gegeven zoals ze in het boek van Bruce Powel Douglass [4] staan. Analyse van ontwerppatronen Eerst worden de verschillende ontwerppatronen per eigenschap van het systeem naast elkaar afgewogen en wordt de beste keuze geselecteerd. Taakbeheer Taken worden gestart door een timer of door een gebruiker. Taken duren dus niet allemaal even lang en in het geval van de taak gestart door de gebruiker zullen ze niet altijd op hetzelfde ogenblik gebeuren. Er moet dus een taakbeheer gekozen worden dat het afhandelen van deze taken kan regelen op het ogenblik dat ze moeten gebeuren. De verschillende patronen in verband met taakbeheer zijn: Message Queuing patroon: Zorgt voor de communicatie tussen threads, door berichten die de ene thread naar de andere stuurt op te slaan in een buffer. De andere thread leest het bericht zodra hij kan. Interrupt patroon: Wanneer een taak moet worden uitgevoerd, zendt deze een interrupt naar het taakbeheer. Het taakbeheer plaatst de andere taken in wacht en laat deze taak uitvoeren. Een voorwaarde voor dit patroon is dat de taak die onderbreekt kort is. Nadat deze taak is afgerond, wordt de oorspronkelijke taak hersteld. Guarded Call patroon: Een manier om een methode uit een andere thread op te roepen, waarbij eventuele deadlocks worden vermeden. Rendezvous patroon: Dit patroon synchroniseert verschillende threads door hun precondities op te leggen. Cyclic Executive patroon: Wanneer alle taken altijd worden uitgevoerd en telkens na elkaar worden afgehandeld, is dit patroon aangeraden. Round Robin patroon: Dit patroon is hetzelfde als het cyclic executive patroon, maar het taakbeheer heeft de optie een taak vroegtijdig te pauzeren en een andere taak voorrang te geven. Static Priority patroon: Elke taak heeft een vaste prioriteit. De taken worden volgens deze prioriteit gerangschikt. Dynamic Priority patroon: Taken hebben een prioriteit, maar deze kan wijzigen.
Voor het thermometersysteem is het interrupt patroon de beste kandidaat. De taken die moeten worden uitgevoerd zijn kort en kunnen op elk moment gebeuren. Door dit patroon te gebruiken, kunnen de taken los van elkaar lopen en hoeft de loggerklasse niet actief te wachten op een gebeurtenis. Geheugenbeheer Er bevinden zich twee verschillende gegevenstypes in het systeem: een temperatuurtype en een statistische waarde. Deze worden bijgehouden in lijsten. De verschillende ontwerppatronen in verband met geheugenbeheer zijn: Static Allocation patroon: Al het nodige geheugen wordt bij initialisatie van het systeem gealloceerd. Tijdens de uitvoering van het systeem gebeuren geen allocaties of deallocaties meer.
48
HOOFDSTUK 5. GEVALSTUDIE: MET ONTWERPPATRONEN Pool Allocation patroon: Wanneer het systeem geheugen moet kunnen vrijgeven en vastleggen, kan dit door het systeem geregeld worden door een pool van de objecten aan te bieden. Telkens wanneer een object nodig is, wordt een object uit de pool genomen. Zo wordt geheugenfragmentatie vermeden. Fixed Size Buffer patroon: Geheugen kan slechts gealloceerd worden in vaste groottes. Zo kan geheugenfragmentatie niet optreden. Smart Pointer patroon: De pointer naar een object wordt zelf een object, waardoor het kan worden aangemaakt en verwijderd en kan nagaan of het object waarnaar de pointer wijst nog steeds bestaat. Garbage Collection patroon: Voorkomt geheugenlekken door na te gaan of er geheugen gealloceerd is waarnaar geen verwijzing bestaat. Garbage Compactor patroon: Een variant van het Garbage Collection patroon, dat ook geheugenfragmentatie voorkomt. In het systeem worden er statistische waarden aangemaakt op het ogenblik dat de gebruiker een statistiek opvraagt. Voor deze statistische waarden is een geheugenpool een goede optie. Wanneer het type nodig is, wordt het aangemaakt en gebruikt om de resultaten te tonen aan de gebruiker. Daarna kan het opnieuw worden verwijderd, dus terug in de pool gestoken worden. ´ resource gebruikt, de thermometer. Om erResourcebeheer In het systeem wordt e´ en ´ thread tegelijk de sensor kan gebruiken, moet de sensor voor te zorgen dat slechts e´ en beschermd worden. De mogelijke patronen zijn: Critical Section patroon: Het gebruik van een resource wordt als een atomische operatie beschouwd en kan niet onderbroken worden. Dit wordt gerealiseerd door het gebruik van een mutex. Priority Inheritance patroon: Een eenvoudige oplossing om prioriteitsinversie, het feit dat een taak moet wachten tot de resource vrij is en dat de duur hiervan niet te voorspellen is, aan banden te leggen. In dit patroon wordt het aantal taken dat op een resource wacht gelimiteerd. Highest Locker patroon: Een variant van het Priority Inheritance patroon, waarbij de beperkingen voor het wachten strikter zijn. Priority Ceiling patroon: Een patroon dat niet alleen prioriteitsinversie aan banden legt, maar ook deadlocks verwijdert. Simultanous Locking patroon: Patroon om deadlocks te vermijden. Alle resources wor´ niet, dan worden er geen resources vastgelegd. den tegelijk vastgelegd. Lukt er e´ en Ordered Locking patroon: De verschillende threads mogen de resources in een vaste volgorde vastleggen. Omdat de taken die de sensor gebruiken slechts kort van de sensor gebruik maken, is het critical section patroon hier aangeraden. De kans dat de sensor door twee verschillende threads tegelijk gebruikt wordt, is ook minimaal, waardoor de andere patronen vooral overhead veroorzaken. Veiligheid Omdat het systeem uit het voorbeeld een klein systeem is en er slechts een minimale verwerking van de gegevens gebeurt, is een veiligheidspatroon hier niet nodig. Het zou enkel rekencapaciteit en geheugen gebruiken dat beter kan worden besteed.
49
HOOFDSTUK 5. GEVALSTUDIE: MET ONTWERPPATRONEN Architectuur De architectuur van het systeem is ook belangrijk, al gaat het om een klein systeem. Met het oog op latere uitbreiding moet ook over de architectuur worden nagedacht. De verschillende architectuur patronen zijn: Layered patroon: Het systeem wordt ingedeeld volgens abstractie. Five-Layered patroon: Speciaal geval van het layered patroon waarbij er vijf lagen van abstractie zijn. Microkernel Architecture patroon: Met dit patroon kan het systeem tijdens de looptijd functies toevoegen en verwijderen. Channel Architecture patroon: Een patroon voor systemen waar gegevens systematisch worden verwerkt. Dit patroon stelt de verwerking van de gegevens voor als een lang traject waarlangs de bewerkingen gebeuren. Dit patroon maakt het latere gebruik van veiligheidspatronen ook gemakkelijker. Recursive Containment patroon: Het systeem wordt ingedeeld volgens functionaliteit. Deze indeling gebeurt recursief: de functionaliteiten worden op hun beurt ingedeeld in deelfunctionaliteiten. Hierarchical Control patroon: Complexe algoritmes worden over verschillende lagen van abstractie verdeeld. Virtual Machine patroon: Zorgt voor een gemakkelijke transformatie van het systeem naar een andere hardware of besturingssysteem. Omdat het systeem relatief klein is, wordt het Layered patroon gebruikt, maar niet in de vorm van het Five-Layered patroon. Het Recursive Containment patroon is interessant, maar heeft niet veel nut in het kleine systeem. Wanneer het systeem groter wordt, wordt dit patroon best wel gebruikt om het overzicht te behouden. Ontwerp van het systeem met ontwerppatronen Wanneer de verschillende ontwerppatronen ge¨ıdentificeerd zijn, worden ze toegepast in het ontwerp van het systeem. Hier wordt verder gewerkt op het ontwerp dat in het vorige hoofdstuk werd gemaakt. Interrupt patroon Figuur 5.2 toont de toepassing van het interrupt patroon in het klassendiagram. Om het interrupt patroon toe te passen, wordt een klasse InterruptVector toegevoegd. Deze klasse bevat het adres van de routine die gestart moet worden bij het optreden van deze interrupt. Elke timer heeft zo een interruptvector, die hij, wanneer de timer afloopt, aanroept. Een verzameling van de verschillende interruptvectoren wordt bijgehouden in de loggerklasse, zodat, bij het aanmaken van een timer, de juiste interruptvector kan worden gelinkt. De routines, die worden aangeroepen bij het optreden van de timer, bevinden zich eveneens in de loggerklasse. De routine handleInterrupt sensor zal een temperatuur opvragen aan de sensor en deze opslaan. De routine handleInterrupt day zal de resultaten van die dag verwerken naar een statistische waarde. De werking van het interruptpatroon wordt aangetoond in de toestandsdiagrammen van de loggerklasse en de timerklasse. Figuren 5.3 en 5.4 tonen deze diagrammen. De loggerklasse zal bij het initialiseren de interruptvectoren aanmaken en deze toeleveren aan de timers, wanneer deze aangemaakt worden. Wanneer een interrupt optreedt, gaat de loggerklasse naar de overeenkomstige toestand, waar de nodige operaties worden uitgevoerd.
50
HOOFDSTUK 5. GEVALSTUDIE: MET ONTWERPPATRONEN Belangrijk is dat, bij het starten van de routine, de toestand van het systeem wordt opgeslagen, zodat na het optreden van de interrupt, het systeem kan verdergaan zoals ervoor. In het toestandsdiagram van de timer verandert er niet zo veel. In plaats van de timervlag aan te zetten, wordt de interruptvector aangeroepen. Pool Allocation patroon Voor de toepassing van het pool allocation patroon worden ´ voor het temperatuurtype en e´ en ´ voor de statistische twee geheugenpools gemaakt, e´ en waarden. Uit deze pools kunnen dan de tijdelijke waarden worden gehaald die nodig zijn voor het verwerken van de resultaten. Omdat de gegevenstypes, nadat ze worden vrijgegeven, terug in de pool belanden, wordt er geen geheugen gefragmenteerd. Figuur 5.5 toont hoe dit patroon het klassendiagram be¨ınvloedt. Er worden twee geheugenpools aan de loggerklasse toegevoegd. Voor elke pool is er een methode om een type te alloceren en een methode om een type vrij te geven. In figuur 5.6 wordt het toestandsdiagram van de loggerklasse getoond. In de initialisatie worden de twee pools aangemaakt: er worden een aantal lege types aangemaakt. Wanneer een tijdelijk gegevenstype nodig is, zoals in de process user output toestand, wordt er een type uit de pool gehaald en ingevuld met de gewenste waarden. Wanneer het type niet meer nodig is, wordt het terug vrijgegeven. Critical section patroon Een kritieke sectie beschermt een resource voor verkeerd gebruik. In dit systeem is de temperatuursensor zo een resource waarrond een kritieke sectie ´ thread tegelijkertijd een waarde aanvragen. wordt gelegd. Op deze manier kan slechts e´ en Figuur 5.7 toont het klassendiagram, aangevuld met het critical sectionpatroon. De algemene loggerklasse, die de rol van scheduler heeft, bevat de methoden om de kritieke sectie ¨ te starten en beeindigen. Deze klasse bevat ook het slot (de variabele taskSwitchingEnabled) dat aangeeft of de sensor in gebruik is of niet. Het kritische sectiepatroon geeft geen aanpassingen in het toestandsdiagram van de loggerklasse of de timerklasse. Om de werking van dit patroon toch te modelleren, is het een goed idee om hier een toestandsdiagram van de klasse temperatuursensor te maken. Figuur 5.8 geeft dit diagram weer. De sensor is steeds in een wachttoestand. Wanneer er een temperatuur wordt opgevraagd, gaat de sensor naar de readTemperature-toestand. In deze toestand start de sensor eerst de kritieke sectie, dan leest hij de temperatuur in. Tenslotte ¨ wordt de kritieke sectie beeindigd. Recursive containment patroon Het recursive containment patroon kan hier moeilijk worden toegepast, aangezien recursie op een klein systeem als dit moeilijk bereikt kan worden. Het heeft wel nut de klassen in te delen volgens functie, zodat bij latere uitbreiding van het systeem dit gemakkelijk kan verlopen en het patroon eenvoudig wordt toegepast. Figuur 5.9 toont hoe het klassendiagram wordt ingedeeld. De loggerklasse werd opgedeeld in twee klassen, een operatingklasse en een loggerklasse. de De loggerklasse bevatte veel functionaliteiten, die beter gescheiden worden over verschillende klassen. Zo is er nu een besturingsklasse, die alle functies op zich neemt die een besturingssysteem normaal zou uitvoeren, zoals het starten van een kritische sectie of toewijzing van een type uit een geheugenpool. De andere klasse, de nieuwe loggerklasse, bevat alle functionaliteit die met de werking van de thermometer te maken heeft, zoals het inlezen en opslaan van de temperatuur en het verwerken van de resultaten.
51
HOOFDSTUK 5. GEVALSTUDIE: MET ONTWERPPATRONEN Op deze manier bevatten de klassen niet te veel functionaliteit en is het eenvoudig terug te vinden waar welke operaties gebeuren. Layered patroon Het layered patroon kan hier worden toegepast. Figuur 5.10 toont hoe het klassendiagram kan worden gerangschikt zodat klassen die hoger staan ook een hoger niveau van abstractie hebben. Er zijn echter geen veranderingen aan de klassen nodig.
5.2.4
Implementatie
De implementatie van het systeem gebeurt, net als in het vorige hoofdstuk, manueel. De toepassing van ontwerppatronen maakt de implementatie van het systeem niet moeilijker. Het implementeren van de ontwerppatronen kan zelfs gemakkelijker genoemd worden, omdat elk patroon een handleiding bevat over hoe het ge¨ımplementeerd wordt.
5.2.5
Evaluatie
Het gebruik van ontwerppatronen biedt enkele significante voordelen tegenover een ontwerp zonder ontwerppatronen. • Elk aspect van een embedded systeem kan op verschillende manieren worden aangepakt, afhankelijk van de vereisten en eigenschappen van het systeem. De verschillende mogelijkheden worden beschreven in de verschillende ontwerppatronen. Elk patroon kan bij andere vereisten en eigenschappen gebruikt worden, waardoor er voor elk systeem er een patroon kan gevonden worden. Het patroon bevat een beschrijving van hoe het wordt toegepast en ge¨ımplementeerd. De ontwerper hoeft dus geen eigen oplossing te bedenken voor het probleem. Die eigen oplossing zal uiteindelijk toch lijken op het ontwerppatroon dat had kunnen toegepast worden. De ontwerper bespaart dus tijd bij het ontwerp en de implementatie. • Het ontwerp van het systeem is gestructureerd en gemakkelijk uit te breiden naar de ´ systeem werken, is overtoekomst toe. Ook wanneer verschillende mensen aan e´ en zichtelijkheid gewenst. Door een overzichtelijk ontwerp te maken, wordt later tijd bespaard bij de uitbreiding of aanpassing van het systeem. Het systeem in het ontwerp uit het vorige hoofdstuk bood voor de specifieke problemen van embedded systemen een slechte oplossing aan (bijvoorbeeld wat betreft geheugenbeheer, waar variabelen werden gealloceerd en vrijgelaten indien nodig, wat tot geheugenfragmentatie zou leiden). Voor deze problemen is nu een oplossing ge¨ımplementeerd die betrouwbaar is en zijn werking reeds heeft bewezen. Het kost ook minder moeite om deze patronen in het ontwerp te betrekken dan om nieuwe oplossingen voor de problemen te bedenken.
5.3
Besluit
De toepassing van embedded ontwerppatronen is een meerwaarde bij het ontwerp van embedded systemen. Er wordt tijd en bijgevolg ook geld uitgespaard wanneer patronen systematisch worden toegepast. Het ontwerpproces van executable UML laat het gebruik van ontwerppatronen volledig toe, waardoor ontwerppatronen gemakkelijk kunnen worden toegepast. Omdat ontwerppatronen elk een vaste structuur hebben, waarbij enkel de klassen die de verschillende rollen
52
HOOFDSTUK 5. GEVALSTUDIE: MET ONTWERPPATRONEN spelen moeten ingevuld worden, zouden ontwerptools ontwerppatronen ook automatisch kunnen toepassen. Zeker voor de gedragspatronen zou dit geen problemen mogen opleveren. Dit zou het toepassen van patronen nog gemakkelijker maken. De ontwerper zou dan enkel nog moeten uitmaken welk patroon hij wil gebruiken en aan de tool aangeven welke klassen participeren in het patroon. De rest van de toepassing van het patroon kan automatisch gebeuren.
53
HOOFDSTUK 5. GEVALSTUDIE: MET ONTWERPPATRONEN
(a) Domeingrafiek
(b) Domeinmodel
(c) Use cases
(d) Activiteitsdiagram
Figuur 5.1: Analysemodellen van het thermometervoorbeeld
54
HOOFDSTUK 5. GEVALSTUDIE: MET ONTWERPPATRONEN
Figuur 5.2: Klassendiagram met het Interruptpatroon
55
HOOFDSTUK 5. GEVALSTUDIE: MET ONTWERPPATRONEN
Figuur 5.3: Toestandsdiagram van de loggerklasse na toepassing van het interruptpatroon
56
HOOFDSTUK 5. GEVALSTUDIE: MET ONTWERPPATRONEN
Figuur 5.4: Toestandsdiagram van de timerklasse na toepassing van het interruptpatroon
57
HOOFDSTUK 5. GEVALSTUDIE: MET ONTWERPPATRONEN
Figuur 5.5: Klassendiagram met het Pool Allocationpatroon
58
HOOFDSTUK 5. GEVALSTUDIE: MET ONTWERPPATRONEN
Figuur 5.6: Toestandsdiagram van de loggerklasse met het Pool Allocation patroon
59
HOOFDSTUK 5. GEVALSTUDIE: MET ONTWERPPATRONEN
Figuur 5.7: Klassendiagram na toepassing van het Criticcal Section patroon
60
HOOFDSTUK 5. GEVALSTUDIE: MET ONTWERPPATRONEN
Figuur 5.8: Toestandsdiagram van de loggerklasse met het Pool Allocation patroon
Figuur 5.9: Klassendiagram na toepassing van het recursive containment patroon
61
HOOFDSTUK 5. GEVALSTUDIE: MET ONTWERPPATRONEN
Figuur 5.10: Klassendiagram na toepassing van het layered patroon
62
Besluit In deze thesis werd onderzocht in welke mate ontwerppatronen worden gebruikt bij ontwerp van embedded systemen. Er werd gekeken in welke mate deze patronen reeds werden ge¨ omgeving. Daarna werd aan de hand van het executable UML-proces bruikt in de industriele een gevalstudie opgezet die enerzijds het executable UML-proces evalueert en anderzijds de toepassing van patronen aantoont. Ontwerppatronen voor embedded systemen: theorie en praktijk Er is reeds veel onderzoek gedaan naar het gebruik van ontwerppatronen bij embedded systemen. Ik maak een onderscheid tussen patronen die specifiek voor een bepaalde hardware ¨ patronen, en de theoretische patronen die een algemene werden ontwikkeld, de industriele methode voorstellen. De theoretische patronen zijn op hun beurt op te delen in architecturale patronen, die de structuur van een systeem vastleggen, en de gedragspatronen, die de werking van het systeem modelleren. Het onderzoek naar theoretische ontwerppatronen werd vooral in de academische wereld ¨ context. Omdat patronen gevoerd, daarom maakte ik een tweede studie in een industriele gebaseerd zijn op best practices worden de meeste patronen reeds (gedeeltelijk) intu¨ıtief toegepast. Ze worden echter niet gestructureerd gebruikt, waardoor hun nut vaak verloren gaat. Er is een onderscheid te merken tussen de toepassing van architecturale en gedragspatronen. Architecturale patronen worden niet toegepast in die zin dat de structuur van het patroon in de praktijk nergens terug te vinden is. Het is juist die structuur die het patroon nuttig maakt. Gedragspatronen worden wel volledig toegepast, wat logisch is aangezien deze patronen het dichtst aanleunen bij de best practices uit de industrie. Executable UML is een afleiding van de UML standaard, waarbij ook een actie-specifieke taal wordt gespecifieerd. Dit zou executable UML uiterst geschikt maken om het modeldriven design proces te volgen. Er zijn echter nog enkele verbeteringen nodig om de taal een meerwaarde mee te geven bij gebruik in de industrie. Zo is de actie-specifieke taal die nu in de tools gebruikt wordt niet meer abstract dan een bestaande programmeertaal zoals Java of C++. De nieuwe taal leren om executable UML toe te kunnen passen zal geen extra meerwaarde opleveren. Tevens is het niet duidelijk of de analysefase, waarin onder andere de domeingrafiek wordt gemaakt, deel uitmaakt van het platform-onafhankelijke model. Ik denk van niet, omdat in de domeingrafiek ook over de implementatie-specifieke aspecten van het systeem wordt gesproken. Naar mijn oordeel wordt de analysefase dus best afzonderlijk van het modeldriven ontwerpproces gezien. Executable UML stelt enkel voor om een domeingrafiek op te stellen tijdens de analysefase. Het lijkt me echter ook aangeraden om eveneens van elk domein een domeinmodel op te stellen. Dit bespaart veel werk bij het opstellen van het ontwerp en biedt de ontwerper de kans om na te denken over het domein in een algemene, niet-technische context. 63
BESLUIT Ook datatypes die door een programmeertaal worden aangeboden, zoals bijvoorbeeld een datum-type, ontbreken en moeten zelf gemodelleerd worden. De meeste tools die executable UML ondersteunen, bieden codegeneratie aan. Deze gegenereerde code is echter niet volledig en zal door de programmeur nog moeten worden aangepast. Ook de automatische verificatie van de modellen is in de meeste tools nog niet vanzelfsprekend. Het is ook zeer de vraag of automatische verificatie en generatie ooit zal gerealiseerd worden. Model-driven ontwerp van embedded systemen Na de studie van ontwerppatronen en hun gebruik, werd een eigen applicatie ontwikkeld waarin enerzijds het executable UML-proces werd gebruikt en anderzijds ontwerppatronen werden toegepast. Er werd voor executable UML gekozen omdat dit een manier is om model-driven ontwerp te realiseren, gebaseerd op een gekende modelleringstaal, UML. Na evalatie van executable UML in het licht van het ontwerp van embedded systemen, merken we dat deze taal hiervoor in principe bruikbaar is. Een embedded systeem is echter afhankelijk van de hardware waarop het draait, waardoor een model van deze hardware in het ontwerp moet worden opgenomen. Hiervoor is in executable UML geen ruimte. Andere aspecten die belangrijk zijn bij het ontwerp van embedded systemen zijn geheugengebruik en rekencapaciteit waarmee bij automatische codegeneratie geen rekening wordt gehouden. Daarenboven is automatisch gegenereerde code doorgaans groot en min¨ dan code geschreven door een ervaren embedded programmeur. der efficient De toepassing van embedded ontwerppatronen is wel een meerwaarde bij het ontwerp van embedded systemen. Er wordt tijd en bijgevolg ook geld uitgespaard wanneer patronen systematisch worden toegepast. Het ontwerpproces van executable UML laat het gebruik van ontwerppatronen volledig toe. Omdat ontwerppatronen een vaste structuur hebben waarbij enkel de klassen die de verschillende rollen spelen moeten ingevuld worden, zouden ontwerptools ontwerppatronen ook automatisch kunnen toepassen. Zeker voor de gedragspatronen zou dit geen problemen mogen opleveren. Dit zou het toepassen van patronen nog gemakkelijker kunnen maken. De ontwerper zou dan enkel nog moeten uitmaken welk patroon hij wil gebruiken en aan de tool aangeven welke klassen participeren in het patroon. De rest van de toepassing van het patroon kan automatisch gebeuren. Wanneer model-driven ontwerp wordt gebruikt om een embedded systeem te ontwerpen, wordt het systeem op een vaste en gestructureerde manier ontwikkeld. Door eerst een model van het systeem te maken, kan het systeem op alle mogelijke manieren getest worden, voordat wordt overgegaan op de dure implementatie. Het gebruik van ontwerppatronen binnen dit proces levert extra garanties voor werkende, robuuste code en is essentieel voor een goed systeem. De huidige manieren om model-driven ontwerp toe te passen, zijn echter nog niet in het stadium waarin ze kunnen gebruikt worden om embedded systemen te ontwerpen. Er ¨ functionaliteiten zoals onder andere een manier om hardware te ontbreken nog essentiele modelleren. Ook het gebruik van ontwerppatronen in die processen, kan nog meer gestroomlijnd worden. Om een bredere toepassing te vinden van model-driven ontwerp in de ¨ omgeving, is het nodig dat deze functionaliteiten uitgebreid ondersteund worden. industriele
64
Bibliografie [1] et. al. A. Corsaro, D. C. Schmidt. Virtual component a design pattern for memory constrained embedded applications. Proceedings of the 9th Conference on Pattern Languages of Programs, Urbana, IL, USA, September, 2002. [2] K. Bjerge. Model-driven development for embedded systems: A case study in rhapsody. 2008. [3] BridgePoint. http://www.mentor.com. [4] Bruce P. Douglass. Real-Time Design Patterns: Robust Scalable Architecture for RealTime Systems. Reading, Massachusets: Addison-Wesley, 2003. [5] DSP Valley. http://www.dspvalley.com/. [6] E.D.&A. http://www.edna.eu/en/. [7] EE Times Embedded Design Center http://www.eetimes.com/design/embedded.
for
Electrical
Engineers.
[8] Embedded Systems Design. http://vault.embedded.com/. [9] EventHelix. Embedded Design Patterns. http://eventhelix.com/RealtimeMantra/Patterns/. [10] E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Reading, Massachusets: Addison-Wesley, 1995. [11] Object Management Group. Model driven architecture. http://www.omg.org/mda, last updated on 15 December 2010. [12] Matsuura S. Ito K. Model driven development for embedded systems. Recent Advances in Software Engineering, Parallel and Distributed Systems, pages 102–108, 2010. [13] Keil. ARM Compilation Tools. http://www.keil.com/arm/realview.asp. [14] BridgePoint Object Language. http://www.mentor.com. [15] Kennedy Carter Limited. Supporting model driven architecture with executable uml. http://www.kc.com/XUML. [16] S. Mellor and M. Balcer. Executable UML: A Foundation for Model-Driven Architecture. Reading, Massachusets: Addison-Wesley, 2002. [17] Pont Michael J. and C. Mwelwa. Developing reliable embedded systems using 8051 and arm processors: Towards a new pattern language. VikingPLoP, September, 2003. [18] MicroElektronica. EasyARM Development System ARM(NXP LPC) Development Board. http://www.mikroe.com/eng/products/view/95/easyarm/. 65
BIBLIOGRAFIE [19] Intel Software Network. Intel Embedded http://edc.intel.com/Step-by-Step/Design/.
66 Design
Center
-
Design.
[20] Visual Paradigm. http://www.visual-paradigm.com. [21] M. Pont. Patterns for Embedded and Time-Triggered Systems. Pearson Education Limited, 2001. [22] K. Soundararajan and Robert W. Brennan. A proxy design pattern to support real-time distributed control system benchmarking. HoloMAS, pages 133–143, 2005. [23] Wikipedia. Wikipedia domain model. http://en.wikipedia.org/wiki/Domain model, last updated on 15 April 2011. [24] Wikipedia - Embedded System. http://en.wikipedia.org/wiki/Embedded system.