Steven
Steven7 min läsning

Vad en version 2 faktiskt kräver: 206 commits av ärliga tillstånd

GeekBye v2 var ingen funktionsrelease. Det var 206 commits inriktade på en enda idé: appen ska aldrig ljuga om sitt eget tillstånd. Här är vad det kostar — inklusive misstaget på en rad i låsfilen som nästan hindrade oss från att skeppa något av det.

Tillförlitlighet
Utveckling
Release
GeekBye-releaser
Vad en version 2 faktiskt kräver: 206 commits av ärliga tillstånd

De flesta "version 2"-releaser är en hög nya funktioner med ett större nummer på. GeekBye v2 var motsatsen. Den skeppade nästan ingen ny funktion som användarna ser. Dess 206 commits var inriktade på en enda, oglamorös idé:

Appen ska aldrig visa dig ett tillstånd som inte är sant.

Det låter självklart tills du räknar hur många sätt en skrivbordsapp tyst ljuger på. Den visar en bock på en uppladdning som fortfarande är på väg. Den säger "ansluten" över en socket som dog för en minut sedan. Den håller tyst medan ditt transkript släpps på golvet. Inget av detta är krascher. De är värre än krascher, för appen ser bra ut medan den har fel — och du får reda på det först senare, när inspelningen du behövde inte finns där.

v2 var releasen där vi gick på jakt efter varenda en av dessa små lögner.

Lögnen vi hatade mest: uppladdningen som "fungerade"

GeekBye kan säkerhetskopiera dina inspelningar till Google Drive. I v1 behandlades anslutningen till Drive som en bakgrundsdetalj — om den fungerade, bra; om den inte gjorde det var felet mestadels osynligt. Appen fortsatte att se ansluten ut. Du antog att dina inspelningar var säkra. Ibland var de inte det.

v2 byggde om detta kring ärliga anslutningstillstånd. Drive är nu alltid i ett av några få uttryckliga, sanningsenliga tillstånd — ansluten, återansluter, frånkopplad — och appen sänder ut varje ändring av det tillståndet till hela gränssnittet i samma ögonblick det händer. När anslutningen är nere talar en global återanslutningsbanner om det för dig, överallt, tydligt. Appen låtsas inte längre att en uppladdning lyckades när den inte gjorde det. Om din säkerhetskopiering inte kan ske just nu vet du det just nu — inte nästa vecka när du går och letar efter filen.

Under ytan är detta en liten arkitektur, inte en slogan: en enda sanningskälla för anslutningen, en händelse som breder ut sig till varje del av gränssnittet när den ändras, och en banner som läser direkt från det tillståndet. Det finns ingen väg där anslutningen är nere och gränssnittet ser uppe ut, eftersom de läser från samma faktum.

Lögnen om den förlorade inspelningen

Den andra stora ärlighetsfixen var inspelningsåterhämtning. Realtidstranskribering behöver en levande anslutning. I v1, om den anslutningen hackade mitt i en session — en Wi-Fi-blipp, en tunnel, en VPN-återanslutning — kunde ljudet under avbrottet helt enkelt vara borta. Transkriptet skulle ha ett hål i sig, och inget berättade det för dig.

v2 ändrade kontraktet: ljud bevaras lokalt under ett anslutningsavbrott och avstäms efteråt. När länken bryts håller GeekBye ljudet säkert på din maskin; när den kommer tillbaka skickas det buffrade ljudet och sys in i transkriptet på rätt plats. Trettio dåliga sekunder av nätverk kostar dig inte längre trettio sekunder av mötet. Detta är grundarbetet som de senare tillförlitlighetsreleaserna byggde direkt på — maskineriet för återanslutning-och-buffring i varför ditt AI-anteckningsverktyg stannar på dålig Wi-Fi är samma idé, härdad.

Lögnen om popup-stormen

Det finns en mer subtil oärlighet i hur appar rapporterar problem: de överrapporterar det. Ett ostabilt nätverksögonblick kan avfyra samma fel fem gånger, och plötsligt har du en hög identiska röda aviseringar som begraver det enda meddelande som betyder något. Det är inte heller ärligt — det är brus som låtsas vara information.

Så v2 lade till kategorinyckad strypning av aviseringar och feldirigering. Fel grupperas efter vad de faktiskt är, och varje kategori hastighetsbegränsas så att ett enda underliggande problem ger ett tydligt meddelande, inte en skur. Ett hastighetsbegränsningsproblem dirigeras till ett hastighetsbegränsningsmeddelande; ett anslutningsproblem dirigeras till ett anslutningsmeddelande. Appen berättar för dig vad som är sant, en gång — samma disciplin som senare hindrade en 429 från att utge sig för att vara en utloggning i dagen vår app DDoS:ade sig själv.

Siffran 206 är poängen

Ärliga tillstånd, återanslutningsbanner, inspelningsåterhämtning, feldirigering av aviseringar — det är fyra idéer. Releasen var 206 commits. Vart tog resten vägen?

In i den oglamorösa långa svansen som "visa aldrig ett falskt tillstånd" faktiskt kräver. Varje ställe där det gamla gränssnittet kunde hamna ur synk med verkligheten måste hittas och kopplas om till att läsa från sanningen istället för en föråldrad kopia. Varje återanslutningsväg måste fås att uppdatera det delade tillståndet istället för att gissa lokalt. Dussintals små tillförlitlighetsfixar över inspelning, transkribering och uppladdningar — var och en stänger en specifik lucka där appen kunde se rätt ut medan den hade fel.

Det här är vad en riktig "version 2" kostar när målet är förtroende istället för funktioner. Det finns ingen enskild rubrik-commit. Det finns 206 små, och releasen känns bara som en enda sak — lugn — eftersom alla 206 drar åt samma håll.

Releasen skeppades nästan inte

Här är krigshistorien, och det är en bra sådan, för den handlar om att vår egen app ljög för oss.

När du klipper en release stämplar ett versionshöjningsskript det nya numret över hela projektet. På v2.0.0 uppdaterade det appens version — men package-lock.json, npm:s exakta beroenderegister, lämnades pekande på den gamla versionen, 1.9.0. Lokalt var allt bra; ingen installerar om beroenden bara för att bygga. Men CI kör npm ci, och hela npm ci:s uppgift är att vägra fortsätta om låsfilen inte stämmer med manifestet. Det är en strikthetsfunktion — och den gjorde exakt vad den skulle, genom att fälla bygget för den största releasen vi någonsin klippt.

Sedan dök en andra, listigare upp under den. En nyare npm hade rensat bort ett valfritt transitivt beroendeencoding-paketet som node-fetch drar in — ur låsfilen som onödigt. Förutom att vår CI:s rena installation faktiskt behövde det, så installationen bröts på ett sätt som inte hade något att göra med vår kod och allt att göra med att registret var subtilt fel.

Båda var fixar på en rad: synka om låsfilen till den verkliga versionen, återställ den bortrensade posten. Båda är också perfekta, ödmjukande exempel på precis det v2 handlade om — ett tillstånd som påstod sig vara sant men inte var det. Låsfilen är tänkt att vara det ärliga registret över vad appen är beroende av. När den drev ifrån verkligheten gjorde bygget precis vad vår app nu gör för användarna: det vägrade låtsas att allt var bra. Att skeppa en tillförlitlighetsrelease visar sig vara ett tillförlitlighetsproblem hela vägen ner.

Tre saker v2 lärde oss

  1. De farliga felen är de tysta. En krasch tillkännager sig själv. Ett falskt "ansluten", en fantomframgångsrik uppladdning, ett transkript med ett osynligt hål — de kostar dig förtroende just för att inget ser fel ut. Jaga de tysta lögnerna.
  2. Ärlighet är en arkitektur, inte ett meddelande. Du kan inte skruva på "säg sanningen" på ett gränssnitt som en banner. Bannern måste läsa från samma enda sanningskälla som allt annat, annars blir den ännu en sak som kan ha fel. Ett faktum, utbrett — aldrig två kopior som kan vara oense.
  3. En version 2 värd numret är mestadels osynlig. Om din v2 är en funktionslista är det en v1.5 med marknadsföring. En riktig v2 är 206 commits ingen kan peka på individuellt, som summerar till en produkt som helt enkelt slutar ljuga för dig.

GeekBye v2.0.0 är grunden varje release sedan dess har byggt på. För vad den grunden bär, se varför ditt AI-anteckningsverktyg stannar på dålig Wi-Fi, dagen vår app DDoS:ade sig själv (v2.0.1) och livetranskribering när brandväggen blockerar WebSockets (v2.0.8). För det lugn det allt var i tjänst av, vad som är nytt i GeekBye v2.