mboost-dp1
Spgsml til udvikling af større komplekse programmer??
- Forside
- ⟨
- Forum
- ⟨
- Programmering
#49
Det giver god mening at teste private metoder, også selvom de kun benyttes internt. En af fordelen ved at gøre det er at du får testet din kode på et niveau hvor kompleksiteten stadig er lav.
Det er markant lettere og sikrere at teste en metode som har een funktion (Den private metode) end at teste en metode som kalder 100 andre metoder (Den public metode) og så håbe at man kan overskue hele den private implementation nok til at sikre at man har fået testet det hele, gennem unit testen af den public metode.
Det giver god mening at teste private metoder, også selvom de kun benyttes internt. En af fordelen ved at gøre det er at du får testet din kode på et niveau hvor kompleksiteten stadig er lav.
Det er markant lettere og sikrere at teste en metode som har een funktion (Den private metode) end at teste en metode som kalder 100 andre metoder (Den public metode) og så håbe at man kan overskue hele den private implementation nok til at sikre at man har fået testet det hele, gennem unit testen af den public metode.
100% coverage er ikke nogen garanti for at koden er fejlfri. Og på den anden sider er coverage på mindre end 100% heller ikke en garanti for at der er fejl i koden.arne_v (38) skrev:Man tester ikke for at få 100% coverage, men fordi at det er nødvendigt.
Coverage procenten er ikke et endegyldigt mål for hvor godt koden er testet, men det er nok den bedste approksimation som kan sætte et tal på hvor grundigt koden er testet.
En ting kan i hvert fald siges med sikkerhed. Unit tests fanger ikke fejl i de kodelinier, der ikke bliver afviklet af unit tests.
Så jeg synes at 100% unit test coverage er et fornuftigt mål at stræbe efter. Der er forskellige måder hvorpå coverage kan beregnes. Jeg bruger selv det gcc/gcov kan gøre for mig, selvom jeg ikke synes det er den optimale måde at beregne coverage. Risikoen for at en uopdaget fejl gemmer sig pga. for dårlig dækning som jeg overså pga. måden dækningsgraden blev beregnet på er ret beskeden. Hvis jeg selv skrev kode til at beregne coverage på den måde jeg hellere ville se det, er der betydeligt større risiko for bugs i den kode jeg skrev til det formål.
Der hvor jeg synes gcc/gcov kommer til kort er at der tælles linier og ikke branches. F.eks.
statement1;
if (condition) {
statement2;
}
statement3;
Hvis aldrig denne kode testes hvor condition evaluerer til falsk vil gcov stadig rapportere 100% coverage. Lidt uhensigtsmæssigt. Et mere problematisk eksempel er:
statement1;
if (condition) statement2;
statement3;
Fordi if og statement2 står på samme linie vises det som en samlet enhed. Det betyder at selvom condition altid er falsk og statement2 aldrig er blevet afviklet vil man stadig se 100% coverage fordi linien som statement2 står på har været afviklet.
Og hvis man har en for eller while løkke mener jeg også man bør dække det grænsetilfælde hvor betingelsen er falsk første gang. Det er dog et lidt upraktisk kriterie fordi der kan være løkker hvor betingelsen aldrig kan være falsk første gang. Det er en udfordring lidt lig med kodefragmenter hvis formål er at rapportere interne fejl i koden.
if (condition) {
fprintf(stderr,"This is not supposed to happen\n");
abort();
}
Man kan selvfølgelig bruge assert(), men assert() kan føre til heisenbugs, og nogle gange vil man gerne have bedre output i tilfælde af en fejlende assertion end hvad assert() kan levere. Ovenstående kode har en linie som kun kan nås hvis der er en bug i koden. I dette tilfælde betyder det altså at coverage skal være under 100% fordi 100% coverage ville betyde at der var en bug i koden.
Bortset fra linier som per design ikke skal kunne nås er det en god idé at stræbe efter 100% coverage. Den største fordel ved at have 100% coverage er at det reducerer risikoen for at introducere nye fejl når man ændrer koden for at tilføje features eller rette fejl.
En 100% coverage betyder at der er en god chance for at alt den funktionalitet man har implementeret også er dækket af unit tests. Dermed er der beskeden risiko for at ødelægge eksisterende funktionalitet ved tilføjelse af nye features.
Om man overhovedet er interesseret i en opdeling er afhængigt af omstændighederne. Der er ikke som sådan noget forkert i at compilere en stor kodebase til en enkelt programfil. Der kan være besparelse af RAM og diskplads hvis man har en fornuftig opdeling i libraries der kan genbruges. Og det kan være nemmere at udsende fejlrettelser hvis man kun skal opdatere de dele af koden der er fejl i.arne_v (39) skrev:C) en fysisk opdeling af deployable code
Men det er simplere at administrere en stor programfil, så hvis ikke man har grund til at bekymre sig om resourceforbruget er det helt fint at have en stor programfil. Man bør så vidt mulig undgå at linke standard libraries ind i sin programfil fordi der kan komme sikkerhedsopdateringer til de libraries, og eksemplarer der er linket ind i et større program bliver nemt glemt når der skal opdateres.
Det kommer an på om man skriver white box eller black box tests. Hvis man laver testdrevet udvikling vil man i sagens natur lave black box tests af den simple grund at tests ikke kan afhænge af strukturen af koden når tests skrives før man overhovedet overvejer hvordan implementationen skal se ud.arne_v (41) skrev:Man skriver stadig unit test af API'et ikke af implementationen.
Men jeg mener faktisk man bør skrive både white box og black box tests. Lave black box tests ud fra APIen. Og lav white box tests der dækker hele koden. Tilsammen vil de to metoder dække langt de fleste tilfælde.
Jeg vil dog sige at hvis man har white box tests med 100% coverage, så har man med god sandsynlighed testet hele APIen. Og det er nemmere at afgøre om man har 100% coverage af implementationen end at afgøre om et udvalg af tests dækker hele APIen.
Desværre ikke. Jeg erindrer at have hørt lidt i en forelæsning og et foredrag. Derudover er det meste erfaring jeg har med det fra den tid hvor jeg arbejdede ved Google. Der var noget intern dokumentation af hvordan man burde teste kode, men det kan jeg af gode grunde ikke vise dig. Selv hvis jeg kunne huske URLen kan den jo ikke tilgås udefra.Darwind (47) skrev:Har du nogle gode eksempler på læsestof til at komme igang med TDD?
Det var ikke fordi jeg lavede særlig meget testdrevet udvikling. Jeg arbejdede godt nok på at min kode skulle være godt dækket af tests, men for det meste skrev jeg alligevel koden før jeg skrev tests til den. Jeg husker kun en enkelt gang hvor jeg var meget bevidst om at skrive test cases før jeg skrev koden, og det kom der godt nok noget mærkelig kode ud af, men det var også skrevet i et obskurt sprog.
Flere gange har jeg været nødt til at skrive unit tests til eksiterende kode som ikke var dækket af tests. Jeg har haft brug for at refaktorere kode som ikke var testet. Jeg måtte først refaktorere koden absolut minimalt for at kunne tilføje unit tests. Når jeg så havde unit tests af den eksisterende kode kunne jeg gå i gang med mere omfattende refaktorering, som også involverede at rette fejl der havde været til stede i den oprindelige kode.
Windcape (35) skrev:På datamatiker uddannelsen forklares der lidt om det. Men ikke meget om faktisk strukturing af større projekter / eller strukturing af kode.
Huh?
Da jeg gik på datamatiker brugte vi temmeligt meget tid på faget "systemudvikling", som netop handler om strukturering af koden i metoder, klasser og pakker, og hvad det ellers hedder i de forskellige sprog. MEGET mere tid end vi brugte på programmering. Det vigtigste jeg synes vi lærte var patterns. At dele op i lag osv, altså hvad man bruger pakker, interfaces osv. til.
Det gav viden nok til at strukturere projekter til datamatiker-niveau, dvs. måske op til en håndfuld udviklere. Store projekter (fx. hundredevis af udviklere) kræver naturligvis at nogen som er specialister i at organisere så store mængder koder - arkitekter.
Windcape (35) skrev:På ingeniør- og datalogi studiet, forklares der stort set intet, da det forventes at være op til de studerende selv at finde ud af.
Jeg kender ikke detaljerne af de uddannelser, men universiteterne underviser naturligvis i arkitektur mv. til udvikling af større systemer. At påstå det er noget folk bare selv finder ud af, er da noget af en fornærmelse af vores højtuddannede arkitekter. (Uanset om det er dig eller skolerne der har den holdning.)
Windcape (35) skrev:Problemet er nok også, at det er meget teknologi-specifikt. I Java tvinges du til at træffe nogle valg, som ikke nødvendigvis er ideele, og i .NET har du større frihed, men forsøger stadigvæk at integere med dit udviklingsmiljø.
Jo større projektet er, jo højere abstraktionsniveau er det nødvendigt at organisere. Og jo højere abstraktionsniveauet er, jo mere sproguafhængigt er det.
Windcape (35) skrev:Og så er der folk som kasper, der bruger emacs og en masse seperate filer i en mappe, og synes det er en fornuftig projektstruktur :p
Huh? Du mener ikke at koden skal putters i filer, og filerne i mapper? Du har bare det hele i et Word-dokument eller hvad?
Windcape (35) skrev:Overordnet set, må det vel være op til erfarne udviklere (nb. erfaring kan fåes andre steder end en arbejdsplads!), at forklare de nye hvordan tingene foregår.
Lidt teoretisk viden fra bøger kan erstatte erfaring fra mange fejlslagne projekter.
Teori uden erfaring er ikke meget værd, men erfaring uden teori tager MEGET lang tid at opbygge, og det koster MANGE spildte ressourcer. Du er nødt til at lære af andres fejl, livet er for kort til at du kan nå at lave alle fejlene selv. Og teori er IKKE noget man lære af at arbejde sammen med en klog, osmose er en rigtig dårlig måde at lære teori.
Desværre lærer de folk alt for mange ubrugelige antipatterns. En af mine venner læser datamatiker nu, og der er alt for meget fokus på Singleton, Factory, og Strategy.myplacedk (53) skrev:Det vigtigste jeg synes vi lærte var patterns. At dele op i lag osv, altså hvad man bruger pakker, interfaces osv. til.
Og de lærer stadigvæk ikke dependency injection, selvom jeg imo. mener det er det vigtigste design-pattern i moderne programmering!
En god arkitekt kan også finde ud af at kode. Og jeg mener godt man kunne have haft mere fokus på arkitektur.myplacedk (53) skrev:kræver naturligvis at nogen som er specialister i at organisere så store mængder koder - arkitekter.
Vi havde mere fokus på udviklingsmodeller, udover det rent tekniske.
Jeg er uenig. Det er ikke min oplevelse. På datalogi undervises der i distributed computing, men fra et mere matematisk synspunkt.myplacedk (53) skrev:men universiteterne underviser naturligvis i arkitektur mv. til udvikling af større systemer
Se bare artiklen om de 2 dataloger, der brugte node.js, fordi de ikke kunne få Java til at skalere.
Det var lidt pun på et typisk C projekt.myplacedk (53) skrev:Huh? Du mener ikke at koden skal putters i filer, og filerne i mapper?
Tit er det bare en masse C filer hulter til bulter, og nogle build scripts.
Windcape (54) skrev:Og de lærer stadigvæk ikke dependency injection, selvom jeg imo. mener det er det vigtigste design-pattern i moderne programmering!
Jeg synes nu det lyder som om du snakker om en eller flere konkrete lærere, og ikke uddannelsens niveau generelt.
Windcape (54) skrev:En god arkitekt kan også finde ud af at kode.
Ja selvfølgelig. Men man bliver ikke arkitekt på en udvikler-uddannelse.
Windcape (54) skrev:Vi havde mere fokus på udviklingsmodeller, udover det rent tekniske.
Udviklingsmodeller er også vigtige, og vi lærte da også hvorfor vandfaldsmodellen er en dårlig ide og fik en introduktion til iterativ udvikling. Men det er altså kun viden til husbehov, en metode-ekspert har mere i rygsækken en bare en datamatiker-afdeling.
Bare for at illustrere at det ikke bare er en sideting for udviklere: På min arbejdsplads har både arkitektur og metoder hver sin afdeling. Udviklere skal have lidt forstand på det, men i større systemer skal der specialister til.
Windcape (54) skrev:Jeg er uenig. Det er ikke min oplevelse.
Du fik fat i at jeg ikke snakker om specifikke uddannelser, ikke? Som sagt så HAR du kurser/moduler som specifikt handler om den slags, uanset hvad du mener. Hvem der så tager dem er en helt anden snak.
Tilbage til spørgeren.
Qw_freak lader til at have lidt baggrund i elektronik, og derfor er jeg bare nød til at spørge hvad formålet med dit "program" er.
Eksempel:
Selv skriver jeg software der har til formål at lave feedback kontrol, på systemer der tit er open ended. F.eks. selvkørende robotter..
Det betyder grundlæggende at jeg ikke kender kravene til softwaren før end softwaren er testet i praksis og har vist sine svagheder.
I praksis har det tit vist sig at selv grundige use-case analyser ikke har taget højde for problemer i omgivelserne.
Det betyder at designet, uanset hvor grundig man laver det, aldrig er fyldestgørende, og ofte falder til jorden ved første system test.
Unit testing afslører kun om modulerne overholder kravspec, men det giver ingen mening når kravene er diffuse, og designet tit gennemgår grundlæggende forandringer når en test fejler.
Derfor har det hidtil vist sig at den effektive vej til et system design er, analyser en simpel case, implementer den, test den i praksis, se hvilke udfordringer der er tilbage, udvid programmet til at kunne håndtere endnu en udfordring.
når spaghetti koden nærmer sig noget der virker, analyser hvad der faktisk sker, (typisk et miskmask af state machines, og lineær programmering), lav et design der har nogenlunde samme opførsel, men er pakket væk i fine objekter, og kan skalere til samme type opgaver.
fortsæt med at identificere uløste udfordringer, og tilføj kode.
På et tidspunkt er du kommet langt nok til at forstå opgaven og skrive kravspec..
programmerne kan blive enormt store, og enormt komplekse, da mine brugere er fritgående dyr / mennesker, og derfor ikke er begrænsede af de knapper brugerfladen har..
------
set fra et elektronik perspektiv:
Et program er forhåbentlig ikke mere komplekst end det behøver at være.
Hvis du kan løse opgaven med 1 fil så gør du det
Hvis du har behov for en brugerflade, så prøv at skille den fra din core funktionalitet.
Filer er bare filer, du kan splitte din kode over så mange du har lyst, du kan altid få en compiler til at samle dem for dig, hold et tema i en fil, f.eks. alt der har med at bruge I/O i en fil, alt der har med at lave beregninger på geometri i en anden.
hvis du har muligheden for at bruge klasser og objekter er det en smart måde at sortere din kode, men du skal være opmærksom på at du kan have flere instanser af dine objekter, og at de ikke nødvendigvis har kendskab til hinanden..
hvis du har forskellige krav til afviklingstid, så brug tråde. De kan hjælpe til at holde kravene på f.eks. signal behandlingen, uden at du skal lave interrupt handling selv.
HVIS du er på en embedded maskine, så lad være, overheadet til operativ system og scheduler er som regel for dyrt, skriv istedet dine tidskritiske ting som interrupt drevede kald.. det er lidt sværere, og du skal selv manage memory, men det kan potentielt gå voldsomt hurtigere..
Hvis du skal lave tunge beregninger som billedbehandling, så brug en tråd, og snak med den via noget nemt, f.eks. sockets. På den måde kan du have en tråd til at håndtere GUI, og en anden til det processor tunge arbejde, det gør at din GUI ikke fryser, men også at du skal tænke dig lidt mere om så du f.eks. ikke starter flere beregningstråde samtidigt..
brug evt. low level ting som Assembly til DSP opgaver, og C til lidt mere komplekse ting, brug C++ hvis du tror at det vil være en fordel at opdele koden efter tema, og brug klasser. Brug C# eller Java eller python eller whatever højniveau til bruger interaktionen..
Qw_freak lader til at have lidt baggrund i elektronik, og derfor er jeg bare nød til at spørge hvad formålet med dit "program" er.
Eksempel:
Selv skriver jeg software der har til formål at lave feedback kontrol, på systemer der tit er open ended. F.eks. selvkørende robotter..
Det betyder grundlæggende at jeg ikke kender kravene til softwaren før end softwaren er testet i praksis og har vist sine svagheder.
I praksis har det tit vist sig at selv grundige use-case analyser ikke har taget højde for problemer i omgivelserne.
Det betyder at designet, uanset hvor grundig man laver det, aldrig er fyldestgørende, og ofte falder til jorden ved første system test.
Unit testing afslører kun om modulerne overholder kravspec, men det giver ingen mening når kravene er diffuse, og designet tit gennemgår grundlæggende forandringer når en test fejler.
Derfor har det hidtil vist sig at den effektive vej til et system design er, analyser en simpel case, implementer den, test den i praksis, se hvilke udfordringer der er tilbage, udvid programmet til at kunne håndtere endnu en udfordring.
når spaghetti koden nærmer sig noget der virker, analyser hvad der faktisk sker, (typisk et miskmask af state machines, og lineær programmering), lav et design der har nogenlunde samme opførsel, men er pakket væk i fine objekter, og kan skalere til samme type opgaver.
fortsæt med at identificere uløste udfordringer, og tilføj kode.
På et tidspunkt er du kommet langt nok til at forstå opgaven og skrive kravspec..
programmerne kan blive enormt store, og enormt komplekse, da mine brugere er fritgående dyr / mennesker, og derfor ikke er begrænsede af de knapper brugerfladen har..
------
set fra et elektronik perspektiv:
Et program er forhåbentlig ikke mere komplekst end det behøver at være.
Hvis du kan løse opgaven med 1 fil så gør du det
Hvis du har behov for en brugerflade, så prøv at skille den fra din core funktionalitet.
Filer er bare filer, du kan splitte din kode over så mange du har lyst, du kan altid få en compiler til at samle dem for dig, hold et tema i en fil, f.eks. alt der har med at bruge I/O i en fil, alt der har med at lave beregninger på geometri i en anden.
hvis du har muligheden for at bruge klasser og objekter er det en smart måde at sortere din kode, men du skal være opmærksom på at du kan have flere instanser af dine objekter, og at de ikke nødvendigvis har kendskab til hinanden..
hvis du har forskellige krav til afviklingstid, så brug tråde. De kan hjælpe til at holde kravene på f.eks. signal behandlingen, uden at du skal lave interrupt handling selv.
HVIS du er på en embedded maskine, så lad være, overheadet til operativ system og scheduler er som regel for dyrt, skriv istedet dine tidskritiske ting som interrupt drevede kald.. det er lidt sværere, og du skal selv manage memory, men det kan potentielt gå voldsomt hurtigere..
Hvis du skal lave tunge beregninger som billedbehandling, så brug en tråd, og snak med den via noget nemt, f.eks. sockets. På den måde kan du have en tråd til at håndtere GUI, og en anden til det processor tunge arbejde, det gør at din GUI ikke fryser, men også at du skal tænke dig lidt mere om så du f.eks. ikke starter flere beregningstråde samtidigt..
brug evt. low level ting som Assembly til DSP opgaver, og C til lidt mere komplekse ting, brug C++ hvis du tror at det vil være en fordel at opdele koden efter tema, og brug klasser. Brug C# eller Java eller python eller whatever højniveau til bruger interaktionen..
Mort (55) skrev:Siden hvornår er Singleton, Factory og Strategy blevet antipatterns ?
Lige præcis singleton er efterhånden blevet et antipattern. Fx. umuliggør det dependency injection, hvilket er vigtigt i en moderne arkitektur, især hvis man vil unit-teste.
http://en.wikipedia.org/wiki/Singleton_pattern#Drawbacks skrev:This pattern makes unit testing far more difficult,as it introduces global state into an application.
It should also be noted that this pattern reduces the potential for parallelism within a program, because access to the singleton in a multi-threaded context must be serialised, e.g., by locking.
Advocates of dependency injection would regard this as an anti-pattern, mainly due to its use of private and static methods.
Forestil dig fx. en metode som bla. skal indsætte noget i en database. Hvis den gør noget i denne stil:
Database.getInstance().insert(...)
Så vil den altid arbejde med den rigtige database. Men ved unit-testing vil du gerne have at den bruge en mock-database, altså en anden database.
I stedet giver du unit'en en database eller en factory:
Database database = new RealDatabase()
eller
Database database = new MockDatabase()
Og så:
new Something(database);
Inde i Something gemmer man så databasen, så eksemplet bliver til:
database.insert(...)
Vupti, problem løst. Something-klassen har ingen anelse om hvilken database der arbejdes med, og det skal den også være ligeglad med.
myplacedk (59) skrev:Lige præcis singleton er efterhånden blevet et antipattern. Fx. umuliggør det dependency injection, hvilket er vigtigt i en moderne arkitektur, især hvis man vil unit-teste.
En singleton umuliggør da ikke dependency injection, det kommer helt an på hvor du implementerer din singleton.
Hvis du vil bruge dependency injection på dit database eksempel, så kan du stadig injecte en singleton ind i den klasse du vil teste. Din singleton kan feks blive returneret af et service locator pattern, som i din unit test i stedet returnerer et mocking object.
Nej. En singleton har per definition en private constructor, og kan derfor ikke oprettes af en service locator.Mort (60) skrev:Din singleton kan feks blive returneret af et service locator pattern, som i din unit test i stedet returnerer et mocking object.
(Og direkte brug af en Service Locator er også et anti-pattern)
Derudover er en singleton meningsløst, da man med dependency injection, netop nemt kan genbruge samme instans.
Det er tilfældigt om de bliver udbudt fra semester til semester.myplacedk (57) skrev:Som sagt så HAR du kurser/moduler som specifikt handler om den slags, uanset hvad du mener. Hvem der så tager dem er en helt anden snak.
Software arkitektur var ikke et muligt tilvalg på ingeniør-uddannelsen. Der så de hellere at folk skrev slamkode i C, uden den mindste overvejelse om kode design.
#60
Jeg tror vi skal differentiere mellem "singleton" og "singleton pattern".
Der er masser af ting som i sin natur kun må eksistere én gang, og det hedder en "singleton". Det giver ingen mening at arbejde imod dette.
"Singleton pattern" er mere end det. Det er også en måde at tilgå denne singleton. Formuleret i én sætning: "Ensure a class has only one instance, and provide a global point of access to it." - det er del 2 der er problematisk.
Jeg tror vi skal differentiere mellem "singleton" og "singleton pattern".
Der er masser af ting som i sin natur kun må eksistere én gang, og det hedder en "singleton". Det giver ingen mening at arbejde imod dette.
"Singleton pattern" er mere end det. Det er også en måde at tilgå denne singleton. Formuleret i én sætning: "Ensure a class has only one instance, and provide a global point of access to it." - det er del 2 der er problematisk.
Windcape (62) skrev:Det er tilfældigt om de bliver udbudt fra semester til semester.
Det er meget almindeligt på universiteterne. Vil du have et bestemt kursus, må du vente til det kommer. Kun de aller mest populære er der hvert semester.
Windcape (62) skrev:Software arkitektur var ikke et muligt tilvalg på ingeniør-uddannelsen.
Jeg er STADIG ligeglad, det er STADIG irrelevant.
Det er da ikke irrelevant.myplacedk (64) skrev:Jeg er STADIG ligeglad, det er STADIG irrelevant.
Pointen er jo at der IKKE som en del af den aleme grundundervisning, undervises i arkitektur.
Det nævnes *MÅSKE* som en del af programmeringsundervisningen, afhængigt af underviseren.
Windcape (65) skrev:Pointen er jo at der IKKE som en del af den aleme grundundervisning, undervises i arkitektur.
What? Troller du nu igen, eller har du glemt hvad vi snakker om?
myplacedk (53) skrev:Jeg kender ikke detaljerne af de uddannelser, men universiteterne underviser naturligvis i arkitektur mv. til udvikling af større systemer.
og:
myplacedk (57) skrev:man bliver ikke arkitekt på en udvikler-uddannelse.
Hvis ikke du kan forstå at softwarearkitektur ER noget der bliver undervist i, så er det ikke noget jeg gider gøre mere ud af.
kasperd (52) skrev:Coverage procenten er ikke et endegyldigt mål for hvor godt koden er testet, men det er nok den bedste approksimation som kan sætte et tal på hvor grundigt koden er testet.
Nej.
Det rigtige mål er hvorvidt alle path gennem koden er udført ikke om al kode er udført.
Derfor windcape snakker om cyklomatisk kompleksitet.
kasperd (52) skrev:En ting kan i hvert fald siges med sikkerhed. Unit tests fanger ikke fejl i de kodelinier, der ikke bliver afviklet af unit tests.
Det er rigtigt.
Man kan ikke teste alle path uden at udføre alle kode linier,
kasperd (52) skrev:Så jeg synes at 100% unit test coverage er et fornuftigt mål at stræbe efter.
Det er ikke en garanti for at alle path er testet.
Og i det tilfælde at man ikke har resourcer til at teste alt og skal prioritere, så vil det formentligt være bedre at teste alle path i kode med høj cyklomatisk kompleksitet og springe noget af den simplere kode over end at opnå 100% coverage.
Code coverage procent er ikke ligegyldig men det er en metric som skal spises med et kilo salt til.
kasperd (52) skrev:Om man overhovedet er interesseret i en opdeling er afhængigt af omstændighederne. Der er ikke som sådan noget forkert i at compilere en stor kodebase til en enkelt programfil. Der kan være besparelse af RAM og diskplads hvis man har en fornuftig opdeling i libraries der kan genbruges. Og det kan være nemmere at udsende fejlrettelser hvis man kun skal opdatere de dele af koden der er fejl i.
Diskplads er som oftest ligegyldig.
Men det er vigtigt at kunne opdatere.
Og at kunne unit teste separat.
kasperd (52) skrev:Men det er simplere at administrere en stor programfil, så hvis ikke man har grund til at bekymre sig om resourceforbruget er det helt fint at have en stor programfil. Man bør så vidt mulig undgå at linke standard libraries ind i sin programfil fordi der kan komme sikkerhedsopdateringer til de libraries, og eksemplarer der er linket ind i et større program bliver nemt glemt når der skal opdateres.
Der kommer også opdateringer til ens egen kode.
Om koden kommer fra Big OS Inc eller Big App Inc bør ikke gøre den store forskel.
kasperd (52) skrev:Det kommer an på om man skriver white box eller black box tests. Hvis man laver testdrevet udvikling vil man i sagens natur lave black box tests af den simple grund at tests ikke kan afhænge af strukturen af koden når tests skrives før man overhovedet overvejer hvordan implementationen skal se ud.
kasperd (52) skrev:Men jeg mener faktisk man bør skrive både white box og black box tests. Lave black box tests ud fra APIen. Og lav white box tests der dækker hele koden. Tilsammen vil de to metoder dække langt de fleste tilfælde.
Jeg ser unit test som ren black box test.
Ved en ny version af et lib skal alle de gamle unit tests virke for at give client kode en vis tillid til at deres kode vil virke med den nye version.
Hvis der er rettet i unit tests fordi den har testet interne ting forsvinder den tillid.
Hvis X er så kompleks at det er ønskværdigt at teste noget internt, så er det bedre at splitte X op i XA og XB. Unit test af XA kan så bibeholdes uændret selvom XB udskiftes med XBNEW (XB og XBNEW har så deres egne unit tests).
Hvis man sætter en lang række if statements efter hinanden vokser antallet af paths exponentielt, men den cyklomatiske kompleksitet vokser kun lineært.arne_v (68) skrev:Det rigtige mål er hvorvidt alle path gennem koden er udført ikke om al kode er udført.
Derfor windcape snakker om cyklomatisk kompleksitet.
Hvor mange testkørsler der skal til for at få den kode rigtig dækket vil jeg ikke regne på klokken 23 om aftenen.
Under alle omstændigheder har jeg aldrig hævdet at det afgørende var at få alle kodelinier afviklet. Men det er det mål som de værktøjer jeg har arbejdet med har brugt.
For det første er white box tests og test af interne funktioner ikke det samme.arne_v (70) skrev:Hvis der er rettet i unit tests fordi den har testet interne ting forsvinder den tillid.
Hvis du tager en API specifikation og skriver unit tests ud fra API specifikationen har du ingen anelse om hvorvidt alt koden er testet. Det er situationen med en black box test.
Hvis du kigger på koden vil du ofte opdage at der er forgreninger der kun kan nås hvis bestemte kombinationer af kriterier er opfyldt. Så kan du skrive en test der sikrer at det er opfyldt og verificere at koden gør som APIen specificerer også i det tilfælde.
Selvom du kiggede på koden for at skrive den unit test er den stadig gyldig for enhver implementation af den pågældende API. Hvis du laver en ny implementation vil de gamle white box tests stadig skulle passere med den nye implementation.
Hvis specialtilfældene var absolut nødvendige må den nye implementation også have brug for lignende specialtilfælde, og det er en god idé at genbruge de tests man har skrevet. Hvis den nye tests på en eller anden smart måde undgår specialtilfælde i koden er det stadig en god idé at genbruge sine tests for at se at den nye smarte metode stadig fungerer.
En white box test af en ny implementation vil måske afsløre at der er ikke er 100% dækning af den nye kode. Så kan man skrive flere unit tests for at lave komplet test af den nye implementation. Det vil så være en udmærket idé at teste de unit tests imod den gamle implementation for at sikre sig at testene giver mening.
kasperd (71) skrev:Hvis man sætter en lang række if statements efter hinanden vokser antallet af paths exponentielt,
Ja. Desværre. Pointen gælder dog stadig,
kasperd (71) skrev:Under alle omstændigheder har jeg aldrig hævdet at det afgørende var at få alle kodelinier afviklet. Men det er det mål som de værktøjer jeg har arbejdet med har brugt.
Det er ret udbredt. Men det gør ikke metric'en bedre.
kasperd (71) skrev:
For det første er white box tests og test af interne funktioner ikke det samme.
Hvis du tager en API specifikation og skriver unit tests ud fra API specifikationen har du ingen anelse om hvorvidt alt koden er testet. Det er situationen med en black box test.
Hvis du kigger på koden vil du ofte opdage at der er forgreninger der kun kan nås hvis bestemte kombinationer af kriterier er opfyldt. Så kan du skrive en test der sikrer at det er opfyldt og verificere at koden gør som APIen specificerer også i det tilfælde.
Selvom du kiggede på koden for at skrive den unit test er den stadig gyldig for enhver implementation af den pågældende API. Hvis du laver en ny implementation vil de gamle white box tests stadig skulle passere med den nye implementation.
Hvis specialtilfældene var absolut nødvendige må den nye implementation også have brug for lignende specialtilfælde, og det er en god idé at genbruge de tests man har skrevet. Hvis den nye tests på en eller anden smart måde undgår specialtilfælde i koden er det stadig en god idé at genbruge sine tests for at se at den nye smarte metode stadig fungerer.
En white box test af en ny implementation vil måske afsløre at der er ikke er 100% dækning af den nye kode. Så kan man skrive flere unit tests for at lave komplet test af den nye implementation. Det vil så være en udmærket idé at teste de unit tests imod den gamle implementation for at sikre sig at testene giver mening.
Denne subtråd startede med diskussion om test af internal inden den bevægede sig lidt over i whitebox/blackbox.
Jeg er voldsomt imod unit tests som kun kan køre mod en specifik implementation.
Jeg har ikke noget imod unit tests som er interessante for en specifik implementation men virker for alle implementationer.
Windcape (54) skrev:En god arkitekt kan også finde ud af at kode.
En software arkitekt er nødt til at kunne kode for at være god til sit job.
Infrastruktur arkitekter, enterprise arkitkter, security arkitekter etc. har ikke det behov.
Solution arkitekter er lidt mere åben for diskussion, men jg vil mene ja.
Windcape (61) skrev:
Og direkte brug af en Service Locator er også et anti-pattern
Nogen som har læst:
http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAn...
:-)
Men prøv og læs den meget grundigt og prøv og træk essensen ud og generaliser den.
Resultatet vilnok overraske dig!
#Singleton
For 10 år siden var det hipt at kunne alle GoF patterns.
Idag er det hipt at mene at Singleton er skidt.
Ofte er argumenterne særdeles tvivlsomme. Eksempel fra den allerede citerede wikipedia artikel:
Hm.
Hvis al tilgang er readonly behøver man ikke serialisering af tilgangen. Udover det som er nødvendig for visibility - men det er ens uanset om det er singleton eller ikke singleton.
Hvis flere tråde modificerer skal tilgangen naturligvis synkroniseres - men det er ens uanset om det er singleton eller ikke singleton.
Det er skidt for performance at serialisere tilgang til et delt objekt fremfor at have et objekt per tråd, hvis det sidste er muligt. Men det har heller ikke noget med singleton at gøre.
Det er rigtigt at singleton per definition er umulig at mocke.
Så hvis man:
- skal unit teste via mocking
- det er umuligt/upraktisk at mocke det som bruger singleton
- det er umuligt/upraktisk at mocke det som singleton bruger
så er singleton et dårligt valg.
Det er imidlertid en del hvis'er. Og jeg mener ikke at det er tilstrækkeligt til at kalde det for et anti pattern.
Det er naturligvis tilstrækkeligt til at man skal tænke sig lidt om!
For 10 år siden var det hipt at kunne alle GoF patterns.
Idag er det hipt at mene at Singleton er skidt.
Ofte er argumenterne særdeles tvivlsomme. Eksempel fra den allerede citerede wikipedia artikel:
It should also be noted that this pattern reduces the potential for parallelism within a program, because access to the singleton in a multi-threaded context must be serialised, e.g., by locking.
Hm.
Hvis al tilgang er readonly behøver man ikke serialisering af tilgangen. Udover det som er nødvendig for visibility - men det er ens uanset om det er singleton eller ikke singleton.
Hvis flere tråde modificerer skal tilgangen naturligvis synkroniseres - men det er ens uanset om det er singleton eller ikke singleton.
Det er skidt for performance at serialisere tilgang til et delt objekt fremfor at have et objekt per tråd, hvis det sidste er muligt. Men det har heller ikke noget med singleton at gøre.
Det er rigtigt at singleton per definition er umulig at mocke.
Så hvis man:
- skal unit teste via mocking
- det er umuligt/upraktisk at mocke det som bruger singleton
- det er umuligt/upraktisk at mocke det som singleton bruger
så er singleton et dårligt valg.
Det er imidlertid en del hvis'er. Og jeg mener ikke at det er tilstrækkeligt til at kalde det for et anti pattern.
Det er naturligvis tilstrækkeligt til at man skal tænke sig lidt om!
Windcape (54) skrev:
Desværre lærer de folk alt for mange ubrugelige antipatterns. En af mine venner læser datamatiker nu, og der er alt for meget fokus på Singleton, Factory, og Strategy.
Og de lærer stadigvæk ikke dependency injection, selvom jeg imo. mener det er det vigtigste design-pattern i moderne programmering!
Nu består de fleste DI frameworks jo af factory og strategy pattern kombineret med en lille rekursiv finesse ....
:-)
Windcape (54) skrev:På datalogi undervises der i distributed computing, men fra et mere matematisk synspunkt.
Se bare artiklen om de 2 dataloger, der brugte node.js, fordi de ikke kunne få Java til at skalere.
Nu mner jeg ikke at deres problemer var relateret til distribueret computing.
Men jg er helt enig i at deres tilgang til software udvikling var super pinlig.
Windcape (61) skrev:Derudover er en singleton meningsløst, da man med dependency injection, netop nemt kan genbruge samme instans.
Singleton pattern og diverse DI framework singleton er lidt forskellige.
Med singleton pattern enforcer programmøren af klassen at der kun findes en instans.
Diverse DI framework singleton giver kalderen mulighed for at få samme instans.
Hvilket i ordenlige programmeringssprog, vil være en statisk klasse.arne_v (79) skrev:Med singleton pattern enforcer programmøren af klassen at der kun findes en instans.
Hvilket er den hyppigste grund til at man valgte at bruge singleton i første omgang.arne_v (79) skrev:Diverse DI framework singleton giver kalderen mulighed for at få samme instans
Jeg kan godt forstå folk synes at skulle ctor injecte 10 dependencies kunne blive ret skræmmende, men med IoC frameworks i dag, er der jo ikke rigtig nogen undskyldning for at lade være.
At genbruge en database instans, uden at skulle wrappe den i en singleton er nemt og smertefrit med IoC. Og netop database er nok det hyppigste eksempel på (mis)brug af singleton som jeg har set.
Jeg kan ikke lige fange din pointe her.arne_v (75) skrev:Men prøv og læs den meget grundigt og prøv og træk essensen ud og generaliser den.
Men jeg synes da at Mark har ret. Derudover så har jeg oplevet mange som har misforstået DI/IoC, ved at bruge container.Resolve over alt frem for ctor/property injection.
Det er allerværst når der bruges en statisk container. Men selv med f.eks. Unity, hvor der injectes en IContainer er det ikke særlig meget bedre.
Man kunne jo ligeså godt have injected de dependencies man skulle bruge i første omgang.
Med IoC sparer man jo også flere linjers kode på den måde! Og det er jo dejligt.
Windcape (80) skrev:
Hvilket i ordenlige programmeringssprog, vil være en statisk klasse.
Hvis det skal gøres rigtigt således at der kan extendes/implementeres, så ender det jo med at blive lidt syntaktisk sukker over at man henter en instans via noget static.
Windcape (80) skrev:Og netop database er nok det hyppigste eksempel på (mis)brug af singleton som jeg har set.
Database connection pool kan laves som singleton. Men database connection som singleton er meget slem.
Da jeg ikke er interesseret i at blive taget til indtægt for noget jeg aldrig har sagt vil jeg lige rette en misforståelse: Jeg har aldrig sagt at man ikke behøver at test kode med en cyklomatisk kompleksitet på 1. Tværtimod mener jeg at det er vigtigt at teste al kode - bl.a. fordi man jo ikke ved om den cyklomatiske kompleksitet vil vedblive at være 1.
Det ville være white box testing hvis man undlod at teste på baggrund af sådan et kriterium.
Hvad jeg har sagt (og står ved) er at (i det mindste i .NET) vil der være kode, man ikke kan unit teste, og at sådan kode bør reduceres så den har en cyklomatisk compleksitet på 1.
Det ville være white box testing hvis man undlod at teste på baggrund af sådan et kriterium.
Hvad jeg har sagt (og står ved) er at (i det mindste i .NET) vil der være kode, man ikke kan unit teste, og at sådan kode bør reduceres så den har en cyklomatisk compleksitet på 1.
Gå til top
Opret dig som bruger i dag
Det er gratis, og du binder dig ikke til noget.
Når du er oprettet som bruger, får du adgang til en lang række af sidens andre muligheder, såsom at udforme siden efter eget ønske og deltage i diskussionerne.