Varför gör vi detta mot oss själva?


För några veckor sedan upptäckte vi att vissa datum på vår webbsida var felaktiga. Istället för att visa det riktiga datumet för en kursleverans så visade vissa sidor alltid dagens datum istället.

Om det här bara hade varit ett godtyckligt datum på sidan så hade det inte varit någon fara. Men det här var leveransdatumet för kursen, det som satt just under den stora fina "BOKA"-knappen. Det vill säga, precis det datumet en prospektiv kund skulle dubbelkolla just innan de bokade. Ajdå.

(Jag vet att, allt annat lika, så är det förmodligen en bra idé att låtsas att vi på Edument är någon sorts övermänskliga utvecklare som aldrig introducerar buggar i vår egen kod. Men så är det inte, hur mycket jag än må önska det. Vi begår misstag. Jag upplever också att det finns gott om framgångshistorier därute som förvärrar survivorship bias inom vår industri. Jag hoppas att läsaren uppskattar en berättelse om ett (litet) fel, dess orsaker, och hur vi alla kan lära oss från misstag som detta. En bra sak med att jobba på Edument är att jag kan vara nästan helt säker på att advokater inte kommer och knackar mig på axeln, och ber mig plocka ned den här artikeln för att den kan presentera oss i dålig dager.)

Tillbaka till buggen. Jag hörde med ett halvt öra när Cecilia (produktägare för webbsidan) pratade med den femte-eller-så besökaren den dagen som hade upptäckt att datumen var fel. Jag blev nyfiken så jag kollade upp stället i koden som var ansvarigt för att spotta ut felaktiga datum. Jag hamnade på den här raden kod:


<Date date={date.date} />

Date är en React-komponent som vi skrev själva för webbsidan. Inuti Date -komponenten delegerar koden klokt nog jobbet med datumformatering till moment() , en funktion i tredjepartsbiblioteket momentjs.

Min allra första tanke, när jag tittade på den här raden kod, var "jag slår vad om att date.date blir undefined på något sätt".

Funktionen moment() förväntar sig en sträng med ett datum, men om den inte får en sådan, så kommer den att falla tillbaka på "nu", det aktuella undflyende ögonblicket av datum och tid. Att skicka in undefined som ett värde i JavaScript är moraliskt likvärdigt med att inte skicka någonting alls. (Situationen genljuder av Tony Hoares miljarddollarmisstag.)

Om buggjakten hade varit en brottsutredning och om jag hade letat efter medel, motiv, och möjlighet, så skulle jag just ha hittat medlet. Definitivt inte första gången i mjukvaruhistorien som mordvapnet visar sig vara värdet undefined .

När jag tittade närmare på kontexten runt den kodraden, så såg det mycket riktigt ut som att date var en sträng redan, och därmed skulle date.date bli ett misslyckat uppslag (eftersom strängar inte har en date -property), och skulle resultera i undefined .

Vi kunde raskt peta upp en fix som ändrade date.date till date . Problemet var löst.

Men jag fortsatte att fundera på vad i vår process som hade släppt igenom det här misstaget. Vi kodgranskar alla våra ändringar på webbsidan. I det här fallet hade tre personer, jag själv inkluderad, tittat på koden innan merge. Minst en person hade till och med kört PR-branchen och testat den, och förmodligen tittat rakt på det felaktiga datumet. Det såg ut som ett datum, så inga larmsignaler ljöd.

Det finns en annan fil i projektet med exakt samma kodrad. Förmodligen hade den felaktiga raden blivit kopierad från den filen. Men i den kontexten hämtades date -variabeln från en större datastruktur, och bara råkade vara ett objekt med en date -property. Samma rad var korrekt i den ursprungliga filen, men felaktig där den klistrades in.

Och det var här som saker gick fel, och ett brott begicks.

Människor gör ju fel ibland. Jag kan inte ens skylla på själva klippandet och klistrandet, eftersom det var en vettig, praktisk sak att göra i det här fallet att bara gå och hämta ett existerande bruk av Date -komponenten, klistra in den, och vänta sig att den funkade på det nya stället. Den felaktiga förväntan var att variabeln date i den nya miljön betydde samma sak, vilket den inte gjorde...

...men vid den punkten gjorde vår utvecklingsmiljö ingenting för att påpeka detta.

I en tidigare bloggartikel "Tandborstning och statiska kontroller" ställde jag den retoriska frågan "Varför gör vi detta mot oss själva?". Varför slänger vi bort all kontextuell information, alla små bitar kunskap om formen på data som vi skickar runt mellan olika delar av programmet, bitarna som skulle hjälpa oss mest att undvika inkonsekvent beteende inom programmet som det vi fick den här gången?

Jag ville skriva den här artikeln för att jag kände att date.date -incidenten är ett bra konkret exempel på någonting som hade kunnat fångas genom att behålla mer typinformation. Mer specifikt, följande hade räckt för att rädda oss i det här fallet:

  • Använd TypeScript.

  • Typ-annotera våra parametrar. Parametern date skulle ha typsatts som string.

Detta skulle ha räckt för att ge oss röda understrykningar under date.date , och buggen hade aldrig gått ut i produktion. "Property date does not exist on type string ", hävdar TypeScripts typkontroll. Den har rätt!

TypeScript underlättar utvecklingen på exakt det här sättet, och stöttar up en med hundra små detaljer varje dag. Det är både en essentiell hjälp, och en påminnelse som gör en ödmjuk inför hur begränsade vi är när vi utvecklar, alltid ett steg från kanten av en ravin. JavaScript, däremot, är som en vän som först uppmanar en att klättra upp för berget utan någonsäkerhetsutrustning, och sedan bara ler gåtfullt när man ofelbart trillar över kanten. Det är häpnadsväckande att vi kan få någonting gjort i JavaScript.

Det finns en risk att hela den här artikeln ger intrycket av att vara dogmatisk och ensidig. Jag inser förstås att valet mellan JavaScript och TypeScript inte alltid är så svart-på-vitt, och det finns många faktorer inblandade. Dessutom, sedan många decennier, har jag betraktat mig som att jag är i det "dynamiska" lägret mer än i det "statiska" lägret... vilket gör mig förvånad när jag märker att TypeScript med dess statiska kontroller verkar funka för mig. Det lyfter min kodkvalité utan att begränsa hur jag använder JavaScript, och utan att få mig att klättra på väggarna med drakoniska typsystemsregler. Ett dynamiskt språk med statiska kontroller — den bästa av två världar.

Så, kommer vi att lyfta över vår webbsida till att använda TypeScript? Ja... så småningom. Med begränsade resurser finns det fortfarande mer brinnande saker att adressera. Men det finns med på vår lista av förbättringar att göra.


Av Carl Mäsak



0 kommentarer