2014-06-03
Alma hittade en bugg i "Almas matteapp" igår. Det var när hon för första gången gjort klart övningen "Ettans gångertabell i ordning" som appen drog upp en errordialog och stängde ner Activity:n som kördes, vilken var den som visar upp resultatet av övningen. Alma utbrast "Men pappa!" med förebrående röst. Ooops. Vad skall man säga? Det är sådant som händer. Speciellt om man inte har en egen QA-avdelning utan sköter allt testandet själv ;)
Alma gjorde sedan två övningar till (ettans gångertabell utan ordning och sjuans gångertabell utan ordning), och efter varje gång kraschade Activity:n som skulle visa övningsresultatet. Illa, illa.
När jag senare på kvällen körde appen i debug-läge från Android Studio konstaterades det snabbt att det var en NPE i en metod som skapade texterna för hur lång tid användaren tog på sig för att lösa övningen. När det var första gången som användaren gjorde en övning var bönan som normalt sett håller föregående övningomgångars bästa tid null, vilket ledde till att Activity:n kraschade när bönan accessades. Inga problem att fixa, men varför hade jag då inte märkt av det själv när jag testat? Jag har ju gjort minst 20 övningar för första gången de senaste veckorna? Och varför har inte Alma och Alice märkt något när de använt appen?
Det visade sig att buggen bara uppkom för användare som har satt inställningen "Visa tidmätningar" till true. Den användaren som jag alltid loggar in med när jag testar har den inställnigen satt till false, så det var därför jag inte märkt av buggen. Gissar att det var samma sak för Alma och Alice. Tror att Alma precis ändrat den inställningen från false till true och det var därför beteendet förändrades för hennes användare nu. Ja, ja. Gött att vi hittade den nu i alla fall innan vi lagt upp appen på Play-butiken.
2014-06-09
I Almas matteapp finns det just nu två saker som är gjorda för att öka intresset för att fortsätta göra övningar: medaljer och utmärkelser. Medaljer får man när man gjort en viss övning ett visst antal gånger. Gör man en övning en gång får man en bronsmedalj, gör man den fem gånger får man en silvermedalj, tio gånger ger en guldmedalj och tjugo gånger en diamantmedalj.
Utmärkelser är ett sätt att belöna att man gör flera olika uppgifter. För vissa utmärkelser spelar det inte någon roll vilken kategori en uppgift tillhör, andra har krav på att uppgifterna man gör skall tillhöra vissa kategorier. För närvarande finns det fyra kategorier: addition, subtraktion, multiplikation och talkompisar. Jag har planer på att utöka listan med kategorier allteftersom jag lägger till fler övningar till appen.
Den första utmärkelsen har jag (till Almas stora förtret) kallat 'Tre ljusstakar'. För att få den behöver man ha fått tre bronsmedaljer. Vet förresten inte riktigt varför jag valde just namnet Tre ljusstakar. Tror att jag associerade brons med mästing och mässing med ljusstakar. Inte helt logiskt kanske, men vad tusan, något skall den ju heta.
Utmärkelser-konceptet är förresten hederligt snott från Project Euler. Vet att det där triggar mig att göra fler uppgifter så jag tänkte att det kanske kunde trigga appanvändarna på samma sätt.
Alma har varit bortrest i några dagar och när hon kom hem igår så berättade jag att jag implementerat en ny utmärkelse: PlusMinus. För att få den behöver man fått guldmedalj på en additionsövning och en subtraktionsövning. Hon frågade då om jag inte kunde göra en utmärkelse som hade med multiplikation att göra. Det lovade jag henne att göra.
Runt kl nio på kvällen plockar jag, mot bättre vetande eftersom jag var rätt trött och borde gå och lägga mig, fram datorn. Startar upp Android Studio som indikerar att det fanns en uppgradering (0.6.0) att installera, vilket jag då gjorde. Efter den obligatoriska omstarten försökte jag bygga projektet. Fel version av SDK-toolsetet. Skit också. Startar upp SDK-managern och uppdaterar toolsetet. Det tar en bra stund. Startar om Android Studio. Bygger om projektet. Fortfarande fel version av toolset:et. In i projektinställningarna. Hittar inställningen för toolset-version och ändrar till den nyligen uppdaterade. Bygger om projektet. Äntligen funkar det. Tidsåtgång på detta: ca 45 minuter. Min dator är snart fem år gammal så allt tar sin lilla stund...
Nu är jag rejält trött och borde verkligen gå och lägga mig. Tänker: 'om jag bara startar koda lite på den nya utmärkelsen så blir det lättare att komma igång imorgon'. Börjar med det jobbigaste: komma på vad utmärkelsen skall kräva och att lägga till namn och beskrivning på den i strings.xml. Detta är något som brukar ta en stund eftersom jag har dålig fantasi och därför svårt att komma på bra namn på saker och ting. Sitter och funderar en stund innan jag bestämmer mig för att utmärkelsen skall kräva att man fått en guldmedalj på tre multiplikationsövningar. Den blir rätt lätt att få eftersom det t.ex. finns två övningar på ettans gångertabell (med och utan ordning). Vad skall utmärkelsen heta då. Svåra frågor. Jag bestämmer mig för att bara ta något: 'Multiplikationstrippel' får det bli. Inte världens bästa namn, men om Alma protesterar alltför mycket så kan man alltid ändra i ett senare läge. Namnet visas bara för användaren. Det används inte internt och sparas inte i databasen, så man kan ändra i strings.xml utan att behöva ta några speciella hänsyn, vilket ju är skönt.
Nu var det bara resten kvar. Är nu ännu tröttare och funderar på om jag verkligen inte borde gå och lägga mig. Väljer dock att fortsätta. Bara lite till.
Alla utmärkelser har en egen klass. Klassen refereras från enumen Awards
. I den enum:en specas för varje enumerarat värde följande saker: värdets ID (1, 2, ...), namn (ref till strings.xml), beskrivning namn (ref till strings.xml) och klassliteralen för den klass som implementerar utmärkelsen.
Klassen som implementerar utmärkelsen skall implementera interfacet Award
. Detta interface definierar endast en metod: boolean requirementsFulfilled(MedalStatisticsDto)
. Denna metod skall returnera true om användaren erhållit utmärkelsen och false om så inte är fallet. Valet görs med hjälp av en böna av typen MedalStatisticsDto
som innehåller data om vilka medaljer som användaren fått.
Fördelen med att spara såpass mycket data i Awards
är att aktivitieten som visar upp listan med utmärkelser (erhållna samt icke än erhållna) blir extremt lätt att skriva. Det den i princip gör är att den loopar över alla värden i Awards
-enumen och i en ListView
visar upp en rad för varje värde. På en rad i ListView
:n skrivs namnet och beskrivningen på utmärkelsen i fråga. Det ritas också ut en ikon om användaren har erhållit utmärkelsen. Aktiviteten bestämmer om användaren erhållit utmärkelsen genom att skapa en instans av den klass som pekas ut av Awards
-enumen och anropa dess boolean requirementsFulfilled(MedalStatisticsDto)
metod. Jättesmidigt, om jag får säga det själv. Och det får jag ju eftersom det är min blogg ;)
I alla fall, när jag väl hade bestämt mig för vad utmärkelsen skulle heta så skapade jag en ny klass som ärvde från Award
och implementerade dess boolean requirementsFulfilled(MedalStatisticsDto)
-metod. Den blev 21 rader. Inklusive @Override
-annotering, tomrader och måsvingar (för left curly brace är ju den rätta placeringen är på raden under statmentet så varje par måsvingarökar ju på radantalet med två). Inte så illa.
Efter det var det bara att lägga till rad med ett nytt enum-värde i Awards
-enumen, testköra och checka in. Testkörningen tog lite tid eftersom jag var tvungen att få guld på tre multiplikationsövningar. Jag hade brons på alla sedan tidigare (testkör alltid alla nya övningar en gång) så jag var tvungen att göra 3 * 4 = 12 övningar var och en innehållande 11 uppgifter. Även om varje uppgift går snabbt (let's face it: ettans och tvåanstabell är inte så svåra) så tar 132 uppgifter sin lilla tid. Funkade som det skulle gjorde det i alla fall.
Kvällens facit: en ny utmärkelse implementerad. Relativ tidsåtgång per aktivitet: strul 50%, namnsättning: 10%, kodning: 15% och test: 25%. Som vanligt med andra ord.
2014-06-13
Förra veckan var första gången jag ändrade en hel klasshierarki för att underlätta skrivandet och underhållandet av enhetstesterna av klasserna i hierarkin. Tidigare har jag gjort mindre justeringar som till exempel ändring av access modifiers eller uppbrytning av en metod i flera mindre metoder, men jag har aldrig förr skrivit om en hel klasshierarki just för detta ändamål. Uppgiften som skulle lösas var att konvertera en struktur av DTO:er till en motsvarande struktur av entiteter. Det som var lurigt var att vissa av DTO:erna innehöll (implicita)referenser till andra entiteter som eventuellt redan existerade i databasen. Ett antal DAO:ar måste alltså anropas på olika ställen under konverteringens gång. Detta är inga större problem för själva produktionskoden. Problemen uppstår när man skall skriva enhetstester för den.
Antag att det finns en klasshierarki för DTO:er A - B - C - D, där A innehåller noll till många B, B noll till många C osv. Dessutom refererar A implicit till entiteten APrim, B till BPrim osv. Motsvarande hierarki för entiteter är AA - BB - CC - DD, där AA har en direkt referens till APrim osv. Se figur 1 och 2.
Antag att varje DAO endast hanterar en entitetstyp och inte löser upp implicita referenser till andra entitetsklasser. Dvs save()
-metoden i DAO:n för AA tar endast emot en instans av klass AA där referensen till APrim är satt till korrekt värde. Ett annat alternativ skulle ha varit att DAO:et för A i sin save()
-metod skulle ha tagit in en implicit referens, t.ex. ett ID och själv anropat APrim-DAO:ets find(int)
-metod. Detta känns dock mindre rent och det verkar bättre att sköta sådan logik i servicelagret.
När hierarkin A - B - C - D skall konvereras till motsvarande struktur AA-BB-CC-DD för entiteter måste alltså metoden/klassen som sköter konvereringen A => AA ha en referens till DAO:arna för AA och APrim samt till konverteraren för B.
Min första ansats var att skriva var sin konverteringsmedod för A, B, C och D i samma klass. DTO:erna innehåller inte så många fält så konverteringsmetoderna blev inte så långa vilket gjorde att klassen som innehöll dem inte blev otympligt stor den heller. Runt 200 rader eller så tror jag den blev.
Jag injicerade DAO:ar för APrim, BPrim och så vidare och allt verkarde OK. Tills jag skulle börja skriva enhetstest. Det första enhetstestet skrev jag för D => DD konverteringsmetoden. Det var inga större problem eftersom D är lövklassen i hierarkin. Jag satte upp testdata, mock:ade DAO:arna för DD och DPrim, anropade konverteringsmetoden och gjorde mina asserts. Inga problem.
Nästa steg var att skriva enhetstest för C => CC-konverteringen. Nu behövde jag förutom att mocka DAO:arna för CC och CPrim även mocka x antal anrop till DD- och DPrim-daoarna! Bah. Jobbigt. Något som var ännu mer jobbigt var att enhetstesterna bara skulle bli besvärligare ju längre upp i konverteringskedjan jag kom. Det här gick ju inte. Insåg att något måste ändras.
En kollega hade tidigare i veckan klagat lite på att kod på ett annat ställe i kodbasen var skrivna på liknande sätt och att det därför var svårt att göra även små ändringar utan att behöva göra stora ändringar i enhetstesterna. Hans förslag på hur man borde har skrivit den koden från början var att man borde delat upp koden i små klasser som kunde enhetstestas var för sig.
Jag tänkte inte överdrivet mycket på saken när han sa det, utan höll bara med om att det lät som en bra ide. Nu började jag dock fundera om inte det skulle vara en god idé att refaktorera om min konverteringskod enligt kollegans förslag.
Sagt och gjort: jag refaktorerade ut varje konverteringsmetod till en egen klass med referenser till de andra konverteringsklasser som de behövde. Det blev alltså fyra nya klasser AConverter, BConverter, CConverter och DConverter, där AConverter har en referens till BConverter, BConverter har en referens till CConverter osv. Dessutom har AConverter en referens till DAO:t för APrim, BConverter en referens till DAO:t för BPrim osv.
Enhetstesterna blev nu mycket enklare att skriva. Ja, enhetstesterna för DConverter såg ju till mångt och mycket ut som enhetstesterna för den gamla metoden för konvertering av D, men de andra blev mycket enklare. De behövde bara två mockar: en för motsvarande Prim-DAO och en för konvertern i nästa steg i kedjan. Se figur 3.
Det blev mycket kortare och lättförståerligare kod som kommer att vara mycket lättare att underhålla.
Känns bra att ha refaktorerat om hela klasshierarkin så den blev bättre. Tack Yonas för tipset! Lite lustigt var det att den var lathet som gjorde att jag tog mig för det i och med att det varit för mycket jobb med att skriva enhetstester med den gamla strukturen. Larry Wall kanske hade rätt ändå ;)
Larry Wall: "The three great virtues of a programmer are: Laziness, Impatience and Hubris"
2014-06-19
Har funderat lite på vad jag lärde mig på Chalmers som jag haft nytta av i arbetslivet och vad jag önskar att jag hade lärt mig. Har även funderat på vilka kurser jag skulle rekommendera en student som går på högskolan nu med avsikt att jobba inom mjukvaruindustrin att läsa. Dessa saker har ett visst samband, men är inte ekvivalenta då man lär sig saker på högskolan som är bra/roliga/nyttiga att kunna i den del av livet som inte är relaterad till arbetslivet. Inte minst lär man sig många saker som är bra att kunna när man spelar frågespel ;) Måste dock i ärlighetens namn säga att just ur frågespelsperspektivet så finns det nog betydligt bättre utbildningar är en civilingenjörsutbildning. Utbildningar i historia och biologi t.ex.
Jag har hela min jobbkarriär jobbat med att konstruera mjukvarusystem av varierande storlek. Systemen har varit av typen "enterprise systems", så min bild av vad som är nyttigt att kunna är så klart färgad av det.
Vad jag inte lärde mig på Chalmers och som jag önskat att jag hade lärt mig:
- Versionshantering
Versionshantering är ju något som man använder dagligen när man jobbar med utveckling i mjukvaruindustrin. Det är i normalfallet verkligen inte raketforskning, men det hade varit lite bra att prova på ett VCS under kontrollerade former. Tror vi läste en kort text som berörde RCS i en kurs (kommer inte ihåg vilken), men det hade varit väldigt nyttigt att få använda ett versionshanteringssystem under t.ex en serie med labbar. Av de VCS:er som jag använt kanske Subversion hade varit det lättaste att lära sig. Git kanske hade varit nyttigare, men det känns lite för komplext för att vara helt optimalt att använda i labbar i en grundkurs. Risken är att det blivit för stort fokus på Git och inte på kursens huvudsakliga innehåll. Det känns även som om strulfaktorn är högre i Git än i SVN och strulfaktorn vill man ju hålla så låg som möjligt i en kurs...
- Strukturera stora mjukvarusystem
Det hade varit extremt nyttigt att lära sig lite om hur man kan strukturera stora system på olika sätt och hur man skall värdera de olika sätten mot varandra. Vi hade en kurs på 3 poäng när jag gick i trean i vilken vi i grupper om 2-5 pers fick genomföra ett projekt. Vad projektet skulle handla om fick vi bestämma ganska mycket själva. Några kompisar och jag skrev ett distribuerat air hockey-spel. Det var skitkul. Vi kodade loss som bara den och resultatet blev förvånansvärt bra. Dock är jag inte säker på att man om man skulle kolla på koden idag skulle vara speciellt imponerad över hur den varken var strukturerad, kommenterad eller testad. Nu gick inte kursen ut på det, men det hade varit nyttigt om någon lärare från datavetenskapliga institutionen hade gått igenom koden och gett kommentarer på arkitekturen (tror iofs inte att det hette så på den tiden).
- XML/XSD
Inte världens roligaste ämne, men ack så nyttigt att kunna. Avser då främst att konstruera en XSD så att de begränsningar som finns angående kardinalitet och elementordning i det som modelleras avspeglas på ett korrekt sätt i XSD:n. Detta är inte så svårt men inte helt trivialt heller. Jag har många gånger under mina år som kodare antigen behövt skapa en XSD från grunden eller sätta mig in i vilka begränsningar som en befintlig XSD ställer på XML-dokument som valideras mot den. Det är då vettigt att i alla fall ha ett hum om hur det hänger ihop. Gick en kurs i XML på Mittuniversistet för några år sedan. Innan kursen började trodde jag att den 1) skulle bli jättetråkig och 2) att jag inte skulle lära mig så mycket, men jag hade fel (som så ofta) på bägge punkterna. Den var helt OK ur ett rolighetsperspektiv och jag lärde mig en hel del, främst om XSD-konstruktion och XSLT.
- Installation och konfiguration av utvecklingsmiljö
När jag gick på Chalmers och gjorde labbar i datavetenskapliga kurser så var alltid utvecklingsmiljön färdiginstallerad och klar att använda. Detta är så klart praktiskt. Man kan koncentrera sig på det stoff som labben handlar om och labbhandledarna slipper få en massa ovidkommande frågor. Tyvärr är det inte så det funkar i arbetslivet, inte där jag jobbat i alla fall. Där kommer man inte till en färdiginstallerad dator som är klar att sätta sig ner och börja producera kod vid. Det är alltid en massa strul med att installera en IDE, ladda ner SDK:er och tredjepartsprodukter.
- Unix/Linux-systemadministration, bash, vi, less, grep, find
På alla de ställen som jag jobbat på så har de system som jag varit med och utveckla driftats på någon form av *nix-plattform. (I ärlighetens namn skall det sägas att Alystra som jag jobbade med på TransWare även och kanske rämst driftades på windows). Det har därför varit mycket värdefullt att kunna navigera runt och utföra grundläggande kommandon inne på diverse test- och produktionsservrar som kört olika typer av *nix-operativsystem. Det är bra att förstå lite om runlevels och att veta hur man lägger till användare samt hur rättighetssystemet fungerar. När det gäller testservrar så är det min erfarenhet att de oftast inte har någon vettig editor, dvs emacs, installerad. Jag har dock inte träffat på någon testserver som inte har haft vi installerat, varför grundläggande kunskap om det programmet är av stort värde när man skall in och ändra i någon konfigurationsfil. Det första vi-kommando man bör lära sig är esc-:-q-!
Med det klarar man sig långt. När man skall kolla loggar, vilket man gör ofta och inte sällan under stor press ("Feature x funkar inte. Fixa!"), så är det bra att kunna använda less, grep, tail och find.
- Något bra scriptspråk, ex Python
Det händer av och till att man behöver skriva program som manipulerar eller genererar textfiler. Att skriva sådana program i Java är ju såklart görbart, men det är inte helt smidigt. Fil-IO har blivit mer lättanvänt i senare versioner av Java än i version 1.1 som var den nyaste som fanns när jag började programmera med språket, men det är fortfarande inte smidigt. Jämför man hur många rader ett program som t.ex. läser indata från en textfil, kör en fråga mot en relationsdatabas baserat på det inlästa värdet och sedan skriver resultatet från frågan till en annan textfil så kan det säkert skilja en faktor fem beroende mellan ett Java-program och ett Python-program. (Ett extra plus är att det är mycket roligare att skriva kod i Python ;) Nu tog jag Python för det är det programmeringsspråk jag gillar bäst, men det finns en uppsjö av andra bra skriptspråk också.
- Testning: enhetstester, komponenttester, systemtesterEnhetstester och komponenttester är någon man som utvecklare skriver själv så att skriva sådana måste man kunna. När det gäller systemtester har i alla fall jag inte skrivit så många sådana själv utan min erfarenhet är att det ofta är specialiserade testare som konstruerar dem, men det är ändå viktigt att förstå vad ett systemtest skall testa och vad det finns för verktyg att skapa sådana i. Det kan även vara så att ett systemtest behöver köra ett litet specialskrivet program (fixtur) för att kunna testa det som skall testas. Vid sådana tillfällen kan man bli tillfrågad om att bistå med hjälp.
- Maven, ant
Koden man skriver måste byggas ihop till något som kan driftsättas på en server (eller annan dator) någonstans. I Java-världen sker sådana byggen ofta med verktyg som maven och ant. På Chalmers vet jag att vi använde make in någon kurs. Det var en mycket bra, men kanske inte så behaglig, erfarenhet eftersom vi på mitt första jobb byggde ihop vårt system med make.
Vad vill jag då rekommendera någon som vill jobba som utvecklare inom mjukvaruindustrin att läsa? Jo, följande:
- Generella kurser inom datavetenskap: algoritmer, datastrukturer mm.Det är viktigt att ha en stabil grund att stå på. Läser man sådana kurser får man en bred kunskap och kan jobba inom många olika delar av fältet. Läser man bara högt specialiserade kurser är risken att man blir för smal. Finns det då inga jobb inom just den specialiseringen kan det vara svårt att komma in på arbetsmarknaden.
- Databaser - SQL: används ju i princip överallt. Ett måste att kunna.
- Maskinnära programmering/assembler: Inte dumt att kunna åtminstone lite grand om lågnivåprogrammering även om man inte tänkt sig att jobba med det. Om inte annat för att inse hur priviligerade vi som kodar i högnivåspråk är ;)
- Kurser där man lär sig det jag tog upp i listan ovan ;)
Övriga råd:
- Installera Linux på en dator och lek runt med den. Installera program, kör en webbserver, lär dig om runlevels, rättigheter, användare mm.
- Installera en databas på datorn. Välj en relationsdatabas som t.ex. Postgres. Lär dig skapa tabeller mm (DDL) samt att lägga till och hämta upp data (DML).
- Installera ett IDE för ditt favoritprogramspråk och använd den tills dess att den känns bekväm.
- Lär dig ett bra skriptspråk, gärna Python. Lägg speciell vikt vid stränghantering och fil-IO. Lär dig accessa databasen du installerade från programspråket.
- Försök hitta något område som du är intresserad av och skriv något program inom det området. Det kan vara en app eller en webbsida eller något annat, det spelar ingen roll, bara du själv gillar det.
- Läs bloggar och artiklar på nätet och försök häng med i trenderna. Hittar du något som låter roligt så prova det!
Detta är mina tankar i frågan. Hade varit kul att höra vad andra tycker och tänker angående detta. Vad önskar ni att ni hade läst i er högskoleutbildning?
Det blev visst inte så mycket skrivet om vad jag har nytta i arbetslivet av det som jag lärde mig på Chalmers. Det här inlägget blev så långt så jag får ta det i ett senare inlägg.
2014-06-23
Har nu implementerat textuppgifter för addition i Almas matteapp. Trodde att det skulle bli ganska enkelt innan jag började. Märkte dock ganska snart efter det att jag börjat implementera att det inte var så lätt som jag trott.
Jag hade tänkt att skapa tio stycken parametriserade strängar för att representera uppgifterna. Strängarna skulle inledas med en beskrivning och avslutas med en fråga. Exempel: Alma har tre glaskulor och Alice har fyra glaskulor. Hur många glaskulor har Alma och Alice tillsammans?. Vidare var tanken att ha ett antal namn, säg tio stycken, och att appen skall slumpa fram vilka som skall användas vid varje körningstillfälle. Detta för att göra det lite roligare för barnen att göra uppgifterna. På samma sätt skall objekten ("glaskulor") och antalen som ingår i uppgifterna slumpas fram.
Android har ett bra stöd för parametriserbara strängar. I strings.xml
skapar man strängar som markörer av typen %1$s
på det ställen man vill parametrisera. 1:an i %1$s
står för att det är den första parametern och s:et för att det är ett strängvärde som skall sättas in. Det finns givetvis andra typparametrar än "s". Hade det stått ett d istället för ett s hade det betytt att ett heltal skulle stoppas in. Precis som i formatsträngen för C:s printf
När man vill använda en parametriserbar sträng från appens Java-kod använder man sig av varargs-metoden getString(int, Object...)
i klassen Resources
. En referens till Resources
kan man få från sin Activity
med hjälp av getApplicationContext().getResources()
. Exempel: för att hämta strängen med id "addition_text_one" från strings.xml
och binda "Alma" och "Alice" till de första parametrarna gör man följande innifrån en Activity
:getApplicationContext().getResources().getString(R.strings.addition_text_one, "Alma", "Alice")
Jag hade alltså tänkt att skapa tio sådana strängar, parametrisera alla namn, objekt och antal för att sedan använda dessa strängar för att skapa uppgifter. Det gick till slut, men var avsevärt jobbigare än jag trott. Vad var det då som gjorde det jobbigt?
- Objekten skall ibland stå i singular ("glaskula") och ibland i plural ("glaskulor").
- I singlular måste det bestämmas om det skall stå "en" eller "ett" framför objektet.
- I listan med namn finns det både pojk- och flicknamn. Det måste därför bestämmas om det skall skall stå "han" eller "hon" i frågorna.
- Bonusjobbighet: Min fantasi är inte i världsklass, så jag fick anstränga mig lite för att hitta på tio basuppgifter som inte var mer eller mindre identiska.
Hur löstes då problemen ovan? För närvarande är de lösta så här:
- I
strings.xml
finns det två arrayer med "saker": en med sakerna i singular och en i plural. På stället i koden som slumpar fram tal till frågorna kollas det om singularformen eller pluralformen skall användas baserat på om det framslumpade talet är ett eller inte. - Det finns i
strings.xml
ytterligare en array som innehåller med lika många items som det finns saker i arrayerna i 1). Denna array innehåller "en" eller "ett" beroende på om motsvarande substantivs genus. - Även detta löstes med en extra array i
strings.xml
. Den här arrayen har samma längd som arrayen med namn och innehåller "male" resp "female" beroende på om motsvarande namn är maskulint eller feminint. - Med ångest, vånda och uteblivet VM-tittande ;)
Är jag nöjd med lösningen? Så där. Det borde gå att hitta på något bättre. Samtidigt vill jag att strängliteralerna skall finnas i strings.xml
och inte i Java-kod. Hade varit trevligt att definera namn och singularformer av sakerna i strings.xml
och sedan anropa ett trevligt externt API för att bestämma reale/neutrum resp om ett namn är maskulint eller feminint. Fast å andra sidan vill jag inte att appen skall behöva komma åt nätverket...
Hade tänkt att gå vidare med att implementera textfrågor för subtraktion, men jag blev lite trött av strulet som var med de här uppgifterna så jag väntar nog ett tag med det. Skall kanske börja med uppgifter angående klockan istället. Vi får la se.
2014-06-29
Har skrivit en recension av Pro Django.
Link to the review
here