SOLID-prin­ci­per­na består av fem rikt­lin­jer för ren, un­der­håll­bar och flexibel kod i ob­jekt­ba­se­rad pro­gram­me­ring. Genom att tillämpa och följa prin­ci­per­na får man en lätt­för­stå­e­lig pro­gram­va­ru­de­sign under långa ut­veck­lings­pe­ri­o­der. Med dessa principer kan man inte bara skriva bättre kod, utan också un­der­hål­la befintlig kod på ett enklare sätt.

Vad är SOLID-prin­ci­per­na och vem har utvecklat dem?

Bra källkod börjar med regler, pro­gram­me­rings­pa­ra­dig­mer och en lämplig pro­gram­me­rings­stil för effektiv och ren kod. Det är precis vad de fem SOLID-prin­ci­per­na, myntade av Robert C. Martin, Bertrand Meyer och Barbara Liskov, sä­ker­stäl­ler. Genom att följa dessa principer i ob­jek­t­o­ri­en­te­rad pro­gram­me­ring (OOP) med språk som Python eller Java skriver du inte bara bättre kod, utan sä­ker­stäl­ler också ef­fek­ti­va­re ko­dun­der­håll, hållbar och flexibel pro­gram­va­ru­de­sign och större säkerhet på lång sikt.

Namnet SOLID re­pre­sen­te­rar den solida pro­gram­me­rings­grund som alla som vill lära sig pro­gram­me­ring bör ha. Akronymen skapades av Michael Feathers, som tog de första bok­stä­ver­na i var och en av de fem prin­ci­per­na för att skapa den:

  • Enkel an­svars­prin­cip: En klass ska ha en, och endast en, anledning att ändras.
  • Öppen-stängd-principen: Pro­gram­va­ru­en­he­ter (klasser, moduler, funk­tio­ner etc.) bör vara öppna för utökning, men stängda för mo­di­fi­e­ring.
  • Liskovs sub­sti­tu­tions­prin­cip: Un­der­klas­ser bör kunna ärva och im­ple­men­te­ra alla metoder och egen­ska­per från över­klas­sen.
  • Principen om gräns­snitts­segre­ga­tion: Gräns­snitt bör inte innehålla fler metoder än vad som krävs för att im­ple­men­te­ra klasser.
  • Principen om be­ro­en­de­in­ver­sion: Klasser bör inte vara beroende av andra klasser, utan av gräns­snitt eller abstrakta klasser.

Vilka fördelar erbjuder SOLID-prin­ci­per­na?

Om det inte finns några regler uppstår kaos, och detta blir särskilt märkbart vid pro­gram­me­ring. Även små fel, fel­ak­tig­he­ter och luckor kan göra bra källkod helt oan­vänd­bar på lång sikt om de lämnas “obe­hand­la­de”. Ibland räcker det med komplexa klasser som gör im­ple­men­te­ring­en svår eller un­der­klas­ser som saknar enskilda egen­ska­per hos sina över­klas­ser. SOLID-prin­ci­per­na sä­ker­stäl­ler att så lite kod som möjligt behöver repareras med re­facto­ring.

SOLID-prin­ci­per­na skapar kod:

  • Tydligt, rent och at­trak­tivt: Pro­gram­va­ra och koder är lättare att förstå, mer effektiva och ser helt enkelt bättre ut.
  • Lätt att un­der­hål­la: Den enkla och tydliga struk­tu­ren gör det enklare för flera med­ar­be­ta­re att un­der­hål­la och hantera både ny kod och äldre kod.
  • An­pass­nings­bar, utbyggbar, åter­an­vänd­bar: Genom för­bätt­rad läsbarhet, minskad kom­plex­i­tet och ansvar samt minskat beroende av klasser kan koden redigeras, anpassas och utökas bättre via gräns­snitt och åter­an­vän­das på ett flexibelt sätt.
  • Mindre fel­be­nä­gen: Ren kod med en enkel struktur innebär att ändringar i en del av koden inte av misstag påverkar andra områden eller funk­tio­ner.
  • Säker och mer till­för­lit­lig: Att minska eller eliminera sår­bar­he­ter, in­kom­pa­ti­bi­li­te­ter och fel för­bätt­rar systemets funk­tio­na­li­tet och till­för­lit­lig­het, vilket i sin tur för­bätt­rar sä­ker­he­ten.

Vad betyder var och en av SOLID-prin­ci­per­na?

SOLID-prin­ci­per­na tillhör de gyllene reglerna för god pro­gram­me­ring och bör vara bekanta för alla som arbetar med ob­jekt­ba­se­rad pro­gram­me­ring. Nedan förklarar vi varje princip i detalj.

SRP: Principen om en enda an­sva­rig­het

Robert C. Martin skapade den ur­sprung­li­ga de­fi­ni­tio­nen för denna princip i ”Agile Software De­ve­lop­ment: Prin­ciples, Patterns and Practices” och skrev:

Citatum

”Varje pro­gram­va­ru­mo­dul bör ha en och endast en anledning att ändras”.

Principen om enstaka ansvar (SRP) innebär att varje klass i ob­jek­t­o­ri­en­te­rad pro­gram­me­ring (OOP) endast ska ha ett enda ansvar. Detta innebär att det endast ska finnas ett enda skäl att modifiera en klass. I motsats till vad många tror innebär detta inte att en klass eller modul endast kan ha exakt en uppgift. Det innebär snarare att den endast ska ansvara för specifika uppgifter som helst inte över­lap­par andra områden.

En över­lapp­ning av an­svars­om­rå­den, såsom att erbjuda funk­tio­ner för olika af­färs­seg­ment, kan påverka klassens funk­tio­na­li­tet när ändringar görs i ett segment. Att ha flera an­svars­om­rå­den och många beroenden kan leda till att en enda ändring i ett område orsakar kodfel eller behov av yt­ter­li­ga­re ändringar.

Principen om enstaka ansvar (SRP) är utformad för att skapa sam­man­häng­an­de moduler med specifika, väl­de­fi­ni­e­ra­de funk­tio­ner eller objekt. Tack vare dess tydliga, struk­tu­re­ra­de upp­bygg­nad med minimala beroenden och oberoende im­ple­men­ta­tio­ner kan mo­di­fi­e­ring­ar och ju­ste­ring­ar göras mer effektivt, snabbt och smidigt.

Notis

Klasser, även kända som ob­jekt­ty­per, är de centrala elementen i ob­jek­t­o­ri­en­te­rad pro­gram­me­ring (OOP). De kan ses som ritningar för objekt, som beskriver deras egen­ska­per så att det är möjligt att återskapa verkliga objekt och begrepp i pro­gram­va­ra. Klasser, även kända som moduler, jämförs ofta med filtyper.

OCP: Öppen-stängd princip

Enligt Robert C. Martin och Bertrand Meyer i ”Object Oriented Software Con­struc­tion” lyder OCP:

Citatum

”Pro­gram­va­ru­en­he­ter (klasser, moduler, funk­tio­ner etc.) bör vara öppna för utökning, men stängda för mo­di­fi­e­ring”.

OCP sä­ker­stäl­ler att du inte behöver skriva om kärnan i pro­gram­va­ran för att im­ple­men­te­ra ändringar. Om djup­gå­en­de ko­dänd­ring­ar krävs finns det en risk för subtila fel och kodfel. En väl­struk­tu­re­rad kod bör till­han­da­hål­la gräns­snitt som kan användas för att utöka den med yt­ter­li­ga­re funk­tio­ner. Nyc­kelor­det här är klassarv.

Nya funk­tio­ner och tillägg med tydliga nya funk­tio­ner och metoder som behöver im­ple­men­te­ras kan enkelt läggas till en su­per­klass via ett gräns­snitt i form av un­der­klas­ser. På så sätt behöver du inte ändra den skrivna, stabila koden. Det förenklar un­der­hål­let och skötseln av pro­gram­va­ran och för­bätt­rar avsevärt ef­fek­ti­vi­te­ten i åter­an­vänd­ning­en av stabila ko­de­le­ment via gräns­snitt.

LSP: Liskovs sub­sti­tu­tions­prin­cip

Enligt Barbara H. Liskov och Jeannette M. Wing i ”Be­ha­vio­ral Subtyping Using In­va­ri­ants and Constraints” anger LSP att:

Citatum

”Låt q(x) vara en egenskap som kan bevisas om objekt x av typ T. Då bör q(y) kunna bevisas för objekt y av typ S, där S är en undertyp av T”.

Det kan låta kryptiskt, men det är faktiskt ganska lätt att förstå: Länkade eller utökade un­der­klas­ser måste fungera som sina över­klas­ser eller bas­klas­ser. Detta innebär att varje un­der­klass måste behålla egen­ska­per­na hos sin re­spek­ti­ve överklass genom arv och att dessa egen­ska­per inte får ändras i un­der­klas­sen. De måste i princip vara utbytbara, därav sub­sti­tu­tions­prin­ci­pen. Över­klas­ser, å andra sidan, får mo­di­fie­ras.

För att förklara detta kan vi titta på det klassiska exemplet från Robert C. Martin om rek­tang­lar och kvadrater. I geo­metri­lek­tio­ner­na lär vi oss följande princip: varje kvadrat är en rektangel, men inte varje rektangel är en kvadrat. En kvadrat har inte bara rät­vink­li­ga sidor som rek­tang­lar, utan alla dess sidor är också lika långa.

I pro­gram­me­ring leder an­ta­gan­det att liknande eller till synes identiska klasser är re­la­te­ra­de eller beroende av varandra till fel, miss­för­stånd och otydlig kod. Av denna anledning är klassen “Rektangel” inte en kvadrat och klassen “Kvadrat” inte en rektangel i pro­gram­me­ring. Båda är fri­kopp­la­de och im­ple­men­te­ras separat. Utan en in­te­gre­rad koppling mellan klasserna kan miss­för­stånd inte leda till fel mellan klasserna. Detta för­bätt­rar sä­ker­he­ten och sta­bi­li­te­ten när man byter im­ple­men­ta­tio­ner i un­der­klas­ser eller över­klas­ser, utan kon­se­kven­ser.

ISP: Principen om gräns­snitts­segre­ge­ring

Enligt Robert C. Martin i ”The Interface Seg­re­ga­tion Principle” de­fi­nie­ras ISP på följande sätt:

Citatum

”Kunderna ska inte tvingas att vara beroende av gräns­snitt som de inte använder”.

ISP anger att användare inte ska behöva använda gräns­snitt som de inte behöver. Med andra ord: För att kunna erbjuda kunderna funk­tio­ner i vissa klasser skräd­dar­sys nya, mindre gräns­snitt efter specifika krav. Detta för­hind­rar att gräns­snit­ten blir för stora och sä­ker­stäl­ler att det inte uppstår starka beroenden mellan klasserna. Fördelen är att pro­gram­va­ra med av­kopp­la­de klasser och flera små gräns­snitt som är skräd­dar­syd­da efter specifika krav är lättare att un­der­hål­la.

DIP: Principen om be­ro­en­de­in­ver­sion

Enligt Robert C. Martin i “The De­pen­den­cy Inversion Principle” är den femte och sista av SOLID-prin­ci­per­na följande:

Citatum

”A. Moduler på hög nivå bör inte vara beroende av moduler på låg nivå. Båda bör vara beroende av ab­strak­tio­ner. B. Ab­strak­tio­ner bör inte vara beroende av detaljer”.

DIP sä­ker­stäl­ler att specifika funk­tio­ner och beroenden inom käll­kods­la­ger är beroende av abstrakta gräns­snitt, inte direkt av varandra. Pro­gram­va­ru­ar­ki­tek­tu­rer är van­ligt­vis or­ga­ni­se­ra­de i högre an­vän­dar­ni­vå­er och lägre, mer abstrakta nivåer. Logiskt sett kan man tro att den abstrakta grunden påverkar beteendet hos de övre lagren. DIP iden­ti­fi­e­rar dock ett po­ten­ti­ellt problem här, eftersom det skapar beroenden för de högre nivåerna på de lägre nivåerna, vilket kan leda till problem.

Istället för att koppla högre nivåer till lägre nivåer bör klasser på höga och låga nivåer vara beroende av abstrakta, mel­lan­lig­gan­de gräns­snitt. Gräns­snit­ten hämtar funk­tio­ner som krävs på högre nivåer från lägre nivåer och gör dem till­gäng­li­ga. På så sätt kan man undvika en bottom-up-hierarki av beroenden, som med tiden kan leda till fel i koden. Detta un­der­lät­tar åter­an­vänd­ning­en av moduler och möjliggör ändringar i lägre klasser utan att det påverkar högre nivåer.

Vad händer om SOLID-prin­ci­per­na inte följs?

Att skapa ren, läsbar kod som förenklar un­der­hål­let bör vara ett primärt mål inom mjuk­va­ru­ut­veck­ling. Om ut­veck­la­re förbiser viktiga rikt­lin­jer som SOLID-prin­ci­per­na kan koden försämras avsevärt på grund av sår­bar­he­ter, re­dun­dan­ser, ac­ku­mu­le­ra­de fel och över­driv­na beroenden. I extrema fall kan koden bli oan­vänd­bar med tiden. Detta är ett betydande problem inom agil mjuk­va­ru­ut­veck­ling, där många personer ofta arbetar med komplexa kod­nings­upp­gif­ter.

Kon­se­kven­ser­na av oren kod eller dålig ko­dun­der­håll in­klu­de­rar:

  • Kodlukt: När kod inte skrivs i enlighet med nöd­vän­di­ga stan­dar­der kan detta orsaka kodlukt eller ”luktande kod”, vilket leder till funk­tions­fel och in­kom­pa­tib­la program.
  • Kod­för­fall: Om koden inte un­der­hålls eller repareras genom re­fak­to­ri­se­ring eller en kostsam kod­gransk­ning kan den bildligt talat ”förfalla” och helt förlora sin funk­tio­na­li­tet. Ett annat uttryck för oläslig, invecklad kod är spa­get­ti­kod.
  • Sä­ker­hets­ris­ker: De problem som uppstår är inte be­grän­sa­de till avbrott, komplex underhåll och kom­pa­ti­bi­li­tets­pro­blem. Det finns också sä­ker­hets­luc­kor som ger skadlig pro­gram­va­ra möj­lig­he­ter att utnyttja koden, inklusive zero-day-exploits.

Vem ut­veck­la­de SOLID-prin­ci­per­na?

SOLID-prin­ci­per­na har sitt ursprung i flera principer som först in­tro­du­ce­ra­des av Robert C. Martin (”Uncle Bob”), en av ini­ti­a­tiv­ta­gar­na till agil pro­gram­me­ring, år 2000 i hans essä med titeln ”Design Prin­ciples and Design Patterns”. SOLID-prin­ci­per­na myntades av Robert C. Martin, Bertrand Meyer och Barbara Liskov. Den fängs­lan­de akronymen po­pu­la­ri­se­ra­des av Michael Feathers, som ordnade om de fem grund­läg­gan­de prin­ci­per­nas initialer i en min­nesvärd ordning.

Vilka liknande pro­gram­me­rings­prin­ci­per finns det?

Inom mjuk­va­ru­ut­veck­ling är principer allmänna eller mycket specifika rikt­lin­jer och re­kom­men­da­tio­ner för åtgärder. Förutom SOLID-prin­ci­per­na, som ut­veck­la­des för ob­jek­t­o­ri­en­te­rad pro­gram­me­ring, finns även andra pro­gram­me­rings­prin­ci­per för ren kod, bland annat:

  • DRY-principen (Don’t repeat yourself) för funk­tio­ner med en enda, unik re­pre­sen­ta­tion
  • KISS-principen (Keep it simple, stupid) för kod som är kon­stru­e­rad så enkelt som möjligt
Gå till huvudmeny