Steven
Steven1 分で読める

たった一つのCSS変数、五回のレビュー、そして嘘をついたSwiftツールチェーン

GeekBye v2.0.7は、オーバーレイ全体を調整可能な半透明にしました — 一行のCSS変更のように聞こえますが、まったくそうではありませんでした。本当の物語は、コードレビューが何を捕まえたかにあります: 薄れることを拒んだ二つの面、同じ不透明度なのに間違って見えた録音バー、そして自分たちのドキュメントがレビュアーに間違ったSwiftのバージョンを伝えたせいで672バイトを行ったり来たりしたコンパイル済みバイナリです。

エンジニアリング
デザイン
ビルド
GeekByeリリース
たった一つのCSS変数、五回のレビュー、そして嘘をついたSwiftツールチェーン

「オーバーレイを半透明にする」は、スライダーとCSSのopacityプロパティのように聞こえる類のタスクです。GeekBye v2.0.7は、まさにそのユーザーに見える成果を出荷しました — アシスタントのパネル越しに、その後ろにあるものを透かして見られる、一つの調整可能な「ライトモード」です。しかしこのリリースの面白い部分は、機能ではありません。それを正しく仕上げるのに要した五回のレビューと、自分たちのドキュメントがレビュアーに嘘をついたせいでサイズが変わったコンパイル済みバイナリの武勇伝です。

UI全体を半透明にする正しいやり方

これの素朴なやり方は、あらゆるパネルコンポーネントに不透明度の値を振りまいて完了と呼ぶことです。それは保守の罠です: 誰かが一つに触れた瞬間に互いにずれていく、十数個のハードコードされた値。

代わりに、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.3.xのリポジトリ内の6.2.1バイナリは、他のすべての開発者のクリーンな再ビルドを壊す、まさにそのずれです。

次のコミットがそれを直しました — そして修正こそが要点です。それは単にバイナリを6.3.xの形に再ビルドし戻した(サイズは89,184へ復元され、始まった場所にぴたりと戻った)だけではありません。それはまた、ドキュメント内の古くなった「6.2.1」の参照を訂正したので、罠が二度と仕掛けられないようにしました。バイナリは二つのコミットにまたがって672バイトを行って戻り、本当のバグは決してバイナリではありませんでした。それは、二つの真実の源 — 強制スクリプトと書かれたドキュメント — が食い違っており、人間が間違った方を信じたことでした。

このリリースが教えた三つのこと

  1. **CSS変数のカスケードは、正しさの境界だ。**三つのレビューバグのうち二つは、継承しなかった変数と、ホバー状態を潰した!importantに行き着きました。ある値が継承を通じて要素に届かなければならない、あるいは詳細度を通じて勝たなければならないなら、その経路はロジックです — スタイリングとしてではなく、ロジックとして検証しましょう。
  2. **等しいパラメータが、等しくない結果を生みうる。**録音バーとアイドルバーは不透明度を共有していたのに、違うブラーが結果を変えたせいで、それでも違って見えました。視覚システムを一つの数字で統一するときは、各面の周りにある他の変数が、その数字の意味を静かに変えていないかをチェックしましょう。
  3. **ドキュメントと強制が食い違うときは、症状ではなく、食い違いそのものを直せ。**バグは悪いバイナリではありませんでした。それは間違ったツールチェーンを名指ししたドキュメントと、そうではないと言う強制スクリプトでした。バイナリを再ビルドするのは症状への対処です。すべての真実の源を一致させることが実際の修正です。なぜなら、次のレビュアーもまたドキュメントを信じるからです。

GeekBye v2.0.7は、すべてのエッジケースをレビュー済みで、ツールチェーンのドキュメントを正した状態で、統一された半透明を出荷しました。それは、その後に続いた信頼性のスプリントの前の、最後の「静かな職人技」のリリースです。その下にある土台については、what a version 2 actually takes(v2.0.0)をご覧ください。兄弟分の磨き上げリリースについては、calm software: the flicker fix and the answer-mode chip(v2.0.3 + v2.0.5)を。そしてオーバーレイが通話中にどう隠れたままでいるかについては、how to stay invisible during screen sharingをどうぞ。

関連記事

穏やかなソフトウェア:ちらつくトグルを葬り、チャットに「今どのモードか」を語らせる
Steven
Steven1 分で読める

穏やかなソフトウェア:ちらつくトグルを葬り、チャットに「今どのモードか」を語らせる

GeekByeの小さなリリースが2本。目玉機能はなし。ただ、クリックのたびにちらついていた設定トグルを直し、会議モードで答えたのかコーディングモードで答えたのかをようやく教えてくれるチャットアシスタントを作った。「穏やかなソフトウェア」が実際にいくらのコストで成り立っているのか、その一つひとつのディテールの話だ。

プロダクト
デザイン
エンジニアリング
ソフトウェアを完璧に届けるための解剖学:テストが見逃したものをコードレビューがどう捉えたか
Steven
Steven1 分で読める

ソフトウェアを完璧に届けるための解剖学:テストが見逃したものをコードレビューがどう捉えたか

GeekBye v2シリーズを通して、同じことが何度も起きています。開発者のマシンではすべてのテストに合格した修正が、コードレビューによって「ほぼ全員にとって失敗していたはずだ」と証明されるのです。これは9つのリリースの背後にあるワークフロー——レビューというゲート、修正より先に不具合を捉える仕組み、そして「自分の環境では動く」を「ちゃんと動く」に変える、出荷前テストの規律の物語です。

エンジニアリング
プロセス
コードレビュー
あなたのMacアプリはマイクへのアクセスを許可する — そして起動するたびに、それを忘れる
Steven
Steven1 分で読める

あなたのMacアプリはマイクへのアクセスを許可する — そして起動するたびに、それを忘れる

GeekByeがマイクの許可を求め、あなたは許可し、動きました。次に起動すると、消えている。しかもアプリは、システム設定 → マイク にそもそも一度も現れなかった。犯人は、アプリを「消えてしまうパス」から静かに実行していたmacOSのセキュリティ機能でした — その診断と、たった一つのプロンプトで済む修正をここに記します。

macOS
権限
エンジニアリング