Hovedopgave. OpenSign Refaktorering. af Paw Figgé Kjeldgaard DATALOGISK!INSTITUT! Master i Informationsteknologi. linien i Softwarekonstruktion
|
|
|
- David Paulsen
- 9 år siden
- Visninger:
Transkript
1 DATALOGISK!INSTITUT! DET!NATURVIDENSKABELIGE!FAKULTET! AARHUS!UNIVERSITET! Hovedopgave Master i Informationsteknologi linien i Softwarekonstruktion OpenSign Refaktorering af Paw Figgé Kjeldgaard 14. Juni 2012 Paw F. Kjeldgaard, studerende Henrik B. Christensen, vejleder
2 OpenSign Refaktorering Paw Figgé Kjeldgaard EVU Master Thesis, Aarhus Universitet, 14. Juni 2012 Abstract Test driven development (TDD) has gained considerable ground in most developing departments, because the technique has proved strong to handle the changes without losing reliability. This is done by having the code under test control. What to do if you want to transfer the qualities that the TDD process leads to, to a software system where there are no tests? Michael C. Feathers has in his book "Working Effectively With Legacy Code" described various techniques of how to achieve and preserve software qualities of reliability and testability in software systems, previously not under test control, when you have to make changes. The use of the techniques require, however, often having to make changes in the existing code to decouple dependencies. However, the changes are sufficiently small, and is carried out in such a way that the risk of introducing defects, is very small. Instead of having to bring an entire software system under test control before one can make a change, one can just bring that part of the system under test control, as will be affected by a given change. For this purpose, Michael C. Feathers defined an algorithm process of change, and described some techniques for how to analyze their way to what needs to be tested. This report uses Michael C. Feathers techniques to show how two tasks can be solved, and describes the experience gained. 2
3 Indholdsfortegnelse 1 Motivation Problemformulering Metode Analyse og Resultat Forandrings algoritme Teknikker til at identificere steder hvor der skal ændres Teknik til at identificere steder der skal testes Afkoblings teknikker Hyperaware redigering Single-Goal redigering Bevar signaturer Stol på compileren Par programmering Test kontrol Tilføjelse af ændringer Kvalitets attributter & taktikker Fleksibelt design Refaktorering af CAPI plugin Identificér steder hvor der skal ændres Find de steder der skal testes Afkobl afhængigheder Skriv tests En rigtig unit test Tests cases Revew af test kode Refaktorer og indfør kopositionelt design Udfør ændringer og refaktorer Fjernelse af gammel Bouncy Castle version Identificér steder hvor der skal ændres Find de steder der skal testes Bryd afhængigheder Skriv tests Refaktorer og indfør kompositionelt design Udfør ændringer og refaktorer Opsummering Fremtidig arbejde Konklusion Referencer Appendix Afkoblings teknikker Tilpas parameter Flyt metode til objekt Eksponer statisk metode Udtræk og overskriv kald Udtræk og overskriv factory metode Udtræk og overskriv getter Udtræk interface
4 8.1.8 Introducer instans delegator Introducer statisk setter Parameter riser constructor Parameter riser metode Flyt metoder op Flyt afhængigheder ned Erstat global reference med getter Nedarv og overskriv metode Skabelon redefinering
5 1 Motivation OpenSign er en samling af Java-applets der giver client-side digital signering funktionalitet ved hjælp af X.509 certifikater. OpenSign består i øjeblikket af to applets, én til at signere tekster og en anden der giver login funktionalitet. OpenSign er et open-source projekt som i dag primært er drevet af Nets DanID A/S. Hen over de sidste 3 år er der sket mange gennemgribende ændringer i OpenSign. Nogen af ændringerne har gået ud på at få ryddet op og fjernet afhængigheder til gamle Java versioner, som ikke supporteres mere. Andre rettelser er lavet for at understøtte nye kryptografiske algoritmer. Den mest gennemgribende ændring har dog været udskiftning af det grafiske framework, for at kunne leve op til det offentliges tilgængeligheds krav [Tilgængelighed]. Der er dog stadig et par steder i arkitekturen, hvor man endnu ikke har fået ryddet op. Et af de steder er det JNI lag som mapper til Windows CAPI. Dette lag gør det muligt at anvende de certifikater og private nøgler, der er installeret i Windows, inde i appletten. Fra og med Java 6 tilbyder JRE en adgang til Windows CAPI via et standard API. Derfor ønsker man at udfase JNI laget. Desuden vil det lukke op for, at man nemt også kunne lave et plugin til keychain, som er den komponent Mac computere benytter til at opbevare certifikater og nøgler, da selv samme API giver adgang til keychain. Denne funktionalitet har længe stået på ønskesedlen hos forretningen. CAPI er en service som tilbyder udviklere af Windows-programmer mulighed for at udføre kryptografiske funktioner. Servicen indeholder følgende funktionalitet: Kryptografiske nøgler. Session eller konventionelle nøgler til data kryptering og private / offentlige nøgler til nøgle transport eller nøgleudveksling. Kodning og de-kodning af data. Serialisering af dataobjekter til ASN.1 koder for transport og når de anvender digitale signaturer. Understøttelse af BER og DER kodning. Data kryptering og dekryptering. Message Digest og digitale signaturer. X.509 certifikater. En binding af attributter til en offentlig nøgle. Bindingen er sikret gennem en Certificate Authority s digitale signatur. CAPI understøtter data strukturer for håndtering af X.509 certifikater samt certifikat opbevaring med gem, hent, slet, list og kontrol funktioner. 5
6 Figur 1 - Illustration af CAPI også kaldet CryptoAPI Udskiftningen af JNI laget vil samtidig løse et potentielt sikkerhedsproblem der findes i appletten. Problemet ligger i at man er nød til først, at gemme det native bibliotek (.dll fil) på det lokale fil system og derefter via Java API læse biblioteket ind. Dette giver en angriber mulighed for, at erstatte biblioteket med ondsindet kode på klientens computer. Risikoen for at dette sikkerhedshul vil blive udnyttet er vurderet som lav. Et andet sted hvor man ønsker at få ryddet op i OpenSign, er der hvor man har en afhængighed til en gammel Bouncy Castle (BC) version (krypto bibliotek). Denne afhængighed vil man gerne have fjernet, men ingen har endnu påtaget sig opgaven, hvilket primært skyldes at man ikke kan gennemskue konsekvenserne ved at fjerne BC. Disse bekymringer går primært ud på om man får introduceret defekter. Man vil gerne ændre OpenSign til at bruge det kryptografiske standard API, der ligger i de nye Java versioner. Dette kan give nogle fordele i forhold til færre udviklings og vedligeholdelses omkostninger, samt at det som tidligere skrevet åbner op for kodegenbrug og adgang til andre certifikat og nøgle opbevarings typer. Lige fra starten af, da man udviklede OpenSign, brugte man ikke meget tid på at dokumentere og designe arkitekturen. Desuden er der lige fra start af ikke skrevet nogen automatiske tests. Man har lavet en lille demo web applikation, som gør det muligt at starte OpenSign med forskellige konfigurationer. Denne har man benyttet til at teste OpenSign manuelt. OpenSign lever til fulde op til Michael Feathers definition på legacy kode, som simpelthen er kode uden tests [Feathers]. Resultatet af ikke at have tests, som Feathers også påpeger, er at udviklere ikke tør refaktorere med fare for at introducere flere defekter. I stedet tilføjer de ekstra kode, som oftest resulterer i øget kompleksitet, hvilket i sidste ende øger muligheden for defekter. Et andet resultat er, at man 6
7 ender med et system, der indeholder klasser med metoder, der er næsten umuligt at teste. Eller at der ikke er struktur på kode, og at der trænger til at blive ryddet op (kan bl.a. ses ved at den samme kode går igen flere steder). Disse symptomer gør sig også gældende i OpenSign. Legacy kode Legacy kode, er kode uden tests. Kode unden tests er dårlig kode. Det er lige meget hvor godt det er skrevet. Det er lige meget hvor pænt eller objekt orienteret eller godt indkasplet det er. Med tests kan man ændre opførsel af koden hurtigt og verificerbart. Uden tests ved man ikke om koden bliver bedre eller dårligere. [Feathers] Testdreven udvikling (TDD) er efterhånden ved at blive almindelig kutyme i de fleste udviklings afdelinger. TDD er en teknik til at udvikle software, der kan modstå ændringsønsker uden at miste pålidelighed [Beck 2002]. Ved brug af TDD får man et øget fokus på software arkitektur kvalitets attributterne modificerbarhed, testbarhed og pålidelighed. For at kunne anvende TDD til at løse de to ovenstående opgaver, skal man have bragt OpenSign under test kontrol. Hvordan griber man det an? Er det muligt at få lavet automatiske tests, som udviklerne kan afvikle under refaktorisering af koden? 7
8 2 Problemformulering Hypotese Ved hjælp af de teknikker som Michael C. Feathers (Feathers) beskriver i bogen Working Effectively With Legacy Code [Feathers], er det muligt at bringe OpenSign under test kontrol. Denne opgave vil evaluere teknikkernes anvendelighed i forbindelse med to refaktorings opgaver, som er beskrevet under motivationen. Opgaverne handler om et subsystem af OpenSign, der skal refaktoriseres for at fjerne en afhængighed til en ældre version af et krypto bibliotek. Samt et JNI lag der skal udskiftes med et standard API, der følger med i nyere Java versioner. Denne opgave ville ikke bringe hele OpenSign under test kontrol. Den vil i stedet forsøge, at anvende de teknikker. som Feathers beskriver til at bringe de 2 subsystemer under testkontrol, så de to refaktorerings opgaver kan udføres med den ønskede pålidelighed. 8
9 3 Metode For at løse opgaven gennemlæses bogen Working Effectivelively With Legacy Code [Feathers] skrevet af Michael C. Feathers (Feathers). Først anvendes Feathers teknikker til at analysere hvilke metoder og klasser, der skal testes i forbindelse med de to refaktorerings opgaver. Derefter anvendes Feathers teknikker til at få afkoblet afhængigheder til anden kode og få indført test kode. Der laves en vurdering af hvor mange tests der skal skrives, for at opnå den ønskede pålidelighed. Gennem det konkrete arbejde vil jeg forsøge at forholde mig kritisk til teknikkerne, og vurdere hvad der virker, og hvad der virker i mindre grad. 9
10 4 Analyse og Resultat For at kunne lave ændringer i legacy kode, så bør man have koden under test kontrol. Dette er et stort dilemma i legacy kode, da det oftest kræver kode ændringer for at kunne implementere tests. Ændringer i kode indebærer risikoen for, at introducere defekter i den eksisterende kode. Dette er det store legacy kode dilemma. Legacy kode dilemma Når kode skal ændres, bør ændringen være understøttet af tests. Men for at introducere tests skal koden ændres. [Feathers] Når man arbejder med at få legacy kode under test kontrol, så arbejder man typisk med tre problem stillinger: registrere, separation & seams. Ideelt set ønsker man ikke at lave ændringer til den eksisterende legacy kode. Man ønsker at kunne lave objekter og skrive tests for dem. Hvorefter man kan foretage sine ændringer. Men desværre er dette ikke altid så nemt. Ofte er man nød til at afkoble afhængigheder for at kunne teste de enkelte klasser og det skyldes tre årsager: 1. Registrere afhængigheder afkobles når det ikke er muligt at tilgå de værdier ens kode beregner, og derfor via tests er umuligt at teste om beregningerne er korrekte. 2. Separation afhængigheder afkobles til at adskille, når man ikke kan få noget kode til køre i et test forløb. Det kan f.eks. være en afhængighed til et subsystem, som man så laver en stub, der simulerer dets opførsel under test. 3. Seams - Den sidste problem stilling er seam s, som er det i sted hvor i koden, hvor det er muligt at ændre på programmets opførsel, uden at man har editeret på det sted. En hver seam har et aktiverings punkt, et sted hvor det muligt at bestemme, hvilken opførsel der skal gælde. Feathers definition på seams stemmer overens med definitionen på hotspots fra framework teorien. Ved brug af bl.a. Feathers afkoblings teknikker, så er det muligt at skabe disse hotspots i legacy koden. Dette kan være nødvendigt i forbindelse med test formål. Hotspot Et sted i koden hvor specialisering kode kan ændre opførsel eller tilføje opførsel til et framework. [Christensen 2007] 10
11 Framework Et framework er et sæt af samarbejdende klasser, der udgør et genbrugligt design til en bestemt klasse af software. [GoF] Hvilken problemstilling der er sværest at håndtere, er svært at give et præcist svar på. Typisk er man nød til at håndtere dem alle, og det er grunden til at man afkobler afhængigheder i legacy kode for at kunne få koden under test kontrol. 4.1 Forandrings algoritme Det kan virke som en temmelig stor opgave at få et helt legacy system under test kontrol, før man kan foretage en ændring. I stedet foreslår Feathers, at man går ind og analyserer hvilken del af systemet der bliver påvirket af en given ændring, og får denne del under test kontrol. Til dette foreslår han at man benytter følgende forandrings algoritme: Forandrings algoritme 1. Identificér steder hvor der skal ændres. 2. Find de steder der skal testes. 3. Afkobl afhængigheder. 4. Skriv tests. 5. Udfør ændringer og refaktorer. [Feathers] Denne opgave vil benytte ovenstående forandrings algoritme til at løse de to opgaver (se afsnit 1), og prøve de teknikker af som Feathers beskriver, der kan hjælpe en igennem algoritmen Teknikker til at identificere steder hvor der skal ændres For at kunne identificere de steder der skal ændres, så skal man forstå sit system. For at lære sit system at kende, foreslår Feathers at man tegner skitser af det. Dette behøver ifølge Feathers ikke at være formelle UML diagrammer, men kan sagtens nøjes med at være simple diagrammer (se Figur 2). Ifølge Feathers vil skitserne uanset udformning kun blive anvendt under analysen af systemet, og skitserne vil være ulæselige for dem, som ikke deltog i analysen. Derfor vælger man notation efter behov. Feathers foreslår at man genbruger notationen fra effekt skitserne (se afsnit 4.1.2). 11
12 Figur 2 skitse af dispatcher Teknik til at identificere steder der skal testes For at finde de steder i koden der skal testes, foreslår Feathers, at man anvender effekt skitse teknikken. Der er ikke meget syntaks i en effekt skitse. Ideen bag syntaksen er at have en separat boble for hver variabel, der kan blive påvirket, og hver metode hvis returværdi kan ændre sig. Nogen gange er variablerne i samme objekt, og andre gange er de på forskellige objekter. Det er ligegyldigt: der laves en boble for de ting der vil ændre sig, og der trækkes en pil til alt, hvis værdi kan ændre sig på runtime på grund af dem. Figur 3 - kombineret effekt skitse Afkoblings teknikker Feathers har beskrevet en række refaktorerings teknikker til at afkoble afhængigheder kategoriseret som dependency-breaking techniques (se appendix 8.1). Disse teknikker kan anvendes uden, at der på forhånd findes test til at bryde afhængigheder og indføre tests. Disse teknikker giver ingen garanti for ikke at introducere defekter. Men ved at følge Feathers fem følgende metodikker kan det mindske risikoen: Hyperaware redigering Single-Goal redigering Bevar signaturer Stol på compileren Par programmering Hyperaware redigering Hyperaware redigering er en mental tilstand hos udvikleren. En tilstand hvor udvikleren har ekstrem fokus på hvert eneste tastaturanslag. Udvikleren ved præcist hvilken konsekvens, hvert 12
13 tastaturanslag har. Brug af automatiske test og par programmering er med til at fremme hyperaware redigering Single-Goal redigering Single-Goal redigering er at have fokus på kun, at udføre en ting ad gangen. At lave ændringer i legacy kode i små skridt, og få dem til at virke, før man går i gang med næste ændring. Dette er også en af nøgle værdierne i testdreven udvikling [TDD] Bevar signaturer Bevar signaturer er en metode til, at mindske muligheden for at indføre defekter i koden under refaktorering. Metoden anvendes bl.a. i teknikken flyt metode til objekt, som kan ses anvendt i afsnit Her kopierer man en metodes signatur med over i det nye objekts constructor, netop for at man skal foretage færrest mulige ændringer i den originale kode Stol på compileren Stol på compileren er en metode til at identificere de steder i koden, der ikke mere kan compilere efter en kode ændring. Det kunne for eksempel være en global variabel, der var blevet indkapslet i en klasse. Compileren finder så automatisk alle de steder, hvor koden ikke mere kan compilere, fordi den globale variabel ikke længere er tilgængelig. Det er vigtigt at holde for øje, at denne metode kun kan anvendes til at lave strukturelle ændringer i koden eller foretage type ændringer. Hvis den anvendes til andet, er der stor risiko for at introducere defekter Par programmering Par programming er en af de 12 Best Pratices fra Extreme Programming [Beck 2000]. I forbindelse med afkobling af afhængigheder anbefaler Feathers par programmering på grund af den kontinuerlige review effekt, som par programmering har Test kontrol For at få legacy kode under test kontrol skrives en række automatiske tests, som består af unit tests. Unit tests kan have forskellige formål, alt efter hvilken situation man befinder sig i: Unit tests der bliver skrevet under testdreven udvikling (TDD), og derfor skrives før produktions koden. Disse tests er med til at beskrive systemets forventede opførsel. Disse tests er med til at sikre at systemet bevarer opførslen efterhånden som systemet udvikler sig, da de opdager utilsigtede ændringer. Unit tests der skrives i forbindelse med fejlretning. Til dette kan man også anvende TDD. I så fald laves der en test, der 13
14 illustrerer defekten ved at testen fejler. Når testen ikke fejler længere, så er defekten rettet. Unit tests der dokumenterer hvordan et system opfører sig. Disse unit tests kalder Feathers for Characterization Tests. Characterization Tests er ifølge Feathers [Feathers] velegnede til legacy kode. Når man skal skrive tests til legacy kode, så er det vigtigt at holde fokus på hvad systemet gør, og ikke hvad det formodes at gøre. Ellers ender man ud i en fejlfindings situation. Derfor giver det heller ikke mening at finde en specifikation frem, og implementere tests ud fra denne, da man ikke kan være sikker på at systemet følger pågældende specifikation. Dette kan skyldes at specifikationen ikke er blevet opdateret efterhånden, som man har tilføjet ny funktionalitet til systemet. Selv om alle tre ovenstående punkter illustrerer forskellige formål med at indføre unit test, har de alle det til fælles, at de bevarer funktionalitet. Når først unit testene er oprettet og indgår i ens test forløb, så er de med til at opdage utilsigtede funktionalitetsændringer under refaktoreringer, eller når der tilføjes ny funktionalitet. For at man med tiden får sit legacy system under test kontrol, så har Feathers opstillet brug af metode reglen (se nedenstående). Denne regel siger, at før man anvender en metode i kode basen af legacy kode, så skal man tjekke, om der findes test for denne metode; hvis ikke, så skal man starte med at skrive test for metoden, før man kalder metoden. Brug af metode reglen Før man bruger en metode i et legacy system, check om der eksisterer tests for den. Hvis der ikke gør det, så skriv nogen. Når man gør det konsekvent, bruger man tests som et medium for kommunikation. Folk kan se på dem og få en fornemmelse af, hvad de kan og ikke kan forvente fra den metode. Den handling at gøre en klasse testbar er i sig selv en tendens til at øge kodens kvalitet. Folk kan finde ud af, hvad der virker, og hvordan, de kan ændre det, rette det, rette fejl, og komme videre. [Feathers] 14
15 4.1.5 Tilføjelse af ændringer Når man skal tilføje ændringer til legacy kode anvender man TDD rytmen. TDD rytmen består af fem trin, som gentages igen og igen. De fem trin er: TDD rytmen 1. Tilføj en test 2. Kør alle tests og se at den nye test fejler 3. Lav en lille ændring 4. Kør alle tests og se at alle tests kører 5. Refaktorer for at fjerne gentagelser [Christensen 2007] Hvis man kun ønsker at refaktorere, for at lave strukturelle ændringer til legacy kode basen, så følger man stadig TDD rytmen. Man springer dog trin 1 og 2 over. I trin 3 laver man så sin refaktorering, hvor efter man i trin 4 kører alle tests, for at sikre at man ikke har fået indført nogen defekter Kvalitets attributter & taktikker Bass har defineret en række kvalitetsattributter [Bass et al., 2003], der benyttes til at beskrive kvaliteten af softwaren. En kvalitetsattribut udtrykker et mål for, hvordan ens system reagerer på et givet input. Til beskrivelse af dette indfører Bass seks begreber: Source of Stimulus, Stimulus, Environment, Artifact, Response og Response Measure, som udgør beskrivelsen af en kvalitetsattribut. Figur 4 - De seks begreber der beskriver en kvalitetsattribut Brugen af disse begreber kan ses illustreret i Figur 5, som viser et eksempel på kvalitetsattributten testbarhed for scenariet code coverage. 15
16 Figur 5 Eksempel på kvalitetsattributten testbarhed der viser et scenarie for kode coverage Alle kvalitetsattributter indeholder en metrik, hvilket betyder at de skal være målbare. Et eksempel på en metrik er 85% path coverage skal opnås på tre timer taget fra ovenstående scenarie. Kvalitetsattributterne skal desuden være systemspecifikke for at kunne benyttes i praksis. Kvalitetsattributter kan grupperes i en række kvalitetskarakteristika, som pålidelighed, modificerbarhed, ydeevne, sikkkerhed, testbarhed og brugervenlighed. Feathers afkoblings teknikker har høj fokus på kvalitetsattributterne testbarhed og pålidelighed gennem hans afkoblings teknikker forbundet med de fem metodikker (se afsnit 4.1.3). Pålidelighed omhandler systemfejl og associerede konsekvenser. En systemfejl opstår, når systemet ikke længere leverer en service, i overensstemmelse med specifikationen. En sådan fejl kan observeres af systemets brugere - enten mennesker eller andre systemer. Testbarhed omhandler den lethed, med hvilken software kan laves til at demonstrere sine fejl gennem (typisk udførelse-baseret) tests. For at et system er tilstrækkeligt testbart, skal det være muligt at styre hver enkelt komponents interne tilstand og input, og derefter observere dets output. Dette sker ofte gennem brug af en test sele, specialiseret software designet til at bearbejde software under test. Når man har høj fokus på nogle enkelte kvalitetsattributter kan det have konsekvenser for andre. Brugen af Feathers afkoblings teknikker har konsekvenser for kvalitetsattributten modificerbarhed. Dette kommer jeg ind på senere. 16
17 Modificerbarhed handler om hvor meget det koster at lave en ændring. Når en ændring er blevet specificeret, skal den nye implementering designes, implementeres, testes og idriftsættes. Alle disse tiltag tager tid og koster penge, og er i begge tilfælde målbare. Figur 6 - Eksempel på kvalitetsattributten modificerbarhed der viser et scenarie for ændring i UI Et system design består af en række beslutninger. Nogle af disse beslutninger har indflydelse på hvordan en kvalitetsattribut reagerer, andre sikrer at man opnår den ønskede funktionalitet. De beslutninger der har indflydelse på kvalitetsattributterne, går også under betegnelsen taktikker. Figur 7 - Taktikker er beregnet til at kontrollere reaktioner på stimuli Feathers teknikker har stor fokus på, at man under afkobling ikke får indført defekter. De teknikker som jeg har i anvendelse i denne opgave, kan jeg kun medgive, at der er en meget lille risiko for at indføre nye defekter, hvis man følger de fem metodikker (se afsnit 4.1.3). Når man så har fået implementeret sine Characterization Tests, så er disse med til at sikre, at man fremover får at vide, hvis man får indført en defekt i den del, som er under test kontrol. Efterfølgende bidrager TDD rytmen til at sikre pålideligheden og måske endda forbedre den. Dette kan ske ved at man skriver en række tests der tester den nye funktionalitet kan håndtere forskellige situationer, som f.eks. fejl detektering. Feathers afkoblings teknikker er i høj grad med til at forbedre systemets testbarhed. Afkoblings teknikkerne gør at man får kontrol med en klasses input og interne tilstand, og derefter kan observere dens output. Taktikken som bliver fulgt er en del af manage input/output taktikkerne (se Figur 8), hvor man med nogle af 17
18 afkoblings teknikkerne forsøger at separere fra implementering, så i de tilfælde, hvor man har en implementering der volder problemer under test, kan erstatte den med en test implementering (Seperate interface from implementantion taktik). Andre afkoblings teknikker går ud på at man benytter muligheden for at kunne overskrive metoder. Dette udnyttes under test til, at ændre på opførselen de steder der volder problemer under test. JUnit frameworket bruges som Record/Playback taktik til at opsamle test data og gemme resultatet på fil systemet. Figur 8 - Testbarheds taktikker Fleksibelt design Feathers afkoblings teknikker anvender primært nedarvnings baseret variabilitetshåndtering. Dette sikrer ikke et fleksibelt design og påvirker kvalitetsattributten modificerbarhed. Brugen af nedarvnings baseret variabilitetshåndtering kan være med til at vanskeligøre implementering af ny funktionalitet og derved forlænge udviklingstiden. Feathes benytter tre typer variabilitetshåndtering: konditionel, nedarvnings baseret og kompositionelt. Variabilitetshåndtering går ud på at finde det sted i koden, hvor der skal indføres ny funktionalitet / opførsel også kaldet variabilitetspunkt og indføre nye varianter. Konditionel variabilitetshåndtering laves ved at indføre forgreninger i koden (f.eks. if- sætninger). Det har en række ulemper. Koden bliver mindre overskuelig. Der skal ændres i eksisterende velfungerende kode med risiko for at indføre en defekt. Den klasse hvor der tilføjes en forgrening får også et ekstra ansvar. Et ofte set problem med 18
19 konditionel variabilitetshåndtering, er at forgreninger har det med at forgrene sig og øge kompleksiteten. Feathers anvender konditionel variabilitetshåndtering i forbindelse med konditionel kompilering af C og C++ kode til at afkoble afhængigheder. Nedarvnings baseret (polymorf) variabilitetshåndtering indføres ved at lave subklasser og overskrive metoder. Denne form for variabilitetshåndtering har nogle fordele i forhold til konditionel. Koden bliver mere læsbar, da den ikke indeholder forgreninger, og koden er forberedt til at håndtere nye varianter. Men metoden har også en række ulemper: Antallet af klasser forøges da hver variant introducerer en ny klasse. I Java der kun understøtter enkelt nedarvning, hvilket betyder at en klasse kun kan have en super klasse, er det ikke muligt at bruge nedarvnings relationen til at håndtere andre typer af variationer. Genbrug på tværs af varianter er besværligt. En compile-time binding af objekttypen. Feathers anvender nedarvnings baseret variabilitetshåndtering i sine afkoblings teknikker. Dette gør han bl.a. i teknikken Flyt metoder op ( se appendix ), hvor de afhængigheder der giver problemer under test efterlades i deres oprindelige klasse, og den funktionalitet, man ønsker at teste, løftes op i en superklasse. Ligeledes kan afhængigheder der giver problemer under test afkobles, ved at flytte dem ned i en subklasse og overskrive dem med simpel eller ingen funktionalitet med teknikken Nedarv og overskriv metode (se appendix ). Figur 9 - Eksempel på nedarvnings baseret variabilitetshåndtering Kompositionelt variabilitetshåndtering indføres ved at lave et interface, hvor klienten så kan vælge mellem forskellige implementeringer (se Figur 10). I forbindelse med denne teknik benyttes processen, hvor et resultat af denne er at kommer frem til hvilket mønster / strategi man vil benytte, for at løse et given problem. Kompositionelt variabilitetshåndtering har få ulemper i form af øget antal klasser, og at klienten skal have kendskab til hvilken strategi / mønstre der er anvendt. Fordelene ved denne metode er: 19
20 Nye varianter kan tilføjes ved at tilføje nye klasser. Man kan ændre opførsel på runtime. Det er muligt at kombinere varianterne uden at påvirke eksisterende varianter. Ansvarsområde er klart adskilt og overdraget til let identificerbare abstraktioner i designet. Da ansvarsområde er blevet adskilt kan det testes uafhængigt. Variant udvælgelse sker lokalt. Figur 10 - Eksempel på kompositionel variabilitetshåndtering I den originale designmønster bog Design Patterns: Elements of Reusable Object-Oriented Software findes der et katalog over 23 forskellige designmønstre [GoF]. Disse mønstre benytter kompositionel design. I samme bog finder man også nedenstående principper for et fleksibelt design. For et fleksibelt design gælder det, at det kun er tilladt at lave kode ændringer i eksisterende kode ved at tilføje ikke ændre. Principper for fleksibelt design 1. Programmer til et interface, ikke en implementering. 2. Favoriser objekt komposition over klasse nedarvning. 3. Overvej hvad der skulle være variabel i dit design. (Indkapsel opførslen der varierer). [GoF] Henrik Christensen [Christensen 2007] benytter de tre principper i sin process til at opnå et fleksibelt design. 20
21 3-1-2 processen 3. Har identificeret noget opførsel der et tilbøjelige til at ændre sig 1. Har erklæret et veldefineret ansvar der dækker denne opførsel og udtrykt det i et interface I stedet for at implementere opførslen selv uddelegeres det til et objekt som implementerer interfacet = 3. Overvej hvad der skulle være variabel i dit design. (Indkapsel opførslen der varierer). = 1. Programmer til et interface, ikke en implementering. = 2. Favoriser objekt komposition over klasse nedarvning. Der indgår ikke test i processen, men Henrik Christensen ligger op til at man anvender TDD sammen med processen, og dermed får testet sin kode processen tager ikke hånd om legacy kode, og får det under test kontrol, før en ændring kan foretages. Dette gør Feathers forandrings algoritme til gengæld. Men de tilhørende afkoblings teknikker foretrækker ikke nødvendigvis kompositionelt design. Her er der størst fokus på kvalitets attributterne pålidelighed og testbarhed fremfor modificerbarhed, når koden skal bringes under test kontrol. For at sikre et fleksibelt design, så man ikke på et senere tidspunkt risikerer at havne i en situation, hvor det er vanskeligt at tilføje ny funktionalitet, på grund af ulemperne ved nedarvning, så foreslår jeg, at man indfører et trin, efter man har skrevet tests i forandringsalgoritmen, hvor man refaktorisere koden de steder, hvor man har anvendt nedarvnings baseret- eller konditionel variabilitetshåndtering, og indfører kompositionelt design i stedet. Dette er med til at forbedre kvalitetsattributten modificerbarhed. Forandrings algoritme (revideret) 1. Identificér steder hvor der skal ændres. 2. Find de steder der skal testes. 3. Afkobl afhængigheder. 4. Skriv tests. 5. Refaktoriser og indfør kompositionelt design der hvor der er anvendt nedarvning, i den kode der er kommet under test kontrol. 21
22 6. Udfør ændringer og refaktorer. Jeg undersøgte og vurderede, at det ikke er muligt at indføre kompositionelt design allerede under afkoblingen, da man så ville fravige fra de fem metodikker, der ligger til grund for Feathers afkoblings teknikker og derved også miste pålideligheden. Men ved at vente til efter at tests er skrevet, så er koden under test kontrol, og man kan refaktorere det pågældende subsystem og indføre kompositionelt design, med den ønskede pålidelighed. Ved valg af kompositionelt design er alle tre hoved taktikker for modificerbarhed i spil. Man forsøger at minimere antallet af moduler / klasser der er direkte påvirket af en ændring (Localize changes). At undgå ripple effect fra en ændring der gør, at det er nødvendigt at foretage ændringer i klasser / moduler, der ikke er direkte berørt af det. Defer Binding Time taktikken er også i spil da det er muligt med kompositionelt design er ændre opførsel på runtime (se Figur 11). Figur 11 - Modificerbarheds taktikker 22
23 4.2 Refaktorering af CAPI plugin I de følgende afsnit anvendes Feathers teknikker til at løse opgaven med at udskifte JNI lag med kald til standard API. Der tages udgangspunkt i forandrings algoritmen (se afsnit 4.1), og for hvert trin i algoritmen laves en analyse af teknikkernes anvendelighed til at løse opgaven Identificér steder hvor der skal ændres For at finde ud af hvad der skal ændres, for at kunne løse den pågældende opgave, skal jeg lære systemet at kende. Her følges Feathers råd om at lave en skitse af systemet. Han lader det være op til en selv at vælge notation men anbefaler at man vælger en notation som f.eks. effekt skitse notationen (se afsnit 4.1.2). Han sidestiller UML med kasse diagrammer og lignende. Da han mener, at de diagrammer / skitser man ender ud med, ofte er uforståelige, for dem som ikke deltog i udforskningen af systemet. Det er korrekt, at hvis man som han foreslår, sidder parvis og udforsker systemet og bruger et stykke papir hvorpå man tegner sit diagram / skitse af systemet, så er effekt skitsen det mest effektive valg. Det vil ikke give mening at gemme denne til brug i dokumentations øje med da skitserne formentlig vil være ulæselige for andre. Jeg giver ham ikke ret i, at man kan sidestille UML med kasse diagrammer og lignende. Hvis man vælger de rigtige views [Bass et al., 2003], så mener jeg, at man kan opnå en bedre dokumentation af sit system, end man kan med effekt skitserne. Ved hjælp af sekvens diagrammer fra et component & connector view [Bass et al., 2003], kan man udlede nogenlunde den samme information, som man får i en effekt skitse. Jeg har observeret at problemet med mange legacy systemer er, at de ofte også halter på dokumentation, og at selvom denne metode tager længere tid end skitse metoden, så vil den oparbejdede dokumentation kunne genbruges senere, hvis man ønsker at rekonstruere arkitektur dokumentationen. Selvom at der vil ske en refaktorering af systemet, vil dele af den UML man har fået genereret kunne genbruges, da UML en typisk ligger gemt elektronisk. Derfor er det bare et spørgsmål om at få dette refaktoreret og ført ajour med systemet. Derfor er det en afvejning af hvad man ønsker. Skitse metoden er klart en letvægts metode og den mest effektive. Men hvis man på sigt ønsker at rekonstruere arkitektur informationen, så bør man overveje om det ikke kan betale sig, at investere den ekstra tid det tager i forhold til skitse metoden, at rekonstruere arkitekturen af subsystemet. Nogle UML værktøjer indeholder værktøjer til reverse engineering, der kan nedsætte tiden det tager at udforme UML diagrammer. 23
24 Til at lære CAPI plugin et at kende, og finde ud af hvad der skal ændres, har jeg valgt, at benytte UML som notation til at tegne mine diagrammer af plugin et. Dette gjorde jeg for at bekræfte mit postulat at et component & connector view kunne give den samme information som en effekt skitse. Først valgte jeg at lave et module view, hvor jeg definerede et klasse diagram (se Figur 12) for at få et overblik over hvilke klasser og interfaces, som plugin et består af. Figur 12 - UML klasse diagram af CAPI plugin For at lære protokollen at kende mellem de forskellige objekter lavede jeg et component & connector view, hvor jeg definerede en række UML sekvens diagrammer (se Figur 13). 24
25 Figur 13 - UML sekvensdiagram eksempler for CAPI plugin Efter at have analyseret CAPI plugin et kom jeg frem til at alle JNI metoder findes i klassen MicrosoftCryptoApi. For at kunne benytte disse metoder, så skal det tilhørende native system bibliotek indlæses på den klient, hvor Java appletten kører. Dette benyttes hjælpe klasssen CapiInitializer til, som bliver kaldt fra CapiKeyStoreHandler, når dennes install metode bliver kaldt fra appletten. Af ovenstående analyse bekræfter det mit postulat at et component & connector view kan benyttes som erstatning for effekt skitsen. Både til at finde ud af hvor der skal ændres, og til hvilke metoder der skal testes. Men at der ligger noget mere arbejde i at lave UML diagrammerne i forhold til at tegne en effekt skitse. Allerede på dette tidspunkt formodes det, at der bliver nogle afhængigheder der skal afkobles, med hensyn til hvorledes de native DLL skal indlæses for at kunne teste Find de steder der skal testes For at kunne refaktorisere CAPI plugin skal det bringes under test kontrol. For at finde ud af hvad der skal testes, har jeg valgt at benytte effekt skitse teknikken (se afsnit 4.1.2). Jeg har valgt at kigge på de to hoved klasser CapiKeyStoreHandler og MicrosoftWindowsCertificateHandler, da de resterende klasser i plugin et kun er hjælpe klasser. Jeg har valgt at se på hvilken effekt det har, hvis man ændrer ved MicrosoftCryptoApi klassen. 25
26 Jeg kendte lidt til koden før. Men med skitse metoden syntes jeg, at man lærer systemet bedre at kende på en hurtig og effektiv måde. Det svære kan være at afgrænse, hvor meget det er man skal ændre, og derved hvilken effekt det kan have på systemet. Ellers er det ligetil at tegne skitserne. Dog kan skitserne have en tendens til at blive temmelig uoverskuelige, hvis der er mange metoder eller afhængigheder i klassen der bliver berørt. Derfor er jeg enig med Feathers i, at effekt skitserne ofte kun giver mening for dem, der har tegnet dem. Af effekt skitsen (se Figur 14) fremgår det, at metoden refreshkeystore kalder metoden getfilteredcertificates. At install metoden laver en ny instans af CapiInitializer, hvorefter dens install metode kaldes, der sørger for at installere det native bibliotek på klienten. Dette betyder at følgende metoder i CapiKeyStoreHandler skal testes: refreshkeystore install Figur 14 - Effekt skitse af CapiKeyStoreHandler Som det ses af effekt skitsen (se Figur 15) skal følgende metoder i MicrosoftWindowsCertificateHandler klassen testes: getissuerdn 26
27 getsubjectdn getserialnumber getnotbefore getnotafter getversion sign getintendedkeyusage På effekt skitsen (se Figur 15) indgår der to constructor bobler. Disse indikerer, at når der laves en ny instans af MicrosoftWindowsCertificateHandler, så laves der en ny instans af MicrosoftCryptoApi i dens constructor. Figur 15 - Effekt skitse af MicrosoftWindowsCertificateHandler Afkobl afhængigheder I det tredje trin af forandrings algoritmen udføres afkoblingen. Her vil jeg lave en analyse af hvilke af Feathers afkoblings teknikker, jeg skal tage i anvendelse, for at opnå at kunne teste de metoder, som jeg har fundet frem til, der skal testes. Under test vil jeg gerne have afkoblet JNI kaldene til CAPI og installering af native bibliotek på klienten. Dette skyldes flere årsager: Jeg vil gerne have kontrol med test data, når jeg skriver tests. At jeg har fuldstændig styr på hvilke certifikater, der bliver returneret, og hvilke værdier disse indeholder, således at jeg i mine tests kan verificere, at metoderne virker efter hensigten. Det skal være muligt at tjekke koden ud, bygge den og køre testene på hvilken som helst maskine, der kan køre Java. 27
28 CapiInitializer laver et kald til en web server, hvorfra den henter det native bibliotek. Herefter installeres biblioteket lokalt på klienten. Afhængigheden til web serveren er problematisk i forhold til tests (se en rigtig unit test afsnit ). Til at bryde afhængigheden til CapiInitializer s kald til web server og undgå installation af native bibliotek, kom jeg frem til at der var to måder man kunne løse problemet på. Figur 16 - install metode i CapiKeyStoreHandler Den første måde var ved at anvende nedarv og overskriv metode teknikken (se appendix ). Dette er en af de grundlæggende teknikker til at bryde afhængigheder. Mange af de andre af Feathers afkoblings teknikker er varianter af den. Den grundlæggende ide er at bruge nedarvning til at fjerne opførsel, som man ikke er interesseret i eller ikke ønsker adgang til. Dette gøres ved, som navnet på teknikken antyder, at man nedarver fra den klasse, som indeholder den problematiske metode. I den nedarvede klasse overskriver man så den problematiske metode. Figur 17 - Eksempel på anvendelse af teknikken nedarv og overskriv til at fjerne afhængighed til CapiInitilizer i CapiKeyStoreHandler s install metode. Den anden måde var ved at anvende teknikkerne udtræk og overskriv factory metode (se appendix 8.1.5) og udtræk interface (se afsnit 8.1.7). Med disse to teknikker gør jeg det muligt at udskifte CapiInitializer med en anden klasse under test, der indeholder en anden opførsel. Udtræk og overskriv factory metode anvendes typisk i situationer, hvor det arbejde der sker under et objekts tilblivelse i dets constructor kan være temmelig irriterende, eller det bør ikke ske, når man vil have det pågældende objekt under test kontrol. Teknikken går ud på at man flytter tilblivelsen af det nye objekt til en create metode. Herefter kan man så nedarve klassen og overskrive create metoden, og eventuelt returnere en anden implementering af samme type. Udtræk interface teknikken anvendes, hvis man ønsker at udskifte et objekt med en anden implementering under test. Den nemmeste måde 28
29 at udtrække interface er ved at benytte sit IDE, som i de fleste tilfælde indeholder denne refaktorerings funktion. Udtræk interface teknikken er en af de stærkeste teknikker til at bryde afhængigheder i et legacy system. Jeg valgte den sidste løsning fordi jeg ikke ønsker at skulle ændre ved install metodens signatur (se linie 83 på Figur 16). Denne metode er beskyttet af en final erklæring, så den ikke kan overskrives. Denne erklæring skal fjernes for at kunne benytte den første løsning. Erklæringen er opstået på baggrund af nogle sikkerheds tests af OpenSign, og derfor ønsker jeg ikke at røre ved det, hvis jeg kan undgå det. En anden grund, der er lige så vigtig, er at det gamle JNI lag skal bestå, for dem som ikke anvender Oracle s JVM på en Windows maskine. Derfor skal det også være muligt på sigt, at ændre opførsel i produktions koden. Figur 18 - Anvendelse af udtræk interface teknikken på CapiInitializer klassen Efter at have anvendt de to teknikker kommer install metoden til at se ud som følgende: Figur 19 - Resultat af afkobling af CapiInitializer i CapiKeyStoreHandler For at bryde afhængigheden til CAPI og JNI laget og skal klassen MicrosoftCryptoApi afkobles. Da denne klasse indeholder alle native metoder til CAPI (se afsnit 4.2.1). Denne klasse skal i stedet erstattes med et test objekt, der kan returnere test data under kontrol. 29
30 Figur 20 getfilteredcertificates metode i CapiKeyStoreHandler MicrosoftCryptoApi klassen bliver benyttet i metoden getfilteredcertificates under indlæsning af certifikater (se linie i Figur 20). For at muliggøre udskiftning af objektet af typen MicrosoftCryptoApi med et test objekt kan teknikken udtræk interface anvendes. Figur 21 - Anvendelse af udtræk interface teknikken på MicrosoftCryptoApi klassen Udtræk interface teknikken er en meget kraftfuld teknik til at afkoble. Men jeg ser også nogle problemer med den. Hvis man kommer ud for en klasse, som man er nød til at afkoble, men som desværre har mange forskellige roller, så ender man også op med et interface, der har mange forskellige roller. Dette bryder med at et interface repræsentere en rolle og mindsker fleksibiliteten og muligheden for genbrug. 30
31 Rolle (software) Et sæt af ansvarsområder og tilhørende protokol med tilhørende roller. [Christensen 2007] Protokol En konvention der beskriver den forventede sekvens af interaktioner eller handlinger, der forventes af et sæt af roller. [Christensen 2007] Udtræk interface teknikken i sig selv er ikke nok til at kunne udskifte MicrosoftCryptoApi objektet med et test objekt. For at det skal kunne lade sig gøre, skal man have kontrol med tilblivelsen af objektet. Til dette kan udtræk og overskriv factory metode anvendes, hvor til tilblivelsen af objektet flyttes til en create metode. Til test formål kan man så lave en klasse der nedarver og overskriver create metoden. Den overskrevne create metode kan så returnere test objektet (se Figur 22). Figur 22 - Udskiftning af objekt under test Da jeg skulle i gang med at skrive tests opdagede jeg, at min analyse ikke var komplet. Inde i metoden getfilteredcertificates laves nye instanser af klassen MicrosoftWondowsCerticateHandler (se linie 131 i Figur 20). Denne klasse laver igen en ny instans af MicrosoftCryptoApi, hvilket giver problemer under test (se linie 84 i Figur 23). Figur 23 - MicrosoftWindowsCertificateHandler constructor Dette erfarede jeg allerede da jeg skrev de første tests til sign metoden for MicrosoftWindowsCertificateHandler. Jeg skrev bl.a. en test der simulerer at en bruger trykker cancel i et CAPI vindue dialog. For at det kunne lade sig gøre, var jeg nød til at skulle lave et hook ind i min MicrosoftCapi implementering, så jeg kunne sætte en fejlkode, for at kunne fremtvinge den rigtige exception type. Her opdagede jeg, at jeg havde glemt at bryde en afhængighed til det gamle JNI lag inde i 31
32 CapiKeyStoreHandler, når certifikat listen blev indlæst fra CAPI, hvilket gjorde at testen blev ved med at fejle. Dette skyldtes at jeg ikke havde fået afkoblet MicrosoftWindowsCertificateHandler fra CapiKeyStoreHandler, og derved ikke udskiftet MicrosoftCryptoApi objektet med et test objekt. Jeg mener at trin 3 og 4 i Feathers forandrings algoritme er en iterativ proces. Jeg mener, at det til tider kan være svært at overskue, hvilke kode konstruktioner der kan give problemer at skrive tests til. Hvilket ofte er baseret på erfaring alt efter hvor kompleks koden er skrevet. Derfor vil man som regel opleve tilbageløb, når man går i gang med at skrive tests. Udtræk og overskriv factory metode er igen et oplagt valg til at afkoble MicrosoftWindowsCertificateHandler fra CapiKeyStoreHandler. Dette skyldes at teknikken er beregnet til at blive anvendt de steder, hvor et objekts tilblivelse kan volde problemer under test. På baggrund af de to foregående trin af forandrings algoritmen ved jeg, at jeg i MicrosoftWindowsCertificateHandler skal have afkoblet afhængigheden til MicrosoftCryptoApi klassen. MicrosoftWindowsCertificateHandler laver en nyt objekt af typen MicrosoftCryptoApi i dens constructor og holder efterfølgende en reference til objektet (se Figur 24). Figur 24 MicrosoftWindowsCertificateHandler Metoderne i MicrosoftWindowsCertificateHandler benytter så referencen til MicrosoftCryptoApi objektet, når de skal kalde CAPI (se eks. i linie 128 Figur 25). Figur 25 - Eks. på brug af MicrosoftCryptoApi objekt referencen For at kunne udskifte MicrosoftCryptoApi objektet med et test objekt har jeg allerede besluttet at benytte udtræk interface teknikken. Men igen kan denne teknik ikke stå alene, og man er nød til at benytte 32
33 udtræk og overskriv factory metode for at kunne komme til at lave udskiftningen (se eks. på udskiftning af objekt i Figur 22). Efter at have anvendt ovenstående teknikker kommer getfilteredcertificates metoden i CapiKeyStoreHandler til at se ud som følgende: Figur 26 - Resultat af afkobling af MicrosoftCryptoApi klassen Udtræk og overskriv factory metode er simpel at udføre. Resultatet af denne kan ses på linierne 123, 131 og i Figur 26. Umiddelbart ser jeg ikke den store fare for at indføre defekter i koden. Jeg benyttede i høj grad de muligheder jeg havde i mit Java IDE [IntelliJ] til at refaktorere koden, så det var forholdsvis få ændringer, som jeg skulle foretage manuelt. Efter at have anvendt IDE til at udtrække interface, som kom til at hedde MicrosoftCapi (se bl.a. linie 123 i Figur 26), så kom factory metoden til at se ud som ovenstående (se linie i Figur 26). IDE et har sørget for at opdatere alle referencer, så koden stadig kan compilere, og har derfor også rettet i koden til MicrosoftWindowsCertificateHandler klassen. Jeg valgte at bibeholde navnet på MicrosoftCryptoApi klassen for ikke at skulle til at ændre i bygge scripts og derved øge risikoen for at introducere defekter. 33
34 Efter af have anvendt udtræk og overskriv factory metode teknikken på MicrosoftWindowsCertificateHandler klassen kommer constructoren og dens nye create metode til at se ud som følgende: Figur 27 MicrosoftWindowsCertificateHandler constructor Figur 28 - MicrosoftWindowsCertificateHandler create metode Resultatet af afkoblingen er, at jeg nu er i stand til at skrive tests til de metoder, jeg har fundet der skal testes. Det er muligt at erstatte klassen der håndterer kald til CAPI med et test objekt, således at man kan opnå at få kontrol med test data. Samt at jeg kan skrive tests der kan afvikles på maskiner der i stand til at afvikle Java Skriv tests Som test framework benytter jeg JUnit [JUnit]. JUnit er et test framework, som er beregnet til at skrive unit tests i Java. Sammen med Maven [Maven], som er det bygge system OpenSign benytter, så er det forholdsvis nemt at tilføje nye tests. Maven [Maven] er styret af konventioner, som bl.a. siger at klasser der indeholder unit tests skal ende med Test, og at de skal være placeret under en bestemt folder struktur (se nedenstående eksempel). Alle klasser som indgår som en del af afkoblings teknikkerner, har jeg valgt at navngive med Fake-. Figur 29 - Eksempel på Maven folder struktur 34
35 En rigtig unit test Allerede under afkoblingen blev jeg enig med mig selv, om at jeg vil afkoble kaldene til CAPI (jeg antager at CAPI virker), og erstatte det med en test implementering, så jeg havde kontrol med data. Jeg overvejede også, hvad jeg skulle gøre med X.509 certifikat objekterne. I første omgang ville jeg lave en test implementering af den abstrakte klasse java.security.cert.x509certifkat, som også Feathers foreskriver, for at lave en rigtig unit test. Som han skriver skal en unit test kunne køre hurtig. En rigtig unit test En unit test der tager 1/10 sekund at køre er en langsom unit test. Unit tests kører hurtigt. Hvis de ikke kører hurtigt, så er de ikke unit tests. Andre slags tests som ofte er maskeret som unit tests. En test er ikke en unit test hvis: 1. Hvis den snakker med en database. 2. Hvis den kommunikerer over et netværk. 3. Hvis den rører fil systemet. 4. Hvis du er nød til at udføre specielle ting i dit miljø (som at editere konfigurations filer) for at køre den. Tests der gør disse ting er ikke forkerte. Ofte er de nødvendige at skrive, og du vil generelt skrive dem i unit test suiter. Men det er vigtigt at være i stand til at separere dem fra rigtige unit tests så du kan have en række tests som du kan køre hurtigt når du laver ændringer. [Feathers] Men det gav lidt problemer med det eksisterende interface, som var defineret i MicrosoftCryptoApi. Her udvekslede man et byte array repræsentation af certifikatet og ikke X509Certifikat typen. Desuden skulle jeg teste signering, og var her ikke klar over, hvor meget jeg skulle implementere og hvordan. Derfor valgte jeg at gå på kompromis med en rigtig unit test, og valgte at læse nogle test certifikater ind fra fil systemet ved brug Java s standard API. Det skal dog siges at certifikat filerne er forholdsvis små, så testene er hurtige på min maskine, selvom de er ude og røre fil systemet. De holder sig pænt under 1/10 sekund. Resultatet blev at jeg lavede to nye hjælpe klasser til at indlæse X.509 certifikat filer, som derefter kan returnere certifikaterne som X509Certifikat objekter. Dette gjorde jeg ved at benytte TDD rytmen (se afsnit 4.1.5). 35
36 Figur 30 - Interface som MicrosoftCryptoApi klassen implementerer Tests cases Som tidligere skrevet er Characterization Tests gode til legacy kode. De går ind og beskriver hvordan koden opfører sig. Med effekt skitse metoden får man fundet frem til hvilke klasser og metoder, der skal testes. Men man får ikke afdækket test situationer. Derfor er det nødvendigt, når man skal skrive sine tests, at gå ind og analysere de metoder der skal testes, og afdække hvilke parametre der skal anvendes, for at kunne teste alle situationer for at illustrere metodens opførsel. Et eksempel på dette var, som jeg allerede har nævnt, da jeg skulle teste sign metoden. Her tester jeg når en signering går godt, og når en bruger vælger at afbryde midt under signeringen. Figur 31 - Udsnit af unit tests for MicrosoftWindowsCertificateHandler Feathers ligger kraftigt op til at man anvender par programmering. Hvilket også er en fordel i denne situation til at analysere sig frem til mulige test cases. Men min erfaring er, at mange som arbejder med legacy systemer ikke anvender denne udviklings proces bl.a. på grund af få udviklere i den pågældende afdeling. Hvis man ikke anvender par programmering, så vil jeg anbefale at man i stedet indfører code review. 36
37 En metode til at undersøge om man får testet sin kode er et code coverage værktøj. Et code coverage værktøj kan rapportere hvilke klasser og metoder linje for linje, der er blevet testet. Der findes et række værktøjer på markedet. Et af dem er OpenSource værktøjet EMMA, som jeg har anvendt på CAPI plugin net. Umiddelbart giver værktøjet et negativt billede af hvor godt plugin net er testet. Men hvis man går det efter, så viser det sig, at det bl.a. skyldes de dele der er blevet afkoblet, som har en negativ indvirkning på resultatet. Det er første gang jeg har anvendt EMMA [EMMA], og det virker knapt så udbygget, som et andet kommercielt værktøj jeg har anvendt, der hedder Clover [Clover]. Clover giver mulighed for at sætte filtre op og danne mere avancerede reporter med letlæselige grafer. Dette kan være nyttigt til at skabe et mere reelt billede af, hvor godt man har testet sin kode. Netop pga. at afkoblet kode eller framework kode ikke skal indgå i rapporten. Figur 32 - EMMA anvendt på CAPI plugin Revew af test kode Man vil opleve at man skriver logik i sine test klasser. Dette kan være medvirkende årsag til, at man ikke finder defekter i legacy kode. Man kan skrive unit tests, som jeg bl.a. har gjort i forbindelse med den klasse, som jeg benytter til at læse certifikater med, for at mindske risikoen. Jeg vil dog stadig mene, det er en god ide at lave code review på test kode, for at minimere muligheden for defekter, hvis man ikke anvender par programmering, som sikrer en kontinuerlig code review Refaktorer og indfør kopositionelt design Under min analyse af Feathers afkoblings teknikker fandt jeg ud af at mange af dem var baseret på brug af nedarvning. Dette er ikke med til at sikre et fleksibelt design. Derfor har jeg indført et ekstra trin i Feathers forandrings algoritme, hvor jeg refaktorerer koden og indfører kompositionelt design, der hvor jeg har anvendt nedarvning i den kode, som nu er under test kontrol. Under afkoblingen har jeg også anvendt teknikker, som er baseret på nedarvning. Det drejer sig om teknikken udtræk og overskriv factory metode. Resultatet af teknikken er en create metode, som skaber familier af beslægtede objekter. Her kan jeg i stedet anvende Abstract Factory mønsteret, hvis formål er at tilbyde et interface til at skabe 37
38 familier af beslægtede eller afhængige objekter uden at specificere deres konkrete klasser [Christensen 2007]. Figur 33 - UML klasse diagram der viser strukturen i Abstract Factory mønsteret Under afkoblingen havde jeg overset en løsning, hvor man i stedet for at flytte tilblivelsen af MicrosoftCapi objektet i MicrosoftWindowsCertificateHandler constructor ned i en create metode ved brug af udtræk og overskriv factory teknikken, kunne flytte dets tilblivelse ud i klienten (CapiKeyStoreHandler). Dette kan man gøre ved at benytte teknikken paramater riser constructor (se appendix ), som også er en del af Feathers afkoblings teknikker. Teknikken kan benyttes, hvis der laves et objekt i en constructor, og man ønsker at udskifte det. Så er den nemmeste metode at flytte dets tilblivelse udenfor constructoren, og lave objektet udenfor klassen. I stedet lader man klienterne give objektet til constructoren, som en parameter. Jeg har valgt at indføre denne løsning, da det så kun bliver CapiKeyStoreHandler, der får en afhængighed til MicrosoftCapiFactory (se Figur 36), som er en del af Abstract Factory mønsteret, der erstatter create metoderne, som opstod under afkoblingen. Dette sker fordi jeg vil rette koden i CapiKeyStoreHandler til at anvende den ny constructor i MicrosoftWindowsCertificateHandler (se linie i Figur 34) og fjerne den gamle constructor, da denne ikke vil blive benyttet mere. Figur 34 - Kode eksempel der viser resultatet af paramater riser constructor teknikken 38
39 CapiKeyStoreHandler nedarver fra KeyStoreHandler og MicrosoftWindowsCertificateHandler nedarver fra AbstractCertificateHandler. Jeg har valgt ikke at gøre noget ved dette design, da super klasserne ikke er under test kontrol og bliver anvendt i andre plugins. Anvendelsen af parameter riser constructor syntes jeg er en simpel teknik at anvende, og jeg ser ikke de store risici for at indføre defekter, når man anvender den. Problemet var ikke så stort på dette tidspunkt af processen, da koden allerede var under test kontrol. Indførslen af Abstract Factory mønsteret blev gjort i små skridt. For hvert skridt byggede jeg alt koden og kørte alle tests for at sikre, at jeg ikke havde fået indført nogen defekter. Jeg erstattede create metoderne i CapiKeyStoreHandler, som bliver overskrevet under test med Abstract Factory mønstreret i stedet. Resultatet af dette blev en række nye klasser, som implementerer de nye interfaces. Men det viste sig også at jeg kunne slette et par test klasser, da der ikke var behov for at nedarve og overskrive mere. Figur 35 - Resultat af refaktorerering i CapiKeyStoreHandler 39
40 Resultatet af løsningen er her vist i et module view repræsenteret som et UML klasse diagram: Figur 36 - Resultat af refaktorerering og indførelse af kompositionel design Udfør ændringer og refaktorer Opgaven gik ud på at erstatte det eksisterende JNI lag og anvende den krypto udbyder (udbyderen hedder SunMSCAPI ), som findes i Oracle s JVM, der giver adgang til CAPI. Min analyse viser at jeg kan anvende det allerede eksisterende design til at tilføje den nye opførsel. Jeg har allerede, da jeg skrev mine tests til plugin et, benyttet Java s standard API. Baseret på disse erfaringer kan jeg konkludere, at jeg kan nøjes med at implementere en variant af MicrosoftCapi interfacet. Der skal ydermere laves en factory klasse, der skaber den nye variant. CapiKeyStoreHandler s constructor skal ændres således, at den anvender den nye factory klasse for den nye variant, hvis SunMSCAPI er installeret på klienten. Hvis den nye variant benyttes, skal der ikke installeres et native bibliotek på klienten. Her kan test varianten genbruges i produktions koden til at afkoble installationen. Med udgangspunkt i den artikel og eksempel kode der findes på Oracle s hjemmeside [Peng 2006], har jeg lavet en implementering af MicrosoftCapi interfacet (se Figur 38). Dette har jeg gjort ved, at følge TDD rytmen, som også Feathers foreskriver, når man skal tilføje ny funktionalitet. 40
41 Resultatet af løsningen er her vist i et module view repræsenteret som et UML klasse diagram: Figur 37 - UML klasse diagram der viser den nye MicrosoftCapi variant Her er et udsnit af koden fra den nye variant: Figur 38 - Udsnit af ny MicrosoftCapi variant 41
42 Bestemmelse af hvilke Abstract Factory objekter der skal laves sker som sagt i CapiKeyStoreHandler s constructor. Figur 39 - CapiKeyStoreHandler's constructor Dette ændres fra kun at være standard factory objekter til, at der tages en beslutning ved at undersøge, om den nødvendige udbyder er installeret på klienten. Hvis det er tilfældet, anvendes de nye varianter af factory klasserne (se linie i Figur 40). Figur 40 - CapiKeyStoreHandler's constructor efter indførsel af ny variant 4.3 Fjernelse af gammel Bouncy Castle version I de følgende afsnit anvendes Feathers teknikker til at løse opgaven med at fjerne BCJCE plugin et fra OpenSign. Der tages igen udgangspunkt i forandrings algoritmen, og undervejs beskrives de erfaringer der er gjort Identificér steder hvor der skal ændres I denne opgave er det lige til at identificere, hvad der skal ændres. Hele BCJCE plugin et skal fjernes fra appletten. Plugin et indeholder kildekoden til den gamle Bouncy Castle version, som man ønsker at fjerne afhængigheden til. Bouncy Castle (BC) er et letvægts krypterings API og udbyder for Java Cryptography Extension (JCE) og Java Cryptography Arhitecture (JCA). Når plugin et bygges bliver koden bl.a. patchet for at få brudt en afhængighed og skabt et hook ind i BC. BC plugin et blev lavet på et tidspunkt, hvor JCE og JCA ikke var standard i Java. Det har fået lov til at overleve, fordi man ikke kan gennemskue hvilke konsekvenser det vil medføre i form af defekter at fjerne det, og fordi man i lang tid har skullet være kompatibel med gamle Java versioner. Man har dog for nylig besluttet, at man nu kun understøtter Java 6 og opefter. Dette skyldes bl.a. at ældre Java versioner kan udgøre en sikkerheds risiko, men ellers ville man heller ikke kunne fjerne det gamle JNI lag (se afsnit 0) Find de steder der skal testes For at finde de steder der skal testes, vil jeg igen anvende Feathers effekt skitse teknik. Feathers opererer med begrebet Interception Point, som simpelthen er det sted i programmet, hvor man kan detektere effekten af en bestemt ændring. I dette tilfælde er det lidt 42
43 mere uklart, hvilke dele der bliver berørt hvis man fjerner BCJCE plugin. Feathers benytter også et andet begreb, som han kalder et Pinch Point. Et Pinch Point er et sted, hvor man med tests mod et par metoder kan detektere ændringer i mange metoder. Jeg mener, at hvis jeg får testet der, hvor man anvender kryptografi, så har jeg fundet Pinch Point der kan afdække fjernelse af BCJCE plugin. Når jeg laver analysen, har jeg derfor valgt udelukkende, at have fokus på der hvor man bruger kryptografi. Appletten skal stadig være i stand til at signere XML, understøtte hash algoritmerne SHA-1 og SHA-256 og understøtte X.509 certifikater. Umiddelbart er det kun en enkelt klasse der har en direkte reference til BC. Men da BC også indeholder en implementering af JCE og JCA, så bør man også teste at ovenstående fungerer, da det er usikkert, hvilken implementering der er gældendende. Den som findes i plugin et, eller den som findes i Java s runtime. Når man skal lave effekt skitse tegninger, og finde ud af hvilke elementer der vil blive berørt af en given ændring, så er det en stor hjælp at have et have et godt IDE, der tilbyder nogle søge muligheder, hvor man bl.a. kan finde andre metoder, der kalder en metode. Dette er med til at sikre, at man får fundet det der skal testes. Når man følger metoder, for at undersøge hvilken effekt en given ændring har, så kommer man ofte til en overvejelse, hvor detaljeret man skal være i sin skitse. Det vigtigste er dog, at metoder og klasser der bliver påvirket af en given ændring tydeligt fremgår af effekt skitsen. I Opensign koden er de fleste kryptografiske metoder samlet i interfacet CryptoSupport, og der findes kun en implementering. Når man begynder at følge implementeringen af de enkelte metoder ses det, at der anvendes flere forskellige kryptografiske objekter, der er en del af JCE og JCA, til at løse den enkelte metodes opgave. Derfor kan en skitse af en enkelt metode blive temmelig kompleks, uden at tilføre mere information end at interface metoden i CryptoSupport, som man startede med at følge, skal testes. Under analyse fandt jeg også klassen SmimeUtil, som har en direkte afhængighed til BC. Men jeg fandt også ud af at klassen ikke blev brugt. Da klassen ikke bliver brugt, så skal den fjernes fra koden. Denne opgave er et tydeligt eksempel på, hvorfor kode der ikke bliver brugt skal fjernes. Det kan bl.a. være med til at gøre det sværere at bryde afhængigheder. Klassen kan dog altid findes frem igen, da den stadig vil ligge i VCS (versions kontrol system). 43
44 Figur 41 - effekt skitse af checksum Som det ses af Figur 41 skal følgende metode: getshavalue testes i klasserne Sha1Checksum og Sha256Checksum. Disse to klasser er desværre kopieret ud i forskellige Maven [Maven] moduler, så man er nød til at gentage testene i de enkelte moduler. Figur 42 - Effekt skitse af SunCryotoSupport Som det ses af Figur 42 skal følgende interface metoderne i SunCryptoSupport klassen som er en implementering af CryptoSupport interfacet testes: sign 44
45 getprivatekey getcertificatechain getcertinfo verify sha1 sha256 httpspost getkeystore Udover at skulle teste krypto delen, så bliver OpenSign s plugin struktur også påvirket, ved fjernelse af BCJCE plugin et. Der skal bygges et modul mindre, så der skal rettes i Maven [Maven] opsætningen. Men OpenSign skal også hente et plugin mindre. OpenSign holder styr på mulige plugins i klassen OpenSignDownloads. Man styrer så ved hjælp af Applet parametre, hvilke plugins der skal hentes. Derfor skal metoden getdownloaditems i denne klasse også testes. Ved at teste denne metode får man også indirekte testet, at DownloadChecksumGenerator klassen indeholder alle de nødvendige checksums til alle de dele, der skal hentes over netværket. Figur 43 - effekt skitse af OpenSignDownloads Bryd afhængigheder I det tredje trin af forandrings algoritmen udføres afkoblingen. Her laves en analyse af hvilke af Feathers afkoblings teknikker, der skal tages i anvendelse, for at kunne teste de metoder, som skal testes. Målene med afkoblingen er denne gang: Jeg vil gerne have kontrol med test data når jeg skriver tests. At jeg har fuldstændig styr på hvilke data der bliver returneret således at jeg i mine tests kan verificere at metoderne virker efter hensigten. Det skal være muligt at tjekke koden ud, bygge den og køre testene på hvilken som helst maskine der kan køre Java. Under min analyse hvor der skulle brydes afhængigheder i SunCryptoSupport klassen fandt jeg kun mulige problemer i httpspost i metoden. For bedre at kunne overskue httpposts metoden, og hvorledes den evt. videre skal afkobles, så flyttes denne metode til en ny klasse. Til dette anvendes teknikken flyt metode til objekt (se appendix 8.1.2). Formålet med denne teknik er netop at håndtere lange metoder og gøre dem mere overskuelige, og nemmere at skrive test til, ved at 45
46 flytte de lange metoder til en nye objekter. Resultatet af teknikken er at man får en ny klasse med constructor der har en signatur der svarer til den originale metodes signatur. Den ny klasse indeholder så en metode med indholdet / koden fra den originale metode. Den originale metode er rettet til at lave en instans af den nye klasse, hvorefter den kalder metoden. Figur 44 - httpspost metoden i SunCryptoSupport Efter at have udført teknikken kom httpspost metoden til at se som følgende: Figur 45 - Resultat af afkobling i SunCryptoSupport klassen For at kunne få den nye klasse til at kompilere, måtte jeg flytte inner klassen SunTrustManager med over. Desuden var det nødvendig, at tilføje en getter metode til CryptoFactory klassen. 46
47 Her er et udsnit af den nye hjælpe klasse: Figur 46 - Resultat af afkobling hvor metode er flyttet til nyt objekt Feathers skriver, at der ikke behøves test, når man anvender denne teknik. Men når man begynder at bryde kode op, er der efter min mening altid mulighed for at fejle. Når man som i dette tilfælde begynder at have klasser der skal flyttes med over øges kompleksiteten. En stor hjælp er selvfølgelig hvis man følger de fem metodikker (se afsnit 4.1.3), hvor man bl.a. benytter par programmering. Her vil der være et kontinuerligt review. Men jeg 47
48 opdagede at mit IDE (IntelliJ IDEA version 11.1) faktisk kunne udføre denne handling for mig, og jeg derved fremover kan automatisere denne handling. En stor hjælp hvis man f.eks. arbejder alene. Som Feathers også skriver i sin bog, bør man teste denne funktionalitet før man begynder at anvende den, så man er fortrolig med den, og stoler på at den virker. Figur 47 - Flyt metode til objekt i IntelliJ IDEA 11.1 Metoden som jeg har flyttet til et nyt objekt (httpspost fra SunCryptoSupport klassen) indeholder funktionalitet til at kalde og modtage et svar fra en web server ved brug af HTTPS protokollen. Selve kommunikationen med web serveren skal afkobles, da dette ikke er del af en unit tests opgave (se definition på en rigtig unit test afsnit ). Kommunikationen mellem OpenSign applet og en web-server hører under integrations test. Målet med afkoblingen er at man kan skrive en test, der kan teste de indledende manøvre i metoden, og teste at koden kan finde ud af at håndtere resultatet fra web-serveren. En løsning kunne være at erstatte URLConnection klassen med et interface (se linie 50 i Figur 46), således at man kan skifte den ud med en anden implementering, som har en anden opførsel under test. URLConnection klassen håndterer kald og svar fra web server. Men URLConnection er en del af standard Java, og er derfor ikke en del systemets kilde kode. Derfor kan man ikke anvende udtræk interface teknikken (se appendix 8.1.7). I stedet kom jeg frem til en løsning, hvor man anvender teknikkerne udtræk og overskriv factory metode og nedarv og overskriv metode. Hensigten med denne løsning er at flytte tilblivelsen af URLConnection objektet til en create metode. Under test laves et test objekt der nedarver fra URLConnection. I test objektet overskrives metoderne getoutputstream og getinputstream. Metoden 48
49 getinputstream bruges til at returnere noget kendt test data. For at dette kan lade sig gøre at udskifte URLConnection objektet med et test objekt, er det nødvendigt også at anvende udtræk og overskriv factory metode, hvor tilblivelsen af HttpsClient sker (se Figur 45). En anden løsning man kunne have anvendt i stedet for nedarv og overskriv metoden til at ændre opførslen for URLConnection er wrap class teknikken. Wrap class teknikken svarer til decorator mønsteret. Hensigten med decorator mønsteret er at tilføje yderligere ansvar til et objekt dynamisk. Jeg valgte denne løsning fra, fordi de ændringer der skal foretages i den eksisterende kode er mere omfattende, end hvis jeg vælger at benytte afkoblings teknikkerne. Ved valg af denne løsning øges risikoen for at indføre defekter og derved mindskes pålideligheden. Figur 48 - Eksempel på anvendelse af decorator mønsteret Wrap class teknikken hører til en kategori af teknikker, som kan benytte til at tilføje ændringer ved at skrive ny kode. Disse teknikker skal dog benyttes med forsigtighed. Man tilføjer testet kode. Men man får nødvendigvis ikke testet koden, der kalder den nye testet kode, med mindre man skriver tests der dækker dette. Resultatet af valgte løsning ses i den efterfølgende kode, hvor man bl.a. ser den nye create metode for URLConnection i linie og kaldet til den i linie
50 Figur 49 - Resultat af udtræk og overskriv factory metode URLConnection test klassen kom til at se ud som følgende: Figur 50 - Den overskrevne URLConnection klasse 50
51 Resultatet af afkoblingen i SunCryptoSupport klassen kom til at se ud som følgende: Figur 51 - Ny create metode i SunCryptoSupport klassen For at kunne benytte URLConnection test klassen under test skal der laves en klasse der nedarver fra SunCryptoSupport. Denne klasse skal overskrive create metoden for HttpsClient og returnere en ny klasse der nedarver fra HttpsClient. Denne klasse skal så overskrive metoden for URLConnection og returnere test klassen. Dette kan gøres på følgende måde: Figur 52 - Test klasse der nedarver fra SunCryptoSupport Figur 53 - Test klasse der nedarver fra HttpsClient Resultatet blev at man nu kan skrive tests til httpspost metoden, hvor man kan teste dens funktionalitet og samtidig undgå kaldet til web serveren. Dette er gjort med Feathers afkoblings teknikker. På baggrund af ovenstående afkobling kan jeg stadig medgive at disse teknikker har stor fokus på pålidelighed og at man får øget testbarheden af sin kode Skriv tests I forbindelse med da jeg skrev unit tests til SunCryptoSupport klassen, så valgte jeg igen ikke at holde mig til hvad der en rigtig unit test (se afsnit 4.2.4). Dette skyldes at jeg gerne vil teste krypto funktionaliteten, og fandt det nemmest at gøre det på noget kendt test data. Der er tale om test data der ligger gemt i filer på det lokale fil system, hvorfra testene bliver afviklet. Da filerne er ikke er særlig store, har det ikke den store indvirkning på testenes afviklings tid. Derfor mener jeg godt testene kan afvikles som en del af TDD rytmen, og ikke som en del af en smoke test eller lignende, som Feathers foreslår at man gør med ikke rigtige unit tests. 51
52 Figur 54 - Eksempler på unit tests til SunCryptoSupport klassen Jeg er enig med ham i, at man skal have fokus på afviklingstiden, når man skriver tests. Det kan være til stor gene, hvis det tager lang tid at køre alle tests, når man udvikler. Jeg har set eksempler på, at folk bliver trætte af TDD, fordi netop det at køre tests tager for lang tid, og TDD derved kommer til at virke demotiverende. Men som også Feathers skriver, kan man blive nød til afvige fra kravene til en rigtig unit test i nogen tilfælde. Jeg syntes dog, at hvis de kører hurtigt, så skal de medtages i den normale kørsel, når alle unit tests køres, hvor Feathers mener de skal holdes ude. Jeg måtte opgive at få testet verify metoden på SunCryptoSupport klassen, da jeg ikke kunne fremskaffe testdata, der kunne give et succesfuldt resultat. Metoden bliver anvendt i cdkort plugin et, som er lavet til håndtere certifikater udstedt på CD-kort. Den test modulus og test koefficient, som jeg anvender i min test, passer ikke til det certifikat som jeg anvender. Derfor fejler testen. Jeg har desværre ikke kunnet fremskaffe et test CD-kort certifikat eller modulus og koefficient værdier der passer til test certifikatet. Derfor har jeg måttet ignorere testen ved i JUnit at sætte på test metoden (se linie 116 i Figur 55). Figur 55 - Unit test for verify metoden Muligheden for at kunne ignorere tests er det godt? Man kan sige at udvikleren altid har haft muligheden, ved enten at slette eller ud kommentere koden. Problemet er bare, har jeg ofte set, at man ikke får gjort noget ved problemet. Jeg mener, at man skal have fokus på, også at få disse tests til at køre, da der potentielt kan ligge nogle problemer / defekter gemt her. Her er annotation løsningen bedre da det bliver rapporteret af JUnit frameworket. 52
53 4.3.5 Refaktorer og indfør kompositionelt design For at få et fleksibel design og derved øge systemets modificerbarhed har jeg valgt at følge den reviderede udgave af Feathers forandrings algoritme, som jeg kom frem til tidligere i denne opgave (se afsnit 4.1.7). Under afkoblingen har jeg anvendt teknikker, som anvender nedarvning. Det drejer sig om teknikkerne udtræk og overskriv factory metode og nedarv og overskriv metode. Jeg har tidligere fundet ud af at Abstract Factory mønsteret kan benyttes, der hvor jeg har anvendt udtræk og overskriv factory metoden (se afsnit 4.2.5). Derfor erstatter jeg create metoderne i SunCryptoSupport (linie i Figur 51) og HttpsClient (se linie i Figur 49) med Abstract Factory mønsteret. Under afkoblingen anvendte jeg også teknikken flyt metode til objekt, hvilket medførte at der blev skabt en ny klasse (HttpsClient), hvor metoden blev delegeret over. I SunCryptoSupport bliver der lavet en instans af den ny klasse og metoden bliver kaldt på denne (se linie i Figur 51). Dette følger ikke den første regel for fleksibel design som siger: programmer til et interface, ikke en implementering [GoF]. For at ændre dette, har jeg valgt at anvende udtræk interface teknikken. Figur 56 - Anvendelse af udtræk interface teknik på HttpsClient Indførslen af ovenstående beslutninger blev igen udført i små skridt. Igen fulgte jeg TDD rytmen for at sikre at jeg ikke fik indført defekter undervejs i refaktoreringen. Resultatet af refaktoreringen ses i den efterfølgende kode: 53
54 Figur 57 - Udsnit af SunCryptoSupport klassen efter refaktorering Figur 58 - Udsnit af HttpsClient implementeringen efter refaktoreringen Refaktoreringen medførte, at selvom jeg fik introduceret nogle nye klasser ved brug af de anvendte mønstre, så kan jeg også slette nogle klasser. Det drejede sig om de klasser hvor der var anvendt nedarvning til at overskrive metoder. 54
55 Resultatet af løsningen er her vist i et module view repræsenteret som et UML klasse diagram: Figur 59 - UML klasse diagram der viser indførelse af Abstract Factory mønsteret Udfør ændringer og refaktorer Efter at have fået krypto funktionerne under test kontrol, så kan BCJCE plugin et fjernes. Dette er en enkel og ukompliceret manøvre, da koden nu er under test kontrol. Derfor kan plugin et fjernes med den ønskede pålidelighed. SmimeUtil klassen med en reference til BC slettes, da det under trin af forandrings algoritmen blev opdaget, at denne klasse ikke blev benyttet mere. Figur 60 - OpenSignDownloads før fjernelse af BCJCE plugin Figur 61 - OpenSignDownloads efter fjernelse af BCJCE plugin Referencen til BCJCE plugin net blev fjernet fra OpenSignDownloads og DownloadChecksumGenerator, da plugin et ikke mere indgår som en del af de plugins, der skal installeres på klienten for at OpenSign kan køre. Figur 62 - DownloadChecksumGenerator før fjernelse af BCJCE plugin Figur 63 - DownloadChecksumGenerator efter fjernelse af BCJCE plugin 55
56 Maven konfigurationen blev tilpasset således, at BCJCE plugin et ikke mere indgår i bygge processen, og koden til plugin et blev fjernet i versions styrings værktøjet (VCS). Figur 64 - Maven pom fil der indeholder BCJCE plugin Figur 65 - Maven pom fil efter fjernelse af BCJCE plugin Disse ændringer blev udført ved at følge TDD rytmen, for at verificere at der ikke var indført nogen defekter. 4.4 Opsummering Det er hermed vist, at det er muligt at bringe OpenSign under test kontrol, for derefter at kunne tilføje ændringer uden stort set at gå på kompromis med pålideligheden. Dette gøres ved brug af Feathers forandrings algoritme og tilhørende teknikker. For at kunne indføre tests i legacy kode, er det ofte nødvendigt, at foretage ændringer i den eksisterende for at afkoble afhængigheder. Men ved brug af Feathers afkoblings teknikker er ændringerne så små, og udføres på en sådan måde, at risikoen for at indføre defekter meget lille. Men mange af teknikkerne benytter nedarvning, hvilket ikke giver et fleksibelt design og nedsætter systemets modificerbarhed. Derfor har jeg valgt at indsætte et ekstra trin i forandrings algoritmen, for at markere, at der skal refaktoreres, de steder som er kommet under test kontrol, og indføre et fleksibelt design, der hvor der er anvendt nedarvning som variabilitets håndtering. 56
57 Kilde-kode Resultatet af disse opgaver er tjekket ind i cvs [cvs] på openoces.org under branchen rel Det kan tjekkes ud ved at benytte nedenstående cvs kommando: cvs -z3 -d :pserver:[email protected]:/opt/cvs co -P -r rel opensign Når der bliver bedt om en adgangskode for anonymous brugeren, så efterlad en blank adgangskode ved at trykke på enter-tasten. 57
58 5 Fremtidig arbejde Da jeg anvendte Feathers forandrings algoritme i forbindelse med de to opgaver (se afsnit 4), og skulle afkoble for at bryde diverse afhængigheder, der voldte problemer under test, så fandt jeg ud, at mit IDE [IntelliJ] faktisk allerede understøttede mange af de afkoblings teknikker (se appendix 8.1), som Feathers har kategoriseret som dependency-breaking techniques. I stedet for manuelt at skulle udføre refaktoreringen, betragter jeg det som mere pålideligt at lade mit IDE udføre arbejdet. Derfor er det område, som jeg skal have udforsket noget mere. Jeg arbejder som konsulent og har efterhånden set mange systemer der bygger på legacy kode (se afsnit 1). Tendensen er, at når en udvikler skal foretage ændringer i et sådan system, enten fortsætter i samme stil og dropper tests, eller indfører nogle tests der tester den nye funktionalitet, uden at teste de ændringer der skal foretages i den eksisterende kode. Jeg hører nok til den del, der får testet den nye funktionalitet. Jeg kendte heller ikke til Feathers forandrings algoritme før dette projekt, men jeg kan klart anbefale metoden og dens teknikker, så derfor vil jeg udbrede den til mine kollegaer, og der hvor jeg kommer til at arbejde fremover. Jeg overvejede på et tidspunkt om man kunne få hele OpenSign under test kontrol ved at teste den gennem demo applikationen, som jeg har omtalt tidligere. Demo applikationen er en lille web applikation, der gennem tiderne er blevet benyttet til at teste OpenSign med. Den kan konfigurere OpenSign i alle mulige konfigurationer. For at automatisere testene ville jeg så benytte et værktøj der hedder Selenium [Selenium], som jeg har set præsenteret af nogle kollegaer, og værktøjet ser ud til at kunne løse opgaven. Det var dog ikke inde for scope i denne opgave. Men i en lignende situation kunne dette også være en løsning på at hurtigt at få legacy kode under test kontrol. Problemet med denne løsning er dog, at man bryder med, hvad der er en rigtig unit test, da det vil kræve netværks trafik at afvikle testene ( se afsnit ). 58
59 6 Konklusion Jeg har nu anvendt Feathers teknikker fra bogen Working Effectivelively With Legacy Code [Feathers] til at løse to givne opgaver (se beskrivelse i afsnit 1) på et software system, hvortil der ikke findes tests. Det er lykkedes mig at få de berørte dele af et software systemet under test kontrol og derefter kunnet foretage de nødvendig ændringer med den tro på at jeg ikke har fået indført nye defekter til systemet. Det betyder at jeg har opnået de samme egenskaber som TDD processen giver. At kunne modstå ændringsønsker uden at miste pålidelighed. Den største risiko for at indføre defekter sker under afkoblingen, hvor man bryder afhængigheder for at kunne indføre tests. Nogle af afkoblingsteknikkerne kunne være lidt risikable at udføre manuelt. Det gjaldt bl.a. flyt metode til objekt teknikken (se afsnit 4.3.3), hvor jeg havde lidt arbejde med at flytte metoden. Jeg erfarede dog at et moderne IDE kunne udføre disse refaktorerings opgaver og derved nedsætte risikoen for defekter. Men generelt syntes jeg at Feathers afkoblings teknikker i høj grad er anvendelige til at få indført tests og enkle at anvende. Derfor medgiver jeg også, at risikoen for at indføre defekter, er meget lille, hvis man følger de fem metodikker (se afsnit 4.1.3), som ligger bag afkoblings teknikkerne. Skitse teknikken viste sig også stærk til at lære et software system at kende og identificere hvilke metoder der ville blive påvirket af en given ændring og i så fald skulle testes. Det er en hurtig og uformel metode som ikke kan bruges til at dokumentere med. En mere formel løsning kunne være brug af UML. Som jeg også skriver ligger der noget mere arbejde i denne løsning. Men min erfaring er at legacy systemer ofte også halter på dokumentationen og at det kunne være en god anledning til at rekonstruere noget af denne (se afsnit 4.2.1). Det bør være med i ens overvejelser, når der skal vælges teknik. Når man skriver tests til legacy kode, er det med et andet formål end man benytter under TDD processen. Under TDD processen skriver man tests efter, hvordan man forventer at et system skal virke. For legacy kode skriver man tests med det formål, at dokumentere hvordan systemet virker. Men i sidste ende indgår alle tests i et samlet test forløb, hvor de er med til at opdage utilsigtede funktionalitetsændringer. Antallet af tests det kræver for at dokumentere legacy kode, afhænger derfor af mulige test cases. En måde at afdække om man har fået testet koden, er ved brug af et code coverage værktøj, der kan rapportere linje for linje, hvilke dele af koden der er testet. Man skal have fokus på at tests kan afvikles hurtigt, fordi et software system ofte vil indeholde mange tests, og det derfor har indflydelse på afviklingstiden at køre alle tests. Derfor skal tests bl.a. undgå netværks trafik og databaser. Disse tests falder udenfor kategorien rigtige unit 59
60 tests (se afsnit ). Feathers mener at de tests der ikke er rigtige unit tests, skal holdes udenfor den normale kørsel. Her kom jeg frem til den konklusion, at hvis afviklingstiden var lav, så bør de tages med. Jeg syntes at Feathers forandrings algoritme virker godt på legacy kode og bidrager til at forbedre kvalitets attributterne pålidelighed og testbarhed. Ulempen er dog ved mange af de afkoblings teknikker som Feathers har katogoriseret under dependency-breaking techniques (se appendix 8.1) favoriserer nedarvning og ikke komposition, og man derved ikke opnår et fleksibelt design (se afsnit 4.2.6). Derfor foreslår jeg også, at man indsætter et ekstra trin i forandrings algoritmen, hvor man efter at have fået koden under test kontrol, refaktoriserer de steder hvor man har anvendt nedarvning, og indfører et kompositionelt design i stedet. Forandrings algoritme (revideret) 1. Identificér steder hvor der skal ændres. 2. Find de steder der skal testes. 3. Afkobl afhængigheder. 4. Skriv tests. 5. Refaktoriser og indfør kompositionelt design der hvor der er anvendt nedarvning, i den kode der er kommet under test kontrol. 6. Udfør ændringer og refaktorer. 60
61 7 Referencer [Feathers] Michael C. Feathers. Working Effectively With Legacy Code. Prentice Hall, 1 edition (22 sep 2004), ISBN-13: [Mahmoud 2004] Qusay H. Mahmoud, Using and Programming Generics in J2SE 5.0, html [Bass et al., 2003] Bass, L., Clements, P., and Kazman, R. (2003). Software Architecture in Practice, 2nd Edition, Addison Wesley, 2003 [Christensen 2007] Henrik Bærbak Christensen. Reliable and Flexible Software Explained: Patterns, Frameworks, and Testing. Short Course Preprint August [EMMA] EMMA: a free Java code coverage tool, [Clover] Clover, Java and Groovy Code Coverage, Atlassian, [GoF] Design Patterns: Elements of Reusable Object-Oriented Software, Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides, Addison-Wesley, [Tilgængelighed] Tilgængelighed, ITST, [CAPI] Cryptography. MSDN. Microsoft. [BC] The Bouncy Castle Crypto API. [CRM 2012] PrimeInk CSP. CSP Functional Specification. Cryptomathic. CSP 7.10 RC9. Marts [OpenSign] The OpenSign project. [Beck 2000] Extreme Programming Explained, Kent Beck, Addison-Wesley, [cvs] Concurrent Versions System, [Selenium] SeleniumHQ, 61
62 [Hash] Hash Functions, FileFormat.Info, [IntelliJ] IntelliJ IDEA, The Most Intelligent Java IDE, JetBrains, [JUnit] JUnit.org, Resources for Test Driven Development, [Maven] Apache Maven, [Peng 2006] Leveraging Security in the Native Platform Using Java SE 6 Technology, Valerie Peng, October 2006, 62
63 8 Appendix 8.1 Afkoblings teknikker I de underliggende afsnit har jeg valgt de teknikker ud fra bogen, som jeg syntes passer godt til Java, samt at man arbejder i et IDE med understøttelse for refaktorering Tilpas parameter Man benytter tilpas parameter teknikken, når man ikke kan anvende udtræk interface teknikken på en parameters klasse, eller hvis det er svært at lave en forfalskning af en parameter. Man skal være påpasselig med at avende teknikken, da den ikke bevarer metode signaturerne. Et eksempel på anvendelse er, hvis en metode har en parameter af typen HttpServletRequest, som er en del af Java s EE framework. Dette interface indeholder over 20 metoder uden at have talt dets super interface med. I Java er det ikke muligt at udtrække et nyt interface, derfor er man nød til at implementere alle metoder i et test objekt. Her kan man med fordel anvende mock objekter for at spare tid. Men man kan også anvende tilpas parameter teknikken, for man flytter de metoder man skal anvende ud i et nyt interface. Teknikken består af følgende trin: 1. Lav det nye interface som du vil bruge i metoden. Lav det så simpel og kommunikativ som muligt, men prøv ikke at lave et interface som kræve andet end trivielle ændringer i metoden. 2. Lav en produktions implementering af det nye interface. 3. Lav en test implementering af det nye interface. 4. Skriv en simpel test hvor test klassen anvendes. 5. Lav de nødvendige ændringer i metoden for at kunne anvende den nye parameter. 6. Kør tests for at verificere at du er i stand til at teste metoden med brugen af test klassen Flyt metode til objekt Lange metoder er svære at arbejde med, og ofte findes der flere af dem i samme klasse. For at gøre det nemmere, at skrive tests til de lange metoder, så er det en god ide, at flytte de enkelte metoder til en ny klasse. Teknikken består af følgende trin: 1. Lav en klasse der skal indeholde metodens kode. 2. Lav en constructor for klassen og bevar signaturene ved at give en præcis kopi af argumenter brugt i metoden. Hvis metoden bruger en instans af data eller metoder fra den originale klasse, så tilføj en reference til den originale klasse som det første argument til constructoren. 3. For hvert argument i constructoren erklær en instans variabel og giv den præcis den samme type som argumentet. Bevar 63
64 signaturene ved at kopiere alle argumenter direkte ind i klassen og formater dem som instans variabel erklæringer. Tildel alle argument til instans variablerne i constructoren. 4. Lav en tom udførsels metode i den nye klasse. Ofte er denne metode kaldt run(). 5. Kopier indholdet af den gamle metode ind i den nye udførsels metode og kompiler. 6. Fejl beskederne fra compileren indikerer hvor i metoden der stadig bruges metoder eller variabler fra den gamle klasse. I hver af disse tilfælde gør hvad det kræver for få metoden til at kompilere. I nogen tilfælde er dette så simpelt som at ændre et kald til at bruge referencen til den originale klasse. I andre tilfælde kræver det lave metoder public på den originale klasse eller introducere getters for at få adgang til instans variabler. 7. Efter at den ny klasse kan kompilere gå tilbage til den originale klasse metode og ændrer den så den laver en instans af den nye klasse og delegerer dets arbejde til den. 8. Hvis der er behov anvendes udtræk interface teknik til at bryde afhængighed på den orignale klasse Eksponer statisk metode Denne teknik kan anvendes, hvis man arbejder med en klasse, der er svær at instantiere i test øjemed, og ønsker at ændre i en metode, som ikke anvender instans data eller metoder. Teknikken går ud på at gøre den pågældende metode statisk ved at udføre følgende trin: 1. Skriv en test der har adgang til den metode som du vil eksponere som en public static metode af klassen. 2. Flyt indholdet af metoden over i statisk metode. Husk at bevare metode signaturer. Brug et andet navn for den statiske metode. 3. Kompiler. 4. Hvis der er fejl relateret til at tilgå instans data eller metoder så tag et kig på disse funktioner og undersøg om disse også kan gøres statiske. Hvis de kan, så gør dem statiske så systemet kan kompilere Udtræk og overskriv kald Nogen gange er afhængigheder der kommer i vejen under test temmelig lokale. Det kan dreje sig om et enkelt metode kald, som man ønsker at udskifte. Til dette anvender man udtræk og overskriv kald teknikken som anvender følgende trin: 1. Identificer kaldet som skal udtrækkes. Find erklæringen for dens metode. Kopier dens metode signatur. 2. Lav en ny metode i den nuværende klasse. Giv den signaturen som blev kopieret. 64
65 3. Kopier kaldet til den ny metode og erstat kaldet med kaldet til den ny metode. 4. Introducer en test subklasse og overskriv den ny metode Udtræk og overskriv factory metode En gang i mellem kan det arbejde der sker under et objekts tilblivelse i dets constructor være temmelig irriterende, eller det bør ikke ske, når man vil have det pågældende objekt under test kontrol. En af teknikkerne til at undgå at det sker er udtræk og overskriv factory metode, som udføres med følgende trin: 1. Identificer et objekt tilblivelse i en constructor. 2. Udtræk alt arbejdet involveret i tilblivelsen og flyt det ind i en factory metode. 3. Lav en test sub-klasse og overskriv factory metoden i den for at undgå afhængigheder til problematiske typer under test Udtræk og overskriv getter Hvis man har et objekt, som man under test ønsker at udskifte med et andet, kan man benytte teknikken udtræk og overskriv getter. Hvis det kun drejer sig om en enkelt metode, hvor i man ønsker at udskifte objekt, så er det som regel lettere at anvende teknikken udtræk og overskriv kald (se appendix 8.1.4). Men når det drejer sig om flere metoder i samme objekt, så kan denne teknik benyttes med fordel. Teknikken indeholder følgende trin: 1. Identificer det objekt som du behøver en getter for. 2. Udtræk alt logik nødvendig for at lave objekt og flyt det ind i getter. 3. Erstat alt brug af objekt med kald til getter og initialiser referencen som holder objektet til null i alle constructors. 4. Tilføj førstegangs logik til getter så at objekt er konstrueret og tildelt til referencen når referencen er null. 5. Nedarv klassen og overskriv getter for at give et andet objekt til test. De getter metoder man får ud af denne teknik, de bliver også kaldt lazy getters. Lazy gettes bliver også brugt i singleton pattern Udtræk interface Denne teknik anvendes, hvis man ønsker at udskifte et objekt med en anden implementering under test. Den nemmeste måde at udtrække interface er ved at benytte sit IDE, som i de fleste tilfælde indeholder denne refaktorerings funktion. De to mest udbredte IDE er Eclipse og IntelliJ IDEA [IntelliJ] understøtter denne funktion. 65
66 I bogen bliver der også beskrevet, hvad man skal, hvis man ikke har IDE understøttelse. Denne har jeg valgt at se bort fra,da jeg mener IDE metoden er den sikreste og hurtigste metode til at udtrække interface. Udtræk interface teknikken er en af de stærkeste teknikker til at bryde afhængigheder i et legacy system Introducer instans delegator Denne teknik anvendes, hvis man under test ønsker, at kunne udskifte en statisk metode. Dette gøres ved at følge følgende trin: 1. Identificer den statiske metode der er problematisk at bruge under test. 2. Lav en instans metode for metoden på klassen. Husk at bevare signaturer. Lad instans metoden delegere til den statiske metode. 3. Find steder hvor den statiske metode er brugt i klassen som er under test kontrol. Anvend parametre riser metode (se appendix ) eller anden bryd afhængighed teknik til at forsyne en instans til stedet hvor det statiske metode kald var udført. 4. Erstat det problematiske kald til den originale statiske metode med kald til delegatoren på instansen introduceret i trin Introducer statisk setter Denne teknik gør det muligt, at udskifte det objekt som en singleton holder på med et test objekt, ved at indføre en statisk setter metode. Teknikken indeholder følgende trin: 1. Nedsæt beskyttelsen af constructoren så du kan lave en test klasse ved at nedarve singleton. 2. Tilføj en statisk setter til singleton klassen. Vær sikker på at setter metoden nedlægger singleton instansen korrekt før instansen tildeles det nye objekt. 3. Hvis du behøver adgang til private eller protected metoder i singleton klassen for at sætte den korrekt op til test, så overvej at nedarve den eller udtrække interface som reference hvis type er typen af interfacet Parameter riser constructor Hvis der laves et objekt i en constructor, og man ønsker at udskifte det er den nemmeste metode at flytte dets tilblivelse udenfor constructoren, og lave objektet udenfor klassen. I stedet lader man klienterne give objektet til constructoren, som en parameter. Parameter riser constructor teknikken udføres ved følge følgende trin: 66
67 1. Identificer constructoren som du vil parameter irisere og lav en kopi af den. 2. Tilføj en parameter til constructoren for det objekt hvis tilblivelse som du vil erstatte. Fjern objekt oprettelsen og tilføj en tildeling fra parameteren til instans variablen for objektet. 3. Hvis du kan kalde en constructor from en constructor så fjern indholdet af den gamle constructor og erstat det med et kald til den gamle constructor. Tilføj et nyt udtryk til kaldet af den nye constructor i den gamle constructor. Hvis du ikke kan kalde en constructor fra en anden constructor så skal du muligvis udtrække enhver gengivelse mellem constructorene til en ny metode Parameter riser metode Hvis der laves et objekt inde i en metode, og man ønsker at udskifte det, er det nemmest at flytte dets tilblivelse udenfor metoden, og i stedet give det som parameter til metoden. Teknikken udføres med følgende trin: 1. Identificer den metode som du vil erstatte og lav en kopi af den. 2. Tilføj en parameter til metoden for det objekt hvis tilblivelse som du vil erstatte. Fjern objekt tilblivelsen og tilføj en tildeling fra parameter til variabel der holder objektet. 3. Slet indholdet af den kopierede metode og lav et kald til den parameter iriserede metode ved brug af objekt skabelse udtrykket for det originale objekt Flyt metoder op Nogen gange har man en række metoder i en klasse, som man gerne vil arbejde med, og de afhængigheder som forhindrer en i at lave en instans af klassen, ikke har relation til metoderne. I en sådan situation kan man flytte metoderne op i en abstrakt super klasse, og nedarve fra denne. På den måde kan man teste metoderne, ved at lave en subklasse, der nedarver fra super klassen. Teknikken indeholder følgende trin: 1. Identificer metoder som du vil flytte op. 2. Lav en abstrakt super klasse for den klasse der skal indeholde metoderne. 3. Kopier metoderne til super klassen og kompiler. 4. Kopier enhver manglende reference som compileren advarer om til den ny super klasse. Husk at bevare signaturer som du gør dette for at nedsætte muligheden for fejl. 5. Når begge klasser kompilerer succesfuldt, lav en subklasse for den abstrakte klasse og tilføj de nødvendige metoder for at kunne udføre dine tests. 67
68 Flyt afhængigheder ned Nogle klasser har kun få problematiske afhængigheder. Hvis afhængighederne er fordelt på kun få metode kald, så kan de fjernes med teknikken nedarv og overskriv metode (se appendix ). Men nogen gange virker denne teknik ikke. Man kan være nød til at skulle bruge udtræk interface teknikken op til flere gange for at fjerne afhængigheder på bestemte typer. Her er flyt afhængighed ned teknikken en anden mulighed. Når man benytter denne teknik, laver man den pågældende klasse abstrakt. Laver en subklasse som bliver den nye produktions klasse, og flytter alle de problematiske afhængigheder ned i subklassen. På den måde kan man tage den originale klasse og nedarve fra den og lave en subklasse, som man kan teste på. Den teknik indeholder følgende trin: 1. Forsøg at bygge klassen som har afhængigheds problemer i dit test setup. 2. Identificer hvilke afhængigheder der giver problemer i bygget. 3. Lav en subklasse med et navn der kommunikerer det specifikke miljø for afhængighederne. 4. Kopier instans variablerne og metoderne som indeholder de dårlige afhængigheder ind i den nye subklasse. Husk at bevare signaturer. Gør metoder protected og abstract i din originale klasse og lav din originale klasse abstract. 5. Lav en test subklasse og ændrer dine tests så at du forsøger at lave en instans af test subklassen. 6. Byg dine tests for at verificere at du kan lave en instans af den nye klasse Erstat global reference med getter Hvis man har problemer med afhængigheder til globale referencer, kan disse indkapsles i getter metoder. De globale referencer kan så ændres i test ved at nedarve klassen og overskrive getter metoden. Denne teknik indeholder følgende trin: 1. Identificer den globale reference som skal erstattes. 2. Skriv en getter for den globale reference. Vær sikker på at adgangs beskyttelsen er løs nok så det er muligt at overskrive getter metoden i subklassen. 3. Erstat referencerne til den globale med kald til getter. 4. Lav en test subklasse og overskriv getter Nedarv og overskriv metode Dette er grunlæggende teknik til at bryde afhængigheder. Mange af de andre teknikker der allerede er beskrevet, er varianter af den. Den grundlæggende ide er at bruge nedarvning til at fjerne opførsel man ikke er interesseret i eller ønsker adgang til. Teknikken indeholder følgende trin: 68
69 1. Identificer afhængigheder som du ønsker at separere eller stedet hvor du ønsker at sense. Forsøg at finde det mindste antal af metoder som du kan overskrive for at opnå dit mål. 2. Gør hver metode mulig at overskrive. Dette gøres på forskellige måder afhængig af programmerings sprog. I Java skal metoderne gøres ikke final. 3. Hvis dit sprog kræver det, juster synlighed for metoderne som du vil overskrive så de kan blive overskrevet i en subklasse. I Java metoder skal mindst være protected for at kunne blive overskrevet. 4. Lav en subklasse der overskriver metoderne. Verificer at du er i stand til at bygge den i dit test setup Skabelon redefinering Hvis et sprog understøtter generics, er det muligt at bryde afhængigheder, ved brug af en teknik der kaldes skabelon redefinering. Teknikken går ud på at lave generic type af den klasse man arbejder på, hvor man ønsker at kunne udskifte en type, der giver problemer under test. Måden hvor på teknikken udføres, afhænger af det programmerings sprog man arbejder med. For Java indeholder teknikken følgende trin: 1. Identificer metoderne som du ønsker at erstatte i klassen som skal testes. 2. Lav klassen om til en generic type. Parameter riser den med de variabler som du vil erstatte. Husk de originale typer for parametrene. 3. Kompiler. 4. De steder der fejler hvor der laves nye instanser af generic typen indsættes de konkrete typer i udtrykket. 5. I test laves en instans af den nye generic type med de ønskede typer. 69
Begreber om Godt Software
Begreber om Godt Software Maintainability (vedligeholdelse): Softwarens evne til at blive ændret (funktionalitet, rettet, forbedrelser, miljø, krav). - Analyserbart: Evnen til at blive fejldiagnosticeret,
Citrix CSP og Certificate Store Provider
Project Name Document Title TDC Citrix Citrix og Certificate Store Provider Version Number 1.0 Status Release Author jkj Date 5-10-2006 Trademarks All brand names and product names are trademarks or registered
Design by Contract. Design and Programming by Contract. Oversigt. Prædikater
Design by Contract Design and Programming by Contract Anne Haxthausen [email protected] Informatics and Mathematical Modelling Technical University of Denmark Design by Contract er en teknik til at specificere
Udfordringer og problemstillinger. En liste over de udfordringer og problemstillinger, der er ved Java og JEE udvikling
Java og JEE 1 2 Udfordringer og problemstillinger En liste over de udfordringer og problemstillinger, der er ved Java og JEE udvikling 3 Generelt om Java og JEE 4 Generelt, I Man undervurderer hvor mange
Hassansalem.dk/delpin User: admin Pass: admin BACKEND
Hassansalem.dk/delpin User: admin Pass: admin BACKEND 1/10 Indledning Dette projekt er den afsluttende del af web udvikling studiet på Erhvervs Lillebælt 1. semester. Projektet er udarbejdet med Del-pin
SWC eksamens-spørgsmål. Oversigt
SWC eksamens-spørgsmål Oversigt #1 Typer og variable #2 Aritmetik og logik #3 Klasser (definition, objekter) #4 Klasser (metoder) #5 Klasser (nedarvning, polymorfi) #6 Conditional statements #7 Repetition
Softwaretest. - også af "ikke testbar" software. DAPUG erfamøde 7. marts 2012 Thomas Vedel, Thomas Vedel Consult email: thomas@veco.
Softwaretest - også af "ikke testbar" software DAPUG erfamøde 7. marts 2012 Thomas Vedel, Thomas Vedel Consult email: [email protected] Hvorfor softwaretest? Software er sjældent fejlfri Test sikrer at softwaren
Arkitektur for begyndere
Denne guide er oprindeligt udgivet på Eksperten.dk Arkitektur for begyndere Denne artikel beskriver forskellige basale n-tier arkitekturer. Som man bør kende og have valgt inden man går igang med at udvikle
Specialiseringen Rapport Lavede Af Rasmus R. Sørensen Side 1 af 6
Side 1 af 6 Indholdsfortegnelse INDHOLDSFORTEGNELSE 1 INTRO 3 STARTEN AF SPECIALISERINGEN 3 ANKOMST TIL SKOTLAND 4 DATABASER 5 NETVÆRK 5 INTERAKTION 5 AFSLUTNING AF SPECIALISERINGEN 5 KONKLUSION 6 Side
STS Designdokument. STS Designdokument
STS Designdokument i STS Designdokument STS Designdokument ii REVISION HISTORY NUMBER DATE DESCRIPTION NAME 0.3 2013-01 N STS Designdokument iii Indhold 1 Introduktion 1 2 Arkitekturoverblik 1 2.1 Eksterne
DM507 Algoritmer og datastrukturer
DM507 Algoritmer og datastrukturer Forår 2016 Projekt, del III Institut for matematik og datalogi Syddansk Universitet 20. april, 2016 Dette projekt udleveres i tre dele. Hver del har sin deadline, således
LEVERANCE 1.3. Model for kvalitetssikring
LEVERANCE 1.3 Model for kvalitetssikring Udarbejdelse af kvalitetssikringsmodel, krav til open source kode og dokumentation og godkendelsesprocedurer m.v. Samt fokus på understøttelse af CE-mærkning. 1
Object-Relational Mapping
Databaser for udviklere () Datamatiker TietgenSkolen Underviser: Allan Helboe 06-06-2010 Problemformulering Denne opgave er et forsøg på at beskrive problemerne der opstår ved anvendelsen af en relationel
Tietgenskolen - Nørrehus. Data warehouse. Database for udviklere. Thor Harloff Lynggaard DM08125
Tietgenskolen - Nørrehus Data warehouse Database for udviklere Thor Harloff Lynggaard DM08125 Juni 2010 Indhold Beskrivelse... 3 Data warehouse... 3 Generelt... 3 Sammenligning... 3 Gode sider ved DW...
Klasser og Objekter i Python. Uge 46 Learning Python: kap 15-16, 19-22.
Klasser og Objekter i Python Uge 46 Learning Python: kap 15-16, 19-22. Klasser og objekter En klasse beskriver en klump af samhørende funktioner og variable En klasse er en beskrivelse. En kage form Klassens
Sundhedsstyrelsens Elektroniske Indberetningssystem (SEI) Vejledning til indberetning via Citrix-løsning
Sundhedsstyrelsens Elektroniske Indberetningssystem (SEI) Vejledning til indberetning via Citrix-løsning Indholdsfortegnelse Indledning... 3 Systemkrav... 4 Installation af Citrix-klient... 5 Tilpasning
DM507 Algoritmer og datastrukturer
DM507 Algoritmer og datastrukturer Forår 2019 Projekt, del III Institut for matematik og datalogi Syddansk Universitet 10. april, 2019 Dette projekt udleveres i tre dele. Hver del har sin deadline, således
DM507 Algoritmer og datastrukturer
DM507 Algoritmer og datastrukturer Forår 2018 Projekt, del II Institut for matematik og datalogi Syddansk Universitet 20. marts, 2019 Dette projekt udleveres i tre dele. Hver del har sin deadline, således
TEKNISKE FORHOLD VEDR. ADGANG TIL VP.ONLINE. Brugervejledning
TEKNISKE FORHOLD VEDR. ADGANG TIL VP.ONLINE vp.online 2011 01-10-2011 Indholdsfortegnelse 1 PROBLEMER MED AT SE VP.ONLINE... 3 2 BROWSER KONFIGURATION... 6 3 SKRIVEADGANG TIL DREV... 7 4 SESSION TIMEOUT
Vejledning til Teknisk opsætning
Vejledning til Teknisk opsætning v. 1.0 Adm4you, 2010. Indhold Kort om denne vejledning... 3 Generelt om easyourtime... 3 Installation af databasen... 3 Sikkerhed og rettigheder... 4 SQL Login... 4 Rettigheder
Succesfuld implementering af automatiseret test
Succesfuld implementering af automatiseret test Forudsætningerne og faldgruberne John Fodeh [email protected] 2006 Hewlett-Packard Development Company, L.P. The information contained herein is subject
DM507 Algoritmer og datastrukturer
DM507 Algoritmer og datastrukturer Forår 2018 Projekt, del II Institut for matematik og datalogi Syddansk Universitet 13. marts, 2018 Dette projekt udleveres i tre dele. Hver del har sin deadline, således
DM507 Algoritmer og datastrukturer
DM507 Algoritmer og datastrukturer Forår 2016 Projekt, del I Institut for matematik og datalogi Syddansk Universitet 29. februar, 2016 Dette projekt udleveres i tre dele. Hver del har sin deadline, således
DM507 Algoritmer og datastrukturer
DM507 Algoritmer og datastrukturer Forår 2019 Projekt, del I Institut for matematik og datalogi Syddansk Universitet 27. februar, 2019 Dette projekt udleveres i tre dele. Hver del har sin deadline, således
Procesbeskrivelse - Webprogrammering
Procesbeskrivelse - Webprogrammering Indholdsfortegnelse Forudsætninger... 1 Konceptet... 2 Hjemmesiden... 2 Server-side... 3 Filstrukturen... 3 Databasehåndtering og serverforbindelse... 4 Client-side...
DM507 Algoritmer og datastrukturer
DM507 Algoritmer og datastrukturer Forår 2017 Projekt, del III Institut for matematik og datalogi Syddansk Universitet 6. april, 2017 Dette projekt udleveres i tre dele. Hver del har sin deadline, således
TDCs Signaturserver. 11/05 - Version 1.0 2005 TDC Erhverv Sikkerhed og certifikater
TDCs Signaturserver Side 2 Indhold Indledning...3 Teknisk projekt... 3 Tekniske forudsætninger... 3 Installation af klienten... 4 Udstedelse af signatur... 4 Anvendelse af signaturen... 6 Eksport af signaturen...
DAXIF# - Delegate Automated Xrm Installation Framework. Delegate A/S
DAXIF# - Delegate Automated Xrm Installation Framework Delegate A/S Agenda Delegate A/S DAXIF# Kun et programmeringssprog Type stærke script (og selvdokumenterende) filer Unit tests afvikles før assembly
Forskellige Java versioner
Denne guide er oprindeligt udgivet på Eksperten.dk Forskellige Java versioner Denne artikel beskriver lidt om de forskellige Java versioner. Den forklarer J2SE/J2ME/J2EE, plugin/jre/sdk og Sun Java/Microsoft
It-sikkerhedstekst ST9
It-sikkerhedstekst ST9 Single Sign-On og log-ud Denne tekst må kopieres i sin helhed med kildeangivelse. Dokumentnavn: ST9 Version 1 Juli 2015 Single Sign-On og log-ud Betegnelsen Single Sign-On (SSO)
Lonbox PCM2001 betjeningsenhed
PROLON CONTROL SYSTEMS Herstedvesterstræde 56 DK-2620 Albertslund Danmark Tlf.: (+45) 43620625 Fax: (+45) 43623125 Lonbox PCM2001 betjeningsenhed Bruger vejledning Oktober 2002 Denne manual beskriver installation
DM517:Supplerende noter om uafgørlighedsbeviser:
DM517:Supplerende noter om uafgørlighedsbeviser: Jørgen Bang-Jensen October 9, 2013 Abstract Formålet med denne note er at give en form for kogebogsopskrift på, hvorledes man bygger et uafgørlighedsbevis
Fang Prikkerne. Introduktion. Scratch
Scratch 2 Fang Prikkerne All Code Clubs must be registered. Registered clubs appear on the map at codeclubworld.org - if your club is not on the map then visit jumpto.cc/ccwreg to register your club. Introduktion
FESD-standardiseringsgruppen Att: Palle Aagaard IT- og Telestyrelsen IT-strategisk kontor Holsteinsgade 63 2100 København Ø
FESD-standardiseringsgruppen Att: Palle Aagaard IT- og Telestyrelsen IT-strategisk kontor Holsteinsgade 63 2100 København Ø Høringssvar vedr. FESD GIS-integrationsmodel version 2.0 Geodata Danmark har
Lærer nye styresystemer Installerer programmer som kun kan bruges i ældre versioner
Virtuel PC Fordele/ulemper Fordele: Lærer nye styresystemer Installerer programmer som kun kan bruges i ældre versioner Ulemper: Reserverer RAM (Windows 7) Problemer med at ureglementeret lukke ned Mister
Når du har hentet disse programmer installerer du dem alle og følger guiden herunder.
Debranding af Nokia mobiler! For at komme i gang skal du have din computer forbundet til nettet, have et datakabel der kan forbinde din Nokia telefon med din computer og hente disse her 3 programmer :
Ugeseddel 4 1. marts - 8. marts
Ugeseddel 4 1. marts - 8. marts Læs følgende sider i kapitel 6 i lærebogen: s. 233 258 og s. 291 317 (afsnit 6.3 overspringes). Begynd at overveje, hvad afleveringsopgaven skal omhandle. Læs vejledningen,
XProtect-klienter Tilgå din overvågning
XProtect-klienter Tilgå din overvågning Tre måder at se videoovervågning på For at skabe nem adgang til videoovervågning tilbyder Milestone tre fleksible brugergrænseflader: XProtect Smart Client, XProtect
Software Dokumentation
Software Dokumentation Jan Boddum Larsen Teknologi B og A på HTX Dokumentation af software i Teknologi I samfundet sker der en bevægelse mod mere digitale løsninger i teknologi. Det betyder at software
Håndbog Til CPR services. Bilag 10 Opsætning af CPR klienten til understøttelse af forskellige installationstyper
Håndbog Til CPR services Bilag 10 Opsætning af CPR klienten til understøttelse af forskellige installationstyper CPR-kontoret Datavej 20, Postboks 269, 3460 Birkerød E-post: [email protected]. Telefax 45 82 51
Øvelse 9. Klasser, objekter og sql-tabeller insert code here
Øvelse 9. Klasser, objekter og sql-tabeller Denne opgave handler om hvordan man opbevarer data fra databasekald på en struktureret måde. Den skal samtidig give jer erfaringer med objekter, der kommer til
VISUELLE GUIDELINES FOR LOG-IN OG SIGNERING MED NEMID. Guide til udseende, sprog og struktur for tjenester, der bruger NemID.
VISUELLE GUIDELINES FOR LOG-IN OG SIGNERING MED NEMID Guide til udseende, sprog og struktur for tjenester, der bruger NemID. November 2015 Indhold Dokumentet indeholder anbefalinger og råd til integration
VIGTIG information til alle kunder som kører backup over Internet via SSL - Kræver kundeaktion inden 17. april 2009!
VIGTIG information til alle kunder som kører backup over Internet via SSL - Kræver kundeaktion inden 17. april 2009! Det er blevet tid til at opdatere certifikater på alle servere som afvikler backup over
Hvem er vi? Kursus Introduktion. Kursuslærerne. Agenda for i dag
Hvem er vi? Kursus Introduktion Anne Haxthausen [email protected] Informatics and Mathematical Modelling Technical University of Denmark 100 studerende med forskellig baggrund: software teknologi It og Kom
2013 SP1. Konfiguration af koncernindblik. Configuration Guide
2013 SP1 Konfiguration af koncernindblik Configuration Guide Intellectual Property Rights This document is the property of ScanJour. The data contained herein, in whole or in part, may not be duplicated,
Hvor er mine runde hjørner?
Hvor er mine runde hjørner? Ofte møder vi fortvivlelse blandt kunder, når de ser deres nye flotte site i deres browser og indser, at det ser anderledes ud, i forhold til det design, de godkendte i starten
Ruko SmartAir. Updater installation
Ruko SmartAir Updater installation Introduktion. Updateren er en speciel enhed som giver os mulighed for at tilføje, læse og skrive funktioner i en offline installation. Med læse og skrive funktionen kan
Adobe Digital Editions
Adobe Digital Editions Kom godt i gang Klik på knapperne nedenfor for at komme videre Forberedelse Download Adobe Digital Editions: Til Windows TRYK HER Til Mac OS TRYK HER Bemærk: Adobe Digital Editions
Installation af kalibreringsprogrammet. (BDE versionen)
Installation af kalibreringsprogrammet. (BDE versionen) Installationen består egentlig af to (3) dele: 1 del der vedrører selv programmet med tilhørende filer ( det kan opdateres ) 2 en del der vedrører
INDHOLDSFORTEGNELSE. INDLEDNING... 7 Kristian Langborg-Hansen. KAPITEL ET... 9 I gang med App Inventor. KAPITEL TO...
INDHOLDSFORTEGNELSE INDLEDNING... 7 Kristian Langborg-Hansen KAPITEL ET... 9 I gang med App Inventor Installation af App Inventor... 10 Trådløs installation... 11 Installation af emulator (Windows)...
Undgå driftsafbrydelser på grund af udløbet virksomheds- eller funktionssignatur
Side 1 af 5 Vejledning 2. august 2013 NITRI Undgå driftsafbrydelser på grund af udløbet virksomheds- eller funktionssignatur Indholdsfortegnelse Formål...2 Virksomhedssignatur...2 Funktionssignatur...3
1. Du bliver mødt af denne boks. Klik på Gem, og gem filen et sted hvor du kan finde den igen.
Ewido hed programmet tidligere, nu hedder det AVG Antispyware og er et program, som først og fremmest skal holde trojanske heste ude fra din maskine. Derudover, beskytter programmet dig mod en hel del
Daglig brug af JitBesked 2.0
Daglig brug af JitBesked 2.0 Indholdsfortegnelse Oprettelse af personer (modtagere)...3 Afsendelse af besked...4 Valg af flere modtagere...5 Valg af flere personer der ligger i rækkefølge...5 Valg af flere
Introduktion til funktioner, moduler og scopes i Python
Denne guide er oprindeligt udgivet på Eksperten.dk Introduktion til funktioner, moduler og scopes i Python Denne artikel er fortsættelsen af "I gang med Python", som blevet publiceret her på sitet for
Fuld installation af Jit-klient
Fuld installation af Jit-klient Indholdsfortegnelse Systemkrav til afvikling af Jit-klienten...3 Opsætning af firewall...4 Om installationsfilen...5 Installation af MSI-filen...6 Om SSL-certifikater...13
LUDUS WEB. Installations- og konfigurations-vejledning. Den 7. april 2009. J.nr.: 4004 V0624 09
LUDUS WEB Installations- og konfigurations-vejledning Den 7. april 2009 J.nr.: 4004 V0624 09 CSC Scandihealth A/S, P.O. Pedersens Vej 2, DK-8200 Århus N Tlf. +45 3614 4000, fax +45 3614 7324, www.scandihealth.dk,
Web CMS kontra Collaboration
Web CMS kontra Collaboration Sammenligning mellem Sitecore og Sharepoint Lars Fløe Nielsen, Evangelism [email protected] Page 1 Sitecore har dyb integration til Microsoft Sitecore har integration til mange
For at du kan downloade og installere SAS version 9.13, skal du have mindst 6.3 GB ledig plads
Installation af SAS System 9.13 via DVD Installation af SAS 9.13 består af to dele. 1) Opdatering af Windows vha. System Requirement Wizard og 2) Installation af SAS 9.13. Installation af SAS version 9.13
Indholdsfortegnelse for kapitel 2
Indholdsfortegnelse for kapitel 2 Kapitel 2. Analyse.......................................................... 2 Analyse af 2.1...................................................... 2 Analysen af Database.................................................
Sådan logger du ind... 2 Hvilke mapper kan du tilgå... 3 Visning af eksempel af en fil... 5 Sådan deler du en fil... 7 Se hvad du deler med andre...
Sådan logger du ind... 2 Hvilke mapper kan du tilgå... 3 Visning af eksempel af en fil... 5 Sådan deler du en fil... 7 Se hvad du deler med andre... 9 Offline synkronisering... 11 Klienter til mobile enheder...
Ruko Security Master Central Database
Ruko Security Master Central Database RSM benytter en central database, til at udveksle låsesystemer mellem Ruko og låsesmeden. Udvekslingen sker via Internettet, så det er derfor nødvendigt at have en
NEMID MED ROBOTTER. Muligheder samt en anbefaling til at løse NemID-opgaver med robotter
NEMID MED ROBOTTER Muligheder samt en anbefaling til at løse NemID-opgaver med robotter 1 En softwarerobot må ikke handle på vegne af et menneske med vedkommendes NemID. Men hvilke andre muligheder er
Casper Fabricius http://casperfabricius.com. ActiveRecord. O/RM i Ruby on Rails
Casper Fabricius http://casperfabricius.com ActiveRecord O/RM i Ruby on Rails Casper Fabricius Freelance webudvikler - casperfabricius.com 9 års erfaring med webudvikling 6 år med ASP/ASP.NET/C# 3 år med
Fable Kom godt i gang
Fable Kom godt i gang Opdateret: 26-03-2018 Indholdsfortegnelse 1. Først skal du installere programmet på din computer 3 2. Når programmet er installeret er du klar til at pakke robotten ud 4 3. Nu er
A Profile for Safety Critical Java
A Profile for Safety Critical Java Martin Schoeberl Hans Søndergaard Bent Thomsen Anders P. Ravn Præsenteret af: Henrik Kragh-Hansen November 8, 2007 Forfatterne Martin Schoeberl Udvikler af JOP processoren
Hvorfor skal vi bruge objekt orienteret databaser?
OODBMS Vs. RDBMS 1 Indholdsfortegnelse Hvorfor skal vi bruge objekt orienteret databaser?... 3 OODBMS i erhvervslivet... 4 Bagsiden af medaljen... 5 OODBMS i praksis... 6 Konklusion... 8 2 Hvorfor skal
EA3 eller EA Cube rammeværktøjet fremstilles visuelt som en 3-dimensionel terning:
Introduktion til EA3 Mit navn er Marc de Oliveira. Jeg er systemanalytiker og datalog fra Københavns Universitet og denne artikel hører til min artikelserie, Forsimpling (som også er et podcast), hvor
Aktuel driftsstatus for IndFak
Aktuel driftsstatus for IndFak Side 1 af 5 Der er på nuværende tidspunkt 72 institutioner, som anvender IndFak. Der er fortsat forskellige driftsmæssige problemer samt uhensigtsmæssigheder i systemet.
NetLogo-simuleringen. Simuleringer og fysiske modeller (henfaldsloven)
NetLogo-simuleringen Simuleringer og fysiske modeller (henfaldsloven) Hvad er en simulering? For at kunne arbejde med en simulering er der to vigtige elementer, man må have en grundlæggende forståelse
Hukommelsesspil. Introduktion. Scratch
Scratch 2 Hukommelsesspil All Code Clubs must be registered. By registering your club we can measure our impact, and we can continue to provide free resources that help children learn to code. You can
Ide med Diff. Mål. Tidsplan. 1.uge: 2.uge:
Side 1 af 5 Ide med Diff. Min ide med differenertierings modulet er at lave et program som kan vise 3d objekter, og få lavede en konverter som kan konventer 3ds filer over til noget som flash kan bruge.
Udlæsning af stregkodefil til scanneren 1. Opret mappen pdt på C-drevet (c:\pdt).
Indholdsfortegnelse Introduktion... 2 Udlæsning af stregkodefil til scanneren... 3 Installation af scanneren... 5 Indlæsning af datafil i scanneren... 7 Brug af scanneren... 8 Sådan scanner du... 8 Sådan
Praktiserende Landinspektørers Forening. Fremtidens matrikulære sagsgang. minimaks og MIA
Praktiserende Landinspektørers Forening Fremtidens matrikulære sagsgang minimaks og MIA 02 Fremtidens matrikulære sagsgang minimaks og MIA Om minimaks og MIA minimaks er Kort & Matrikelstyrelsens nye matrikulære
Opsætning af Backup. Hvis programmet registreres korrekt vises nedenstående skærmbillede. Genstart herefter programmet.
Opsætning af Backup Dette er en guide til opsætning af backup med Octopus File Synchronizer. Det første der skal ske er, at programmet skal registreres (programmet kan dog bruges i 30 dage, hvis det ikke
Miniprojekt2011. Formålet er at lære og indlære god objektorienteret programudvikling og programmering med Java, samt undervejs at opfylde studiekrav.
Miniprojekt2011 Projektbeskrivelse Der skal fremstilles en lille java application på PC, hvor brugeren kan foretage interaktioner med en simpel database på disken via et grafisk brugerinterface. Formålet
GUIDE TIL CLOUD DRIVE
GUIDE TIL CLOUD DRIVE Dette er en guide du kan anvende til nemt at komme effektivt i gang med at anvende Cloud Drive Indholdsfortegnelse 1. Tilgængelige Cloud Drive klienter 2. Guide til Windows klienten
