Naboer

Jeg er gået i gang med at lave nogle nye funktioner i app'en. En stor del af arbejdet handler ikke om at tilføje noget som sådan men at få de funktioner der allerede er der til at virke mere hensigtsmæssigt. Men der er osse nogle nye ting man kommer til at kunne.

En ting jeg allerede har arbejdet med men som fortjener at blive gjort endnu bedre er at tage med i betragtning når man kan gå mellem stop. Lige nu er app'en ret striks omkring hvilket stop mener og kigger ikke altid på stop i nærheden. Det er jeg i gang med at gøre den lidt mere afslappet omkring.

For at kunne gøre det har app'en brug for at vide hvilke stop der er i nærheden af hinanden. Jeg kalder det at stoppene er naboer. Til det jeg skal lave er det nyttigt at vide for et givet stop, hvilke andre stop er der indenfor sådan rimelig gå afstand. Lige nu bruger jeg 1,25 km som radius – det er det man kan gå på et kvarter hvis man går 5 km/t. Der er i omegnen af 30.000 stop i Danmark og mange af dem, specielt inde i byerne, har mange naboer indenfor 1,25 km. Rekorden er Sankt Markus Allé & Vodroffsvej på Frederiksberg der har 149 andre stop indenfor 1,25 km. I alt er der 4,7 millioner "naboskaber", altså par af stop der er naboer. Jeg vil gerne gemme listen af naboer for hvert stop som en del af app'en for den er ret tung at beregne men 4,7 millioner er alt for meget – det ville fylde mere end hele resten af køreplanerne. Det jeg har arbejdet på denne uge er at løse det problem: hvordan gemmer jeg naboskaberne mellem stop uden at det fylder for meget.

Den løsning jeg er endt med at lave udnytter at når stop er i nærheden af hinanden har de gerne de samme andre stop som naboer. Det kan godt være Sankt Markus Allé & Vodroffsvej har 149 naboer og Danas Plads har 144 men fordi de ligger lige klods op og ned af hinanden er langt de fleste af de naboer de samme for de to. Måske 130 af dem er naboer til begge stop. Hvis jeg gemte en særskilt liste af naboer for hver af de to stop ville der være 293 i alt (149 + 144) men hvis jeg laver en liste med de 130 naboer de har til fælles og deler den mellem de to fylder det kun 163 tal (130 + 19 + 14). 19 er det antal stop Sankt Markus Allé & Vodroffsvej har ud over de 130 de begge har og 14 er det samme for Danas Plads. Det er en pladsbesparelse på næsten 50%.

Det har krævet lidt snilde at få til at virke og specielt at få systemet til selv at kunne genkende hvornår det er en god ide at dele naboer mellem flere stop. Men nu fungerer det og sparer så meget plads at det er realistisk at gemme nabo-listerne sammen med køreplanerne. Stoppet lige udenfor mit kontor bruger f.eks 3 delte nabo-lister som andre stop i nærheden osse henviser til.

Hvert screenshot viser en af de delte lister. De mørke stop er dem der indgår i listen, de lyse er andre stop der henviser til den liste. Her er et andet eksempel, det er et tilfældigt stop i Roskilde der osse bruger 3 delte nabo-lister

Meget af tiden når jeg arbejder på algoritmer går det op i meget abstrakte begreber: tal, afstande, afbildninger, scorings-funktioner, osv, ting der når jeg arbejder med dem ligger fjernt fra det praktiske problem jeg er i gang med at løse. Men når det så virker er det virkelig interessant at tage de løsninger algoritmen finder på og kigge på dem på et kort. Jeg kan ikke forklare præcis hvorfor der er tre delte nabo-lister lige der i Roskilde men det ser da meget fornuftigt ud.

Kosmetiske ændringer

I løbet af sidste uge har jeg lavet forskellige små-ændringer til app'en. Blandt andet ikonet som jeg nævnte tidligere. Den mest synlige ændring er nok at man ikke længere kan vælge til/fra på et google maps kort. Man kan næsten det samme men den nye måde at søge på google maps er blevet lidt mere skrabet. Her er hvordan det så ud før:

Og her er efter:
De minder om hinanden men kortet er væk. Det er fordi google har ændret på deres betingelser så man (det vil sige jeg) nu skal betale for at lave auto-complete og at vise kort. Det er jeg sådan set okay med og den nye udgave laver netop auto-complete som koster en smule. Men at vise kort koster bare uforholdsmæssigt meget så det er jeg blevet nødt til at slå fra.

Nyt android ikon

En af de ting man opdager når man laver en app er at man til en vis grad skal løbe for at stå stille. Google ændrer f.eks løbende kravene til android apps, de opfinder nye ting og fjerner gamle ting. Nogen gange er det noget man skal forholde sig til og bruge tid på bare for at ens app kan blive ved med at køre. Det er det samme med Apple og iPhone apps.

Det nyeste tiltag er at app ikoner skal fungere anderledes på android. Hvor det i gamle dage bare var et billede i en bestemt størrelse skal det nu være mere kompliceret. Det er for at de kan vise dit ikon med forskellige former, runde, firkantede, rund-oval, hvad ved jeg. Og animere dem på fancy vis. Det ser sådan set meget fedt ud men det kræver at jeg laver et nyt ikon i deres nye format. Så har jeg samtidig benyttet lejligheden til at ændre det en smule. Ikke meget, bare en anelse.

Brugerstatistik

Denne post er længere og måske mere tør end sædvanligt. Det er fordi den handler om noget jeg synes er virkelig vigtigt så jeg vil gerne være ekstra åben og detaljeret omkring det.

Den sidste uge har jeg arbejdet på fejlrapportering og brugerstatistik. Første gang google fjernede A til B fra play store var det fordi jeg ikke havde slået googles indbyggede fejlrapportering og brugerstatistik fra. Det gjorde jeg dengang, slog begge dele fra, så jeg stod uden begge dele. Dengang skrev jeg mit eget system til fejlrapportering så jeg har helt styr på at der ikke bliver gemt information om brugere derigennem, men jeg lavede ikke noget system til brugerstatistik. Det slog jeg fra uden at have en erstatning fordi jeg først skulle finde ud af hvordan jeg overhovedet gør det.

Brugerstatistik er viden om hvordan brugerne faktisk bruger din app. Hvis man har en fysisk forretning får man automatisk en masse viden om ens kunder: man kan se hvor de går hen, hvilke varer de kigger på, hvilke varer de køber, hvilke spørgsmål de stiller, osv. Den viden er super nyttig. Fordi A til B er en app får jeg i udgangspunktet intet at vide om hvordan folk bruger den. Hvilke funktioner bruger de? Hvordan bruger de dem? Fungerer de godt eller dårligt? Er folk forvirrede eller synes de det er nemt? I udgangspunktet har jeg ingen anelse. Det er der forskellige løsninger på og en af dem er at opsamle statistik om hvad folk gør.

Det der gør brugerstatistik svært, ikke kun for mig men for alle der lave en app, er at det rammer et spændingfelt mellem faktorer der trækker i forskellige retninger. Blandt andet:
  1. hvad brugerne er interesseret i at app udvikleren ved
  2. hvad udvikleren har brug for at vide
  3. hvad udvikleren har lyst til at vide
  4. hvad lovgivningen så kræver af udvikleren

Typisk er brugeren interesseret i at udvikleren ved så lidt som muligt om dem. Omvendt har udvikleren lyst til at vide så meget de overhovedet kan. Samtidig kræver loven at hvis udvikleren gemmer så detaljerede data om brugere at de er personhenførbare så skal brugeren have en masse rettigheder over dem. Så hvad gør man?

De fleste apps og websites "løser" problemet ved i det store hele at ignorere punkt 1 og 4 og gå all in på punkt 2 og 3. At ignorere punkt 1 har ikke de store konsekvenser, antallet af folk der som mig er villige til ikke at bruge en app fordi den overvåger dem er forsvindende lille. Man skulle tro at punkt 4 var sværere at ignorere men det er næsten lige så nemt: det er der første gang du bruger app'en hvor du trykker godkend til at langt juridisk dokument du ikke har læst, og så må de gøre hvad de vil med dine data. (Eller, jeg tror faktisk ikke et øjeblik på at det holder i retten men det gør ingen praktisk forskel så længe ingen trækker virksomheder i retten over det.)

Allerhelst ville jeg slet ikke at samle brugerstatistik men efter det meste af et år uden det må jeg bare indse at det er virkelig svært at leve uden. Det billede jeg har haft i baghovedet da jeg designede det var: nogen steder er der sådan nogen standere ved siden af cykelstierne der tæller hvor mange cyklister der er kørt forbi. Systemet ved ikke at det er mig der er kørt forbi, det eneste den holder styr på er at en eller anden er. Fra et privacy synspunkt er det helt fint med mig og jeg mener ikke det er urimeligt at opsamle den slags. Det jeg har forsøgt er at opsamle statistik i app'en i samme ånd.

Helt konkret den måde det virker er at app'en holder styr på hvilke dage du bruger den, og hvilke uger, måneder, og år. Det er bare internt i app'en, det bliver i første omgang ikke sendt nogen steder. Så f.eks hvis du har brugt app'en torsdag, lørdag, og søndag sidste uge ville den internt, på din telefon, have noteret at du brugte den sådan her:

  1. Mindst en gang på dagen torsdag den 2. maj 2019
  2. Mindst en gang på dagen lørdag den 4. maj 2019
  3. Mindst en gang på dagen søndag den  5. maj 2019
  4. Mindst en gang i ugen der starter 29. april
  5. Mindst en gang i måneden maj 2019
  6. Mindst en gang i året 2019

Hvor mange gange du bruger den, om det er 1 eller 100, er ligemeget.

På et tidspunkt den følgende uge, lad os sige det er den 8. maj i dette tilfælde, kigger app'en igennem det den har noteret og ser om der er noget omkring perioder der er overstået. I så fald sender den en besked med den information tilbage til en server jeg har sat op. I dette tilfælde ville den sende de 5 første elementer på listen fordi den 8. maj er vi forbi de dage og vi er inde i den næste uge og måned. Det sidste element kan ikke sendes endnu fordi vi stadig er i året 2019. Den besked der bliver sendt indeholder intet om hvem det drejer sig om, kun en at en eller anden ukendt bruger derude der brugte app'en i de angivne perioder.

Serveren har en tæller for hver periode og den holder styr på hvor mange har brugt app'en mindst en gang for hver givet dag, uge, måned, osv. Og altså ikke per bruger, men samlet for alle brugere. Når serveren modtager en ny besked løber den igennem og lægger 1 til for hver periode der er nævnt. Det er alt hvad den gemmer, derefter smider den beskeden væk.

Det vil sige at jeg kan ikke følge nogen brugere individuelt det eneste jeg kan se er hvor mange brugere der har været indenfor en given periode. Præcis ligesom cykel tælleren bare holder styr på hvor mange der er cyklet forbi. Med tiden kommer jeg til at tilføje flere ting der bliver noteret, f.eks hvis jeg tilføjer en ny funktion vil jeg gerne vide hvor mange der har brugt den indenfor en given periode. Og jeg kan osse inddele data med noget ekstra information f.eks android version. Det svarer til hvis cykel tælleren ikke kun talte hvor mange der var passeret men delte dem op i to grupper, de der kørte over og de der kørte under 25 km/t. Det giver lidt mere information men princippet er det samme, der bliver aldrig gemt information for specifikke brugere men kun et samlet tal for alle brugere. Brugerne bliver bare underopdelt, f.eks efter android version.

Den måde jeg ser resultaterne er med et værktøj jeg osse lavede sidste uge, wot:

$ wot stats ls
--- start_activity / day ---
2019-05-02 1
2019-05-04 1
2019-05-05 1

--- start_activity / week ---
2019-04-29 1

--- start_activity_by_version:27 / week ---
2019-04-29 1
Det skal læses som: den 2., 4., og 5., maj var der i alt 1 bruger der brugte app'en, det var der osse ugen der startede 29. april (dvs sidste uge). Og sidste uge var der en bruger der havde android 27 installeret der brugte app'en. (Jeg har testet koden på min egen telefon sidste uge så brugeren er i alle tilfælde mig selv.)

For at demonstrere hvor lidt data der bliver gemt er her et kig på de underliggende data som ligger til grund for det værktøjet viser:


Næste gang der kommen en opdatering af køreplanerne, forhåbentlig denne uge, opdaterer jeg app'en og så bliver statistikken rullet ud til alle brugere. Med tiden tænker jeg at lave en indstilling så man kan slå det helt fra fordi selv om jeg synes det er uproblematisk at opsamle ved jeg der er folk der er ligeglade med hvad jeg synes, de vil bare kunne slå det fra. Og det er i princippet fair nok. Men det bliver ikke lige det næste jeg laver.

Op ad bakke

Jeg er tilbage efter ferie. Eller, jeg kom faktisk tilbage sidste uge.

Jeg havde besluttet mig for at når jeg kom tilbage efter påsken ville jeg have taget stilling til hvordan jeg skulle fortsætte projektet. Det havde jeg sådan set osse: jeg tænkte, jeg kan ikke stoppe her jeg bliver nødt til som et minimum at blive færdig med iPhone udgaven. Derfor er jeg gået i gang med designe brugergrænsefladen til iOS, hvilket har været meget sjovt at komme i gang med. Jeg har allerede det basale system til at virke der og at se hvordan det kommer til at se ud osse begynder det at ligne noget der kan blive til noget. Her er bogmærker skærmen sammenholdt med mit design til Android.

Det var det ene positive indslag. Derudover har de sidste uger primært været surt show. Advarsel: resten af dette opslag er bare mig der klager min nød. Det reflekterer hvor jeg er henne hvilket er det denne dagbog er til for men jeg ved ikke om jeg vil anbefale nogen, inklusiv mig selv senere, at læse det.

Mens vi var på ferie fjernede google android app'en fra play store igen. Af samme grund som sidste gang: at jeg gemmer folks data uden at have en datapolitik, og så i øvrigt ikke flere detaljer. Sidste gang var det en fejl jeg kunne rette men hvad skulle jeg gøre denne gang – jeg havde allerede after min bedste overbevisning løst problemet første gang. Det ødelagde lidt en dag af ferien. I sidste ende viste det sig at jeg har en alpha udgave af app'en som ingen bruger, bogstaveligt talt det er umuligt for brugere at installere den. Derfor har jeg ikke opdateret den siden før app'en blev fjernet sidste gang. Jeg opdaterede den og det løste åbenbart problemet, app'en er tilbage.

Det virkelig deprimerende er at A til B nu er blevet fjernet to gange. Den første gang kan man godt sige var reel men denne gang var komplet meningsløs. Googles politik er at hvis jeg får fjernet en app nok gange, jeg er i tvivl om hvor mange, bliver jeg selv fjernet som udvikler. Så kan jeg aldrig udgive en app på google play igen og endnu værre: firmaer jeg arbejder for er i risiko for at blive "smittet" med min blokering. Så hver gang det sker er det ikke bare for sjov, det kan have virkelig langtrækkende konsekvenser for mig.

Okay. Så da jeg kom tilbage fra ferie tænkte jeg, jeg opdaterer lige køreplanerne. Da jeg testede de nye køreplaner viste det sig at nu viser app'en pludselig ikke tog fra Aarhus til København før til juli. Det er ikke fordi togene ikke går men i de data jeg får fra rejseplanen er rejsen pludselig knækket over i to: Aarhus til Odense og så Odense til København. Man kan osse se det på rejseplanen selv.
Teknisk set skal man "skifte" tog i Odense – men det er ikke passageren der skifter, det er toget der skifter navn. Det giver ikke meget mening for mig, eller passagerer forestiller jeg mig, men det må give mening for rejseplanen på en eller anden måde. Essensen er at fordi A til B kun viser direkte forbindelser og der er et "skift" mellem Aarhus og København indtil juli er A til B ubrugelig i forhold til tog over Fyn fra nu og indtil juli. Super.

Okay. Så tænkte jeg, jeg kaster mig over noget rent teknisk det kan da ikke gå galt. Google sendte en mail for nogle måneder siden om at de har lavet nogle ændringer til hvordan apps bruger google maps. Specifikt den funktion jeg bruger til at vælge til/fra på et kort. Jeg tænkte jeg kunne få fixet det. Da jeg så dykkede ned i det viste det sige at "ændringen" består i at de bare fjerner den funktion helt. De har nogle nye funktioner man kan bruge til selv at bygge noget tilsvarende men her er hagen: hvis man bruger de nye funktioner koster det hver gang, hvilket det ikke gjorde før. Så ja jeg kan godt bruge tid på at bygge noget der virker som det gør i dag, selv om det er træls i sig selv, men så hver gang en bruger vælger et sted på google maps skal jeg betale google. Jeg ved stadig ikke hvad jeg gør i forhold til det.

Jeg kæmper i forvejen med motivationen til at fortsætte projektet så sådan tre tilbageslag i rap, de to sidste på samme dag, er ikke nogen hjælp. Jeg gav lidt op hen imod slutningen af sidste uge og jeg har svært ved at svinge mig op til at gå videre med iPhone udgaven.