Refactoring är inte alltid så lätt…

2013-07-29

Jag har stött på ett litet problem; Jag sitter och skall göra en liten refactoring av en klass och funderar på hur man bäst skall gå tillväga. Här är min main-kod i min klass:


try {
 initialize();
 if (this.orderId.equals("")) {
  createErrorResponseOrderNumberIsMissing();
  outputResponse.println(jsonReturn.toJSON());
  return;
 }
 this.orderDocument = allOrders.getDocumentByKey(this.orderId);
 if (this.orderDocument == null) {
  createErrorResponseOrderNotFound();
 } else {
  processOrderDocument();
  createResponseMessage();
 }
 outputResponse.println(jsonReturn.toJSON());
} catch(Exception e) {
.... exception handling snipped out of this example... not of interest right now! ...
}

Mitt problem med koden är att jag inte gillar att ha två olika exit-points i koden; du har en om ordernummer saknas och en annan för alla andra resultat. Jag skulle vilja ha endast en exitpoint – den som finns precis före catch-satsen. Men hur löser jag att det finns två villkor som måste uppfyllas varav det andra inte kan kontrolleras såvida inte en lookup utförs, där argumentet för lookupen baseras på det första värdet i villkoret?

Jag vill ju inte utföra lookupen om ordernummer inte finns angiven – då kommer jag att få en massa följdfel som inte är önskvärt. Jag skulle önska att lookupen hellre returnerade en exception om man anger ett sträng utan innehåll som argument. Det gör den. Det blir då NullPointerException. Jag skulle kunna fånga upp detta fel och hantera detta, men eftersom det kan bli NullPointerException var somhelst i koden så har jag ingen koll att just denna NPE handlar om att ordernummer saknas.

Hur löste jag detta?

Det var tanken på att hantera ett exception som ledde mig åt rätt håll. Eftersom lookupen utförs av en 3:e parts produkt som jag inte kan modifiera så beslöt jag mig för att ändra min klass ”ReturnMessage” – vilket är den lokala variabeln jsonReturn som sätts i initialize() till objektet ReturnMessage;

this.jsonReturn = new ReturnMessage();

Jag beslutade mig för att den inte fick initieras utan argument. Konstruktorn utan argument togs bort så att man måste ange ReturnMessage(String id) istället. I konstruktorn kan jag sedan slänga en egen (ny) exception; OrderIdMissingException.

Nästa förändring som var tvunget för att detta skulle fungera är att ändra hur man initierar jsonReturn. Detta lades till i initialize()-metoden:

this.jsonReturn = new ReturnMessage(getOrderId());

(Och nej – jag kan inte lägga in exception-kontrollen i ”getOrderId”-metoden, för denna används på fler ställen där det skall vara fullt legalt att använda en tom sträng och inget exception får då genereras!)

I main-funktionen kunde jag sedan lägga till catch-sats för detta exception och skapa felmeddelandet där istället:


catch(OrderIdMissingException exception) {
 createErrorResponseOrderNumberIsMissing();
}

Jag flyttade också outputResponse.println(jsonReturn.toJSON()); till finally-satsen. Så här blev koden till slut:


try {
 initialize();
  this.docOrder = allOrders.getDocumentByKey(jsonReturn.orderId);
  if (this.docOrder == null) {
   createErrorResponseOrderNotFound();
  } else {
   processOrderDocument();
   createResponseMessage();
  }
 } catch(OrderIdNotSuppliedException missingOrderIdException) {
  createErrorResponseOrderNumberIsMissing();
 } catch(Exception e) {
... exclueded exceptionhandling from example...
 } finally {
  outputResponse.println(jsonReturn.toJSON());
 }

Eller är det någon som har förslag på en bättre lösning?


SOLID programmering; del 2

2013-03-18

Dags för del 2 i serien om SOLID.

Del 2 – Open/Closed Principle

Bokstaven ”O” i akronymen SOLID betyder ”Open/Closed Principle”. Den dikterar följande:
En klass skall vara öppen för tillägg men stängd för ändringar.

Så vad betyder det egentligen? Jo, eftersom man i en produktionsmiljö vill ändra källkoden så lite så sällan som möjligt så bör man designa sitt program till att tillåta att programmet kan ändra sitt beteende utan att man behöver ändra källkoden. Att ändra källkoden innebär kodgranskning, godkännande osv osv, som kan vara en ganska omfattande procedur.

Det finns flera olika tolkningar om hur detta skall uppnås. En av de tidigaste sätten dikterade att du skall aldrig ändra en klass såvida den inte innehåller buggar och rena fel. Tillägg och ändringar skall läggas i en ny klass som ärver från den ursprungliga klassen. Den nya klassen behöver inte alltid ens ha samma interface som den klassen som den ärver ifrån.

Under 90-talet utvecklades dock en annan variant av arv; arv via abstrakta interface. Detta innebär att man ärver från en abstrakt basklass och med polymorfism kan den nya klassen utföra den nya funktionen baserat på ärvda eller nya interface.

I den här delen så har jag inte något kodexempel som illustrerar detta, då det mer handlar om arkitektur och design. Om jag hittar ett bra exempel så kommer jag att återkomma till denna princip.


Sortering av en Collection med Vector

2013-03-11

Här kommer ett litet intressant programmeringsproblem jag råkade ut för nyligen.

Att sortera en Vector är inga större problem; du anropar bara Collections.sort(myVector) och den sorterar alla items i din Vector. Men hur gör man egentligen om man har en hel collection av vectorer där man sedan skall sortera vectorerna baserad på ett av deras index/items?

T.ex. jag har


Vector vector1 = new Vector();
Vector vector2 = new Vector();
Vector vector3 = new Vector();

där jag har populerat ett antal items i varje vector, t.ex:


vector1.add("e");
vector1.add("f");
vector1.add("g");

vector2.add("a");
vector2.add("x");
vector2.add("m");

vector3.add("s");
vector3.add("o");
vector3.add("p");

och jag sedan lägger dem alla i en ny vector:


Vector<Vector> all = new Vector<Vector>();
all.add(vector1);
all.add(vector2);
all.add(vector3);

Om jag nu försöker skriva Collections.sort(all) så kommer det inte att fungera; editorn kommer att klaga på ”Bound mismatch: The generic method sort(List<T>) of type Collection is not…….” och du kommer inte att kunna kompilera koden. Hur gör jag om jag vill sortera på varje vectors första item? Eller andra? Eller låta användaren välja?

För att lösa detta så behöver vi skapa en s.k. Comparator, som implementerar metoden compare:


import java.util.Comparator;
import java.util.Vector;

public class VectorComparator implements Comparator<Vector<String>> {
@Override
public int compare(Vector<String> o1, Vector<String> o2) {
//TODO: Auto-generated code
}
}

Metoden compare skall returnera -1, 0 eller 1 beroende på om o1 är större än, lika med eller mindre än o2. Då behöver vi veta vilket index som vi skall använda oss av i vector o1 och o2. Vi lägger till följande privata fält och konstruktor för klassen:


private int useIndex = 0;

public VectorComparator() {
}
public VectorComparator(int index) {
this.useIndex = index;
}

Och då kan vi beräknade compare-metoden till följande:


return o1.get(useIndex).toString().compareTo( o2.get(useIndex).toString());

Här är hela klassen då jag har lagt till lite felhantering i compare-metoden:


import java.util.Comparator;
import java.util.Vector;

public class VectorComparator implements Comparator<Vector<String>> {
private int useIndex = 0;

public VectorComparator() {
}
public VectorComparator(int index) {
this.useIndex = index;
}

@Override
public int compare(Vector<String> o1, Vector<String> o2) {
if (useIndex <= o1.size() && useIndex >= 0) {
return o1.get(useIndex).toString().compareTo( o2.get(useIndex).toString());
} else {
throw new RuntimeException("Index out of bounds; max size is '" + Integer.toString(o1.size()) + "'!");
}
}
}

Nu kan vi använda vår comparator för att sortera:


VectorComparator comparator = new VectorComparator(1);
Collections.sort(all,comparator);

och vår collection av vectorer kommer att vara sorterad på varje vectors andra item!

Svårare än så var det inte…

Vill du veta mer om Comparator? Läs här: Vogella.com eller på Java Doc.


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.


Kommentera inte din kod!

2012-10-02

Det här är ett ämne som delar oss programmerare i två väsenskilda läger; De som anser att man SKA kommentera i kod och de som anser att kommentarer är överflödiga.

Är du en duktig programmerare så kommer kommentarer att vara onödiga; du kan strukturera koden så att den blir lättläst och lätt att förstå. En dålig progammerare behöver kommentarer för att fylla upp sina kunskapsluckor, vilket egentligen bara gör att koden blir ännu mer svårläst. Dålig kod blir tyvärr inte bättre med kommentarer – snarare tvärtom. Ännu mer text att läsa för att förstå koden… Inte precis rätt väg att gå om man tänker lite logiskt på problemet. Bättre då att strukturera sin kod att den går att läsa och förstå lika lätt som en bok eller en tidning.

Vilka är då de vanligaste felen? Ja, i den kod som jag sett genom åren så är det följande:

Kommentaren kommenterar kod som är självklar

T.ex.

private double summery() {
double first = 1;
double second = 1;
//Returnera summan av first och second:
return first + second;
}

Vad i hela friden gör kommentaren för nytta där? Den gör bara att mängden text som ögat måste scanna igenom blir större och det tar längre tid för dig att läsa och förstå koden i sin helhet. Bort med sådana kommentarer!
Jag kan förstå att man lägger in sådana här kommentarer när man ägnar sig åt pseudo-kodning, men när man är klar med den riktiga koden så skall sådana kommentarer raderas!

Kommentar är helt felaktig


private double summary() {
double first = 1;
double second = 1;
//Returnera summan av first och second:
return first * second;
}

Här kommer man att hoppa till när man läser: Vad är det som är rätt? Är det kommentaren som är korrekt och koden felaktig eller tvärtom? Detta härrör sig troligtvis från att kommentaren en gång i tiden har varit helt korrekt, men sedan har förutsättningarna ändrats, koden har justerats, men kommentaren ligger kvar orörd.
Ta bort sådana här kommentarer i sin helhet! De kommer aldrig att uppdateras och skapar bara förvirring om vad som faktiskt gäller när man skall korrigera buggar, korrigera ändrade förutsättningar mm.

Det här felet är mycket vanligt i Java program och framförallt när programmeraren har använt editorns inbyggda funktion för att automatiskt lägga till en JavaDoc-stub. JavaDoc kommentarer har en förmåga att snabbt bli föråldrade och felaktiga. Ju mer programmeraren har lagt in i JavaDoc-kommentaren, desto större är risken att den innehåller felaktigheter. Så vilken nytta fyller då JavaDoc-kommentaren?

Kommentar ligger på fel plats

Inte så vanligt fel, men det inträffar. Man kan efter att ha kollat igenom hela koden kommit på att en viss kommentar faktiskt är felplacerad och borde ligga i en annan funktion eller på annan plats i koden. Detta inträffar då man har gjort ”klipp-och-klistra” kodning: Man har flyttat koden som kommentaren tillhör men inte själva kommentaren. Den ligger kvar på ursprunglig plats och detta skapar förvirring (återigen).

Men behövs aldrig kommentarer då?

Jo, det finns alltid undantag till alla regler. Det kan ibland hända att koden blir välidgt komplex och man behöver förklara vilken affärslogik som ligger bakom koden, eller helt enkelt en kommentar att ”det borde finnas ett bättre sätt att göra detta, men jag vet inte”. Dvs det kan finnas tillfällen då du känner på dig att koden är onödigt komplex, men du vet inte hur man skall kunna göra detta på bättre sätt. Då kan kommentaren fungera som en ”TODO”-minnesanteckning tills att du har hunnit fråga en kollega eller kollat upp på nätet. Men detta innebär att du har som mål att även eliminera denna kommentar!

Men det är väl bra att skriva JavaDoc så att användaren av min funktion vet vilka parametrar som förväntas och vad som kommer ut av funktionen?

Nej. En funktion med ett väldigt tydligt funktionsnamn som beskriver vad den gör, kommer att bättre tala om för mig vad det blir för resultat av funktion. De parametrar som behövs skall vara tydligt namngivna så att jag inte behöver fundera på vilken betydelse de har. Då behövs ingen JavaDoc. Om funktionen är så komplex att funktionen måste beskrivas, då behöver du troligtvis skriva om hela funktionens arkitektur. Något står inte rätt till då. Dessutom har jag sett allt för många exempel på JavaDoc som inte blivit uppdaterad då funktionen/klassen har blivit uppdaterad. Detta skapar förvirring. Funktionen/klassen kommer att utföra något på ett annat sätt än vad som är beskrivet i kommentaren. Vad är det som gäller? Resultatet eller kommentaren?

Ett litet test: Vilken av följande går snabbast att läsa och förstå?


/*
* This function will search all books
* in the database and return the author
* of a book with provided ISBN
*
* Parameter: searchISBN (String)
* Return: Name of Author (String)
*/
function String search(searchISBN) {
....
}

eller den här:


function String getAuthorOfBook(String ISBN) {
...
}


Felhantering

2012-09-11

I teorin så är det ganska enkelt att hantera fel, men som vanligt så är det inte alltid det lättaste att översätta teori i praktik. Jag har sett otaliga sätt och tillämpningar på hur felhantering har implementerats i allehanda programspråk, och jag måste säga att jag inte är helt övertygad om att något sätt som något programspråk erbjuder är det mest optimala.

Problemet jag har är tvåfalt: Det är dels en ren syntaxfråga – vilken syntax krävs av språket för att indikera och hantera fel och den andra delen handlar om den mer rena abstrakta observationen vad som skall felhanteras och hur.

Syntax

I Java har vi s.k. Try…Catch…Finally satser som är ett helt ok att hantera fel och som har blivit mer eller mindre en de facto standard. Det fungerar men för mig är det väldigt mycket som stör mitt öga. Det blir väldigt mycket ”klutter”. Tyvärr har ju även .Net implementerat denna syntax.

Ruby använder andra ord men det är samma syntax som Java/.Net Try/Catch; ”Begin…Rescue…End”.

I LotusScript så är vi tvingade att använda det förhatliga ”On Error Goto” som inbjuder till spaghetti-kod.

I C så har vi ingen syntax för felhantering – vi använder svarskoder (”return codes”) från våra metoder för att indikera hur det resulterade där int 0 vanligtvis betyder att metoden lyckades.

Jag inte tycker om try…catch-syntaxen. Den stör mitt öga. Om nu varenda funktion/metod har felhantering så kommer varenda en att innehålla en try-catch sats och då kommer du ha mycket kod för ingenting. Det blir väldigt mycket text som ditt öga måste ignorera för att se vad koden faktiskt gör. Jag gillar inte principen att man skriver något som inte behöver läsas.

Det finns ett sätt att slippa try..catch men det är inget sätt jag rekommenderar. Det är att använda CHECKED EXCPTIONS enbart. Det är bara ett sätt att dölja felhanteringen och flytta problematiken. Dessutom så är checked exceptions ett brott mot Open/Closed principle. Tyvärr så finns det vissa bibliotek som tvingar oss att använda CHECKED EXCEPTIONS, så då är vi tvingade att skriva Wrappers för dessa för att få bort otyget.

Hur borde det se ut då? Hmm. Det är en svår nöt att knäcka. Personligen så skulle jag vilja kunna göra något i stil med att deklarera i början av en funktion vilka fel som har felhantering och hur dessa skall hanteras, men att koden för att hantera dessa fel INTE LIGGER I SAMMA METOD som resten av koden:


public void myTestFunction() {
 Declare Error IllegalFunctionCallException informUser(IllegalFunctionCallException);
 ...
 Throw new IllegalFunctionCallException("Test");
 ...
}
public void informUser(Exception e) {
 //Handle the error caused...
}

Problemet med detta är att det är bara minimal skillnad från klassiska ”On Error Goto” syntaxen och kan potentiellt göra spaghetti av din kod. Dock har det här tillvägagångssättet den fördelen att båda metoderna blir mer lättlästa. Du skulle också kunna återanvända metoder för felhantering så att du slipper repetera felhanteringen. Samma sak kan iofs uppnås med try-catch men med någon slags ”declare” sats så kan du skriva allt på en rad och det upptar inte nämnvärd utrymme i din metod.

Men hur skall koden se ut då??!! Ja du… om jag hade svar på den frågan så vore jag glad och kanske skulle kunna tjäna en slant. Så tills vidare får jag leva med den näst bästa lösningen och det är att använda try-catch-satser.

Så problemet kvarstår. Detta får mig att fundera vidare på vad vi egentligen använder Exceptions till.

Hur använder vi Exceptions?

Det finns ju i princip två typer av undantag/exceptions: Rena run-time fel såsom I/O error osv. dvs sådana fel som vi som programmerare inte har kontroll över. I normala fall skall detta inte inträffa, men möjligheten finns. Alltså måste detta hanteras på något sätt.

Den andra typen av undantag/exception som finns är när vi använder Exceptions istället för den gamla C-varianten som RETURKOD! Vi låter anropande metod veta att vi misslyckades genom att sända tillbaka ett Exception. Detta anser jag vara förkastligt! Skillnaden mellan returkod och exception är i dessa fall endast semantisk och bidrar inte till att koden blir bättre. Semantisk? Ja, koden blir i princip densamma: Anropande kod måste fortfarande analysera om metoden lyckades eller ej: Med returkod så sker analysen omedelbart:
If returnValue==0 Then...
Med felhantering så sker den indirekt:

try {
 callThisMethod();
catch (Exception e) {
 //Didn't succeeded with call to callThisMethod();
}

Det andra problemet med denna typ av felhantering är att det blir mycket mer komplicerat om vi i try-satsen skulle anropa 3-4 olika funktioner. Hur vet vi då i catch-sektionen exakt vilken metod som fallerade? Detta sätt att felhantera känns fel. Rakt upp och ner fel på alla sätt och vis.

Det borde gå att konstruera din kod så att du inte anropar en metod innan du vet att den kommer att lyckas. Undantag blir då endast Runtime-errors såsom I/O problem mm som inte kan förutses och som ligger utanför din applikations kontroll.

Ta t.ex. ett exempel om vi har en metod som gör resize på en JPG-bild, men som av någon anledning inte hanterar något annat bildformat. Då är det vanligt att man i metoden skriver en if-sats som evaluerar vad det är för bildformat på bilden och sedan genererar en Exception om det inte är en JPG. Exempelvis:


public void resizeJPG(String filePath) {
 if (getFilepathExtension(filePath).equalsIgnoreCase(".jpg")) {
  //Process image
 } else {
  Throw new IllegalFiletypeException("Unsupported filetype!");
 }
}

Borde man inte göra tvärtom? Se till att man inte anropar funktionen om bilden inte är en JPG? Då blir resizeJPG() metoden renare och mer lättläst. Visst; du flyttar if-satsen uppåt i kedjan, men med rätt design bör inte det bli problem. En sådan sak borde kanske till och med avhjälpas med att tillämpa Factory Design Pattern och lägga hela evalueringen i Factory-klassen. Tydligare än så kan det inte bli.

Kvar att hantera i resizeJPG() metoden blir att hantera I/O-fel och fel som genereras från grafik-biblioteken. Dessa typer av fel kommer man ”tvingas” att hantera på samma sätt som tidigare, dvs i resizeJPG() metoden och skicka uppåt med en ny Throw för att meddela anropande funktion att det blev ett fel som inte gick att hantera. Fördelen är att try-catch satsen i anropande metoden blir lite mindre komplex:


public void resizeAll(...) {
 try {
  resizeJPG(...);
 } catch(ImageCreationException e) {
  //Process error; possibly show error to user... and/or create a log entry
 }
}
public void resizeJPG(...) {
 try {
  //Process image
 } catch(IOException e) {
  Throw new ImageCreationException("Unable to create image...",e);
 } catch(Exception e) {
  Throw new ImageCreationException("Unable to create image...",e);
 }
}

Eftersom vi använder Factory Design Pattern så kommer funktionen ”resizeJPG()” bara att utföras när Factory har skapat en klass som innehåller den här metoden när käll-filen är av typen JPG. Om filen inte är en JPG så kommer en annan klass att skapas som rapporterar ett fel till användaren att han bara får använda JPG-filer… resizeJPG() kommer då aldrig att anropas/användas.

Varför kodar inte folk på det här sättet? Kanske för att de inte ser skillnad på Exception och Exception. De betraktar alla exceptions som runtime och man använder svångrem och hängslen: ”Måste säkerställa att det inte blir fel i den här metoden, så vad kan gå fel… bäst att koda in alla tänkbara scenarior…” istället för att jobba sig uppåt i abstraktionen.

En tanke slog mig…

En liten tanke dök upp: Vad skulle hända om man kunde definiera flera fel på samma catch-rad:

...
} catch(IOException, NullPointerException, Exception e) {
...
}

Då skulle det bli mindre kod då vi på flera typer av fel skulle utföra samma kod. Lättare att läsa, mindre kod och framförallt mindre duplicerad kod. Duplicering är en av alla de saker som orsakar buggar i programkod. Frågan är bara om detta skulle få några andra konsekvenser än vad jag kan förutse just nu.

Oj… det blev ett långt inlägg men jag tycker hela konceptet med felhantering är stort och komplext. Dock är det av stor vikt att man gör det rätt. Vad är rätt? Jag vet inte, jag provar mig fram fortfarande.

Är det någon som har någon bra bok/artikel/tips på det här med felhantering så mottar jag det med tacksamhet!


Vad är en klass?

2012-09-07

Vad är egentligen en klass när vi pratar om programmering – vare sig det är Java, .Net, eller php…? Jag har under 20 års tid använt klasser till höger och vänster, men egentligen aldrig funderat på vad en klass EGENTLIGEN är. Googlar man frågan så finner man tusentals artiklar som handlar om HUR man använder klasser och vilka delar som utgör en klass, men ingenstans har jag funnit svaret på den mer övergripande (något abstrakta) frågeställningen: vad är egentligen en klass?

Därför tog jag ett steg tillbaka och funderade själv; när använder man klasser och varför? Programmerar du Java så kan du inte undvika att använda klasser – du kan inte ens starta ett Java-projekt utan ha en klass med en main() funktion i den. Jo, jag använder klasser för att samla ihop funktioner som hjälper mig att hantera en enskild uppgift. Visst kan en klass i princip utföra flera uppgifter, men läser man ”Clean Code – A Handbook of Agile Software Craftsmanship” av Robert C. Martin så skall ju varje klass endast utföra en endaste sak och göra det transparent (dvs det skall inte råda några tveksamheter om vad klassen gör).

Räcker det med att säga att en klass är samlad kod som innehåller en eller flera metoder som skickar data mellan sig med hjälp av lokala fält? Nej, jag tycker inte det. En klass är ju inte bara en samling funktioner – hela den här samlingen av fält och metoder representerar ju någonting annat. De representerar ju ett objekt, eller? Egentligen inte! Går vi vidare i abstraktionen av fält, metoder, klasser och objekt så landar jag i den här formuleringen:

En klass är en abstraktion av ett objekts strukturella uppbyggnad samt definition av hur den skall konstrueras.

Vad betyder då det här? Jo, att en klass är den abstrakta representationen av ett objekt. Det är först när du har instansierat en klass som det faktiskt blir ett objekt som du processar. Den abstrakta representationen definierar också hur du skall konstruera objektet och vilka externa beroenden som klassen har.

Det här betyder att klassen och objektet är två separata entiteter. Klassen är en mall, en slags ritning över hur objektet faktiskt skall se ut och fungera. Objektet lever sedan sitt liv inne i klassen och styrs av dess regelverk. Klassen definierar hur objektet får användas och vad objektet får göra. Klassen definierar vilka beroenden objektet har att rätta sig efter.

Än sen då?

Hur hjälper det här mig när jag programmerar? Behöver man verkligen förstå att klassen är abstraktion av ett objekt? Det kan det göra – det beror på hur du programmerar och angriper en uppgift. Det är väldigt lätt hänt att man börjar programmera och skriver en klass som gör det, och så bygger man ut den när man upptäcker att det behövs göras mer saker med objektet. Då blir koden väldigt snabbt dålig och svårhanterlig.

Om du då istället tänker på att klassen är en abstraktion så ”tvingar” denna insikt dig att först göra en abstraktion av objektet innan du faktiskt kodar din första rad. Detta kan spara dig mycket problem längre fram…

Vad är Din syn på saken?

Hur långt ifrån sanningen är jag, enligt dig? Skriv en kommentar och ge mig Din syn på saken.