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.

Annonser

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.


Angående heder och svek…

2013-01-09

Det pågår en liten debatt på Aftonbladets ”Superbloggen” just nu angående heder och svek i spelvärlden…

Om heder och svek i spelvärlden

Kortfattat går det ut på att en viss person har sedan länge skrävlat om att han skall publicera en bok som skall bli en storsäljare och då slagit vad med Dan Glimne om när den skulle vara utgiven. Detta datum har passerats och den överenskomna vadslagningssumman har inte betalats till Dan. Han blev lite ”irriterad” och författade då ovanstående inlägg.

Vad gäller vadslagning så är jag glad att min mamma alltid har varit oerhört sträng kring pengar, spel och vadslagning. Hon har alltid avrått mig från vadslagning men gav mig ett råd om hur man kan göra det för att både behålla sin heder och för att inte bli blåst av någon annans oheder:

– Slå aldrig vad om belopp du inte fysiskt har på fickan just vid vadslagningstillfället. Aldrig. Då riskerar du aldrig i att hamna i läget att du inte kan betala om du förlorar.

– Om du har pengar på dig och slår vad: Se till att lägga dina och din ”motståndares” pengar i ett kuvert och ge till en tredjepart som ni båda litar på att förvalta tills vadet blir avgjort och be denne att ge kuvertet till vinnaren. Om du vinner så kan du alltid lita på att du får dina pengar och om du förlorar så har du alltid betalt din skuld. Bådas heder och vänskap kan bibehållas.

– Lita aldrig på andra när det gäller pengar. Gör du det får du vara beredd på att förlora pengar, vänskap och/eller heder.

Det här har gjort att jag ibland har tvingats avstå vad som jag har varit ganska säker på att jag borde vinna – jag har helt enkelt inte haft pengarna på fickan och har istället valt att behålla hedern och vänskapen. Jag har ibland lånat ut pengar, men bara till 2-3 personer som jag litar till 110% och som har visat att de är hedersamma att återbetala sina skulder.

Samma filosofi har jag också sedan använt i pokerspelen där hemma: Vi slantar alltid upp pengarna INNAN vi spelar och vi spelar aldrig någonsin med lånade pengar. Inga ”Äh, du vet att jag har de pengarna – du får tillbaka dem imorgon” godtas.


God Jul och Gott nytt år!

2012-12-23

Det har inte blivit så många inlägg på sistone då det har varit svårt att få tiden att räcka till. Så det får väl bli ett nyårslöfte att skriva lite mer frekvent…! 🙂

Nu skall vi fira jul och nyår och sedan tar vi nya friska tag 2013.

GOD JUL!


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) {
...
}


Satsa aldrig pengar på en hålstege…

2012-09-20

Enligt mig så tycker jag att en av de svåraste lägen jag kan hamna i är när floppen kommer upp och det visar sig att jag har en hålstege.. Vad i h-e skall man då ta sig till? Det är så fruktansvärt sällan som jag träffar de där fyra outsen som behövs. Väldigt ofta slänger jag handen kanske trots att oddsen finns för att syna. Jag hatar verkligen hålstege.

Men att slänga en hand som i det långa loppet skulle kunna betala sig är ju bara dumt, så jag måste lära mig att hantera den situationen. Så vad göra?

Min erfarenhet säger mig att en hålstege i en multipott är en riktigt dålig idé även när oddsen finns. Du vinner inte tillräckligt mycket för att motivera alla förluster. Dessutom så blir det väldigt ofta split pott i en multipott. Nä, en hålstege spelas bäst i headsup-läge.

Ett möjligt undantag är om bordet är väldigt passivt. Och då menar jag väldigt passivt. Typ rundcheck på flopp och kanske bara en mini-bet på turn. Men på dessa bord kan man ju spela nästan vad som helst och vinna i längden, så den typen av bord använder jag inte som någon måttstock.

Varför inte spela hålstegar i multivägspott? Detta för flera anledningar:

  • – Det är större risk för att du faktiskt inte har fyra outs. Risken aär större att någon av de andra aktiva spelarna faktiskt sitter med en av dina outs är markant större.
  • – Oftare än annars så drar du mot split pott, vilket gör att oddsen inte blir till din favör. I heads up så är split pot (på fullbordad stege) ovanligare har jag märkt.
  • – Om du inte har hålstege som drar till nötstegen så är det lätt att du faktiskt drar dött. Vad händer om du sitter med 78, bordet är TJx och upp kommer 9an? Väldigt ofta i en flervägspott sitter någon med KQ och du har just förlorat…

Hålstegar i multivägspott är komplicerat och därför undviker jag dem i dessa lägen. Heads-up är en helt annan sak, men då spelar faktiskt korten mindre roll – det är ett mycket mer spel mot din motståndare än vad ni faktiskt har för kort. Mycket mer psykologi än faktiskt spel.

Men hur spelar ni andra hålstegdrag, rent generellt?