Home » Programmering » 10 fejl som alle programmører laver
10 fejl som alle programmører laver

10 fejl som alle programmører laver

Share

Uanset hvor længe du har programmeret, har du begået fejl som disse

Når man begynder at programmere, bliver man hurtigt desillusioneret. Computeren er ikke længere den ufejlbar- lige og perfekte maskine – »gør, som jeg mener, ikke som jeg siger« bliver et tilbagevendende udråb.

Om natten, når de forbistrede nisser omsider går i seng, ligger man og grubler over de fejl, man har begået i dagens løb, og de er værre end nogen gyserfilm. Derfor reagerede vi med en blanding af frygt og lydighed, da vi blev bedt om at skrive denne artikel.

Vi regnede med, at vi kunne få teksten fra hånden i løbet af et par timer og smutte ned på baren uden de sædvanlige natlige mareridt. Problemet med den slags opgaver er blot: Hvilket sprog taler vi om?

Vi kan ikke blot køre op med de hyppigste ti fejl, man kan begå i C#, Delphi, JavaScript eller noget lignende. På en eller anden måde skulle vores toptiliste omfatter alle sprog. Pludselig virkede opgaven sværere. Nisserne begyndte at skræppe op i vores hoveder. Nå, lad os få set på det…

1. Man skriver til compileren, ikke til mennesker

Når folk bruger en compiler til at lave applikationer, har de en tilbøjelighed til at glemme, at den vidtløftige grammatik og syntaks, der kræves for at gøre programmeringen nemmere, bliver skudt til side, når prosaen skal konverteres til maskinkode. En compiler er ligeglad med, om du bruger et datanavn på ét bogstav eller et, der er lettere at læse for mennesker.

Compileren er ligeglad med, om du skriver optimerede udtryk eller sætter parenteser omkring underudtryk. Den tager din kode, der kan læses af mennesker, parser den til abstrakte syntakstræer og konverterer disse træer til maskinkode eller en form for mellemsprog.

På det tidspunkt er dine navne historie. Hvorfor ikke bruge mere læselige eller semantisk signifikante datanavne end blot i, j eller x? Nu om dage er den ekstra tid, det tager at oversætte længere datanavne, diminutiv. Til gengæld sparer du megen tid, når du eller en anden programmør skal læse din kildekode, hvis koden er skrevet, så den er selvforklarende og nemmere at forstå.

En tilsvarende pointe: Du har måske lært operatørrangfølgen udenad i en grad, så du kan udelade unødvendige parenteser i dine udtryk, men hvad med den næste programmør, der skal se på din kode? Kender han rangfølgen for operatører på et andet sprog bedre end på dette, hvilket får ham til at fejllæse din kode og foretage forkerte antagelser om, hvordan den virker?

Vi antager, at alle ved, at multiplikation (eller division) finder sted før addition og subtraktion, men det er også alt. Hvis der er andet i et udtryk, smider vi parenteser ind for at sikre, at vi skriver det, vi havde til hensigt at skrive, og at andre mennesker kan læse det, vi har på hjerte. Compileren er komplet ligeglad.

Undersøgelser har vist, at den tid, der bliver brugt på at vedligeholde en kode, er mindst fem gange så lang som den tid, der blev brugt på at skrive den. Det er fornuftigt at skrive sin kode, så andre kan læse og forstå den.

2. Man skriver store rutiner

Da vi var begyndere, fandtes der en tommelfingerregel, der sagde, at rutiner aldrig burde være længere end et ark leporellopapir – og det omfattede den kommentarboks foroven, som var moderne dengang.

Siden da, især i de seneste år, har metoderne haft en tendens til at være meget mindre – blot få linjer kode. Strengt taget kun kode nok til, at man kan fatte dens betydning og hurtigt forstå den. Lange metoder er upopulære og bliver som regel brudt op.

Årsagen er ekstremt enkel: Lange metoder er svære at forstå og derfor svære at vedligeholde. De er også svære at teste ordentligt. Hvis man erindrer, at test er en funktion af antallet af mulige stier gennem en metode, fremgår det, at jo længere metoden er, desto flere test skal man skrive, og desto mere indviklede bliver disse test.

Der findes faktisk en god målestok, som man kan bruge på sin kode for at vise, hvor kompleks den er, og dermed hvor sandsynligt det er, at den har fejl: Cyklomatisk kompleksitet.

Cyklomatisk kompleksitet blev udviklet af Thomas J. McCabe senior i 1976. Den er meget kompliceret, hvis du vil bruge den ordentligt, men der findes en nem og enkel metode, som du kan bruge på farten.

Tæl blot antallet af »if«-statements og løkker i din kode. Tilføj 1, så får du CC-værdien i din kode. Det er en anslået optælling af antallet af kodens eksekveringsstier. Hvis din metode har en værdi, der er højere end 10, bør du skrive den om.

3. For tidlig optimering

Den her er enkel. Når vi skriver kode, sidder der somme tider en smålig djævel på skulderen af os og siger, at den her raffinerede kode ville være en anelse hurtigere end den, du lige har skrevet.

Glem alt om, at den raffinerede kode er sværere at læse og vanskeligere at forstå; du barberer millisekunder af denne løkke. Det kaldes for tidlig optimering. Den berømte computervidenskabsmand Donald Knuth sagde engang: »Vi bør glemme små effektivitetsforbedringer omkring 97 procent af tiden: For tidlig optimering er roden til alt ondt.«

Med andre ord: Skriv din kode klart og rent. Profiler den så for at finde ud af, hvor de virkelige flaskehalse er, og optimer dem. Lad være med at gætte på forhånd.

4. Brug af globale variabler

Da vi begyndte i branchen, havde masser af sprog slet intet greb om lokale variabler, og vi måtte derfor bruge globale variabler. Der fandtes underrutiner, men man kunne ikke definere en variabel til brug i blot denne rutine – man var nødt til at bruge en, der var synlig fra hele ens kode.

Se også:  Guide: Lav apps til mobilen

Ikke desto mindre er de så tillokkende, at man næsten føler, at man er grøn og miljøbevidst, når man bruger dem. Man definerer dem kun en gang og bruger dem over det hele, og man fornemmer, at man sparer kostbar hukommelse, Men det er det med at bruge dem over det hele, der giver problemer.

Det fine ved globale variabler er, at de er synlige overalt. Det er også det værste ved globale variabler: Man kan ikke styre, hvem der ændrer dem, eller hvornår variablen bliver tilgået. En global kan have en bestemt værdi før et kald til en rutine, og den kan være anderledes, når man får styringen igen, men man bemærker det ikke.

Da folk fandt ud af, at globale variabler var skadelige, kom der naturligvis noget med et andet navn, men det var blot en global variabel i forklædning. Det var en singleton, et objekt der skal repræsentere noget, hvoraf der kun kan være en i et givet program. Et klassisk eksempel kan være et objekt, der indeholder information om dit programs vindue, det placering på skærmen, dets størrelse, dets overskrift og lignende.

Hovedproblemet med singletonobjektet er muligheden for test. Der er tale om globale objekter, og derfor bliver de dannet, når de bliver brugt første gang, og først destrueret, når selve programmet lukker ned.

[pt id=’2012322′ size=’large’ link=’file’]

 

Denne vedholdenhed gør det ekstremt svært at teste dem. Senere test bliver skrevet ud fra den betragtning, at der er kørt tidligere test, som arrangerede singletonens indre tilstand.

Et andet problem er, at en singleton er et komplekst globalt objekt, og der blevet sendt en reference til det gennem programmets kode. Din kode er nu afhængig af en anden klasse. Og den er koblet til den singleton.

Under test ville du være nødt til at bruge denne singleton. Dine test ville så blive afhængige af dens tilstand, tilsvarende det problem du havde med at teste denne singleton i første omgang. Derfor skal man ikke bruge globale, og man skal undgå singletons.

5. Man foretager ikke skøn

Du skal netop til at skrive en applikation. Du er så spændt på det, at du går i gang og begynder at designe og skrive den. Du frigiver den, og pludselig bliver du overvældet af problemer med ydelse eller mangel på hukommelse.

Nærmere undersøgelser viser, at selvom dit design virker udmærket med et lille antal brugere, poster eller elementer, skalerer det ikke – tænk på Twitters barndom, hvis du vil have et godt eksempel.

Eller også virker det glimrende på din forrygende udvikler-pc på 3GHz med 8GB ram og et ssd-drev, men på en almindelig pc er det langsommere end en grønlandsk gletsjer i januar.

En del af din designproces burde have omfattet nogle skøn, nogle hurtige beregninger. Hvor mange samtidige brugere har du tænkt dig? Hvor mange poster? Hvilken responstid sigter du på?

Prøv at lave skøn over den slags spørgsmål, så kan du træffe beslutninger om de teknikker, du kan indbygge i din applikation, såsom forskellige algoritmer eller caching. Lav være med at kaste dig hovedkulds ind i programmeringen. Tag dig tid til at vurdere dine mål.

6. En ved siden af

Denne fejl begår alle hele tiden. Den består i at skrive en løkke, der øges en gang for ofte eller en gang for sjældent. Følgen er, at løkken drejes et ukorrekt antal gange. Hvis koden i løkken besøger elementer i et array en ad gangen, kan man tilgå – eller endnu værre: Skrive til – et ikkeeksisterende element i arrayet, eller elementet bliver måske helt overset.

En grund til, at du kan komme ud for at ramme en ved siden af, er, at du glemmer, om indekser til arrayelementer er nulbaserede eller etbaserede. I nogle sprog forekommer det endda, at et objekt er nulbaseret, mens andre er etbaserede.

Der findes så mange varianter af denne fejl, at moderne sprog eller deres runtimes har funktioner såsom (»for hver-løkker«) for at undgå behovet for at tælle gennem elementer i et array eller en liste. Andre bruger funktionelle programmeringsteknikker, der kaldes map, reduce og filter, til at undgå gentagne gennemgange af samlinger.

Brug moderne »funktionelle« løkker frem for gentagne løkker.

7. Man undertrykker undtagelser

Moderne sprog bruger et undtagelsessystem til at rapportere fejl i stedet for de gamle traditionelle øvelser med at tjekke fejlbehæftede tal. Sproget inkorporerer nye nøgleord til at sende og fange undtagelser, og det bruger navne såsom throw, try, finally og catch.

Det påfaldende ved undtagelser er deres evne til at afvikle stakken. De vender automatisk tilbage fra indlejrede rutiner, indtil undtagelsen er fanget og bearbejdet. Så skal du ikke længere tjekke for fejltilstande og gøre din kode til et morads af fejltest. Alt i alt giver undtagelser mere robust software, forudsat at de bliver brugt rigtigt.

Catch er den mest interessante: Med den kan du fange en undtagelse, der er blevet smidt, og handle på baggrund af undtagelsens art. De største fejl, programmører laver med undtagelser, er dobbelte.

Den første er, at programmøren ikke er tilstrækkelig specifik i arten af den undtagelse, han fanger. Hvis man fanger en undtagelsestype for generelt, kan man uafvidende komme til at beskæftige sig med undtagelser, der burde overlades til anden kode højere oppe i kaldskæden. Disse undtagelser bliver i realiteten undertrykt og går måske til grunde.

Se også:  Guide: Lav apps til mobilen

Den anden fejl er mere skadelig: Programmøren ønsker ikke, at nogen undtagelser forlader hans kode, og derfor fanger og ignorerer han dem. Det kaldes den tomme catch-blok. Han tror for eksempel, at kun visse former for undtagelser kan blive smidt ind i denne kode, og at han derfor kan ignorere dem.

I virkeligheden kan der forekomme andre farlige runtime-undtagelser. Man kan komme ud for manglende hukommelse-undtagelser, ugyldige kodeundtagelser og lignende, og programmet burde slet ikke køre videre med dem. Sørg for, at dine undtagelses-catch-blokke er så specifikke som muligt.

8. Man gemmer hemmeligheder som rå tekst

En af os arbejdede engang i en bank. Den købte et nyt computersystem, der skulle styre handel med obligationer. En del af jobbet bestod i at tjekke dette system for at se, om det virkede som foreskrevet, og om det var fejlfrit. Det drejede sig trods alt om millioner af kroner hver dag.

Dengang var det som nu: En virksomhed løber større risiko for at blive bedraget af en ansat end af en udenfor. Efter 15 minutter med en simpel hex-editor viste det sig, at administratorens kodeord var gemt som rå tekst.

Datasikkerhed fortjener en fyldigere behandling, end vi har plads til her, men du må aldrig, aldrig gemme kodeord som rå tekst. Standarden for kodeord er at gemme den maltrakterede udgave af det oprindelige kodeord og derefter gennemgå den samme maltraktering af et indtastet kodeord for at se, om de stemmer.

Her er et nyttigt vink: Hvis et website tilbyder at maile dit originale kodeord til dig, bør du glemme alt om det og forlade sitet. Det er et enormt sikkerhedsproblem. En dag bliver det site hacket.

Du læser om alle de login-funktioner, der er blevet manipuleret, og du mærker panikken melde sig. Lad være med at være en af dem, hvis information er blevet manipuleret, og lad være med at gemme kodeord eller andre »hemmeligheder« som rå tekst i dine applikationer.

9. Man verificerer ikke brugerinput

I de gode gamle dage blev vores programmer kørt af enkeltpersoner, et ad gangen. Vi tog brugerinputtet med knusende ro. Herregud, hvis programmet gik ned, gik det kun ud over en person – den ene bruger af programmet på det tidspunkt. Vores inputverifikation var begrænset til tal-verifikation eller datatjek eller andre former for inputverifikation. Tekstinput blev ikke verificeret synderligt.

Så kom nettet. Pludselig bliver dit program brugt over hele verden, og du har mistet forbindelsen med brugeren. Ondsindede brugere kan indføre data i dit program med det formål at overtage din applikation eller dine servere.

[pt id=’2012323′ size=’large’ link=’file’]

 

Der er foretaget et væld af luskede angreb, som har draget fordel af manglen på tjek af brugerinput. Det berømteste er SQL-injektion, selv om urent brugerinput kan fremskynde et XSS-angreb (cross-side-scripting) via opmarkeringsinjektion.

Begge former bygger på, at brugeren som en del af normalt input leverer noget tekst, der indeholder enten SQL- eller html-fragmenter. Hvis applikationen ikke verificerer brugerinput, bruger den det måske blot, som det er, og forårsager, at noget hacket SQL bliver eksekveret, eller at noget hacket html/JavaScript bliver produceret. Det kan føre til, at applikationen går ned, eller at den bliver overtaget af hackeren.

Man skal derfor altid gå ud fra, at brugeren er en hacker, der prøver at ødelægge eller overtage din applikation. Man skal verificere brugerinput.

10. Man er ikke ajour

Alle de foregående fejl er blevet omhyggeligt behandlet på nettet og i forskellige bøger. Vi har ikke fundet noget nyt – disse og andre fejl har man kendt i årevis.

Nu om dage skal man gøre sig umage for at undgå at komme i berøring med moderne design- og programmeringsteknikker. Hvis man ikke tager sig tid til at sætte sig ind i programmering – og holder sin viden ved lige – begår man den største fejl, en programmør kan begå.

Man bør lære om teknikker som tdd og bdd, om SLAP og SOLID og om forskellige agile-teknikker. Denne viden er mindst lige så vigtig som at forstå, hvordan man skriver en løkke i sit foretrukne sprog.

Lad være med at være ligesom de andre: Læs McConnell og Besk og Martin og Jeffries of The Gang of Four og Hunt & Thomas og så videre. Sørg for at være ajour med kunsten at programmere.

Så kom vi igennem toptilisten over de fejl, programmører begår, uanset sprog. Der er andre, der måske kan være mere ødelæggende end disse, men frygten for disse fejl står i et rimeligt forhold til konsekvenserne af at begå dem. De var slemme nok for os, sidste gang vi begik dem.

Når det gælder den tiende fejl i denne artikel, anbefaler vi, at en udvikler holder sig ajour med moderne teknikker til udvikling af applikationer. Hvis du følger disse teknikker, kan du undgå mange af de andre fejl, vi har nævnt.

Som vi nævnte i indledningen, kan forskellige sprog have deres særheder, som man skal undgå, men i det store og hele består den bedste måde at undgå fejl på i at lade være med at begå dem. Det kan du kun opnå via bedre uddannelse.

Her er en kort liste over bøger, som vi finder uvurderlige, når det gælder om at blive en bedre programmør, uanset hvilket sprog det drejer sig om.

McConnell – Code Complete 2
Hunt & Thomas – The Pragmatic Programmer
Gamma, Helm, Johnson & Vlissides – Design Patterns
Fowler – Refactoring
Beck – Test-Driven Development
Evans – Domain-Driven Development
Martin – Agile Software Development

[themepacific_accordion] [themepacific_accordion_section title=”Fakta”]

Testdrevet udvikling

[/themepacific_accordion_section] [/themepacific_accordion]


TAGS
javascript

DEL DENNE
Share

Seneste Tech test
Seneste konkurrencer

Mest populære
Populære
Nyeste
Tags

Find os på de sociale medier

Modtag dagligt IT-nyhedsbrev

Få gratis tech-nyheder i din mail-indbakke alle hverdage. Læs mere om IT-UPDATE her

Find os på FaceBook

Alt om DATA

Lautrupsgade 7,
DK-2100 København Ø
Telefon: 33 91 28 33
redaktion@altomdata.dk

Datatid TechLife

Lautrupsgade 7,
DK-2100 København Ø
Telefon: 33 91 28 33
redaktion@datatid.dk

Audio Media A/S

CVR nr. 16315648,
Lautrupsgade 7,
DK-2100 København Ø
Telefon: 33 91 28 33
info@audio.dk
Annoncesalg / Prislister:
Lars Bo Jensen: lbj@audio.dk Telefon: 33 74 71 16
Annoncer: Medieinformation


Alt om DATA, Datatid TechLife  © 2019
Privatlivspolitik og cookie information - Audio Media A/S