"Radbryt höll på att sluta med psykbryt"

Säg konnichiwa till Sven Jonsson, en av Once Upons apputvecklare. Från fjärde våningen i Kichijoji i Tokyo, ja han bor och jobbar där, skriver han om vår sprillans nya layoutmotor. Denna stora tekniska förändring som möjliggör massor av roliga lösningar framöver.  Men motorarbetet har inte bara rullat autostrada och här berättar han nu för första gången om ett av de största hindren; ett ynka radbryt. Det gick så långt att Sven höll på skapa ett monster för att få bukt med problemet.  Är du förresten själv utvecklare? I så fall löser du kanske produkt-teamets huvudbry redan efter halva texten.

Det är i början av 2021 och ett långt utvecklingsprojekt börjar äntligen gå mot sitt slut. Hela hösten har vi jobbat med den största tekniska förändringen hittills, en layoutmotor som gör det möjligt för användare att producera böcker snabbt och smidigt på våra servrar, samtidigt som vi genom en fiffig lösning kan visa exakt hur boken kommer att se ut i vår app. Vi definierar våra layouter i html och sedan använder vi ett bibliotek i appen som översätter html till vyer i React Native. Allt känns bra, implementationen är enkel och appen blixtsnabb. Vi köper en tårta* som vi ställer i kylen och våra händer värker av alla självgoda high-fives vi gjort med varandra (efter att vi spritat våra händer förstås).

Men så upptäcker vi problemet. När testböckerna trycks märker vi att ibland stämmer inte radbrytningarna överens mellan tryck och appen. Förstås enormt frustrerande! Det här borde upptäckts tidigare. Men ingen fara på taket, med lite css-magi så är det strax löst. En av våra utvecklare tar på sig rollen att undersöka. Vi sneglar med längtande blick mot tårtan och fortsätter sy ihop appen inför lansering.

Bara någon dag senare kommer utvecklaren tillbaka och säger med försiktig röst att hen tror att det nog inte finns någon enkel lösning på det här, men att om någon annan vill försöka så kanske? Sturska räcker vi en efter en upp handen och med lansarna högt hållna är det upp till kamp mot draken. Men ingenting fungerar. Draken är en väderkvarn och att ändra css:en tar sig bara formen av en avancerad whack-a-mole.

Järnspikar. Vad ska vi göra? En möjlighet är att lansera ändå och försöka fixa felet efteråt men vi inser ganska snabbt att vi inte vet om problemet alls går att lösa med nuvarande teknologi. Vi vet helt enkelt inte hur stora förändringar som måste göras. Den parallella utvecklingen av ny funktionalitet i appen är på tekniskt väldigt tunn is. Vi flyttar tårtan från kylen till frysen och flaggar för att releasen blir försenad.

Utvecklarna samlas nu kring runda bordet för att spåna fram möjliga lösningar. Någon kommer med en kreativ idé, att vi helt enkelt lägger in texten rad för rad och låter de små förändringarna som är mellan plattformarna sväljas upp av lite bredare rader. Lite olika mellanrum mellan ord känns som en helt okej kompromiss. Alla håller med om att det kan fungera men för att det ska gå så måste vi veta hur lång en rad ska vara och denna radlängd måste vara samma mellan alla plattformar. Vi hittar ett bibliotek som gör det åt oss, men måste köra det genom en webbvy eftersom att det använder sig av en html canvas för att mäta texten.

Stopp! Hade vi pausat här och tänkt ytterligare ett varv så hade det antagligen besparat oss en dryg månad av utvecklingstid. Har du förresten redan nu en idé av vad vi borde gjort istället? Jag kan lite snabbt meddela att vi ständigt söker nya utvecklare så ansök och hjälp oss att undvika den här typen av misstag igen**.

Läs mer: Är du den vi söker? Läs mer om våra utvecklartjänster här.

En sprint senare och vi har en prototyp som fungerar både på server och i appen. Vi gör tester på olika telefoner för att se om det verkligen är så att biblioteket för textmätning fungerar på alla plattformar. Resultaten är väldigt lovande. I förbifarten nämner någon tårtan i frysen. En annan modig utvecklare ställer den på nytt i kylen för långsam upptining.

Men så börjar vi testa på fler språk, och språk som innehåller olika alfabet. Vi inser då att ett problem är att typsnittet vi använder inte stödjer flera teckenuppsättningar som används i Europa som t.ex. grekiska och kyrilliska. Det är något som varit dolt i appen tidigare. Eftersom boken skapats på användarens telefon används helt enkelt de reservtypsnitt som finns, men då telefoner har olika reservtypsnitt och servern andra betyder det att böckerna kan se ut på ett sätt i appen och på ett annat när de kommer hem i brevlådan.

Jämmer och elände. Ännu en sak vi kunde insett tidigare. Men eftersom vi ännu inte uttryckligt stödjer dessa språk i appen så har det inte testats fullt ut.

Som sagt använder vi i det här läget en modul som översätter våra layouter från html till React Native vyer och det enda sättet att byta teckensnitt är att nästla textfält i varandra. I den webbvy som används för mätning av textlängd är det inga problem. Vi använder bara fallback fonts i css. Ledtråd nummer två om en annan enklare lösning än den vi strax ska bege oss in på.

Tårtan åker in i frysen ännu en gång och jag tar på mig uppgiften. Så hur ska jag veta vilket språk som används? Jo, jag måste läsa av varenda tecken som användaren skriver in och översätta det till unicode och samtidigt ta ut unicodetecken från de typsnitt som vi har och helt enkelt byta typsnitt beroende på tecken. Det blir förstås lite mer problematiskt genom att det finns överlappning mellan dem. Vårt huvudtypsnitt innehåller en del grekiska tecken som måste raderas från det enorma uppslag av unicodes som jag tagit ut från fontfilerna. Nästan lite osannolikt så fungerar allt faktiskt, men någonstans vet jag att jag skapat ett monster som kommer att slå tillbaka och bita oss när vi minst anar.

Läs mer: Intresserad av vår tech stack? Ett litet klick här är allt som krävs!

Jodå, Herkules-vansinne-evigt-mörker, så kommer nya problem. På längre texter så är appen superseg. Vi har använt textfält även i scrollen och på böcker med mycket text så blir det helt ohanterligt med nästlade textfält. Jag bestämmer mig där och då för att ta skärmskott på layouterna som vi skapar och använda bilder istället för textfält. Detta är dock lättare sagt än gjort. Dessa bilder måste uppdateras vid rätt tillfälle och fungera i böcker där flera användare samarbetar. Vi testar och buggfixar, testar och buggfixar. Vi är redan i slutet av april och alla vill bara få det klart. Dagliga checkins avbryts ibland av små cyniska skratt och vi har alla fått den där tusenmila-blicken du kan få om du sett något vackert gå sönder. Vår lösning hade en gång i tiden varit så enkel.

Det är då vi inser något fundamentalt (något du kanske redan insett?). Hur kommer det sig att vi kan mäta texten korrekt i en webbvy? Vi har tänkt att det är något speciellt med biblioteket och dess canvas-lösning, men är det sant? Vi testar att rendera text i en webbvy på alla plattformar och upptäcker att så länge den är exakt lika stor i pixlar så renderas texten exakt lika. Det går ju naturligtvis inte rendera flera webbvyer samtidigt och den måste vara exakt lika stor på alla plattformar. Men om vi renderar den utanför bild, tar ett skärmskott på webbvyn:n så hey presto har vi en lösning där vi klarar oss utan monstret ovan. Vi andas ut, ingen av oss hade känt en riktigt stark tilltro till vår lösning på flera veckor.

Ärligt talat är jag dock fortfarande lite stolt över monstret jag var med och skapade. Kanske har du någon gång gjort ett litet oskyldigt brott du kom undan med, t.ex. snattat på ICA när du var liten. Då vet du vad jag menar. Det finns skam men också inte sällan en stolthet, kanske över att du vågade. Jag är bara glad att det aldrig gick ut i drift, men om du ber riktigt snällt så kanske jag tar dig med till tiden på GitHub och visa det sovande monstret.

Så där är vi nu. Lösningen ligger ute i drift. Tårtan är uppäten. Men vi är inte nöjda än. Appen har blivit seg när förhandsgranskningar skapas och en del användare har haft problem vid uppdatering och inlogg. Vi jobbar just nu på att förbättra vår nuvarande lösning och utforskar också bättre sätt att göra det på (bland annat Skia). Som jag skrev tidigare så behöver vi fler hjärnor till vårt team, inte bara för att lösa problem av det här slaget utan även för att jobba fram nya lösningar. Exakt vad får vi hitta på tillsammans.

*The cake is a lie

** Nåja, för att göra oss lite rättvisa så fanns det i själva verket funktionalitet som vi ville ha som gjorde att vi bortsåg från att utforska alla vägar, men eftersom vi i slutändan ändå tvingades att skippa den funktionaliteten så hade det varit bättre att göra det förr snarare än senare.

Sven Jonsson, apputvecklaresven.jonsson@onceupon.se