
Какво всъщност изисква една Версия 2: 206 комита честни състояния
GeekBye v2 не беше издание с нови функции. Бяха 206 комита, насочени към една-единствена идея: приложението никога не бива да лъже за собственото си състояние. Ето колко струва това — включително еднолинейната грешка в lockfile, която за малко да ни попречи да пуснем каквото и да било от всичко това.
Повечето издания „версия 2" са купчина нови функции с по-голямо число върху тях. GeekBye v2 беше точно обратното. То не достави почти никаква нова видима за потребителя възможност. Неговите 206 комита бяха насочени към една-единствена, неефектна идея:
Приложението никога не бива да ти показва състояние, което не е вярно.
Звучи очевидно, докато не преброиш по колко начина едно десктоп приложение тихо лъже. Показва отметка върху качване, което още е в полет. Казва „свързано" върху сокет, който е умрял преди минута. Мълчи, докато транскрипцията ти се изхвърля на пода. Нито едно от тези неща не е сривване. Те са по-лоши от сривване, защото приложението изглежда наред, докато греши — и разбираш чак по-късно, когато записът, от който имаше нужда, го няма.
v2 беше изданието, в което тръгнахме на лов за всяка една от тези малки лъжи.
Лъжата, която мразехме най-много: качването, което „успя"
GeekBye може да прави резервно копие на записите ти в Google Drive. Във v1 връзката към Drive се третираше като детайл на заден план — ако работеше, чудесно; ако не, провалът беше най-вече невидим. Приложението продължаваше да изглежда свързано. Предполагаше, че записите ти са в безопасност. Понякога не бяха.
v2 преизгради това около честни състояния на връзката. Drive вече винаги е в едно от няколко явни, правдиви състояния — свързан, преповързва се, изключен — и приложението излъчва всяка промяна на това състояние към целия интерфейс в мига, в който тя се случи. Когато връзката е паднала, глобален банер за преповързване ти го казва, навсякъде, ясно. Приложението вече не се преструва, че качване е успяло, когато не е. Ако резервното ти копие не може да се случи точно сега, разбираш го точно сега — не следващата седмица, когато тръгнеш да търсиш файла.
Отдолу това е малка архитектура, а не лозунг: един източник на истина за връзката, събитие, което се разпръсква към всяка част от интерфейса при промяна, и банер, който чете директно от това състояние. Няма път, в който връзката да е паднала, а интерфейсът да изглежда вдигнат, защото и двете четат от един и същ факт.
Лъжата за изгубения запис
Вторият голям поправ на честността беше възстановяването на записите. Транскрипцията в реално време има нужда от жива връзка. Във v1, ако тази връзка засечеше по средата на сесия — трепване на Wi-Fi, тунел, преповързване на VPN — аудиото по време на прекъсването можеше просто да изчезне. Транскрипцията имаше дупка в себе си, и нищо не ти казваше.
v2 промени договора: аудиото се пази локално по време на прекъсване на връзката и се помирява след това. Когато връзката падне, GeekBye пази аудиото в безопасност на машината ти; когато тя се върне, това буферирано аудио се изпраща и се зашива в транскрипцията на правилното място. Лоши тридесет секунди мрежа вече не ти струват тридесет секунди от срещата. Това е основата, върху която по-късните издания за надеждност строяха директно — механиката на преповързване-и-буфериране в защо твоят AI notetaker спира при лошо Wi-Fi е същата идея, закалена.
Лъжата за бурята от изскачащи прозорци
Има по-фина нечестност в начина, по който приложенията докладват проблеми: те свръхдокладват. Един нестабилен мрежов момент може да задейства една и съща грешка пет пъти, и изведнъж имаш куп идентични червени toast-ове, погребващи единственото съобщение, което има значение. И това не е честно — това е шум, който се прави на информация.
Затова v2 добави тротлиране на toast-ове по категории и насочване на грешки. Грешките се групират по това какви са всъщност, и всяка категория е рейт-лимитирана, така че един-единствен базов проблем произвежда едно ясно съобщение, а не барабанен огън. Проблем с рейт-лимит се насочва към съобщение за рейт-лимит; проблем с връзката се насочва към съобщение за връзка. Приложението ти казва какво е вярно, веднъж — същата дисциплина, която по-късно попречи на един 429 да се маскира като изход от профила в деня, в който нашето приложение си направи само DDoS.
Числото 206 е самата идея
Честни състояния, банер за преповързване, възстановяване на записите, насочване на toast-ове — това са четири идеи. Изданието беше 206 комита. Къде отиде останалото?
В неефектната дълга опашка, която „никога не показвай фалшиво състояние" всъщност изисква. Всяко място, където старият интерфейс можеше да се разсинхронизира с реалността, трябваше да бъде намерено и пренастроено да чете от истината вместо от остаряло копие. Всеки път на преповързване трябваше да бъде накаран да обновява споделеното състояние, вместо да гадае локално. Десетки малки поправки за надеждност из записа, транскрипцията и качванията — всяка затваряща конкретна пролука, където приложението можеше да изглежда правилно, докато греши.
Ето колко струва една реална „версия 2", когато целта е доверие вместо функции. Няма един-единствен заглавен комит. Има 206 малки, и изданието само усеща се като едно нещо — спокойствие — защото и 206-те дърпат в една и съща посока.
Изданието за малко да не се случи
Ето военната история, и тя е добра, защото е за това как нашето собствено приложение излъга нас.
Когато режеш издание, скрипт за вдигане на версията подпечатва новото число из целия проект. При v2.0.0 той обнови версията на приложението — но package-lock.json, точният регистър на зависимостите на npm, беше оставен да сочи към старата версия, 1.9.0. Локално всичко беше наред; никой не преинсталира зависимости само за да компилира. Но CI изпълнява npm ci, а цялата работа на npm ci е да откаже да продължи, ако lockfile-ът не е съгласен с манифеста. Това е функция за строгост — и тя направи точно каквото трябва, като провали компилацията за най-голямото издание, което някога бяхме рязали.
После отдолу изплува втора, по-коварна. По-нов npm беше окастрил незадължителна преходна зависимост — пакета encoding, който node-fetch дърпа със себе си — от lockfile-а като ненужна. Само че чистата инсталация в нашия CI наистина имаше нужда от нея, така че инсталацията се счупи по начин, който нямаше нищо общо с нашия код и всичко общо с това, че регистърът беше едва доловимо грешен.
И двете бяха еднолинейни поправки: пресинхронизирай lockfile-а към реалната версия, възстанови окастрения запис. И двете са също така перфектни, смиряващи примери за точно това, за което ставаше дума във v2 — състояние, което твърдеше, че е вярно, а не беше. Lockfile-ът е предназначен да бъде честният запис на това, от какво зависи приложението. Когато се отклони от реалността, компилацията направи точно това, което сега прави нашето приложение за потребителите: отказа да се преструва, че всичко е наред. Оказва се, че доставянето на издание за надеждност е проблем на надеждността чак до дъно.
Три неща, на които ни научи v2
- Опасните провали са тихите. Сривването се обявява само. Фалшиво „свързано", фантомно успешно качване, транскрипция с невидима дупка — тези ти струват доверие именно защото нищо не изглежда наред. Лови тихите лъжи.
- Честността е архитектура, а не съобщение. Не можеш да залепиш „казвай истината" върху интерфейс като банер. Банерът трябва да чете от същия единствен източник на истина като всичко останало, иначе става още едно нещо, което може да е грешно. Един факт, разпръснат — никога две копия, които могат да си противоречат.
- Една версия 2, достойна за числото, е предимно невидима. Ако твоят v2 е списък с функции, това е v1.5 с маркетинг. Реален v2 е 206 комита, които никой не може да посочи поотделно, събиращи се в продукт, който просто спира да те лъже.
GeekBye v2.0.0 е основата, върху която е строило всяко издание оттогава. За това, което носи тази основа, виж защо твоят AI notetaker спира при лошо Wi-Fi, деня, в който нашето приложение си направи само DDoS (v2.0.1) и транскрипция на живо, когато файъруолът блокира WebSocket-и (v2.0.8). За спокойствието, в чиято услуга беше всичко, какво е новото в GeekBye v2.