SOLID programmering; Del 1

2012-10-22

SOLID är en akronym för 5 principer inom programmering som om de används korrekt hjälper dig att skapa stabil, utvecklingsbar och kvalitativt bra kod. SOLID introducerades av Michel Feathers och har uppmärksammats och lyfts fram av Robert C. Martin. SOLID skall ses mer som riktlinjer än som regler då det alltid kommer att finnas tillfällen då man inte kan tillämpa en eller flera av dessa principer, men om man alltid strävar efter att följa dem så kommer man i längden att underlätta livet för både dig själv och andra programmerare.

Jag tänkte ta upp dessa fem principer i en serie på 5 blogginlägg, och titta lite närmare på vad de står för. Jag börjar från början med bokstaven ”S” – ”Single Responsibility Principle”.

Del 1 – Single Responsibility Principle

Single Responsibility Principle deklarerar att varje klass skall ha endast ett ansvar och det ansvaret skall vara till fullo inkapslad i klassen. Alla de tjänster som klassen tillhandahåller skall vara för att tillgodose det ansvaret och ingenting annat.

Vad innebär detta? Vad är ”endast ett ansvar”? Såsom jag ser det så är definitionen av ”endast ett ansvar” beroende av vad klassen förväntas utföra. T.ex. en klass skall endast hämta en kund från kundregistret. Den skall inte både göra det OCH skriva ut kunduppgifterna på webben. Detta är två skilda ansvar. Det gör att om man behöver ändra i kundregistret så påverkas bara klassen som hämtar kunduppgifterna och ingenting i front-end påverkas. Och det är ju precis det vi vill – kunna ändra utan att påverka andra saker.

Robert C. Martin definierar detta ansvar till att vara att

en klass skall endast ha en anledning att förändras.

Han jämför med att en klass inte skall sammanställa/kompilera (compile) och skriva ut en rapport därför att den då har två anledningar till att förändras: Antingen kan rapporten (data) förändras eller så kan formatet för rapporten ändras. Detta gör att det blir svårt att ändra i klassen.

Jag skulle vilja ta denna princip ytterligare ett steg ner i klass-hierarkin: Även metoderna i en klass skall utgå från den här principen: De skall hantera/utföra endast en sak, alternativt ha endast ett ansvarsområde (enligt Robert C Martins definition). Så fort de har ansvar för flera saker så skall den delas upp i flera metoder. Detta gör att metoden då blir lättare att testa med Unit Tester och färre fel letar sig in i koden.

Ett sätt att hitta en klass eller metod som har för stort ansvarsområde är att om du har svårt att ge klassen/metoden ett meningsfullt namn som tydligt specificerar vad den gör – då har du troligtvis fel scope på din klass/metod och bör bryta upp den i två eller flera block. I mitt exempel så blir det tydligt: Jag kan döpa min klass till t.ex. ”CustomerLookup”; det är tydligt att då avses endast en läsning från kundregistret på en (1) kund. Inget annat. Om jag hade varit tvungen att döpa den till ”CustomerLookupAndPrint” så avslöjas att klassen gör för mycket. Ordet ”And” betyder ju att det är två saker som kombineras…

Glöm inte del 2 i Single Responsibility Principle!

Glöm nu inte bort att även de exponderade metoderna skall stödja ansvaret och ingenting annat! Det är väldigt lockande att ge en massa publika metoder bara för att underlätta saker och ting, men som i själva verket inte är klassens ansvar.

Ta t.ex. min klass ”CustomerLookup” som har som ansvar att hämta en kund från kundregistret. Det är väldigt lockande att expondera toString() och därigenom bestämma hur den skall formatteras på webben. Faktum är att detta är ju inte klassens ansvar! Således skall toString() inte bestämma över formattering. Däremot skall CustomerLookup expondera en metod för att ge t.ex. kundens namn ”getCustomerName()” (eller bara customerName()), och en annan metod för adressen osv. Då får klassen som sedan hanterar formattering på webben själv bestämma vilken uppgift som placeras vart och hur.

Som kuriosa; Vad skall då toString() vara i CustomerLookup? Personligen skulle jag använda toString() för att ge hela kund-recordsetet i en kommaseparerad sträng. Då är det lätt att använda den i en jämförelse för att se om kunduppgifterna har ändrats;

CustomerLookup customer = new CustomerLookup("777777-7777");
String compare = customer.toString();
String anotherCompare = "7777777-7777,Nisse Hult, Avägen 1, 999 99 Storstad";
if (compare.equalsIgnoreCase(anotherCompare)) {
//Nothing has changed...
} else {
//Oh.... Something is different here!
}

Ok, nu hamnade vi på ett litet sidospår här… men jag tror jag har gjort tydligt om vad Single Responsibility Principle innebär för mig.

Detta är för mig en av de viktigaste principerna i hela SOLID-akronymen. Det räcker väldigt långt att börja med denna princip. Följ mig i nästa avsnitt så skall jag gå igenom nästa bokstav: ”O” – ”Open/Closed principle”!

Läs mer…

SOLID SOLID (Object-oriented Design) enligt Wikipedia.
Single Responsibility Principle SRP – Single Responsibility Principle enligt Wikipedia.

Annonser