Steven
Steven6 хв читання

Одна CSS-змінна, п'ять раундів рев'ю та ланцюжок інструментів Swift, що збрехав

GeekBye v2.0.7 зробив увесь оверлей регульовано напівпрозорим — що звучить як однорядкова зміна CSS і абсолютно нею не було. Справжня історія — про те, що виловило код-рев'ю: дві поверхні, які відмовлялися згасати, панель запису, що виглядала неправильно за тієї самої прозорості, і скомпільований бінарник, який стрибнув на 672 байти, бо наша власна документація підказала рецензенту неправильну версію Swift.

Інженерія
Дизайн
Збірка
Релізи GeekBye
Одна CSS-змінна, п'ять раундів рев'ю та ланцюжок інструментів Swift, що збрехав

«Зробіть оверлей напівпрозорим» — це той тип задачі, що звучить як повзунок і CSS-властивість opacity. GeekBye v2.0.7 випустив рівно цей результат для користувача — єдиний регульований «світлий режим», що дозволяє бачити крізь панелі асистента те, що за ними. Але цікава частина цього релізу — не сама функція. Це п'ять раундів рев'ю, які знадобилися, щоб зробити її правильно, і фронтова історія про скомпільований бінарник, що змінив розмір, бо наша власна документація збрехала рецензентові.

Правильний спосіб зробити цілий інтерфейс напівпрозорим

Наївний варіант — розсипати значення прозорості по кожному компоненту-панелі й вважати справу зробленою. Це пастка супроводу: десяток зашитих значень, які розповзаються тієї ж миті, щойно хтось торкнеться одного.

Натомість v2.0.7 використовує одну спільну CSS-утиліту й токен для кожної поверхні. Є єдиний клас overlay-surface, який обчислює фон панелі з двох користувацьких властивостей: базової прозорості, яку кожна поверхня оголошує для себе (панель керування, чат, бульбашки транскрипту, блоки коду тощо — кожна обирає свою власну), і глобального множника альфи, що живе в корені оверлея й представляє налаштування повзунка користувача. Кожна поверхня читає той самий множник; кожна зберігає власний характер. Критично: масштабується лише фон панелі — текст, іконки й backdrop-blur лишаються повністю відмальованими, тож «напівпрозорий» ніколи не означає «нечитабельний».

Два рішення в цьому дизайні варто виокремити, бо саме вони — різниця між функцією, що допомагає, і тією, що породжує звернення до підтримки:

  • За замовчуванням оверлей повністю непрозорий. Налаштування прозорості постачається на рівні 100% — тобто нічого не робить. Ніхто не побачив, як його оверлей раптом став прозорим після оновлення; прозорість там, коли ви до неї потягнетеся, і невидима доти.
  • Налаштування валідується захисно. Є одне джерело правди для мінімуму, максимуму, значення за замовчуванням і кроку, а також нормалізатор, який захищає порожній/відсутній випадок. Це важливо через одну підступність JavaScript: Number(null) дорівнює 0, тож наївно приведене відсутнє налаштування миттєво перемкнуло б оверлей у найпрозоріший стан замість стану за замовчуванням. Нормалізатор ловить це, перш ніж воно станеться.

Потягніть повзунок — і весь оверлей перетонується наживо, посеред запису, бо кожна поверхня підписана на те саме налаштування. Без перезапуску, без перезавантаження.

Що виловило рев'ю (і чого тест на одному моніторі ніколи б не виловив)

Ось де «одна CSS-змінна» перестала бути простою. Три баги виринули на рев'ю, і два з них — той самий урок у різних масках.

Панель, яка не хотіла згасати. Оверлей клавіатурних скорочень уперто залишався щільним, поки все інше ставало напівпрозорим. Причина: він відмальовується поза піддеревом DOM, що несе змінну прозорості, тож ніколи не успадкував значення, що каскадувало вниз від кореня оверлея. Користувацькі CSS-властивості успадковуються через дерево DOM — і якщо вузол насправді не є нащадком того місця, де ви встановили змінну, він мовчки не отримує нічого. Виправлення — встановити змінну локально й на цій панелі теж.

Підсвітка при наведенні, яка зникла. Кнопки Fn/Assist втратили своє блакитне сяйво при наведенні. Утиліта прозорості встановлювала фон із !important (вона мусить перемагати типові значення поверхонь), і це переїхало фонову підсвітку hover: на тому самому елементі. Колізія специфічності. Виправлення — зробити підсвітку при наведенні так само наполегливою, щоб вона могла відвоювати перемогу при наведенні.

Обидва ці випадки — та сама глибинна істина: каскад CSS-змінної — це справжня межа коректності, а не деталь стилізації. Успадкування й специфічність вирішують, чи ваше значення взагалі досягне елемента, і жодне з них не проявиться на скріншоті, поки не стане помилковим.

Однакова прозорість, різний вигляд. Найтонший: панель запису й панель очікування були виставлені на ідентичну базову прозорість — і все одно виглядали помітно по-різному. Чому? Пігулка запису використовувала важче backdrop-blur, а сильне розмиття над темним фоном усереднюється в бік темнішого результату — тож однакова альфа дала неоднаковий вигляд. У неї також була ледь помітна межа там, де панель очікування мала яскраву кайму градієнтного кільця. Виправлення узгодило рівень розмиття й кільце. Урок закарбувався: однакова альфа — це не однаковий вигляд, щойно в гру входить розмиття. Прозорість — це система взаємодіючих ефектів, а не одне-єдине число.

Бінарник, що змінив розмір, бо документація збрехала

Тепер фронтова історія, і це мій улюблений жанр — той, де інструментарій і документація не збігаються, а сумлінний рецензент потрапляє під перехресний вогонь.

GeekBye постачає деякі попередньо скомпільовані бінарники Swift (нативні помічники для таких речей, як виявлення зустрічей). Оскільки скомпільований бінарник закомічено в репозиторій, кожен розробник мусить компілювати його з точно тією самою версією Swift — різні ланцюжки інструментів дають різні байти з ідентичного вихідного коду, а це означало б фантомний git-конфлікт щоразу, коли хтось перезбирає. Тож є скрипт, який застосовує одну конкретну версію: Swift 6.3.x, перевіряється під час збірки.

Під час рев'ю цього релізу рецензент зауважив, що бінарник слід перезібрати відповідно до «мандатованого репозиторієм ланцюжка інструментів». Розробник зробив саме це — і розмір бінарника змінився з 89,184 байтів на 88,512. Повідомлення коміту навіть казало, що це «відновлення байт-стабільного виводу» шляхом перезбирання з Swift 6.2.1, «мандатованим репозиторієм ланцюжком інструментів».

От тільки 6.2.1 була неправильною версією. Скрипт-регулятор збірки вимагав 6.3.x. Проблема була в тому, що текстова документація — README й посібник для контриб'юторів — усе ще казала 6.2.1 у кількох місцях. Тож сумлінний рецензент і сумлінний розробник, обидва прагнучи зробити правильно, пішли за документацією прямісінько до коміту саме того артефакту, який скрипт-регулятор існує, щоб відкидати. Бінарник 6.2.1 у репозиторії 6.3.x — це точно той дрейф, що зламав би чисту перезбірку кожному іншому розробнику.

Наступний коміт це виправив — і виправлення тут головне. Він не просто перезібрав бінарник назад до форми 6.3.x (розмір відновлено до 89,184, рівно туди, де все починалося). Він також виправив застарілі згадки «6.2.1» у документації, щоб пастку не можна було знову захряснути. Бінарник стрибнув на 672 байти й назад за два коміти, а справжній баг ніколи не був у бінарнику. Він був у тому, що два джерела правди — скрипт-регулятор і письмова документація — не збігалися, а людина довірилася не тому.

Три речі, яких навчив цей реліз

  1. Каскад CSS-змінної — це межа коректності. Два з трьох багів рев'ю зводилися до змінної, яка не успадкувалася, і !important, який збив стан наведення. Якщо значення мусить досягти елемента через успадкування або перемогти через специфічність, цей шлях — логіка; перевіряйте його як логіку, а не як стилізацію.
  2. Однакові параметри можуть давати неоднакові результати. Панель запису й панель очікування ділили прозорість і все одно виглядали по-різному, бо інше розмиття змінило результат. Коли ви уніфікуєте візуальну систему на одному числі, перевірте, що інші змінні навколо кожної поверхні не змінюють тихцем того, що це число означає.
  3. Коли документація й регулятор не збігаються, виправляйте розбіжність — а не лише симптом. Баг був не в поганому бінарнику; він був у документації, яка назвала неправильний ланцюжок інструментів, і скрипті-регуляторі, який казав інакше. Перезбирання бінарника лікує симптом. Узгодження кожного джерела правди — ось справжнє виправлення, бо наступний рецензент теж довіриться документації.

GeekBye v2.0.7 випустив однорідну прозорість — усі граничні випадки переглянуто, а документацію ланцюжка інструментів поставлено на місце. Це останній із релізів «тихого ремесла» перед спринтом надійності, що настав опісля. Про фундамент під ним див. чого насправді коштує друга версія (v2.0.0); про споріднений реліз шліфування — спокійне програмне забезпечення: виправлення мерехтіння й чип режиму відповідей (v2.0.3 + v2.0.5); а про те, як оверлей лишається прихованим під час дзвінка — як залишатися невидимим під час демонстрації екрана.

Схожі статті

Спокійне програмне забезпечення: як ми прибрали миготливий перемикач і навчили чат казати, у якому він режимі
Steven
Steven6 хв читання

Спокійне програмне забезпечення: як ми прибрали миготливий перемикач і навчили чат казати, у якому він режимі

Два невеликі релізи GeekBye без гучних функцій — лише перемикач у налаштуваннях, який перестав миготіти, і чат-асистент, який нарешті каже, чи відповів він у режимі зустрічі, чи в режимі кодування. Ось скільки насправді коштує «спокійне програмне забезпечення», по одній деталі за раз.

Продукт
Дизайн
Інженерія
Анатомія доведення ПЗ до досконалості: як код-рев'ю зловило те, що не змогли тести
Steven
Steven5 хв читання

Анатомія доведення ПЗ до досконалості: як код-рев'ю зловило те, що не змогли тести

Упродовж усієї серії GeekBye v2 повторюється те саме: виправлення проходить кожен тест на машині розробника, а потім код-рев'ю доводить, що воно б не спрацювало майже ні в кого. Ось робочий процес за дев'ятьма релізами — ворота рев'ю, відлови на етапі виправлення і дисципліна «протестуй до відвантаження», яка перетворює «у мене працює» на «працює».

Інженерія
Процес
Код-рев'ю
Ваш застосунок для Mac отримує доступ до мікрофона — і забуває його при кожному запуску
Steven
Steven5 хв читання

Ваш застосунок для Mac отримує доступ до мікрофона — і забуває його при кожному запуску

GeekBye попросив доступ до мікрофона, ви його надали, і все запрацювало. Наступний запуск: доступу немає. А в Системних параметрах → Мікрофон застосунок узагалі не з’явився. Винуватцем виявилася функція безпеки macOS, що тихо запускає застосунок зі шляху, який зникає — ось діагноз і виправлення в одне натискання.

macOS
Дозволи
Інженерія