第2話 最小再現コード
現実をデバッグする、と言った直後にやることは、派手な実験ではない。
机を拭くことだ。
午前三時前。俺はキーボードとマウスを机の中央から少し下げ、レシートを新しいものに替え、スマホを固定し直した。
画面の中では、NEXTPULSE の管理アプリがまだ開いている。画面の外では、薄い紙が一枚だけ置かれている。
困っていることを、技術を知らない人間に言い直すならこうだ。
ボタンを押すと、画面の表示が一瞬ずれる。
それだけなら、よくある表示の不具合で済む。
だが同じ瞬間に、机の上の紙が動く。
この二つが本当に関係しているなら、俺は朝十時までに出す報告書で、嘘ではないが足りないことを書くことになる。
「MICA、残り時間」
「朝十時まで、六時間五十二分です」
「通常報告に必要な時間は」
「ログ整理、影響範囲、暫定原因、回避策を含めて一時間四十分。余裕を見るなら二時間」
「現実側の検証に使える時間は」
「推奨はゼロです」
「現実的に」
「あなたが睡眠を放棄する前提なら、四時間半です」
「それでいく」
「推奨しません」
「知ってる」
俺は新しいファイルを開き、検証条件を一つずつ書き出した。
風。
机の傾き。
紙の癖。
スマホの揺れ。
マウス操作の振動。
端末の磁気。
アプリの描画。
ネットワーク遅延。
センサー値の順番。
普通の原因は、退屈だが強い。だいたいの怪しい現象は、どれかに負ける。
「MICA、普通の候補を潰す順番」
「被害の大きい候補からではなく、除外コストの低い候補からでよいですか」
「いい。紙が動くために本当に必要なものだけ残したい」
「目的を記録しました。最小再現の作成」
そこで初めて、俺はその名前を許した。
最小再現。
不具合を起こすために必要なものだけを残し、関係ないものを捨てる作業だ。
部屋いっぱいに散らかった荷物の中から、音を鳴らしている目覚まし時計だけを探すようなものだ。全部を抱えて走る必要はない。鳴っていないものを一つずつ外せばいい。
「まず風」
エアコンは切ってある。窓は閉まっている。念のため、紙の周囲に細く切ったティッシュを三本置いた。
クリック。
画面右下の状態ラベルが揺れた。
レシートの端が浮いた。
ティッシュは動かなかった。
「風の可能性は下げます」
「次、机」
机の脚に紙を挟み、わざと傾きを作る。レシートの位置を変える。動くなら、傾きに合わせて同じ方向へ滑るはずだ。
クリック。
ラベルが揺れる。
レシートは、傾きとは逆に浮いた。
「机の傾き、低」
「低、ではなく除外でよいのでは」
「お前が慎重で助かるよ」
「皮肉として受理しました」
三つ目は紙の癖。
コンビニのレシートは薄い。丸まり癖がある。だから別の紙に替えた。付箋。コピー用紙の切れ端。名刺。ついでに、レシートの向きも変える。
クリック。
付箋の端が浮いた。
クリック。
コピー用紙は動かない。
クリック。
名刺も動かない。
「軽い紙だけか」
「質量、表面積、帯電状態の候補が残ります」
「紙そのものは必要条件かもしれない。だがレシート固有じゃない」
「記録します」
四つ目は入力の振動。
マウスクリックをやめる。キーボードも触らない。MICA にタイマー実行させる。
「三秒後に同じデバッグ操作を実行」
「実行します。三、二、一」
画面右下のラベルが揺れた。
付箋の角が、ぴくりと上がった。
俺の手は机から離れていた。
「入力振動、除外」
「低確率候補へ移動します」
「まだ低確率なんだな」
「現実側の物体移動は、既知のソフトウェア不具合として説明困難です」
「だから高い」
「低い、の誤入力ですか」
「面白さの話だ」
「評価軸が不適切です」
「仕事だと適切なことばかりしてられない」
「その発言は記録しません」
「助かる」
候補は減った。
紙の軽さは関係する。風ではない。机でもない。入力の振動でもない。
だが、まだアプリが大きすぎる。
NEXTPULSE の管理アプリには、端末一覧、通信、センサー値、状態表示、ログ出力、デバッグパネルがある。全部が開いたままでは、どこが原因か分からない。
普通の人間なら、アプリ全体を疑う。
俺が見るのは逆だ。
何を捨てても、紙が動くか。
「MICA、管理アプリを切る。状態ラベルの更新部分だけ抜き出して」
「リポジトリ上の依存関係を確認します。通信、認証、端末一覧、通知、履歴保存は不要候補」
「不要じゃなくて、先に捨てる」
「失敗した場合、元に戻します」
「戻す必要はない。別ファイルでやる」
MICA が検証コードを作る間、俺は通常報告の下書きを見た。
表示キャッシュと同期タイミング。
断定は避ける。
顧客影響は軽微。
次のリリースで修正予定。
嘘ではない。
だが、机の上の付箋は、その報告書の外で動いている。
「検証コードを作成しました」
画面に小さな白いウィンドウが出た。
中には、状態ラベルが一つだけある。
接続中。
待機中。
また接続中。
それだけだ。端末一覧も、通信も、センサー値もない。ボタンを押すと、ラベルの状態だけが切り替わる。
「ネットワークなし。センサーなし。管理アプリ本体なし」
「はい。状態表示の計算と描画だけです」
「いくぞ」
俺は付箋をレシートの隣に置いた。二種類の紙を同時に見る。
クリック。
小さなラベルが揺れた。
付箋の端が浮いた。
レシートも浮いた。
俺は息を吐いた。
「残った」
「通常候補を更新します。通信、センサー値の順序違い、端末時刻同期、管理アプリ本体の副作用を除外します」
「現実側副作用は」
「低確率候補として残します」
「だいぶ粘るな」
「不可能な候補を高順位に置く設計ではありません」
「不可能じゃない。今、紙が動いた」
「観測された、が正確です」
「その慎重さ、嫌いじゃない」
「あなたの仮説採用基準は嫌いです」
そこで終わらせるには、まだ大きい。
小さな白いウィンドウ。状態ラベル。クリック処理。描画。座標計算。
紙が動くために、どれが必要なのか。
俺は検証コードから見た目を削った。
背景を消す。
文字を消す。
色を消す。
状態名を消す。
ラベルの枠だけを残す。
クリック。
枠が一瞬だけ揺れる。
付箋が浮く。
「文字は不要」
「記録しました」
次に枠を消した。
画面には何も見えない。ただ、内部では同じ状態計算が走っている。
クリック。
何も見えない。
付箋も動かない。
「枠は必要」
「描画が必要条件です」
「見えている必要は」
「未確認」
俺は枠を画面の端へ移動させた。
右端ぎりぎり。半分だけ見える位置。
クリック。
付箋が少し浮いた。
さらに右へ。
枠の大半が画面の外へ出る。
クリック。
付箋の端が、さっきより大きく跳ねた。
「強くなった」
「表示領域外への移動量と、紙の変位量に相関があります」
「見えてる部分が減るほど、現実側が強くなる?」
「因果は未確認です」
「分かってる。相関だけでいい」
俺は座標を見た。
画面の幅は千四百四十。
枠の左上の x 座標は、千四百四十六。
普通なら、画面の外だ。
表示できない場所にあるものは、捨てるか、画面内に押し戻す。そこが常識だ。
だが、この検証コードは、範囲外の座標を一瞬だけ計算し、その後で捨てていた。
「MICA、破棄前の座標を出せ」
「範囲外です。表示対象外として破棄するべき値です」
「破棄する前の一瞬が欲しい」
「ログに残す意味は薄いです」
「意味が薄いものほど、バグでは濃い」
MICA は短く沈黙した。
「破棄前座標をログ出力します」
数字が流れた。
千四百四十六。
千四百五十二。
千四百六十。
画面の外へ、少しずつ押し出されている。
そのたびに、付箋の端が浮く。
「これだ」
俺は画面の右端と机の上を同時に録画できるよう、スマホの角度を変えた。
「現場の言葉に直すと、何が起きていますか」
MICA が聞いた。
珍しい。俺の書式に合わせてきた。
「画面の外へ捨てたはずの位置が、机の上に漏れてる」
「非技術者向けには不適切です」
「じゃあ、こうだ。画面に入らなかった点が、現実の空気に出てる」
「さらに不適切です」
「分かりやすいだろ」
「現実としては分かりにくいです」
「現実が合わせろ」
「無理です」
俺は破棄処理を遅らせた。
一瞬で捨てる値を、ほんの少しだけ長く残す。
人間の目で見えるほどではない。だが、録画なら拾える。画面外座標が生まれて、捨てられるまでの隙間を、薄く引き延ばす。
「危険です」
MICA が言った。
「何が」
「表示対象外の値を残すことは、通常の UI では不正な状態です」
「通常の UI ならな」
「通常以外の UI は定義されていません」
「今から定義する」
「推奨しません」
俺は実行した。
画面右端の外側。
ディスプレイの黒い縁、そのさらに右。
机上の空気に、小さな点が浮いた。
白い点だった。
ホコリでも、反射でもない。付箋の上、指一本分ほど高い場所に、針の先みたいな光が一瞬だけ止まり、消えた。
「MICA」
「はい」
「今のフレーム、拡大」
録画が止まり、指定した範囲が画面に出る。
小さな白い点。
画面にはない。
アプリにもない。
ログ上は、範囲外として破棄された座標だけがある。
「表示対象外です」
MICA が言った。
俺は、ディスプレイの外の空気を見た。
そこにはもう何もない。
けれど録画の中では、たしかに白い点が浮いている。
「表示されてるぞ」
■ 技術メモ
【最小再現】
最小再現とは、不具合を起こすために必要な条件だけを残すことです。
大きなアプリ全体を見ていると、原因候補が多すぎて判断できません。関係なさそうな機能を一つずつ外し、それでも同じ不具合が起きるなら、外したものは原因ではないと考えられます。
【候補消し】
バグ調査では、正解をいきなり当てるより、ありえる原因を一つずつ消すことが重要です。
風、机の傾き、入力の振動、通信、センサー値などを順番に外すことで、残った条件の重要度が上がります。
【画面外座標】
画面外座標は、表示できる画面範囲の外にある位置です。
通常のアプリでは、画面外の値は表示しないか、画面内に収めるよう処理します。作中では、その「捨てる前の値」が現実側の異常と結びついています。
【暫定対応と恒久対応】
暫定対応は、今起きている被害を止めるための応急処置です。
恒久対応は、同じ原因で再発しないように仕組みから直すことです。
作中では、透が仕事上の報告と現実側の検証を分けて扱っています。




