
Jedna proměnná CSS, pět kol revize a Swift toolchain, který lhal
GeekBye v2.0.7 udělal celý overlay nastavitelně průsvitným — což zní jako jednořádková změna v CSS a rozhodně nebylo. Skutečný příběh je to, co odhalila revize kódu: dvě plochy, které odmítaly zprůhlednět, nahrávací lišta, jež vypadala špatně při stejné neprůhlednosti, a zkompilovaná binárka, která poskočila o 672 bajtů, protože naše vlastní dokumentace řekla revidujícímu špatnou verzi Swiftu.
„Udělej overlay průsvitným" je ten typ úkolu, který zní jako posuvník a vlastnost CSS opacity. GeekBye v2.0.7 přinesl přesně tento výsledek viditelný pro uživatele — jediný nastavitelný „světlý režim", který ti umožní vidět skrz panely asistenta na to, co je za nimi. Ale zajímavá část tohoto vydání není ta funkce. Je to pět kol revize, kterých bylo potřeba, aby to bylo správně, a válečná historka o zkompilované binárce, která změnila velikost, protože naše vlastní dokumentace lhala revidujícímu.
Správný způsob, jak udělat celé UI průsvitným
Naivní verze tohoto je posypat hodnotou neprůhlednosti každou komponentu panelu a prohlásit to za hotové. To je past na údržbu: tucet natvrdo zakódovaných hodnot, které se rozejdou ve chvíli, kdy se kdokoli dotkne jedné z nich.
Místo toho v2.0.7 používá jednu sdílenou pomocnou třídu CSS a token pro každou plochu. Existuje jediná třída overlay-surface, která počítá pozadí panelu ze dvou vlastních vlastností: základní neprůhlednosti, kterou si každá plocha deklaruje sama pro sebe (ovládací lišta, chat, bubliny přepisu, bloky kódu a tak dále si každá vybere svou vlastní), a globálního násobitele alfy, který sedí na kořeni overlay a představuje nastavení posuvníku uživatele. Každá plocha čte stejný násobitel; každá si zachovává svůj vlastní charakter. Zásadní je, že se škáluje jen pozadí panelu — text, ikony a backdrop-blur zůstávají plně vykreslené, takže „průsvitný" nikdy neznamená „nečitelný".
Dvě rozhodnutí v tomto návrhu stojí za zmínku, protože jsou rozdílem mezi funkcí, která pomáhá, a tou, jež generuje tikety podpory:
- Výchozí stav je plně neprůhledný. Nastavení neprůhlednosti se dodává na 100 % — no-op. Overlay nikoho se při aktualizaci najednou nestal průhledným; průsvitnost je tam, když po ní saháš, a do té doby neviditelná.
- Nastavení je obranně validováno. Existuje jediný zdroj pravdy pro min, max, výchozí hodnotu a krok, plus normalizátor, který hlídá prázdný/chybějící případ. To má význam kvůli jedné pasti v JavaScriptu:
Number(null)je0, takže chybějící naivně převedené nastavení by přichytilo overlay do jeho nejprůhlednějšího stavu místo výchozí hodnoty. Normalizátor to zachytí, než se to může stát.
Zatáhni za posuvník a celý overlay se přebarví naživo, uprostřed nahrávání, protože každá plocha je přihlášena k odběru stejného nastavení. Žádný restart, žádné znovunačtení.
Co odhalila revize (a co by test na jednom monitoru nikdy neodhalil)
Tady „jedna proměnná CSS" přestala být jednoduchá. V revizi vyplavaly tři chyby a dvě z nich jsou tatáž lekce v jiném klobouku.
Panel, který nechtěl zprůhlednět. Overlay klávesových zkratek zůstal tvrdohlavě plný, zatímco všechno ostatní zprůsvitnělo. Příčina: vykresluje se mimo podstrom DOM, který nese proměnnou neprůhlednosti, takže nikdy nezdědil hodnotu kaskádující dolů z kořene overlay. Vlastní vlastnosti CSS se dědí skrz strom DOM — a pokud uzel ve skutečnosti není potomkem místa, kde proměnnou nastavuješ, tiše nedostane nic. Oprava spočívala v tom, že jsme proměnnou nastavili lokálně i na tom panelu.
Hover odstín, který zmizel. Tlačítka Fn/Assist ztratila svou azurovou hover záři. Pomocná třída pro průsvitnost nastavovala pozadí pomocí !important (musí zvítězit nad výchozími hodnotami plochy) a to převálcovalo hover: odstín pozadí na tomtéž prvku. Kolize specificity. Oprava spočívala v tom, že jsme hover odstín udělali stejně důrazným, aby mohl při hoveru získat vítězství zpět.
Obě jsou tatáž základní pravda: kaskáda proměnné CSS je skutečná hranice správnosti, ne detail stylování. Dědičnost a specificita rozhodují o tom, zda tvá hodnota vůbec dorazí k prvku, a ani jedno se neobjeví na snímku obrazovky, dokud to není špatně.
Stejná neprůhlednost, jiný vzhled. Ta nejjemnější: nahrávací lišta a nečinná lišta byly nastaveny na totožnou základní neprůhlednost, a přesto vypadaly viditelně jinak. Proč? Nahrávací pilulka používala silnější backdrop-blur a silný blur nad tmavým pozadím průměruje k tmavšímu výsledku — takže stejná alfa vytvořila nestejný vzhled. Měla také slabý okraj tam, kde nečinná lišta měla jasnou hranu s gradientním prstencem. Oprava sladila úroveň blur a prstenec. Lekce zůstala: stejná alfa není stejný vzhled, jakmile do hry vstoupí blur. Průsvitnost je systém vzájemně působících efektů, ne jediné číslo.
Binárka, která změnila velikost, protože dokumentace lhala
Teď ta válečná historka a je to můj oblíbený druh — ten, kde se nástroje a dokumentace neshodnou a pečlivý revidující se ocitne v křížové palbě.
GeekBye dodává několik předkompilovaných binárek Swift (nativní pomocníky pro věci jako detekce schůzek). Protože je zkompilovaná binárka commitnutá do repozitáře, každý vývojář ji musí zkompilovat s přesně stejnou verzí Swiftu — různé toolchainy produkují různé bajty z identického zdroje, a to by znamenalo fantomový git konflikt pokaždé, když někdo znovu sestaví. Takže existuje skript, který vynucuje jednu konkrétní verzi: Swift 6.3.x, kontrolovanou při buildu.
Během revize tohoto vydání revidující upozornil, že by se binárka měla znovu sestavit, aby odpovídala „toolchainu předepsanému repozitářem". Vývojář udělal přesně to — a velikost binárky se změnila z 89,184 bajtů na 88,512. Zpráva commitu dokonce uváděla, že „obnovuje bajtově stabilní výstup" opětovným sestavením se Swiftem 6.2.1, „toolchainem předepsaným repozitářem".
Jenže 6.2.1 byla špatná verze. Vynucovací skript buildu vyžadoval 6.3.x. Problém byl, že prozaická dokumentace — README a průvodce pro přispěvatele — na několika místech stále uváděla 6.2.1. Takže svědomitý revidující a svědomitý vývojář, oba snažící se udělat správnou věc, následovali dokumentaci rovnou k tomu, že commitli přesně ten artefakt, který vynucovací skript existuje proto, aby odmítl. Binárka 6.2.1 v repozitáři 6.3.x je přesně ten posun, který by rozbil čisté opětovné sestavení každému jinému vývojáři.
Následující commit to opravil — a ta oprava je pointa. Nejenže znovu sestavil binárku zpět do její podoby 6.3.x (velikost obnovena na 89,184, přesně tam, kde začala). Také opravil zastaralé odkazy na „6.2.1" v dokumentaci, aby past už nešlo znovu nastražit. Binárka poskočila o 672 bajtů a zpátky během dvou commitů a skutečná chyba nikdy nebyla binárka. Bylo to tím, že dva zdroje pravdy — vynucovací skript a psaná dokumentace — se neshodly a člověk věřil tomu špatnému.
Tři věci, které nás toto vydání naučilo
- Kaskáda proměnné CSS je hranice správnosti. Dvě ze tří chyb z revize se scvrkly na proměnnou, která se nezdědila, a na
!important, jenž převálcoval hover stav. Pokud hodnota musí dorazit k prvku skrze dědičnost nebo zvítězit skrze specificitu, ta cesta je logika — ověřuj ji jako logiku, ne jako stylování. - Stejné parametry mohou dát nestejné výsledky. Nahrávací lišta a nečinná lišta sdílely neprůhlednost, a přesto vypadaly jinak, protože jiný blur změnil výsledek. Když sjednocuješ vizuální systém na jedno číslo, zkontroluj, zda ostatní proměnné kolem každé plochy tiše nemění to, co dané číslo znamená.
- Když se dokumentace a vynucování neshodnou, oprav ten nesoulad — ne jen symptom. Chyba nebyla špatná binárka; byla to dokumentace, která uváděla špatný toolchain, a vynucovací skript, jenž říkal něco jiného. Opětovné sestavení binárky léčí symptom. Dát každý zdroj pravdy do souladu je skutečná oprava, protože i další revidující bude věřit dokumentaci.
GeekBye v2.0.7 dodal jednotnou průsvitnost, se všemi hraničními případy prošlými revizí a s dokumentací toolchainu uvedenou na pravou míru. Je to poslední z vydání „tichého řemesla" před sprintem spolehlivosti, který následoval. Pro základ pod ním viz co ve skutečnosti vyžaduje verze 2 (v2.0.0); pro sesterské leštící vydání klidný software: oprava blikání a čip režimu odpovědi (v2.0.3 + v2.0.5); a pro to, jak overlay zůstává skrytý při hovoru, jak zůstat neviditelný během sdílení obrazovky.