Principerna för programvaruutveckling är en uppsättning specifika regler och rekommendationer som ingenjörer bör följa under programimplementeringen om de vill skriva vacker, tydlig och underhållbar kod. Det finns ingen magisk stav som kan förvandla ett virrvarr av variabler, klasser och funktioner till perfekt kod, men det finns några tips och råd som kan hjälpa en ingenjör att avgöra om han gör rätt.
Låt oss ta en titt på dessa grundläggande rekommendationer. Några av principerna nedan är Python-specifika, men de flesta är inte det.
Mät två gånger och skär en gång
Jag tror att det är den viktigaste principen av alla. Om du bara lär dig en enda princip från det här inlägget bör det vara den här. Vi, utvecklare/arkitekter/chefer människor kämpar med bristande uppmärksamhet, dumma misstag och felskrivningar, personliga problem, dåligt humör och kallt kaffe. Inget av detta är relevant – problemet måste lösas. För mig som ingenjör innebär denna princip att välja rätt lösning på problemet, välja rätt tillvägagångssätt för att lösa problemet, välja rätt verktyg för att lösa problemet, förtroende för den byggda lösningen. Att välja här innebär att man måste tänka efter, hitta de nödvändiga resurserna, sätta ihop rätt grupp, tänka på utformningen, tänka på tillvägagångssättet, fastställa uppgifter, kontrollera resultatet och ta ansvar för detta. Detta är ”Engineering as is”. Jag tror att jag själv inte är redo att beskriva det med korrekta ord.
Don’t Repeat Yourself (DRY)
Det är en ganska enkel men mycket användbar princip som säger att det är en dålig idé att upprepa samma sak på olika ställen. För det första är den relaterad till behovet av ytterligare stöd och modifiering av koden. Om något kodfragment dupliceras på flera ställen i ett program finns det en stor sannolikhet för två katastrofala situationer:
- När man gör ens små ändringar i källkoden måste man ändra samma kod på flera ställen. Det kommer att kräva ytterligare tid, ansträngning och uppmärksamhet(ofta är det inte lätt).
- Den första punkten följer på den andra. Du eller en annan utvecklare i ditt team kan råka missa en av ändringarna(det kan hända helt enkelt genom att slå samman grenar i vcs) och drabbas av efterföljande buggar i applikationen. Dessa buggar kan vara frustrerande för dig eftersom du har hört att en sådan bugg redan har rättats.
I det här avseendet finns det en rekommendation – om en kod återfinns i listan mer än två gånger bör den placeras på ett separat sätt. Detta är en allmän rekommendation. Faktum är att du bör tänka på att skapa en separat metod även om du stöter på en upprepning en andra gång.
Occams Razor
Det är en mycket vanlig idé, som kom till programmering från filosofin. Principen fick sitt namn av den engelske munken William of Oakham. Principen säger: ”Enheter ska inte multipliceras utan nödvändighet”. Inom tekniken tolkas denna princip på följande sätt: Det finns ingen anledning att skapa onödiga entiteter utan nödvändighet. Det är därför alltid en bra idé att först fundera över fördelarna med att lägga till ytterligare en metod/klass/verktyg/process osv. Om man trots allt lägger till ytterligare en metod/klass/verktyg/process etc. och man inte får några andra fördelar än ökad komplexitet, vad är då poängen?
Keep It Simple Stupid (KISS)
Detta är en princip som liknar principen ovan, men som har en något annorlunda innebörd. Denna princip säger att koden måste vara så enkel som möjligt utan komplexa strukturer, annars kommer det att försvåra felsökning och underhåll av koden. Dessutom blir det svårare för en annan programmerare att förstå kodens logik, vilket i sin tur också kräver ytterligare tid och ansträngning. Därför bör du alltid försöka använda enkla konstruktioner som löser problemet så mycket som möjligt utan många förgreningar, djup nesting och överdrivet överbelastade klasstrukturer. Genom att göra detta kommer du att göra livet enklare för dig själv och dina kollegor, eftersom komplexitet genererar buggar. Kom ihåg vad Peter Hintiens sa: ”Enkelhet är alltid bättre än funktionalitet”.
You Aren’t Gonna Need It (YAGNI)
Ett problem som många programmerare lider av. Viljan att på en gång implementera all nödvändig (och ibland även onödig) funktionalitet från början av projektet. Det vill säga när en utvecklare lägger till alla möjliga metoder till klassen från allra första början och implementerar dem, och kanske till och med aldrig använder dem i framtiden. Enligt denna rekommendation bör man alltså först och främst implementera endast det man behöver och senare, om det är nödvändigt, utöka funktionaliteten. På så sätt sparar du ansträngning, tid och nerver på att felsöka kod som egentligen inte behövs.
Stor design i förväg
Innan du börjar utveckla funktionalitet bör du först fundera över applikationsarkitekturen och designa hela systemet till tillräckligt små detaljer, och först därefter gå vidare till implementering enligt en fördefinierad plan. Principen har rätt att existera, men på senare tid har det förekommit en hel del kritik mot den. Det hänger först och främst samman med att planen är föråldrad under projekteringen och utarbetandet. I detta sammanhang är det nödvändigt att göra efterföljande ändringar fortfarande. Men det har också obestridliga fördelar, vid korrekt utformning är det möjligt att avsevärt minska kostnaderna för ytterligare felsökning och korrigering av fel. Dessutom är sådana informationssystem i regel mer lakoniska och arkitektoniskt korrekta.
Undervik för tidig optimering
”För tidig optimering är roten till allt ont (eller åtminstone det mesta av det) inom programmering” – Donald Knuth
Optimering är en mycket riktig och nödvändig process för att snabba upp programmet samt för att minska förbrukningen av systemresurser. Men allting har sin egen tid. Om optimering utförs i ett tidigt skede av utvecklingen kan det göra mer skada än nytta. Först och främst hänger det samman med att utvecklingen av en optimerad kod kräver mer tid och ansträngning för utveckling och support. I det här fallet måste man ganska ofta kontrollera att den valda utvecklingsmetoden är korrekt i början. Därför är det till en början mer lönsamt att använda ett enkelt men inte det mest optimala tillvägagångssättet. Och senare, när man uppskattar hur mycket detta tillvägagångssätt saktar ner arbetet med en applikation, går man över till en snabbare eller mindre resurskrävande algoritm. Dessutom kan kraven ändras så länge som du initialt tillämpar den mest optimala algoritmen, och koden hamnar i soporna. Det finns alltså ingen anledning att slösa tid på för tidig optimering.
Princip för minsta förvåning
Denna princip innebär att din kod ska vara intuitiv och uppenbar, och inte överraska en annan utvecklare när denne granskar koden. Om metoden till exempel heter ”Making cookies” men du får potatis som resultat är den koden dålig (uppenbarligen). Dessutom bör du försöka undvika sidoeffekter och dokumentera dem om du inte kan undvika dem.
S.O.L.I.D.
”SOLID” är faktiskt en grupp av objektorienterade designprinciper. Varje bokstav i ”SOLID” representerar en av principerna, som är:
- Enkelt ansvar innebär att varje modul eller klass ska ha ansvar för en enda del av den funktionalitet som tillhandahålls av programvaran och att detta ansvar helt och hållet ska kapslas in av klassen;
- Öppet-lutet innebär att programvaruenheter (klasser, moduler, funktioner osv.) bör vara öppna för utvidgning, men stängda för ändring;
- Liskovsubstitution innebär att den ärvda klassen bör komplettera, inte ersätta, basklassens beteende;
- Gränssnittssegregation innebär att ingen klient bör tvingas att vara beroende av metoder som den inte använder;
- Beroendeinversion innebär att programmeraren bör arbeta på gränssnittsnivå och inte på implementationsnivå.
Om dessa principer tillämpas tillsammans hjälper en utvecklare att skapa kod som är lätt att underhålla och utöka med tiden.
Law of Demeter
Den grundläggande idén med den här principen är att dela upp ansvarsområdena mellan klasser och kapsla in logiken inom en klass, metod eller struktur. Flera rekommendationer kan urskiljas från denna princip:
- Klasserna eller enheterna bör vara oberoende
- Du bör försöka minska antalet kopplingar mellan olika klasser (så kallad koppling).
- De associerade klasserna ska finnas i en modul/ett paket/en katalog (även kallad kohesion).
Följs dessa principer blir applikationen mer flexibel, begriplig och lätt att underhålla.
Slutsats
Fellow developers let’s be engineers! Låt oss tänka på design och bygga robusta och välimplementerade system, snarare än att odla organiska monster. De uppräknade principerna är starkt korrelerade och sammankopplade i sin essens. Naturligtvis har jag inte skapat dem, men en liten påminnelse skadar inte, åtminstone är mitt minne definitivt inte perfekt.
Rekommenderade böcker
- Clean Code by Robert C. Martin
- Clean Architecture by Robert C. Martin