Steven
Steven6 min leestijd

Kalme software: een flikkerende schakelaar killen en chat leren zeggen in welke modus hij staat

Twee kleine GeekBye-releases, geen opvallende features — alleen een instellingenschakelaar die stopte met flikkeren en een chatassistent die eindelijk vertelt of hij in meetingmodus of coderingsmodus antwoordde. Dit is wat "kalme software" werkelijk kost, één detail per keer.

Product
Design
Engineering
GeekBye Releases
Kalme software: een flikkerende schakelaar killen en chat leren zeggen in welke modus hij staat

Niet elke release is een oorlogsverhaal. Sommige zijn gewoon een lijst van kleine, bijna onzichtbare dingen die stilletjes fout waren — het soort dingen dat niets laat crashen, maar een app net iets onbetrouwbaar, net iets schokkerig, net iets niet-van-jou doet aanvoelen. GeekBye v2.0.3 en v2.0.5 waren twee van die. Geen nieuwe features. Alleen rust.

"Kalme software" klinkt als een stemming. Het is eigenlijk een stapel specifieke beslissingen. Hier zijn er drie.

Een schakelaar die niet kon kiezen

Er was een instellingenschakelaar — die het audioherstel regelt — die flikkerde als je erop klikte. Tik hem aan, en voor een fractie van een seconde toonde hij aan, sprong dan terug naar uit, en kwam dan tot rust. Een minieme visuele hapering, maar je oog vangt hem op, en het leest als de app weet niet zeker wat hij aan het doen is.

De oorzaak is een klassieke UI-race die een optimistische update heet. Als je op een schakelaar klikt, heeft de app twee keuzes: wachten tot de instelling daadwerkelijk is opgeslagen en dan de schakelaar bijwerken (correct, maar voelt traag), of de schakelaar meteen omzetten en op de achtergrond opslaan (voelt direct). GeekBye deed het tweede — meteen omzetten — maar hij herlas ook de opgeslagen waarde toen die terugkwam. Dus de volgorde was: je klikt, de schakelaar springt optimistisch aan, de echte opgeslagen waarde arriveert een tel later, en voor één frame waren de twee het oneens en stuiterde de schakelaar zichtbaar.

De oplossing is om de optimistische waarde en de bevestigde waarde netjes te laten overeenkomen — de schakelaar committeert zich aan de toestand die jij koos en gaat zichzelf niet meer in twijfel trekken als de opslag bevestigt. Daarnaast deed v2.0.3 een weinig glamoureuze tekstronde: de beschrijving van audioherstel werd ingekort om aan te sluiten bij de rijen ernaast, en de bewoording van de instellingen werd menselijker gemaakt. Niets hiervan is een feature. Alles ervan is het verschil tussen een instellingenpaneel dat in elkaar gezet aanvoelt en een dat aanvoelt alsof er aan is gepiekerd.

Een tour die niet wegging

Nieuwe-gebruikerstours zijn precies één keer nuttig. Het probleem is die één-keer-heid: nadat je hem hebt gezien, wordt een onboardingoverlay die je niet kunt wegklikken rommel die signaleert deze app denkt dat je nog nieuw bent. v2.0.3 loste beide kanten daarvan op — de producttour kan nu verborgen worden, en als je hem echt terug wilt, is er een Tour opnieuw afspelen-knop. Toon hem wanneer hij helpt, ga uit de weg wanneer dat niet zo is, en laat de gebruiker hem op zijn eigen voorwaarden oproepen. Respecteren dat de gebruiker niet meer nieuw is, is zijn eigen kleine vorm van rust.

De assistent die niet wilde zeggen hoe hij dacht

Dit is degene die er echt toe deed, en hij hangt samen met een dieper probleem dat we al aan het najagen waren.

De assistent van GeekBye antwoordt anders afhankelijk van de context. In een meeting zou "wat vind jij hiervan?" een gemoedelijk, meetingbewust antwoord moeten krijgen. In een codeersessie zouden dezelfde woorden een technisch antwoord moeten krijgen. Dus de backend haalt de vraag door het juiste kader — noem het meetingmodus of coderingsmodus — en dat kader verandert werkelijk het antwoord dat je krijgt.

Het probleem: de app vertelde je nooit welke modus antwoordde. Dus als de assistent je een code-getint antwoord gaf op een gemoedelijke vraag — of een codevraag beantwoordde alsof je aan het kletsen was — leek het alsof de AI gewoon fout was. Hij was niet fout; hij stond in de andere modus, en jij had geen manier om dat te zien. Een verborgen toestand deed correct gedrag kapot lijken. (De moduslogica zelf is een groter stuk werk — de orchestrator die beslist hoe niet-code-vragen tijdens een codeersessie beantwoord moeten worden — maar dat alles heeft geen nut voor je als je de beslissing die hij nam niet kunt zien.)

v2.0.5 voegde een alleen-lezen modus-chip toe aan de chat: een klein label dat toont of de assistent in meetingmodus of coderingsmodus antwoordde. Alleen-lezen is het hele punt — het is geen bediening die je instelt, het is een venster op een beslissing die het systeem al heeft gemaakt. Je stopt met gissen waarom een antwoord vreemd voelt; je kunt het kader zien waaruit het kwam.

Het detail dat de chip eerlijk maakt

Hier is de engineeringkeuze die het waard is om door te geven, want het is het soort ding dat een erop geschroefde indicator scheidt van een betrouwbare.

De modusinformatie komt van de backend als deel van de gestreamde respons — een klein mode-frame in de server-sent event stream. Maar een oudere client die van vóór deze feature dateert, zou niet weten wat een mode-frame is; in het beste geval negeert hij het, in het slechtste geval rendert hij iets vervormds. Dus de client kondigt zijn capaciteit aan: hij stuurt een request-header die zegt ik weet hoe ik een modus-chip moet tonen, en de backend zendt het mode-frame alleen uit naar clients die het hebben gestuurd. Oude clients ontvangen nooit een signaal dat ze niet aankunnen; nieuwe clients krijgen precies het frame waar ze om vroegen.

Het is een één-header-handshake, en het is het verschil tussen "we hebben een feature toegevoegd" en "we hebben een feature toegevoegd zonder iemand te breken die nog niet heeft geüpdatet." Dezelfde reviewronde scherpte de rest van het gedrag aan: de chip wist zichzelf bij een reset en wanneer de gesprekscontext verandert (een verouderd moduslabel is zijn eigen kleine leugen), en hij verschijnt alleen in de chatweergave waar hij thuishoort.

Wat twee "geen-feature"-releases ons leerden

  1. Hapering is een vertrouwenssignaal. Een flikkerende schakelaar, een stuiterende switch, een label dat een frame te lang blijft hangen — geen ervan zijn bugs in de crash-zin, maar elk ervan fluistert deze app heeft het niet helemaal onder controle. Rust is de afwezigheid van die gefluister, en je verdient het één race condition per keer.
  2. Een verborgen modus doet correct gedrag op een bug lijken. De assistent deed het juiste en kreeg de schuld ervoor, puur omdat de gebruiker het kader niet kon zien. Wanneer je systeem een onzichtbare beslissing neemt die de output verandert, toon de beslissing — een alleen-lezen chip is vaak de hele oplossing.
  3. Nieuwe features horen onzichtbaar te zijn voor clients die ze niet kunnen gebruiken. De capability-header-handshake betekent dat het modussignaal alleen clients bereikt die het kunnen renderen. Achterwaartse compatibiliteit is geen versiecheck die er later op wordt geschroefd; het is een client die zegt wat hij begrijpt en een server die het antwoord respecteert.

Dit zijn de releases waar niemand changelog-koppen over schrijft, en ze zijn een groot deel van waarom GeekBye v2 aanvoelt zoals het aanvoelt. Voor de release waarop deze rust werd gebouwd, zie wat een versie 2 echt kost (v2.0.0). Voor het betrouwbaarheidswerk ernaast, de dag dat onze app zichzelf DDoSte (v2.0.1) en waarom je AI-notulist midden in een meeting stopt met opnemen (v2.0.9).