Programming Project Report. Programmeringsprojekt i PaSOOS fagpakken. 20097733 Bobby Nielsen; 20097626 Jon Rune Jørgensen

Relaterede dokumenter
dsoftark E2007 Gruppe 14: Anders, Troels & Søren 15. november 2007 Rapport til a. 1 'TDD rytmen'

Begreber om Godt Software

RMI introduktion. Denne artikel beskriver Java RMI (Remtote Method Invocation).

Martin Olsen. DM507 Projekt Del I. 19. marts 2012 FOTO: Colourbox

Algoritmeskabeloner: Sweep- og søgealgoritmer C#-version

DANMARKS TEKNISKE UNIVERSITET

Kursusgang 11. Oversigt: Sidste kursusgang Værktøjer til udvikling og implementering af HCI-design Oversigt over Java Swing

//Udskriver System.out.println("Hej " + ditfornavn + " " + ditefternavn + "."); System.out.println("Du er " + dinalder + " aar gammel!

DM507 Algoritmer og datastrukturer

b) Udvid din implementation af forme til at understøtte.equals. To objekter af samme form er ens hvis de har samme værdier i felterne.

dsoftark E2007 Gruppe 14: Anders, Troels & Søren 15. november 2007 Rapport til a. 1

Abstrakte datatyper C#-version

SWC eksamens-spørgsmål. Oversigt

Ugeseddel 4 1. marts - 8. marts

Spil Master Mind. Indledning.

DM507 Algoritmer og datastrukturer

RMI avanceret. Denne artikel beskriver nogle mere avancerede features i RMI. Den gør det muligt at lave mere realistiske applikationer.

Målet for disse slides er at diskutere nogle metoder til at gemme og hente data effektivt.

Arkitektur for begyndere

DM507 Algoritmer og datastrukturer

Videregående Programmering Obligatorisk opgave - 3. semester, efterår 2004

Succesfuld implementering af automatiseret test

Grådige algoritmer. Et generelt algoritme-konstruktionsprincip ( paradigme ) for optimeringsproblemer.

University of Southern Denmark Syddansk Universitet. DM502 Forelæsning 4

Køreplan Matematik 1 - FORÅR 2005

Test af It-komponent

DM507 Algoritmer og datastrukturer

Test med JUnit 3. Denne artikel introducerer JUnit 3. Den forklarer ideen med JUnit. Og den viser hvordan man konkret bruger det.

DM507 Algoritmer og datastrukturer

Forelæsning Uge 2 Torsdag

Rekursion C#-version

SmartFraming Et vindue til nationale sundhedssystemer. Version 3.0

Introduction til.net remoting i C#

Forelæsning Uge 2 Torsdag

Ide med Diff. Mål. Tidsplan. 1.uge: 2.uge:

Secure O matic. Gruppe 5 2. SEMESTERPROJEKT. Udgave. Testspecifikation

Skriftlig eksamen i Datalogi

Indholdsfortegnelse for kapitel 3

Systematisk testning af program til udregning af mellemskat

Sortering. Eksempel: De n tal i sorteret orden

Exceptions i Delphi. Try except

Forelæsning Uge 2 Torsdag

Forelæsning Uge 2 Torsdag

I det kommende afsnit vil vi løbende komme ind på de enkelte resultater og samtidig komme med bud på, hvordan disse kunne løses i fremtiden.

Sortering af information er en fundamental og central opgave.

Sortering. Eksempel: De n tal i sorteret orden

Hvad er et distribueret objekt? Plan Objekter, objektreferencer, metoder, parameteroverførsel. Objekter: notation

import java.awt.event.*; import java.awt.*; Container <- Panel <- Applet Component <- Button <- Checkbox <- ScrollPane <- Label

Projekt - Visual Basic for Applications N på stribe

Introduction til.net remoting i VB.NET

DM507 Algoritmer og datastrukturer

Sortering af information er en fundamental og central opgave.

Forelæsning 17, tirsdag 2. november 1999 Søgning efter en given værdi i en tabel. Programmering 1999

A Profile for Safety Critical Java

Programmering C Eksamensprojekt. Lavet af Suayb Köse & Nikolaj Egholk Jakobsen

Skak, backgammon & dam

DM507 Algoritmer og datastrukturer

DRONNINGER (QUEENS) Opgave 1

Hassansalem.dk/delpin User: admin Pass: admin BACKEND

Indledning. Hvorfor det forholder sig sådan har jeg en masse idéer om, men det bliver for meget at komme ind på her. God fornøjelse med læsningen.

Listen over reserverede ord er meget lang, men de væsentligste vil jeg beskrive her i denne artikel:

Nye testteknikker fra ISTQB - direkte fra hylderne. Ole Chr. Hansen

PHP 3 UGERS FORLØB PHP, MYSQL & SQL

Test med NUnit. Denne artikel introducerer NUnit. Den forklarer ideen med NUnit. Og den viser hvordan man konkret bruger det.

Lavet af Danni jensen og David Olsen

Mm7: A little bit more about sorting - and more times for exercises - November 4, 2008

FESD-standardiseringsgruppen Att: Palle Aagaard IT- og Telestyrelsen IT-strategisk kontor Holsteinsgade København Ø

Invarianter. Invariant: Et forhold, som vedligeholdes af algoritmen gennem (dele af) dens udførelse. Udgør ofte kernen af ideen bag algoritmen.

Viditronic NDVR Quick Guide. Ver. 2.0

Obligatorisk projekt 3.

University of Southern Denmark Syddansk Universitet. DM502 Forelæsning 3

Målet for disse slides er at beskrive nogle algoritmer og datastrukturer relateret til at gemme og hente data effektivt.

Note om RMI af Peter Kjærsgaard

Grådige algoritmer. Et generelt algoritme-konstruktionsprincip ( paradigme ) for optimeringsproblemer.

ZBC Vordingborg Marcus Rasmussen, Oliver Meldola, Mikkel Nielsen 17/ The Board Game

App til indmelding af glemt check ud

R15 PaSOOS (22/ )

XProtect-klienter Tilgå din overvågning

Mircobit Kursus Lektion 3 (Du skal her vælge Lets Code Og nederst Microsoft Block Editor.)

Ferieregnskab (Rapport-ID: 74)

AAU, Programmering i Java Intern skriftlig prøve 18. maj 2007

Spilstrategier. 1 Vindermængde og tabermængde

JSP, Tomcat. Tutorial lavet af Jákup W. Hansen TSU semester 10.october 2007

Forelæsning Uge 2 Mandag

MJPower engineering Ecu Link.

Skriftlig eksamen i Datalogi

Algoritmedesign med internetanvendelser ved Keld Helsgaun

Unity Guide 1 CONTENTS

Procesbeskrivelse - Webprogrammering

Computerspil. Hangman. Stefan Harding, Thomas Bork, Bertram Olsen, Nicklas Thyssen og Ulrik Larsen Roskilde Tekniske Gymnasium.

Kursusarbejde 3 Grundlæggende Programmering

PHP guide af Daniel Pedersen

Studiepraktik. Thomas Bøgholm Mikkel Hansen Jacob Elefsen

Andengradsligninger. Frank Nasser. 12. april 2011

De rigtige reelle tal

Som sagt kræves der helst lidt viden om OOP hvis man virkelig vil lærer noget, og ikke bare lave copypaste

Omskrivningsregler. Frank Nasser. 10. december 2011

Introduktion til projekter

Lønstigning mellem to selvvalgte perioder (Rapport-ID: 67)

Greenfoot En kort introduktion til Programmering og Objekt-Orientering

Transkript:

Programming Project Report Programmeringsprojekt i PaSOOS fagpakken Underviser: Henrik Bærbak Christensen 08-06-2011

Indhold 1 Udvikling og test af binær søgning... 2 1.1 TDD på binær søgning... 2 1.1.1 Endelig test list... 2 1.1.2 Interessante iterationer... 2 1.1.3 Reflektioner... 4 1.2 Savoia, TDD og Black-Box Testing... 6 1.2.1 Sammenligning af Savoias tilgang ift. TDD principper... 6 1.2.2 TDD tilgang ift. Savoia fordele, ulemper og defekter... 8 1.2.3 Black-Box Testing teknikker... 9 1.2.4 Sammenligning af vores TDD test cases med vores EC+BV tests... 10 1.2.5 Sammenligning af vores EC+BV test cases med Savoias tests... 11 1.2.6 Beautifulness... 11 2. HotGammon GUI... 12 2.1 Boardgame framework... 12 2.2 Vores implementering... 12 2.2.1 Klassediaqgram... 13 2.2.2 Rollediagram... 15 2.2.3 Sekvensdiagram Move checker... 16 2.3 Udviklingsprocessen... 18 2.4 Samlede erfaringer... 18 3. Distributionseksperiment vha. Architectural Prototyping... 20 3.1 Dice roll scenariet... 20 3.2 Flyt af brik scenariet (Move checker)... 22

1 Udvikling og test af binær søgning 1.1 TDD på binær søgning En opgave der går ud på at udvikle algoritmen for binær søgning vha. TDD, en algoritme vi alle kender. Det store spørgsmål er om TDD er relevant til en sådan opgave. 1.1.1 Endelig test list 1. Returner -1, for array (Ø), hvor der søges efter værdien 1 (target). 2. Returner -1, for array (1,2,3), hvor der søges efter værdien 0 (target). 3. Returner 1, for array (1,2,3), hvor der søges efter værdien 2 (target). 4. Find midt af array: Returner 1, for array (1,2,3) med tre elementer. 5. Find midt af array: Returner 0, for array (1) med 1 element. 6. Find midt af array: Returner 2, for array (1,2,3,4) med 4 elementer. 7. Find første halvdel: Returner true, for array (1,2,3), hvor der søges efter værdien 1 (target). 8. Find anden halvdel: Returner false, for array (1,2,3), hvor der søges efter værdien 2 (target). 9. Returner 0, for array (1,2,3), hvor der søges efter værdien 1 (target). 10. Delarray: Find target med værdien 1 i array (1), og returner index 0. 11. Delarray: Returner -1 for array (2), hvor der søges efter 1 (target). 12. Delarray: Returner 0 for array (1,2), hvor der søges efter 1 (target). 13. Delarray: Returner 2 for array (1,2,3), hvor der søges efter 3 (target). 14. Returner 7, for array (0,1,2,3,4,5,6,7,8,9), hvor der søges efter værdien 7 (target). 1.1.2 Interessante iterationer Iteration 3 Test 3: Fjern fake it. Vi har behov for at finde den del af array som indeholder target. Derfor har vi brug for at finde midten af array, og teste om target er større eller mindre. Vi skriver en test, som kan drive udviklingen af en metode, som kan finde midten af array. Vi tilføjer test 4 til testlisten, og sætter iteration 3 på stand by, mens vi går videre med test 4. Test list 1. Returner -1, for array (Ø), hvor der søges efter værdien 1 (target). 2. Returner -1, for array (1,2,3), hvor der søges efter værdien 0 (target). 3. Returner 1, for array (1,2,3), hvor der søges efter værdien 2 (target). 4. Find midt af array: Returner 1, for array (1,2,3) med tre elementer. Det interessante ved iteration 3 er anvendelse af TDD princippet Child Test. Test 3 er egentlig en test af den endelige metode til binær søgning. Idet vi har brug for en metode til at håndtere en mindre del af algoritmen, introducerer vi en mindre test case for at fremdrive en ny metode, en hjælpemetode om man vil. Efterfølgende tog vi fat i test 3 igen i iteration 9, hvor testen endte med at blive fuldført med succes. Iteration 7

Vi kan nu finde midten af arrayet, og har brug for at finde ud hvilken halvdel, som target findes i. Vi har altså behov for at undersøge om target er mindre end værdien i midtpunktet (første halvdel) eller større eller lig med midtpunktet (anden halvdel). Test 7: Vi skriver en test som kan fremtvinge en metode til at bestemme, hvilken halvdel som target er i. Vi anvender Fake It, og lader blot metoden returnere true. Vi skriver endnu en test for at triangulere, og fremdrive metodens andet retursvar (returtypen er en boolean). Test list 1. Returner -1, for array (Ø), hvor der søges efter værdien 1 (target). 2. Returner -1, for array (1,2,3), hvor der søges efter værdien 0 (target). 3. Returner 1, for array (1,2,3), hvor der søges efter værdien 2 (target). 4. Find midt af array: Returner 1, for array (1,2,3) med tre elementer. 5. Find midt af array: Returner 0, for array (1) med 1 element. 6. Find midt af array: Returner 2, for array (1,2,3,4) med 4 elementer. 7. Find første halvdel: Returner true, for array (1,2,3), hvor der søges efter værdien 1 (target). 8. Find første halvdel: Returner false, for array (1,2,3), hvor der søges efter værdien 2 (target). Iteration 7 indførte en boolsk metode, til bestemmelse af om target er i første eller anden halvdel af den del af array som der søges i. Denne iteration viser anvendelsen af Fake It, med efterfølgende triangulering ved at tilføje en ny test til listen, som kan teste/fremdrive metodens andet retursvar. Iteration 13 Test 12: Testen skrives, og den fejler. Det viser sig, at det ikke er helt let at få testen igennem. Vi taget et break, og laver en do over. Efter at være startet forfra på søgning i delarray fuldføres testen OK, andre tests fejler, men de guider os i retningen af løsningen. Efterhånden fuldføres alle tests OK. Et par dages break og en do over resulterede i, at vi hurtigt fik denne test igennem. Refactoring: I vores metode til at finde midtpunktet af array har vi overført arrayet som parameter, hvilket vi ser ikke er nødvendigt. Vi retter testene af metoden til, og lader dette drive fjernelsen af parameteren. Alle tests er OK igen. Vi ser et behov for at triangulere yderligere, og tilføjer test 13. Test list 1. Returner -1, for array (Ø), hvor der søges efter værdien 1 (target). 2. Returner -1, for array (1,2,3), hvor der søges efter værdien 0 (target). 3. Returner 1, for array (1,2,3), hvor der søges efter værdien 2 (target). 4. Find midt af array: Returner 1, for array (1,2,3) med tre elementer. 5. Find midt af array: Returner 0, for array (1) med 1 element.

6. Find midt af array: Returner 2, for array (1,2,3,4) med 4 elementer. 7. Find første halvdel: Returner true, for array (1,2,3), hvor der søges efter værdien 1 (target). 8. Find anden halvdel: Returner false, for array (1,2,3), hvor der søges efter værdien 2 (target). 9. Returner 0, for array (1,2,3), hvor der søges efter værdien 1 (target). 10. Delarray: Find target med værdien 1 i array (1), og returner index 0. 11. Delarray: Returner -1 for array (2), hvor der søges efter 1 (target). 12. Delarray: Returner 0 for array (1,2), hvor der søges efter 1 (target). 13. Delarray: Returner 2 for array (1,2,3), hvor der søges efter 3 (target). Iteration 13 må nok siges, at være en af de vigtigste iterationer i vores løsning. Det er her vi formår, at finde frem til target i et array med mere end et element. Test First og Assert First er de principper som først anvendes. Test First, som det primære i TDD. @Test public void shouldreturnindex0for2elementsarraywithtarget() { assertequals( 0, bs.searchpartarray(new int[]{1,2}, 1, 0, 1) ); } Iterationen startede med en session af et par timers varighed, som ikke førte til at vores nye, og de gamle tests kunne fuldføres med succes. Udviklingen gik i stå. Vi kom ingen vegne. Sessionen endte med beslutningen om at bruge to TDD principper: Break og Do Over. Efter et par dage, blev udviklingen genoptaget, dvs. iterationen startet forfra fra scratch, og efterfølgende blev iterationen afsluttet på ca. en halv time. Et godt eksempel på både Break og Do Over. I iterationen er det en kombination af den nye test og de gamle tests, som fremdriver produktionskoden. Efter at den nye test var OK, var der ældre tests som fejlede, og som derfor var med til at triangulere en løsning på plads. I løbet af iterationen viste det sig, at metoden til at finde midtpunktet i array ikke var optimal. Der var bl.a. ikke behov for at overføre vores array, som parameter, hvilket testene skrevet mhp. på metoden ellers havde fremdrevet. Lidt refactoring: Rettelse til parameterlisten medførte en ændring af metoden, som efterfølgende udførte opgaven bedre, og på en måde som var mere anvendelig i omfavnende metoder. 1.1.3 Reflektioner Efter vores mening er TDD ikke velegnet til at fremmane en defineret algoritme. Med TDD udvikles funktionalitet, der som sådan er defineret med test cases. Disse tests tester som sådan produktionskoden, som en black box, og tager ikke hensyn til algoritmen, som er anvendt i metoderne. En af de gode ting ved TDD er netop, at algoritmen i produktionskoden ikke vurderes. Det betyder, som vi ved, at vi kan ændre en algoritme, og hvis testen fuldføres OK, så er algoritmen, set fra en funktionel vinkel, i orden. Det var ikke en let opgave, at forsøge at fremtvinge en binær søgealgoritme med TDD. Det at ingen produktionskode må skrives, uden at en test kræver det, finder vi noget besværligt ifm. at udvikle algoritmen. Man skal tage virkelig små skridt for at sikre, at man følger TDD til punkt og prikke, hvilket betyder, at man i udviklingen af en algoritme, som denne, skal indføre en masse metoder for at produktionskoden skal være drevet frem af testkoden. Dette kan betyde, et performance overhead. I vores første forsøg kom vi frem til en metode, som kunne returnere det delarray, hvori target befandt sig. Det

betød, at der blev oprettet et array, hver gang den sorterede række af elementer blev halveret. Et performance overhead, som er stærkt uønsket i en søgealgoritme. Vi har anvendt TDD Rhythm og TDD principper, er som sådan lykkedes med at anvende principperne. Det er vores opfattelse, at TDD generelt ikke er velegnet til udvikling af algoritmer, men derimod udvikling af produktionskode, som repræsenterer noget funtionalitet.

1.2 Savoia, TDD og Black-Box Testing En sammeligning af Alberto Savoias tilgang til test af algoritmen for binær søgning ift. TDD og Black-Box Testing principper. 1.2.1 Sammenligning af Savoias tilgang ift. TDD principper I følgende tabel diskuteres hvorvidt Savoia anvender principper fra Test Driven Development (TDD). TDD Principle Test First Test List One Step Test Isolated Test Evident Tests Savoia s approach Savoia tager udgangspunkt i en kendt algoritme for binær søgning, og derfor anvender han ikke dette princip. Ydermere laver han en lille rettelse af produktionskoden, da han er bekendt med et problem, som opstår med meget store arrays. Efterfølgende ønsker han at lave tests som kan bevise algoritmens korrekthed. Hen ad vejen er der dele af funktionen, som han gerne vil teste for sig selv. Dog vælger han ikke at skrive testen først. Derimod koder han den ændring som han gerne vil teste før han skriver testen. Så han driver ikke noget på plads med tests. Han laver sine tilpasninger for, at han kan lave tests af dele af funktionen. Savoia opretter ikke en test liste, som han kan tage udgangspunkt i og vedligeholde hen ad vejen. I stedet beskriver han en strategy for hvordan han vil udføre en række tests. Hans strategi er at starte med en smoke test, tilføje nogle tests af grænseværdier, fortsætte med flere grundige og udtømmende tests, og slutte af med nogle performance tests. Hen ad vejen beskriver Savoia meget kort hvad det er for noget, han vil teste, men han har ikke en struktureret liste, hvor alle hans test cases er beskrevet. På et tidspunkt i forløbet begynder Savoia at definere nogle teorier, som egentlig er nogle udsagn, som skal gælde for den binære søgefunktion. Disse teorier programmerer han som tests. Efterhånden finder han på flere teorier, som danner grundlag for tests. Listen af teorier er det nærmeste Savoia kommer en egentlig TDD Test List, men han er ikke konsekvent omkring definitionen af teorier for alle tests. Savoia starter med smoke tests, som er test af det mest basale i algoritmen. De simpleste tests laver han først, og fortsætter med mere og mere komplekse tests. Som sådan starter han med tests som han er sikker på og lette at lave, og som han egentlig lærer af i forhold til at finde på flere og mere udtømmende tests. Savoia bruger også sine smoke tests til at opbygge en tillid til produktionskoden. Tests som man hurtigt kan eksekvere hver dag. Som sådan er det samme ide, som findes i TDD, da man her også gøres tryg af at se tests gå succesfuldt igennem. Savoia vælger at samle flere af sine tests, i hvad der svarer til en junit test case. Eksempelvis samler han fem tests i en ifm. sine grænseværditests af midtpunktsberegningen. Dette betyder at han mindre præcist ved hvori en eventuel fejl ligger i beregningen. Ydermere laver han tests som egentlig udfører op imod 1000 tests med tilfældige værdier på flere af hans test teorier i en udførsel. Denne samling af flere tests gør det igen sværere at få et præcist indblik i hvad og hvordan der testes, samt hvor og hvordan fejl opstår. Savoia s testkode er ikke nødvendigvis særlig simpel. I flere tilfælde anvender han løkker og tilfældighedsgeneratorer for at udføre en større mængde tests. Dette gør testkoden testkoden langt mere kompleks og mindre præcis, end hvis man havde defineret hver enkelt test med konstante værdier for

Fake It Triangulation Assert First Break Evident Data Obvious Implementation Representative Data Automated Test Test Data Child Test Do Over Regression Test parametre. Dette vil også betyde, at testen kan udføres præcis ens hver gang. Man kan stille spørgsmålstegn ved, om der bør være et eneste tilfældigt element i testkode. Savoia bruger som sådan ikke princippet. Der er dog et tilfælde, hvor han indfører noget midliertidigt produktionskode, som han anvender til at finde ud af om hans tests er gode nok. En form for Fake It-kode som returnerer et resultat, som kan bruges til at verificere testen. Savoia triangulerer ikke produktionskode på plads. Han laver tests af grænseværdier, der som sådan er enslydende tests, blot med forskellige parametre. Dette svarer som sådan til en triangulation, og han kan tilpasse produktionskoden i fald testen fejler. Savoia tester produktionskode som er skrevet, og dermed benytter han ikke dette princip. I de enkelte tilfælde hvor han retter produktionskoden, gør han det før han skriver sine tests. Savoia skriver, at hvis man vil lave smuk kode, kan det hjælpe at træde væk fra produktionskoden, og se på den med kritiske øjne, ved at lave tests. Dette kan muligvis hjælpe, hvis man er kørt fast i et problem i udviklingen. Mht. til evident data kan vi ikke sige meget til Savoias tests. Hovedsagligt er det simpelt at forstå hvad der testes, hvilket dog også skyldes, at testdataene naturligt er simple. I Savoias test, hvor han anvender en tilfældighedsgenerator, er det af gode grunde ikke til at vide, hvad det er for testdata der anvendes. Disse tests er knap så gennemskuelige, og det er kun givet hvad antallet af tests er, max antal elementer i array, samt max værdi i array. Savoia vælger,at opdele koden i flere funktioner. Det gør han for at muliggøre test af delelementer af algoritmen. Disse funktioner, som er simple, implementerer han uden videre. I gennem sit forløb med skrivning af tests af søgealgoritmen kommer Savoia godt rundt om de områder der er vigtige at teste. Hans får testet grænseværdierne, både med hensyn til værdierne i arrayet og indexværdierne. Savoia anvender junit til at automatisere sine tests. Savoia går ind for udviklere skriver automatiseret tests til deres kode, men han mener, at der vil gå en rum tid før størstedelen af udviklere er overbevist og skriver testkode i deres daglige udviklingsarbejde. Savoias testdata er rimelig tilfældig. Det kommer særdeles til udtryk iden del af hans tests, som anvender en tilfældighedsgenerator til generering af testdata. Kun i Savoias tests af grænseværdier er der tænkt over testdataene. Her ser vi dog, at han tænker godt og grundigt over testdata, og kommer godt rundt. Savoia udfører som sådan ikke nogen child tests på baggrund af en for stor test. Men han omskriver sin produktionskode for at teste et delement af algoritmen, og skriver dernæst en mindre test, som kan teste dette delemenet. I forløbet med at teste den binære søgealgoritme kommer Savoia ikke til et punkt, hvor han ikke umiddelbart kan komme længere, og har derfor ikke behov for at lave en Do Over. Savoia går ind for regression test. Det giver udvikleren tillid til koden. Savoia skriver også, at han er glad for at samle alle sine smoke tests i en test suite,

som kan hurtigt kan udføres ifm. hver build. Tillid og tro på koden er vigtigt for Savoia, ligesom det er en vigtig grundsten i TDD. 1.2.2 TDD tilgang ift. Savoia fordele, ulemper og defekter Fordele ved TTD ift. Savoias tilgang: 1. Der er tests til al produktionskode. Ikke kun tests til de elementer af funktionen, som synes kritiske. Savoias tests udspringer groft set fra hans fantasi, hvilket betyder, at hans fantasi sætter grænsen for hvad der bliver testet. 2. Alle vores TDD tests kan genproducere en eventuel fejl 100 % sikkert. Det skyldes, at vi ikke som Savoia indfører tests, med tilfældigt input. I de tests, hvor Savoia anvender tilfældigt input, kan han ikke udføre præcis den samme test hver gang, hvilket er en risiko, da han ikke 100 % sikker kan genteste en fejl. Ydermere bliver Savoias tests unødvendigt komplicerede, og han kan lettere komme til at indføre fejl i testkoden. 3. TDD sikrer, at alle udviklere har det samme mål, nemlig det mål at skabe noget kode, ved at skrive nogle tests som driver koden frem. Savoias tilgang er hans egen, og det er hans ideer om tests, som kommer til udtryk. Som han skriver, er det forskelligt fra udvikler til udvikler. Med TDD er der en række principper, man som udvikler skal følge, hvilket betyder en større ensretning af de tests der skrives ift. den funktionalitet som skal skabes. Ulemper ved TDD ift. Savoias tilgang: 1. TDD er grundlæggende anvendelig til udvikling af kode (produktionskode), og ikke til test af kode, som er givet. Mange af TDD principperne tager udgangpunkt i at der skal skrives noget produktionskode, og ikke bare testkode. Derfor ser vi i vores udvikling ikke så meget på hvad der er vigtigt at teste for algoritmen. Derimod søger vi at skrive tests, som kan skabe algoritmen. For Savoias vedkommende er algoritmen givet, og han kan koncentrere sig om, at skrive tests som tester algoritmen. Forskellen er derfor, at vi søger at skabe en algoritme vha. TDD, hvor Savoia går efter at teste om algoritmen er korrekt, og om er der dele af implementeringen der vil medføre fejl. 2. Vi har i denne opgave erfaret, at TDD ikke er specielt egnet til udvikling af en særlig algoritme. Som sådan er valget af algoritmer ligegyldig ifm. med TDD. Ved udvikling med TDD, søger vi netop, at skrive tests som tester funktionaliteten, og lader valget af algoritmer være åbent. Således kan algoritmer optimeres eller udskiftes, uden at det påvirker funktionaliteten. 3. Vi har, med vores TDD udvikling, ikke nogen tests, som søger at teste grænseværdier. Årsagen til dette er, at TDD ikke lægger op til tests af grænseværdier, men derimod til tests som kan drive udvikling af noget funktionalitet. Defekter nævnt af Savoia, som eksisterer i vores implementation: 1. Vores implementation risikerer at resultere i en integer overflow exception, da vi ikke har været opmærksomme på at teste søgning i arrays af så stor størrelse, så denne exception kunne forekomme. Idet vores søgemetode er opdelt i mindre metoder, med forskelligt ansvar, så kan vi let indføre en test, som kan teste aspekterne af at finde midtpunktet i array, og dermed teste os frem til en løsning, som ikke medfører en overflow exception.

2. Vi har ikke nogen tests, som søger at teste grænseværdier. Årsagen til dette er, at TDD ikke lægger op til tests af grænseværdier, men derimod til tests som kan drive udvikling af noget funktionalitet. 3. Vi har ingen tests, som sikre, at vores implmentation rent faktisk er en binær søgning. Savoia gør det, at han laver en særlig implementering af den binære søgning, hvor han tilføjer nogle linier kode, som tæller antallet af sammenligninger, og det resultat, som han lader metoden returnere er antallet af sammeligninger, som der skal til for at finde target, men han leverer ikke positionen af target med retur, hvilket vil sige, at metoden kun kan bruges til at tælle antal sammenligner, og dermed om algoritmen tilsvarer effektiviteten af en binær søgning. I vores implementation kunne vi tilpasse koden lidt, og tilføje en decorator (Decorator pattern), som kunne have til ansvar, at tælle antal sammenligninger. 4. Ingen af vores tests indeholder negative tal, hvilket betyder, at vi som sådan ikke er sikre på, at vores algoritme kan håndtere negative tal. Men som sagt bør test skrevet ifm. TDD ikke stå alene, men bør bistås af tests som udspringer af ækvivalensklassepartitionering og grænseværdianalyse. 1.2.3 Black-Box Testing teknikker Applikering af black-box testing teknikkerne Equivalence classes (EC) og boundary value analysis (BV) på algoritmen for binær søgning. 1. Equivalence classes Condition Invalid ECs Valid ECs Input array er tomt Array.length = 0 [1] Input array indeholder Array.length = 1 [2] et element Input array indeholder Array.length mod 2 = 1 [3] et lige antal elementer Input array indeholder Array.length mod 2 = 0 [4] et ulige antal elementer Input array indeholder Array[0..n] < 0 [5] negative elementer Input array indeholder Array[0..n] > 0 [6] positive elementer Input array indeholder Array[0..n] = 0 [7] neutrale (0) elementer Preconditions Integer [8]; Sorted [9] tilfredsstillet Preconditions ikke tilfredsstillet Non integer [10]; Not sorted [11] Target i array Integer [12] Target ikke i array Integer [13] Target er positivt Integer [14] Target er negativt Integer [15] Target er 0 Integer [16] 2. Test cases, hvor vi udelader alle ECs hvor preconditions ikke tilfredsstilles.

ECs covered Test case Expected output [1],[13],[16] ({Ø}, 0) -1 [2],[7],[12],[16] ({0}, 0) 0 [2],[7],[13],[14] ({0}, 1) -1 [3],[6],[12],[14] ({0,1,2}, 1) 1 [3],[6],[13],[14] ({0,1,2}, 4) -1 [4],[6],[12],[14] ({0,1}, 1) 1 [4],[6],[13],[14] ({0,1}, 2) -1 [3],[6],[12],[14] ({0,1,2}, 1) 1 [3],[6],[13],[14] ({0,1,2}, 4) -1 [2],[7],[13],[15] ({0}, -1) -1 [3],[5],[12],[15] ({-3,-2,-1}, -1) 2 [3],[6],[13],[15] ({0,1,2}, -4) -1 [3],[5],[13],[15] ({-3,-2,-1}, -4) -1 [4],[5],[12],[15] ({-1,0}, -1) 0 [4],[6],[13],[15] ({0,1}, -2) -1 [4],[5],[13],[15] ({-1,-2}, -3) -1 [3],[5],[12],[15] ({-3,-2,-1}, -1) 2 [3],[6],[13],[15] ({0,1,2}, - 4) -1 3. Boundary value analysis Test case Expected output ({Ø}, 0) -1 ({0}, 0) 0 ({0}, Integer.MIN_VALUE) -1 ({0}, Integer.MAX_VALUE) -1 ({Integer.MIN_VALUE, 0}, Integer.MIN_VALUE) 0 ({0, Integer.MAX_VALUE }, Integer.MAX_VALUE) 1 De EC og BV test cases vi her er kommet frem til, kan vi kode tests ud fra. Vi kan dermed supplere vores TDD test cases, og opnå en mere udtømmende test af vores algoritme for binær søgning. 1.2.4 Sammenligning af vores TDD test cases med vores EC+BV tests En sammenligning af hvorvidt vores TDD test cases matched vores EC og BV tests. Vi ser på om henholdvis TDD fandt nogle tests som EC og BV ikke gjorde, og omvendt. Vores TDD test cases dækker delementer af algoritmen, hvorfor nogle af vores TDD tests ikke er sammenlignelige med vores EC og BV tests. I vores TDD test cases har vi ingen tests, hvor array indeholder negative værdier, eller hvor target er negativt. Det har vi derimod i vores EC og BV tests. Derudover har vi ingen TDD tests hvor array indeholder et enkelt neutralt element (0) eller udelukkende neutrale elementer (kun 0 er). Vi har heller ingen TDD test cases som grænseværdierne for en integer, hvilket vores BV tests gør. Øvrige EC og BV tests dækkes af vores TDD tests, dog ikke med helt de samme arrays og targets, men forskellene her er kun en mindre forskydning af værdier i array eller target. Til gengæld dækkes vores TDD

test case 14 ikke af EC og BV tests, og det er den af vores test med det største array. Egentlig burde vi have tests, som tester de øvre grænser for størrelsen af array. 1.2.5 Sammenligning af vores EC+BV test cases med Savoias tests 1. Savoia tester med nogle arrays, som er væsentligt større en alle de arrays, vi har i vores tests. Derfor kan han være mere sikker på, at søgning også fungerer efter hensigten med de større arrays. Han tester dog heller ikke de øvre grænser for størrelsen af array. 2. Ligesom os tester Savoia med et array med element, hvor target henholdsvis er og ikker er i array. 3. Savoia tester ikke den binære søgemetode, som en black box, idet han går ind og ekstrahere midtpunktberegning i en selvstændig metode, således han kan teste for integer overflow exception. I vores EC og BV analyse har vi set på søgningen som en black box, hvorfor vi ikke her har tests af midtpunktberegningen. 4. Ligesom Savoia tester vi, hvor vi forventer, at target er på henholdsvis første midterste og sidste plads i array. 5. Ligesom Savoia tester vi med arrays indeholdende Integer MIN_VALUE og MAX_VALUE, og hvor vi søger efter disse to grænseværdier i array. 6. Vi har ikke som Savoia nogle test, hvor værdier er genereret tilfældigt. 7. Savoia har en test af effektiviteten af søgningen, hvilket vi ikke har i nogen af vores tests. 1.2.6 Beautifulness Om noget er smukt (beautiful) er et spørgsmål om smag. Vi mener ikke Savoia s fremgangsmåde er smuk. Han tester de aspekter af algoritmen, som han kan komme frem til på forskellige måder. Men spørgsmålet er om hans tests er fyldestgørende? Efter vores mening er TDD smukkere, idet produktionskoden drives frem af testkoden, som betyder test af produktionskoden som sådan er fyldestgørende, og så er testene med sikkerhed skrevet. Det er smukt. Som bekendt skal TDD ikke stå alene. Der bør suppleres med ækvivalensklasseanalyse, grænseværditests mm. Måske er det smukke ved tests, at det faktisk er en ret stor udfordring at få gennemført en komplet test.

2. HotGammon GUI Udvikling af en GUI til HotGammon (Backgammon). 2.1 Boardgame framework I forbindelse med udvikling af en GUI til HotGammon har vi valgt at bruge BoardGame udvidelsen til MiniDraw-frameworket. Det betyder at vi i forbindelse med initieringen af MiniDraw gør brug af bl.a. BoardActionTool og BoardDrawing fra BoardGame. BoardActionTool er et værktøj specielt tilpasset til brætspil, der gør det muligt at flytte brikker og klikke på ubevægelige figurer (Props) og få udført en handling, der er tilknyttet til den aktuelle figur. BoardDrawing er ligeledes specielt tilpasset til brætspil, og håndterer visningen af brætspillets figurer. BoardDrawing er i sig selv et 'frozen spot', men konfigureres via tre hotspots, nemlig FigureFactory, PositionStrategy og PropAppearanceStrategy, der henholdsvis bruges til at definere startopstillingen af spillets figurer, den eksakte placering af figurerne på brættet og til ændring af de ubevægelige figurers fremtræden. BoardDrawing implementerer BoardGameObserver, der spiller Observer-rollen i Observer Pattern, og har ansvaret for at gentegne spillets figurer ved notificering af ændringer i spillet. I forbindelse med FigureFactory defineres Maps med de figurer (BoardFigure) der vises i spillet. En BoardFigure defineres af et billede, en angivelse af om figuren kan bevæges, samt et hotspot til en Command. Denne Command spiller Command-rollen i Command Pattern. 2.2 Vores implementering Ovenstående er udgangspunktet for vores integration af HotGammon- og MiniDraw/BoardGameframeworks. FigureFactory har vi implementeret i klassen 'HotGammonPieceFactory', der initerieres med en instans af Game. Ud fra brikkernes placering i Game genereres et tilsvarende Map over brikkernes placering til brug for MiniDraw. I denne klasse defineres også et Map over de ubevægelige figurer (terningerne). I forbindelse med oprettelsen af figurerne tilknyttes en Command til hver af disse. Vi har implementeret to typer af Commands, nemlig 'MoveCommand' og 'DieRollCommand', der bruges i forbindelse med oprettelse af henholdsvis brikker og terninger. Execute-metoderne i disse Command-implementeringer kalder relevante metoder i Game, når der spilles. PositionStrategy har vi implementeret i klassen 'HotGammonPositioningStrategy'. Her defineres den eksakte placering af brættets figurer. I forbindelse med brikkernes placering bruges hjælpeklassen 'Convert'. For de ubevægelige figurers vedkommende returneres de samme positioner hver gang. PropAppearanceStrategy har vi implementeret i klassen 'HotGammonPropAppearanceStrategy'. Her defineres ud fra terningernes værdier i Game, hvilke billeder der skal vises for de to terninger. Efter initiering af henholdsvis Game og GUI, vil vi gerne have at GUI'en bliver notificeret om ændringer i Game. Derfor har vi tilføjet GUI'en som Observer til Game. Desværre var den type Observer som BoardDrawing implementerer, nemlig BoardGameObserver, ikke kompatibel med den type Observer som

vores Game opererer med, så her blev vi nødt til at lave en Adapter: 'GameObserverAdapter', for at kunne tilføje en Observer af den rigtige type til Game. 2.2.1 Klassediaqgram Herunder ses klassediagram (figur 1) udvisende de udviklede klasser med implementerede interfaces og deres sammenhæng.

GameObserver GameObserverAdapter HotGammon +main(args :String[]) -editor :DrawingEditor -boardgameobserver :BoardGameObserver<Location> +GameObserverAdapter(e :DrawingEditor) +checkermove(from :Location, to :Location) +dicerolled(values :int[]) +setmessage(message :String) Factory -game :Game HotGammonFactory +HotGammonFactory(game :Game) +createdrawingview(editor :DrawingEditor) :DrawingView +createdrawing(editor :DrawingEditor) :Drawing +createstatusfield(editor :DrawingEditor) :JTextField -game :Game PropAppearanceStrategy HotGammonPropAppearanceStrategy +HotGammonPropAppearanceStrategy(game: Game) +calculateimagenameforpropwithkey(key :String) :String Constant +die1propname :String +die2propname :String PositioningStrategy<Location> HotGammonPositioningStrategy +calculatefigurecoordinatesindexedforlocation(location :Location, index :int) :Point +calculatefigurecoordinatesforprops(keyofprop :String) :Point FigureFactory<Location> HotGammonPieceFactory Convert -game :Game +HotGammonPieceFactory(game :Game) +generatepiecemultimap() :Map<Location, List<BoardFigure>> +GeneratePropMap() :Map<String, BoardFigure> -maplocation2rectangle :Map<Location, Rectangle> +xy2location(x :int, y :int) :Location +locationandcount2xy(location :Location, count :int) :Point -definelocation2rectanglemap() -processarectangleforlocation(l :Location, r :Rectangle) -game :Game Command DieRollCommand +DieRollCommand(game :Game) +execute() :boolean +setfromcoordinates(fromx :int, fromy :int) +settocoordinates(tox :int, toy :int) -game :Game -dx, dy, tx, ty :int Command MoveCommand +MoveCommand(game :Game) +execute() :boolean +setfromcoordinates(fromx :int, fromy :int) +settocoordinates(tox :int, toy :int) Figur 1 - Klassediagram

2.2.2 Rollediagram Herunder ses et rollediagram (figur 2) som beskriver anvendelsen af patterns, samt sammenhængen mellem de implementerede klasser og interfaces. HotGammon Strategy:Strategy PropAppearanceStrategy HotGammonPropAppearanceStrategy Abstract Factory:Abstract Factory Strategy:Concrete Strategy Factory Strategy:Strategy PositioningStrategy<Location> HotGammonFactory HotGammonPositioningStrategy Abstract Factory:Concrete Factory Abstract Factory:Concrete Product Strategy:Concrete Strategy Abstract Factory:Abstract Factory BoardDrawing FigureFactory<Location> HotGammonPieceFactory Abstract Factory:Concrete Factory Command:Command Command Command MoveCommand Command:Concrete Command Command:Receiver Observer:Subject Adapter:Client <<interface>> Game Adapter:Adaptee <<interface>> BoardGameObserver DieRollCommand Command:Concrete Command <<interface>> GameObserver Adapter:Target GameObserverAdapter Adapter:Adapter Observer:Observer Observer:Concrete Observer Figur 2 - Rollediagram

2.2.3 Sekvensdiagram Move checker Herunder ses sekvensdiagram (figur 3) som viser protokollen mellem vores game framework og Minidraw, når en bruger flytter en brik fra en position til en anden.

Figur 3 - Sekvensdiagram: Move checker

2.3 Udviklingsprocessen Ved udvikling af GUI har vi brugt TDD-principper, idet vi er gået ud fra en testliste og taget små skridt. Vi startede med kun at vise selve brættet og enkelte brikker og terninger. Dernæst gik vi videre til at kunne vise figurer der var defineret i Game og ikke bare i GUI'en. Først ved at bruge et simpelt StubGame med kun to brikker, og siden udvide til at bruge en mere udbygget Gameimplementering. I denne fase har vi fået vores FigureFactory og PositionStrategy på plads. I næste fase er vi begyndt at flytte med brikkerne ved at tilføje BoardActionTool, og en Command til brikkerne (MoveCommand). I første omgang har vi bare udskrevet til konsollen, når en brik er flyttet, for dernæst at kalde move-metoden i en Game-implementering. Her har vi også brugt et simpelt StubGame, der også bare udskrev til konsollen, når et træk var udført. I sidste fase arbejdede vi på at kunne reagere på notificeringer fra Game. Dette drejede sig bl.a. om at kunne vise hvilket terningekast der er blevet slået. Her har vi via en Adapter tilføjet en Observer til Game, og fået udviklet en PropAppearanceStrategy og en Command til terningerne (DieRollCommand). Notificeringer om bevægelse af brikker er også kommet på plads i denne fase. Senere har vi tilføjet muligheden for at vise statustekst i GUI'en. Efter at have lavet en GUI til spillet, var det meget lettere lige at teste forskellige scenarier, som man ellers ikke lige havde tænkt over tidligere. Det kunne f.eks. være at tage modstanderens brik og rykke den i sin egen retning, eller at tage brikker fra brættet, selv om det ikke er tilladt. Det medførte at vi efter kun få spil havde en længere liste over defekter ved vores spil: Selv om man har brikker i baren, kan man rykke med sine andre brikker. Det er altid sort der starter. Man får ikke fire træk ved to ens terninger. Man kan tage brikker fra brættet, selv om man har brikker andre steder end sit indre hjemland. Man kan ikke bruge højere terningekast til at tage brikker fra brættet. Hvornår er der fundet en vinder Brikker der har slået en anden brik ud, opfører sig underligt Disse defekter er dog blevet udbedret nu. 2.4 Samlede erfaringer Set i bakspejlet er det faktisk ikke særlig meget kode, der skal skrives for at integrere Game og GUI. Det betyder imidlertid ikke, at det bare er noget man sætter sig ned og gør på 5 minutter. I hvert fald ikke første gang man bruger et framework. Til indlæring af hvorledes et framework skal bruges, er det en god hjælp at se hvorledes andre projekter gør brug af frameworket. Også selv om det er en helt anden type brætspil.

Og når man går i gang med integrationen mellem Game og GUI er det ligeledes en stor hjælp at anvende principper fra TDD, såsom at lave en testliste og tage små skridt. Dermed er det lettere at holde fokus, så man ikke mister overblikket, fordi man vil for meget på en gang. Endelig skal det igen nævnes at for vores vedkommende betød tilstedeværelsen af en GUI, at det blev meget mere synligt, hvilke regler vi ikke havde fået implementeret korrekt fra starten af.

3. Distributionseksperiment vha. Architectural Prototyping Målet er at lave en architectural prototype, som vi kan eksperimentere med (sandbox), således vi kan komme frem til en model for distribution af vores spil HotGammon. Vi ønsker at komme frem til en model for distribution, der medfører at domain kode udføres på en server, og GUI kode udføres på en klient (klassisk client/server arkitekttur). I vores AP (arkitektturprototype) er det eneste interessante forbindelsespunkterne mellem domain og GUI. Her vil der ved distribution være behov for implementering af funktionalitet, som kan interagere over netværket. I vores AP vil vi derfor kun fokusere på, at arbejde med protokollen mellem domain og GUI. Det vil vi gøre ved, at udskrive udførte metodekald til skærmen. For at kende rækken af metodekald og dermed forbindelsespunkterne mellem domain og GUI, vil vi indsamle (høste) data om dette fra det oprindelige system (spil) vha. JSeq. JSeq kan f.eks. anvendes til trace af metodekald udført ifm. handlinger udført i et program. 3.1 Dice roll scenariet Step 1 Analyse af dice roll Indsamling af data vedr. dice roll med JSeq. [JSeq] hotgammon.view.dierollcommand.setfromcoordinates [JSeq] hotgammon.view.dierollcommand.settocoordinates [JSeq] hotgammon.view.dierollcommand.execute [JSeq] hotgammon.domain.common.gameimpl.nextturn [JSeq] hotgammon.domain.common.gameimpl.winner [JSeq] hotgammon.domain.variants.gammamonwinnerstrategy.determinewinner [JSeq] hotgammon.domain.common.gameimpl.getcount [JSeq] hotgammon.domain.common.gameimpl.getcount [JSeq] hotgammon.domain.variants.randomdicerollstrategy.rolldice [JSeq] hotgammon.domain.common.gameimpl.identicaldice [JSeq] hotgammon.domain.common.gameimpl.identicaldice [JSeq] hotgammon.view.gameobserveradapter.dicerolled [JSeq] hotgammon.view.hotgammonpropappearancestrategy.calculateimagenameforpropwithkey [JSeq] hotgammon.domain.common.gameimpl.dicethrown [JSeq] hotgammon.view.hotgammonpropappearancestrategy.calculateimagenameforpropwithkey [JSeq] hotgammon.domain.common.gameimpl.dicethrown [JSeq] hotgammon.domain.common.color.tostring [JSeq] hotgammon.view.gameobserveradapter.setmessage Step 1 Harvest og implementation De primære komponenter er GameImpl og GameObserverAdapter. For disse to klasser laver vi stubklasser. hotgammon.domain.common.gameimpl APGameImpl hotgammon.view.gameobserveradapter GUI Vi tager kun den kode (harvesting), som skal til for at lave et scenarie tilsvarende spillets. Det vil sige Observer koden, og kode som er nødvendig for at scenariet har den rigtige sekvens af metodekald. Derudover laver vi en klientklasse (ArchProto), som kan kalde GUI-klassens metoder.

Ved udførsel udskriver de enkelte metoder til System.out, hvilket viser sekvensen af metodekald. Step 1 Konklusion Vi har nu vores AP version 1, hvor vi har høstet (harvest) scenariet fra originalkoden. Vores AP s adfærd efterligner arkitektonisk et terningkast, som det udføres, når en spiller klikker på en terning (dice roll). Vi kan vælge, at tilføje yderligere scenarier, eller at arbejde på distribution af scenariet for terningkastet. Step 2 RMI Vi vælger,at indføre distribution med RMI til vores scenarie i AP en. Vi starter med refactoring af koden, således at hver klasse findes i hver sin fil. Fælles kode lægger vi i archproto.common, klientkode (ArchProto og GUI) i archproto.client og serverkode (APGameImpl) i archproto.server. Vi laver to ant target. Target ap-server starter serveren, og target ap-gui starter klienten. Vi indfører RMI mellem domain og view. APGameImpl o extends UnicastRemoteObject o throws RemoteException o RMISecurityManager o Starter RMI på port 60000 (LocateRegistry.createRegistry(60000)) o Binder servicen (Naming.rebind("//" + host + ":60000/Game", apgame);) GUI o o extends UnicastRemoteObject catch(remoteexception re) ArchProto o Forbinder til service (Game game = (Game)Naming.lookup("//" + host + ":60000/Game");) GameObserver o extends Remote o throws RemoteException Game o o extends Remote throws RemoteException Color, Location o implements Serializable java.security.policy (java.policy) Step 2 Resultat Vi kan nu starte vores server i en prompt og klienten i en anden prompt, og se hvorledes programmerne interagerer via RMI (over localhost).

Kun view objekter Kun domain objekter Step 2 Konklusion Vi har nu: Modularisering (en klasse pr. fil) Introduceret RMI Henholdsvis server- og klientprogram Build (java.policy fil og run targets) Vi har formået at distribuere terningkastet vha. RMI på localhost. Dette har vi gjort i et sikkert miljø (sandbox), hvor vi ikke har risikeret, at ødelægge vores originalkode. Vi har nu i vores AP et eksempel på den kode, som vi har brug for, til implemetering af RMI i vores spil. 3.2 Flyt af brik scenariet (Move checker) Med samme fremgangsmåde kan vi tilføje, det scenarie, som udspiller sig ifm. flyt af en brik. Vi udfører følgende: Indsamling af sekvens for metodekald med JSeq. Harvesting Indfører kun de nødvendige metoder i vores stubklasser, hvor disse metoder udskriver deres metodenavn til skærmen. Indfører RMI på de nye metoder. Resultat Før indføring af RMI (begge scenarier udført sekventielt):

Efter indføring af RMI (begge scenarier udført sekventielt): Konklusion Vi har nu indført RMI for scenarierne for terningkast og flyt af brik i vores AP. I forbindelse med at RMI indføres for det første scenarie, er der en masse RMI opsætning som kommer på plads, og der er knap så mange ændringer som skal laves ved implementering af RMI for de efterfølgende scenarier. Retrofitting af RMI-koden vi er kommet frem til i vores AP i spillet (originalkoden) er ikke noget, vi har udført. Dette var dog heller ikke en del af kravene til opgaven. Anvendelse af en arkitekturprototype anser vi som en god strategi for eksperimentering med forskellige udvidelser til et system. Den oprindelige funktionalitet (originale scenarier) kan simuleres simpelt, og de mere komplekse eksperimenter kan udføres uden at ødelægge originalkoden, og uden at være påvirket af de originale processeringer.