Vem räknar ut vem som vann?

I ett spel där man tävlar mot andra finns en fråga som avgör allt annat: vem räknar ut vem som vann?

Om svaret är ”spelarens webbläsare” har man inte byggt ett spel. Man har byggt ett formulär där deltagarna fyller i sina egna resultat.

Klienten är en fiende som råkar vara trevlig

Det låter dramatiskt, men det är den enda hållbara utgångspunkten. Allt som körs i användarens webbläsare kan läsas, ändras och ersättas. Det är inte ett tecken på illvilja hos användaren — det är en egenskap hos plattformen.

I ett spel med ekonomi — där man köper, säljer och tävlar om pengar som betyder något för spelarna — blir det snabbt konkret. Räknas loppet i webbläsaren och resultatet skickas in, då är resultatet en önskan, inte ett utfall.

Så motorn flyttades till servern. Klienten skickar vad spelaren gör; servern räknar vad som händer och skickar tillbaka tillståndet över en öppen förbindelse. Klienten ritar. Ingenting mer.

Det gör klienten dummare och hela systemet ärligare.

Buggarna som avslöjade var sanningen bodde

Under samma arbetspass fixade jag ett par fel som vid första anblick såg orelaterade ut, men som visade sig ha samma rot.

Saldot uppdaterades inte efter en reparation. Pengarna drogs på servern, men vyn visade ett gammalt värde — för den läste från något som bara fylldes vid inloggning. Det är samma sorts fel som identitetsförväxlingar och avdrift i konfiguration: två ställen som påstår sig veta samma sak, och bara det ena har rätt.

Fixen var inte att uppdatera kopian oftare. Den var att sluta ha en kopia — vyn frågar servern, och frågan ställs om efter varje händelse som kan ha ändrat svaret.

Och två klassiska: klienten anropade en adress som inte fanns på servern, och läste ett fält som hette något annat i svaret. Båda är triviala, båda kostar en kväll, och båda hade fångats av ett test som kör på riktigt i stället för mot en påhittad server.

Sjuttiofyra tester som klickar

Därför blev nästa steg en testsvit som startar en riktig webbläsare, loggar in, klickar sig igenom spelet och kontrollerar vad som faktiskt står på skärmen.

Enhetstester hade inte hittat något av det ovan. Varje del fungerade utmärkt för sig. Felen satt i skarvarna — mellan klient och server, mellan namn i ett svar och namn i koden som läser det. Skarvar syns bara när man går hela vägen.

Sådana tester är långsammare och krångligare än enhetstester, och de betalar tillbaka första gången någon ändrar ett fältnamn på serversidan.

Vad jag tar med mig

Bestäm var sanningen bor, en gång, och håll fast vid det. Det är samma princip som gäller för inventarium, för nätverkskonfiguration och för identitet. Ett spelresultat är inte annorlunda: någon räknar, alla andra visar.

Ett cachat värde är ett löfte om att hålla det uppdaterat. Det löftet bryts alltid, i något flöde man inte tänkt på. Fråga i stället.

Och en observation om att bygga spel med agenter: buggarna ovan är exakt de en modell producerar när den skriver klient och server var för sig. Den håller inte kontraktet mellan dem i huvudet — den gissar rimliga namn. Testerna som kör på riktigt är inte en lyx i det arbetssättet. De är det som gör det möjligt.

Skrivet av Daniel Azzarri · Om · Alla inlägg