Man lever så länge man lär

Inlägg taggade ‘objektorientering’

Veckans nya programspråk: Python

Jag har fuskat en gnutta i Python förut, i tjänsten, men då har det handlat om enkla modifieringar av kod som någon annan skrivit. Nu skrev jag programmet själv, från början till slut. Det tog ett par fredagstimmar och sedan hade jag mitt (samma gamla vanliga) program även i Python-skrud. Programmet (eller scriptet, om man så vill) är ganska precis lika långt som det i Ruby och hälften så långt som det i Objective-C. Skillnaden mellan Ruby och Python blev mindre än jag förväntat mig, men det beror nog mycket på att jag egentligen programmerar i något annat språk. Det vill säga, att jag inte utnyttjar språken som en riktig kännare av dem skulle ha gjort.

De delar mitt program främst består av är kommandoradstolkning, inläsning från fil, mönstermatchning och datum-/tidsaritmetik. Det är intressant att se skillnaderna i hur man gör saker i respektive språk, och hur variabler ser ut innan de fått värden. Jag är säker på att jag missar vissa saker, men kan ju gå tillbaka framöver. Faktum är att jag tänker mig att jag ska göra just det i något senare skede, försöka sätta mig in i språket på djupet och verkligen förstå dess själ. Ja, det låter kanske smått högtravande och kommer väl förmodligen aldrig att bli av, men då får det vara så.

Just nu verkar det som om nästa version av Programmet blir skriven i Rust.

Veckans nya programspråk: Ruby

Ja, det var väl egentligen förra veckans programspråk eftersom det var i söndags jag roade mig med att skriva ett litet program i Ruby. Och det programmet skrevs utifrån samma krav som det jag veckan innan skrev i Objective-C. Exakt likadant blev det dock inte då jag kom på nya saker att göra och färdigt blev det inte heller. Visst, programmet fungerar nu, men räcker ju inte för att jag ska känna mig nöjd.

Kod är mer än funktion

En viktig sak i min programmeringsfilosofi är nämligen att ett program inte är klart bara för att det bevisligen fungerar. Där ser jag stor skillnad mellan mig själv och nyare utvecklare, som ofta inte utvecklat känslan för skönhet och långsiktighet i koden – både det rent visuella i hur källkoden ser ut och det mer designmässiga.

Kod som kommunikation

Och det jag menar med långsiktighet här handlar mycket om kommunikation, d.v.s. att koden ska vara begriplig för mig själv och andra som kan behöva uppdatera den i framtiden, och om en robust design, d.v.s. det ska gå lätt att uppdatera koden när kraven förändras. För det gör de, om programmet/systemet hanteras på rätt sätt.

Implementera inget onödigt

Men tro nu för guds skull inte att jag förespråkar att man implementerar krav som ännu inte finns! Nej, vi ska implementera det som behövs, varken mer eller mindre. Vi kan visserligen hålla i bakhuvudet det som kommer sedan, i den mån vi vet om det, för att inte råka skära av vägen framåt, men vi implementerar inget onödigt.

We are not done yet!

I min värld kan det när koden fungerar ännu vara rätt mycket arbete kvar att göra. Och då räknar jag inte med sådana saker som att skriva unittestkod, för det har jag ju gjort medan jag utvecklade det funktionella. Nej, det handlar om att titta igenom koden ett par varv till, snygga till och refaktorera för både läs- och underhållsbarhet. Utöver detta kanske man också justerar designen, både på högre och lägre nivå. Fast det sista beror ju också av om man har mandat att göra designförändringar.

Refactoring

Refaktorering är en njutning när man känner sig trygg i att man täckt upp den viktiga funktionaliteten med hjälp av unittester – gör man fel i sin refaktorering märks det ju på att testerna inte längre går igenom utan signalerar fel. Baren blir röd, som vi säger i Eclipse-världen. Vi kör red/green/refactor!TDD-lingo.

Ruby är mer kortfattat?

Det fascinerar mig att programmet som landade runt 150 rader i Objective-C blev mindre än hälften så långt i Ruby. Fast då är ju som sagt inte funktionen densamma så man kan inte göra en direkt jämförelse. Sedan skriver jag olika bra i respektive språk och inget av programmen är heller färdigt, men ändå… rätt stor skillnad!

En del av skillnaden kommer dock säkert att försvinna när jag inför mina förenklade algoritmer i det längre programmet. Och kanske också med mer objektorienterade koncept i det kortare. Vem vet, de båda blir kanske i slutänden precis lika långa.

Namnsättning

En annan lustighet är att jag av någon anledning bytte namnsättningsprincip när jag växlade språk. I Objective-C använder jag samma namngivning som i Java, d.v.s. camelCase. I Ruby fann jag mig plötsligt skriva mer i ”C-stil”, d.v.s. snake_case.

Framtida ändringar

Saker jag vill göra med Ruby-programmet är t.ex. att göra det mer objektorienterat, för som det nu var skrev jag det mer som ett script med några hjälpfunktioner. Jag vill alltså bryta ut delar av koden till en separat klass, med ”riktiga” metoder. Och så vill jag förstås (som vanligt) skriva unit-tester för dessa – kod utan unit-tester är inte riktig riktig kod. Och på något sätt kopplar jag ihop objektmetoder och unittestkod.

Andra saker jag gjorde hade att göra med editering och versionshantering.

Editor

Första versionen av programmet skrev jag direkt i kommandorads-vi. Det var inte helt angenämt, så jag installerade TextMate. Programmet gav mig färgkodning och som bonus en fantastiskt fin ikon i form av en rosalila blomma, som fick mig att vilja älska det. Dessvärre var det inte jättekul att redigera kod i detta program heller. Och jag inser nu att jag förmodligen kunde ha fått färgkodning med hjälp av vim om jag bara kommit på tanken att installera den (men det gjorde jag förstås inte då).

Sedan blev jag påmind om Sublime Text, som Kodsnackarna nämnde i något av de avsnitt jag lyssnat på, och som GP enligt uppgift använder både hemma och på jobbdatorn. Jag installerade Sublime och blev lite kär på direkten. I Sublime fick jag bl.a. hjälp med att skriva variabelnamnen rätt och konstaterade att den verkar värd att utvärdera. Det är nog inte otänkbart att betala de 70 USD programmet kostar.

Versionshantering

Det här med versionshantering, då. Där var det ganska självklart att använda git, eftersom det är den versionshanterare jag vill lära mig – dels för att det är den som är ”den” och dels för att jag vill förstå hur den skiljer sig från mitt tjänsteverktyg som är Rational Team Concert. Nu innehåller RTC mer än versionshantering, men ändå.

Jag skapade mig ett git-repository för projektet, och checkade in min programfil. Fine, men nu vill jag lära mig mer om git-användning och skicka upp min kod till familjens NAS för safekeeping och möjlighet att kanske dela koden med andra.

Påskläsning

Till min hjälp i lärandet om git har jag skaffat ett par e-böcker. Kanske kan dessa få bli min påskläsning, måhända parallellt med H.P. Lovecrafts The Call of Cthulhu.

Med tanke på att vi reser bort tror jag inte det blir någon programmering denna helg, men annars låter det som en rolig idé att prova ett nytt programspråk varje vecka. Tänk så många språk man hinner med på bara ett år! Och jag undrar vad det gör med ens förmåga att programmera – blir man kanske mer förvirrad än upplyst?

Provprogrammerar i Objective-C

I fredags fick jag för mig att installera Xcode som utvecklingsmiljö på min MacBook Pro för att skriva ett enkelt program i (och därmed lära mig lite) Objective-C, som är det programmeringsspråk man använder i Apple-världen för Mac OS X och iOS.

Jag nöjde mig på kvällen med att göra Xcode-installationen, sätta upp mitt projekt och kolla upp Objective-C som hastigast. Programspråket såg lite skumt ut, men verkade möjligt att lära sig. Kombinationen C och objektorientering kan nog funka. Jag har ju programmerat i både C och Java, och en del andra mer obskyra språk.

Ändå pirrade det allt lite i magen – hur skulle det gå? Jag stod i begrepp att ge mig in på något nytt och främmande. Vet inte varför sådant gör mig nervös, men det gör det samtidigt som jag ändå någonstans vet att jag grejar det. Hur som helst tedde det sig som en utmärkt idé att där bryta för dagen och övergå till familjeliv, för att dagen efter läsa in mig på ämnet och börja koda. Och det var ungefär så det blev.

Det vill säga, jag läste mycket mindre än jag tänkt innan jag var igång med själva kodandet. Uppgiften jag ålagt mig handlade om att läsa data från en textfil, tolka innehållet genom att extrahera relevant information och göra några beräkningar.

Jag började med att läsa in hela filens innehåll och skriva mycket rudimentär kod för att identifera de rader som var av intresse och plocka ut det data jag behövde. Efter något femtiotal rader kod började jag sakna de konstruktioner jag obehindrat svänger mig med i Java-världen. Det är så frustrerande att inte veta hur man bäst gör saker i det aktuella programspråket, hela tiden tvingas googla efter exempel. Men visst, man lär sig. Jag lärde mig. Jag är nog inte en så gammal hund ändå.

Jag säger: Stack Overflow måste väl ändå vara världens bästa resurs!

I stort sett hela lördagen satt jag sedan och programmerade. Jag lärde mig skapa och hantera några enklare objekt. Jag lärde mig att börja med hakparentes för att kunna anropa metoder på ett objekt och hur man fick IDE:n att visa vilka metoder som finns. Jag lärde mig hur man skapar och använder reguljära uttryck (denna gudomliga skapelse!) för att hitta och extrahera datum och klockslag ur strängar. Jag lärde mig att jämföra tidpunkter och addera tidsintervall. Samt en del annat.

Mitt program består i nuläget av ungefär 150 rader kod, i en och samma källkodsfil, inklusive kommentarer och tomrader. Jag har en main-metod och 6 hjälpfunktioner. Det finns ytterligare någon sak jag vill testa, men programmet fungerar som det är.

Jag har bekantat mig mycket lite med själva utvecklingsmiljön än så länge, även om jag i alla fall lärt mig sådant som att kommentera block av kod och checka in koden i mitt lokala git-repository. Så här långt är Xcode rätt frustrerande och jag saknar Eclipse. Antar (hoppas!) att det främst beror på att Xcode är annorlunda, men det finns en möjlighet att Xcode faktiskt inte har de funktioner jag är van vid.

Det mest frustrerande är nog just det där att jag inte känner språket ännu – jag vet inte vilka metoder jag kan förvänta mig hitta på ett objekt och inte hur de namnges. Ibland tar det en evighet att begripa hur jag ska göra, ibland går det på ryggmärg – många gånger går saker faktiskt att göra på nästan exakt samma sätt som i Java.

Utöver att lära mig mer om själva programmeringen vill jag bli bättre kompis med utvecklingsmiljön (Xcode) och lära mig en massa om versionshanteringen (git). Och så vill jag givetvis också lära mig hur man kan unittesta kod i den här miljön.

En vacker dag tänker jag mig att prova på iOS-utveckling genom att skriva en app. Eller så blir det Android i stället – det är ju den plattform jag använder dagligdags. Oavsett vilket har jag en uppgift att lösa. Automatisera det jag idag gör manuellt.

Hur som helst var det riktigt roligt att utföra uppgiften – det kan nog bli mer sånt!

Programmering: Tillstånd – från en stor maskin till flera mindre klasser

Jag har egentligen inte i mitt tidigare liv stött på konceptet tillståndsmaskin när det handlar om programmering, även om jag har ett svagt minne av att begreppet dök upp i något av de tekniska ämnen jag läste på gymnasiet. Det var inte alls särskilt länge sedan ämnet dök upp i en programmeringsteknisk diskussion med sambon. Han, som har både mer formell utbildning och bättre teoretiska kunskaper än jag, förklarade principen och jag blev entusiastisk och lanserade konceptet på jobbet och fick positiv respons och sedan har det rullat på. Jag gillar tillståndsmaskiner!

Jag tror inte att jag är världsbäst på att förklara det hela, men kan ju ändå försöka ge min bild. Konceptet innebär att saker hela tiden befinner sig i ett visst tillstånd, och går vidare till andra tillstånd enligt ett förbestämt mönster eller schema – inte nödvändigtvis likadant från gång till gång. Ett eller flera tillstånd kan t ex upprepas eller måste inte finnas alls. Alla sådana saker specificeras av mönstret/schemat.

Förresten, det är ju inte så att det alltid finns en formell beskrivning heller – ibland sitter det hela bara i huvudet, man förstår själva processen. Det kan vara så enkelt som att man köper en sak: går in i affären, väljer vara (eller varor), betalar, får ett kvitto, går ut ur affären. Eller så låter man bli att betala och får därför inget kvitto. Eller kanske man går runt i butiken varv efter varv innan man till slut känner sig redo att passera kassan. Och så vidare. Processen är flexibel och kan varieras.

En fördel med att använda tillståndsmaskiner i programmeringen är att man slipper hålla hela bilden i huvudet. Det räcker med att se på den närmaste omgivningen och förstå var man man kommer ifrån, och vad man därför ska göra eller förvänta sig härnäst. Typ så ser jag på det. En tillståndsmaskin gör jobbet mycket enklare. Och ja, för att det påståendet ska vara sant måste det självfallet handla om ett problem som är lämpligt att lösa med en tillståndsmaskin, men det säger sig självt.

Utan tillståndsmaskinen kommer man antagligen att skriva kod som är kladdig och svårläst och därmed blir knepig både att följa, underhålla och vidareutveckla. Och kladdig och svårbegriplig kod tycker jag är bland det värsta en programmerare kan skriva. Det är att göra alla, både sig själv och framtida förvaltare av koden, en mycket stor otjänst. Om koden är kladdig från början blir den inte bättre när man ändrar i den. Inte ens om man själv är den som skrivit den från början. Tro mig.

Här skulle jag lätt kunna dra ut på sidospår för att prata programmeringsmetodik i största allmänhet (Code Complete-läsandet sätter sina spår och väcker sovande björnar), men nu tror jag ändå att det var historien om tillståndsmaskinen jag hade tänkt berätta så jag låter bli det. Kanske någon annan gång. Till programmeringen!

Låt säga att vi ska jobba oss igenom någon form av datastruktur, som är/behöver vara ordnad efter ett visst schema, och behöver titta på eller hantera varje bit data på olika sätt beroende på var i det här schemat vi (d.v.s. vi som lever i koden) befinner oss. Då tuggar vi oss igenom strukturen bit för bit och gör det som behövs för var och en av dem. För att hålla reda på var i schemat vi befinner oss kan vi t ex använda states, eller tillstånd om man nu ska prata svenska. Fine. Det finns ju i Java (och även andra språk) en datatyp för uppräkning och den kan vi använda.

Vi har en variabel som representerar det aktuella tillståndet med hjälp av ett värde ur en enumeration (uppräkning, här: lista över möjliga tillstånd), och så gör vi saker och sätter om värdet på variabeln vartefter vi tar oss fram i schemat/mönstret. Och på slutet kollar vi om det slutliga tillståndet stämmer med vad vi förväntat oss. Allt är fint, men koden känns inte riktigt bra och framförallt när man hanterar många olika tillstånd blir det väldigt oöverskådligt. Man tycker att det borde kunna finnas bättre sätt att lösa problemet. Och det gör det förstås. Det gör det nästan alltid.

Jag och sambon pratade vidare om tillståndsmaskiner och han planterade för några dagar sedan en tanke om att i stället representera tillstånden med klasser, som då skulle ha en hanteringsmetod med den logik som annars ligger i case-satserna. Det lät roligt, om än lite svårt att föreställa sig först, så jag blev sugen på att åtminstone testa. Sent igår gjorde jag sålunda ett provskott och kunde då konstatera att det var snabbt och lätt att skapa tillståndsklasser och peta in hanteringsmetoderna i dem.

Därefter åkte jag hem och fortsatte där med att skapa fiktiv exempelkod, helt tagen ur luften, och visa för sambon hur hans lösning förvanskats och implementerats av min hjärna och nu tänkte jag att jag kunde visa lösningen även för mitt framtida jag. Och naturligtvis även för er som läser detta inlägg och eventuellt är intresserade.

Så här ser det ut när jag representerar mina tillstånd med hjälp av enumerationer:

/* metoden som gör det övergripande jobbet */ {
	State currentState = Begin;

	while (we.haveMoreThings()) {
		switch (currentState) {
		case Begin:
			currentState = we.handleBegin(thing);
			break;
		case StateA:
			currentState = we.handleStateA(thing);
			break;
		case StateB:
			currentState = we.handleStateB(thing);
			break;
		case StateC:
			currentState = we.handleStateC(thing);
			break;
		case End:
			currentState = we.handleEnd(thing);
			break;
		default:
			throw new IllegalStateException("Hey, what!?");
		}
	}

	if (!currentState.isTheEnd()) {
		throw new IllegalStateException("We are not done yet!");
	}
}

private State handleBegin(Object thing) {
	// Här gör vi massor av spännande hantering...
	// ... och sedan returnerar vi nytt tillstånd:
	return StateA;
}
// ... här blir det alltså en metod per hanterat tillstånd.

Och så här ser det ut när jag i stället representerar mina tillstånd med klasser:

/* metoden som gör det övergripande jobbet */ {
	State currentState = Begin;

	while (we.haveMoreThings()) {
		currentState = currentState.handle(thing);
	}

	if (!currentState.isTheEnd()) {
		throw new IllegalStateException("We are not done yet!");
	}
}

Det vill säga: tillståndet sköter hanteringen. Jag vet vilken version jag föredrar.

Så, kan man kanske undra, hur ser det då ut bakom kulisserna?

I det första fallet lade jag (av flera olika skäl) mina tillstånd i egen, separat fil:

	enum State {
		Begin, StateA, StateB, StateC, End;
	
		public boolean isTheEnd() {
			return this == End;
		}
	}

… och i det andra fallet hamnar handle-metoderna i stället i ett State-interface, där jag även lagt tillståndsklasserna (som varken behövs eller bör synas utifrån). Det är en bra idé att stoppa undan ovidkommande information för att undvika förvirring.


interface State {

	public State handle(Object thing);
	public boolean isTheEnd();

	public static final State Begin = new Begin();
	public static final State StateA = new StateA();
	public static final State StateB = new StateB();
	public static final State StateC = new StateC();
	public static final State End = new End();
	
	public class Begin implements State {

		@Override
		public State handle(Object thing) {
			// Här gör vi massor av spännande hantering...
			// ... och sedan returnerar vi nytt tillstånd:
			return StateA;
		}

		@Override
		public boolean isTheEnd() {
			return false;
		}

		private Begin() { /* no outside construction, please */ }
	}
	// ... här blir det alltså en klass per hanterat tillstånd.
}

Hade detta varit i den riktiga världen hade jag valt att lägga tillståndsklasserna i egna, separata filer och gjort dem ”package private”, men i exempelkoden ville jag hålla strukturen likadan utifrån sett för att göra jämförelsen dem emellan enklare.

Nåväl, så här ser det ut just nu. Exemplet ovan gör inga anspråk på att vara vare sig korrekt eller komplett eller ens i närheten av realistiskt, men jag tycker att det fyller en funktion och hoppas att någon av mina läsare får glädje eller nytta av det.

Själv kommer jag garanterat att fundera vidare och skruva och fixa och dona och fiffa och mojja och vad man nu gör med kod. Kod, och ens tänkande kring den, evolverar ständigt. Ibland går det snabbt och ibland går det långsamt, men jag finner det i praktiken omöjligt att stå stilla. Det går alltid att göra koden bättre!

Kommentarer, funderingar, förslag?

Etikettmoln