Softwareudviklingsprincipper er et sæt specifikke regler og anbefalinger, som ingeniører bør følge under programimplementeringen, hvis de ønsker at skrive smuk, klar og vedligeholdelsesvenlig kode. Der findes ingen tryllestav, der kan forvandle et miskmask af variabler, klasser og funktioner til perfekt kode, men der er nogle få råd og tips, der kan hjælpe en ingeniør med at afgøre, om han gør det rigtige.
Lad os tage et kig på disse grundlæggende anbefalinger. Nogle af nedenstående principper er Python-specifikke, men de fleste er ikke.
Mål to gange og skær én gang
Jeg tror, at det er det vigtigste princip af alle. Hvis du kun lærer ét princip af dette indlæg, bør det være dette. Vi, udviklere/arkitekter/ledelsesfolk kæmper med manglende opmærksomhed, dumme fejl og trykfejl, personlige problemer, dårligt humør og kold kaffe. Intet af dette er relevant – problemet skal løses. For mig som ingeniør betyder dette princip at vælge den rigtige løsning på problemet, at vælge den rigtige tilgang til problemet, at vælge de rigtige værktøjer til at løse problemet, at have tillid til den opbyggede løsning. At vælge betyder her at gøre sig nogle overvejelser, finde de nødvendige ressourcer, sammensætte det rigtige hold, tænke over design, tænke over fremgangsmåden, fastsætte opgaver, kontrollere resultatet og bære ansvaret for dette. Dette er “Engineering as is”. Jeg tror ikke, at jeg selv er klar til at beskrive det med korrekte ord.
Don’t Repeat Yourself (DRY)
Det er et ret simpelt, men meget nyttigt princip, som siger, at det er en dårlig idé at gentage det samme forskellige steder. Først og fremmest hænger det sammen med nødvendigheden af yderligere støtte og ændring af koden. Hvis et eller andet kodefragment duplikeres flere steder i et program, er der stor sandsynlighed for to katastrofale situationer:
- Når man foretager selv små ændringer i kildekoden, er man nødt til at ændre den samme kode flere steder. Det vil kræve ekstra tid, indsats og opmærksomhed(ofte er det ikke let).
- Det første punkt følger efter det andet. Du eller en anden udvikler fra dit team kan ved et uheld overse en af ændringerne(det kan ske blot ved at sammenlægge grene i vcs) og stå over for de efterfølgende fejl i applikationen. Disse fejl kan være frustrerende for dig, fordi du har hørt, at en sådan fejl allerede er blevet rettet.
I denne henseende er der en anbefaling – hvis en kode findes i listen mere end to gange, bør den placeres på en separat måde. Dette er en generel anbefaling. Faktisk bør du overveje at oprette en separat metode, selv hvis du støder på en gentagelse anden gang.
Occams Razor
Det er en meget almindelig idé, som kom til programmering fra filosofien. Princippet har fået sit navn fra den engelske munk William of Oakham. Dette princip siger: “Enheder skal ikke mangfoldiggøres uden nødvendighed”. Inden for teknikken fortolkes dette princip således: Der er ingen grund til at skabe unødvendige entiteter uden nødvendighed. Det er således altid en god idé først at overveje fordelene ved at tilføje endnu en metode/klasse/værktøj/proces osv. Hvis man tilføjer endnu en metode/klasse/værktøj/proces osv. og man ikke får andre fordele end øget kompleksitet, hvad er så meningen?
Keep It Simple Stupid (KISS)
Dette er et princip, der minder meget om ovenstående, men det har en lidt anden betydning. Dette princip siger, at koden skal være så enkel som muligt uden komplekse strukturer, da det ellers vil besværliggøre fejlfinding og vedligeholdelse af koden. Desuden vil det være vanskeligere for en anden programmør at forstå kodens logik, hvilket igen vil kræve ekstra tid og kræfter. Derfor bør du altid forsøge at bruge enkle konstruktioner, der løser problemet så meget som muligt uden talrige forgreninger, dyb indlejring og overdrevent overbelastede klassestrukturer. Ved at gøre dette vil du gøre livet lettere for dig selv og dine kolleger, fordi kompleksitet genererer fejl. Husk, hvad Peter Hintiens sagde: “Simplicity is always better than functionality”.
You Aren’t Gonna Need It (YAGNI)
Et problem, som mange programmører lider under. Ønsket om at implementere al nødvendig (og nogle gange endda unødvendig) funktionalitet på én gang fra starten af projektet. Det vil sige, når en udvikler tilføjer alle mulige metoder til klassen helt fra starten og implementerer dem, og måske endda aldrig bruger dem i fremtiden. I henhold til denne anbefaling skal man således først og fremmest kun implementere det, man har brug for, og senere, hvis det er nødvendigt, udvide funktionaliteten. På den måde sparer du kræfter, tid og nerver på at fejlfinde kode, som der ikke rigtig er brug for.
Stort design på forhånd
Hvor du begynder at udvikle funktionalitet, bør du først tænke over applikationsarkitekturen og designe hele systemet til tilstrækkeligt små detaljer, og først derefter gå videre til implementering efter en foruddefineret plan. Princippet har sin eksistensberettigelse, men på det seneste har der været en hel del kritik af det. Det hænger først og fremmest sammen med planens forældelse under projekteringen og udarbejdelsen. I den forbindelse er det nødvendigt at foretage de efterfølgende ændringer stadig. Men det har også ubestridelige fordele, ved korrekt projektering er det muligt at reducere omkostningerne til yderligere fejlfinding og korrektion af fejl betydeligt. Desuden er sådanne informationssystemer som regel mere lakoniske og arkitektonisk korrekte.
Undgå for tidlig optimering
“For tidlig optimering er roden til alt ondt (eller i hvert fald det meste af det) i programmering” – Donald Knuth
Optimering er en meget korrekt og nødvendig proces for at fremskynde programmet samt for at reducere forbruget af systemressourcer. Men alt har sin egen tid. Hvis optimering udføres i de tidlige faser af udviklingen, kan det gøre mere skade end gavn. Først og fremmest hænger det sammen med, at udviklingen af en optimeret kode kræver mere tid og kræfter til udvikling og support. I dette tilfælde er man ret ofte nødt til at kontrollere korrektheden af den valgte udviklingstilgang i første omgang. Derfor er det i første omgang mere rentabelt at anvende en enkel, men ikke den mest optimale tilgang. Og senere, når man vurderer, hvor meget denne fremgangsmåde forsinker arbejdet med en applikation, skal man gå videre til en hurtigere eller mindre ressourcekrævende algoritme. Desuden kan kravene ændre sig, så længe du i første omgang implementerer den mest optimale algoritme, og koden ryger i skraldespanden. Så der er ingen grund til at spilde tid på for tidlig optimering.
Principle Of Least Astonishment
Dette princip betyder, at din kode skal være intuitiv og indlysende og ikke overraske en anden udvikler ved gennemgangen af koden. Hvis metoden f.eks. hedder “making cookies”, men du får kartofler som resultat, så er den kode dårlig (naturligvis). Desuden bør du forsøge at undgå sideeffekter og dokumentere dem, hvis du ikke kan undgå dem.
S.O.L.I.D.
“SOLID” er faktisk en gruppe af objektorienterede designprincipper. Hvert bogstav i “SOLID” repræsenterer et af principperne, som er:
- Enkelt ansvar angiver, at hvert modul eller hver klasse skal have ansvaret for en enkelt del af den funktionalitet, som softwaren leverer, og at dette ansvar skal være fuldstændig indkapslet af klassen;
- Åbent-lukket angiver, at softwareenheder (klasser, moduler, funktioner osv.) bør være åbne for udvidelse, men lukkede for ændring;
- Liskov-substitution siger, at den arvede klasse bør supplere, ikke erstatte basisklassens adfærd;
- Grænsefladesegregation siger, at ingen klient bør tvinges til at være afhængig af metoder, som den ikke bruger;
- Dependency inversion siger, at programmøren bør arbejde på grænsefladeniveau og ikke på implementeringsniveau.
Når disse principper anvendes sammen, hjælper de en udvikler med at skabe kode, der er let at vedligeholde og udvide over tid.
Law of Demeter
Den grundlæggende idé med dette princip er at opdele ansvarsområderne mellem klasser og indkapsle logikken i en klasse, metode eller struktur. Der kan skelnes mellem flere anbefalinger ud fra dette princip:
- Klasserne eller enhederne bør være uafhængige
- Du bør forsøge at reducere antallet af forbindelser mellem forskellige klasser (såkaldt kobling).
- De tilknyttede klasser skal være i ét modul/pakke/mappe (også kaldet kohæsion).
Folger man disse principper, bliver programmet mere fleksibelt, forståeligt og let at vedligeholde.
Konklusion
Lad os være ingeniører, udviklere! Lad os tænke på design og bygge robuste og velimplementerede systemer, i stedet for at dyrke organiske monstre. De oplistede principper er i høj grad korreleret og forbundet i deres essens. Selvfølgelig har jeg ikke skabt dem, men en lille påmindelse skader ikke, i hvert fald er min hukommelse bestemt ikke perfekt.
Anbefalede bøger
- Clean Code by Robert C. Martin
- Clean Architecture by Robert C. Martin