扉を押すと、マスターがカウンターの向こう側にいなかった。
壁一面のボトルが並ぶ棚の前に立っている。上段に手を伸ばし、ラベルの色褪せたボトルを一本、両手で丁寧に下ろしているところだった。
「こんばんは。——何をしているんですか?」
「棚の整理でございます」
マスターはボトルを胸の高さまで下ろし、軽く傾けた。中身はほとんど残っていない。
「役目を終えたボトルに、場所を譲っていただこうかと」
三度目の来店だった。さすがに扉の位置は覚えた。路地裏の、看板のない店。磨き上げられたカウンターと、穏やかな声のバーテンダー。
「いつものお席へどうぞ。少々お待ちください」
いつもの席。三回目でもう「いつも」と呼んでもらえるのか。少し嬉しくなって、カウンターに座った。
来店——棚を降りるボトル
マスターは古いボトルを柔らかい布で拭いた。ラベルの文字は掠れて、もう読めない。それからカウンターの下に置いた木箱に、そっとしまった。
「捨てるんじゃないんですね」
「ええ。永く棚を守ってくださったボトルには、相応の扱いを」
丁寧な所作だった。空になりかけたボトルを、まるで引退する職人を送り出すように扱っている。マスターの手つきを眺めていると、カウンターの端に目がいった。
麻布をかぶったボトル。先週も、その前の週もあった。でも——
「あれ、あのボトル、動きました?」
前回はもう少し端にあった気がする。今日は、私のほうに近い。
マスターが顔を上げて、穏やかに微笑んだ。
「そうですか?」
それだけだった。にこにこしているだけで答えになっていない。でも、このバーではそういうものらしい。二回通って、それくらいはわかるようになった。
「今夜も、おすすめをお願いします」
まだ自分では選べない。でも、三回目になると「おすすめをお願いする」ことに気恥ずかしさがなくなっている。知らないものを選ぶのが恥ずかしいのではなく、マスターに任せるのが信頼になっている——と思いたいだけかもしれないけれど。
「かしこまりました。少々お待ちください」
マスターが棚の整理を終え、カウンターの内側に戻りかけたところで、扉が開いた。
スーツ姿の女性が、少し躊躇うように入ってきた。名刺入れを片手に、店内を見回している。
「あの、ここ……ウイスキー専門のバーですよね? 知り合いに勧められて」
「いらっしゃいませ。どうぞ、お好きなお席に」
女性はカウンターの隅に腰を下ろした。背筋がまっすぐで、几帳面な人なのだろうと思った。名刺入れをバッグにしまってから、メニューを探すように棚を見上げた。
「水割りで、何か軽いもので……」
声は落ち着いていたけれど、どこか疲れた色がにじんでいた。マスターが水割りを差し出すと、一口飲んで、ようやく少し肩の力が抜けたようだった。
それからぽつりぽつりと話し始めた。
「実は、コードの掃除を任されてるんです」
掃除。コードの掃除。プログラムのことは詳しくないけれど、なんとなくイメージは湧いた。
「前任者が……3年前に辞めた方なんですけど、残したコードが大量にあって。静的解析っていうツールで『未使用です』って出てるメソッドが20以上。コメントアウトっていう、消したようで消してない状態のブロックも数百行」
「消していいものなのか判断がつかなくて」——と、彼女は言った。口癖のように。「消して何か壊れたら、私の責任になりますし」
掃除屋さん、と心の中で呼んだ。割り当てられた仕事がコードの掃除で、責任感の強さが姿勢にも言葉にもにじんでいる。大変そうだ。
ノートPCを取り出し、画面をカウンターに向けた。
| |
「active_methodだけが今のシステムで使われていて、それ以外は全部……たぶん、使われてないんです。たぶん」
その「たぶん」に、恐怖が詰まっているのが伝わった。
私は掃除屋さんに向かって、つい口を挟んでいた。
「うちもそういうの、あるんですよ。創業メンバーの田中さんが書いたコード、3年前から残ってて——怖くて消せないですよね、ああいうの?」
なぜそんなことを口にしたのか、自分でもわからない。掃除屋さんの「前任者のコード」という言葉に引っかかって、自分の会社のことがぽろっと出てしまった。
掃除屋さんが少し驚いた顔をして、それから共感するようにうなずいた。「わかります。書いた人への遠慮もありますよね」
マスターが答えなかった。
棚から下ろしたボトルを持ったまま、一拍。二拍——。ただ沈黙があった。考えているのか、聞き流したのか、私にはわからなかった。それから何事もなかったように、布でボトルを拭き始めた。
テイスティング——四半世紀の澱
マスターがカウンターの内側に戻り、一本のボトルを取り出した。私の前にグラスを置く。前の二回とは色合いが違った。深い琥珀色に赤みが差していて、光を通すと暗い宝石のように輝く。
「ボウモア 25年でございます」
「25年!」
思わず声が出た。ウイスキーには詳しくないけれど、「25年」が長いことくらいはわかる。前回より明らかに高そうだ。
「四半世紀をシェリー樽で過ごしたシングルモルトです。長い熟成はときに美しい複雑さを生みますが——同時に、澱を残すこともございます」
「澱?」
「底に沈む不純物です。取り除いても味に影響はありません。しかし、そこにあること自体が、ボトルの中身を濁らせます」
鼻を近づけた。甘い果実の奥に、重い煙のような香りが潜んでいる。前回のジョニーウォーカーよりもずっと深い。口に含むと、最初に甘みが広がって、それから遅れて重厚な苦みがやってきた。25年という時間の厚みが舌の上に乗っているようで、前の二回のどのウイスキーとも違う存在感があった。
「……おいしい。けど、重い」
「ええ。時間の重さは、味にも出ます」
マスターがカウンター越しに、掃除屋さんのほうに向き直った。
「お客さま、先ほどのコードを拝見してもよろしいですか」
掃除屋さんがノートPCの画面を差し出した。マスターはしばらく静かに目を通してから、口を開いた。
「この_legacy_batch_exportと_format_legacy_csv。呼び出し元はございますか」
「ないはずです。静的解析でも未使用と出ています。でも——」
「消して何か壊れるかもしれない、と」
「ええ。リフレクションとか、動的な呼び出しで使われてる可能性もゼロとは言い切れなくて……」
マスターが静かにうなずいた。
「その不安は正当です。しかし——名前をつけましょう。この状態を、Dead Code と呼びます」
Dead Code。死んだコード。名前だけで、冷たい響きがした。
私は掃除屋さんに身体を向けて聞いた。
「でも、置いてあるだけなら害はないんじゃない? 念のため残しておくのがリスク管理ってものでしょ?」
うちの会社でも、古い在庫は捨てずに倉庫に残している。新しい商品に干渉しなければ、それで問題ないはず——経営者としてはそう考える。
掃除屋さんが「そうなんです、そう思いたいんですけど……」と言いかけたところで、マスターがさっき棚から下ろしたボトルに目をやった。ラベルの読めない、中身のほとんど残っていないボトル。
「棚に古いボトルを並べ続けると、どうなりますか」
私と掃除屋さんの両方を見ながら、マスターは続けた。
「新しいボトルを置く場所がなくなります。そして何より——お客さまが棚を見たとき、どれが飲めるボトルでどれが空のボトルか、区別がつかなくなります」
確かに。壁一面に並ぶボトルの中に空のボトルが混じっていたら、選ぶのに困る。
マスターは掃除屋さんに向き直った。
「Dead Code が問題になる理由は3つあります」
なぜ問題なのか
「まず、認知負荷の増大です」
マスターの声は穏やかだったけれど、指摘は鋭かった。
「LegacyServiceを保守する方は、_legacy_batch_exportが使われているのかどうか、毎回確認しなければなりません。《読まなくていいコード》と《読むべきコード》の区別がつかない。それだけで、読む人の時間と集中力を奪います」
掃除屋さんが深くうなずいた。「まさにそれです。引き継いだとき、全部読もうとして3日かかりました。半分は読まなくてよかったコードだったのかもしれないのに」
「次に、変更への恐怖です。Dead Code のせいでクラスが大きく見え、《このクラスは複雑だ》と感じてしまう。実際には動いていないコードが、動いているコードへの変更を心理的に阻害します」
掃除屋さんの声が小さくなった。「……ファイルを開くたびに気が重くなるんです。行数が多いだけで、触りたくなくなる」
「最後に、偽の依存関係です」
マスターが画面を指さした。_format_legacy_csvの中の$nameと$id。
「この Dead Code がname属性を参照しているために、属性名を変更しようとしたとき、まだ使っている箇所があると誤認されます。存在しない依存の幽霊に振り回されるのです」
掃除屋さんの目が見開かれた。「3番目、まさにそれです。_format_legacy_csvが$nameと$idを使ってるから、name属性のリネームができないって言われて——」
「使われていないコードが、使われているコードの進化を止めている」
マスターがボウモアのボトルを軽く傾けた。
「——澱が、ウイスキーを濁らせるように」
場所を取るだけじゃなかった。私は自分の会社の倉庫を思い浮かべた。処分できない古い在庫のせいで、新しい商品の棚が足りないだけじゃなく、古い在庫の管理番号が新しいシステムの邪魔をしている——そういうことなのか。
ブレンド——敬意を持った退場
「じゃあ消せばいい、って話なんでしょうけど……」
掃除屋さんの声には、まだ恐怖が残っていた。
「その判断が怖いんです」
マスターが穏やかにうなずいた。
「恐れるのは正しい反応です。大切なのは、手順を持つことです」
手順1: 呼び出し元の追跡
「まず、本当に呼ばれていないことを確認します。静的解析だけでは不十分な場合があります」
Perlの場合、grep -rnでの直接検索に加え、can()や文字列でのメソッド名呼び出しがないかを確認する——とマスターは説明した。
掃除屋さんが身を乗り出した。「動的呼び出しの可能性はどうすればいいんでしょうか」
「Devel::Coverでカバレッジを計測してください。一定期間運用して、一度も通らないコードは——事実上、死んでいます」
「テストの網をかけて、反応がなければ確定、ということですか」
「ええ。——棚のボトルを少し動かして、誰かが気づくか観察するようなものです」
掃除屋さんが初めて小さく笑った。来たときの硬い表情が、少しだけ緩んだ。
手順2: deprecation マーキング
「確信が持てない場合は、即座に削除せず、まず非推奨であることを宣言します」
| |
「警告を出して運用します。一定期間、警告が一度も出なければ——確証を持って削除できます」
「罠を仕掛けるみたいですね」と掃除屋さんが言った。
「ええ。呼ばれていれば、名乗り出てくれますから」
私は横から口を挟んだ。
「ねえ、それって念のため残しておくのと何が違うの? 警告が出るか出ないかだけの差じゃない?」
掃除屋さんが私を見た。マスターも一度こちらに目を向けてから、ゆっくり答えた。
「よい着眼点です。《念のため残す》は、判断を保留しています。deprecation マーキングは、判断を実行しています。前者は時間が経つほど手がつけられなくなりますが、後者は時間が経つほど根拠が積み上がります」
保留と実行の違い。置いておくのと、仕掛けを置いておくのとでは、全然違うのか。「とりあえず残す」と「期限を決めて残す」——経営でも同じだ。期限のない「保留」は、ほぼ「永久に放置」と同義だと、身に覚えがある。
掃除屋さんが隣から私に向かってうなずいた。「そこ、私も同じこと思ってました。でも今の説明で……なるほどって」
手順3: 削除とバージョン管理への信頼
「確証が持てたら、削除します」
マスターが見せたのは、こういうコードだった。
| |
掃除屋さんが画面を見比べた。「……これだけ?」
「これだけです」
私が思わず声を上げた。「え、消しちゃうの? コメントで残しておかないの? バックアップは?」
「コメントアウトされたコードは、次に読む方を迷わせます」
マスターの声は穏やかだったけれど、はっきりしていた。
「《これは消していいコメントなのか、戻すべきコメントなのか》と。判断の負荷が、また一つ増えるのです」
「でも、必要になったら?」
「バージョン管理がすべての履歴を保持しています。必要になれば、いつでも取り出せます」
マスターはさっき棚から下ろしたボトルを、ちらりと見た。
「コメントアウトは《まだ未練がある》という状態です。——未練を断ち切ることと、敬意を失うことは、違います」
掃除屋さんが、しばらく黙っていた。マスターも急かさなかった。グラスの中の氷がかすかに鳴った。
「……手順があれば、やれそうです」
声が、来たときより一段軽くなっていた。
「怖いのは《消していいかわからない》であって、《消すこと自体》が怖いわけじゃなかったんですね」
マスターが静かにうなずいた。
「おっしゃる通りです。判断の根拠があれば、敬意を持って退場いただけます」
なぜこれで問題が消えるのか
「先ほどの3つの問題が、どう変わったか確認しましょう」
マスターが手を挙げて、一つずつ指を折った。
「認知負荷——LegacyServiceはactive_methodだけになりました。何をするクラスか一目でわかります」
「変更への恐怖——クラスが小さくなれば、影響範囲が明確になります。《このクラスに触りたくない》がなくなります」
「偽の依存関係——nameをリネームしたければactive_methodだけを見ればよい。幽霊の依存に怯える必要がなくなります」
掃除屋さんが深く息をついた。
「判断の根拠があれば、敬意を持って退場いただけます」
マスターの声は、さっき棚のボトルを布で拭いていたときと同じ温度だった。コードの話をしているのに、あの古いボトルを丁寧に箱にしまう所作と、同じことを言っている。
ラストオーダー——とりあえず動いてるし
掃除屋さんが立ち上がった。来たときの強張りが消えていて、表情が一回り柔らかくなっている。
「月曜にDevel::Coverを入れてみます。それで——根拠を作ってから」
「お気をつけて。役目を終えたコードへの敬意を、忘れずに」
掃除屋さんが小さくうなずいて、扉のところで振り返った。私にも軽く会釈する。
「ありがとうございます。話に付き合っていただいて。少し、気が楽になりました」
「頑張ってね、掃除屋さん」
——口に出してから、しまったと思った。でも彼女は笑って、扉の向こうに消えた。
店内に静けさが戻った。
マスターが棚の前に戻り、古いボトルをもう一度手に取った。柔らかい布で丁寧に拭いてから、木箱にそっとしまう。一連の所作が、さっきの「敬意を持った退場」そのものに見えた。
「マスター。そのボトル、捨てないんですか」
「蒸留所が閉鎖され、もう二度と造られないウイスキーです。棚に置き続けるのは新しいボトルの邪魔になりますが、このボトルが存在したという記録は——」
マスターがカウンターの下からテイスティングノートを取り出し、何かを書き留めた。
「——ここに残します」
前にも見た、革表紙の手帳。マスターが丁寧な筆跡で何かを書き留めていた。
ボウモア 25年の残りを傾けた。最初に飲んだときより、甘みの輪郭がはっきりしている。澱の話を聞いたあとだからか、「重い」とだけ思っていた味わいの中に、シェリー樽の甘さと煙の苦さが別々に感じられた。25年の重みも、底に沈む不純物も、このグラスの中にある。
……うちのも、3年か。
ボウモアの余韻が舌に残っているうちに、掃除屋さんの話が頭の中で田中さんのコードと重なった。
マスターがいつもの穏やかな顔で、カウンターを拭き始めた。
先週は「動いてるからいいのよね」で片づけた。今夜は同じ言葉が浮かんで、すぐに沈んだ。
——いいの。動いてるんだから。
マスターが木箱を静かにカウンターの下にしまい、店じまいの支度を始めた。
店を出ると、路地裏の夜風がぬるかった。春の終わりの匂いがする。
歩きながら、マスターが棚から下ろしたボトルのことを考えていた。——古いものには、古いなりの敬意が要るのだと、なんとなく思った。
🥃 マスターのテイスティングノート
本日の銘柄: ボウモア 25年 お客さまの症状: デッドコード(Dead Code)
ノージング(香り)── 問題の検知
静的解析で「未使用」と報告されるメソッドや、コメントアウトされたまま放置されたコードブロックがコードベースに点在していたら、このアンチパターンを疑いましょう。「念のため残してある」「前任者が書いたコードだから怖くて消せない」——この言葉が聞こえたら、ほぼ確定です。
パレット(味わい)── 問題の本質
Dead Code は「場所を取るだけ」ではありません。読む人の認知負荷を増やし(読むべきコードと読まなくていいコードの区別がつかない)、変更への恐怖を植え付け(クラスが本来より複雑に見える)、偽の依存関係で生きたコードの進化を阻害します。使われていないコードが、使われているコードの変更を止めている——それが Dead Code の本当の害です。
フィニッシュ(余韻)── 解決の方針
3つの手順を踏みます。①呼び出し元の追跡(grep -rn + Devel::Cover で本当に使われていないことを確認)、②deprecation マーキング(warn で非推奨を宣言し、一定期間監視して根拠を積み上げる)、③削除(コメントアウトではなく完全削除。バージョン管理が履歴を保持)。「念のため残す」は判断の保留ですが、deprecation は判断の実行です。
ペアリング(相性の良いパターン)
- Lava Flow —— Dead Code の大規模版。溶岩流のように固まった古いコードが地層をなす
- Devel::Cover —— Perl のコードカバレッジ計測ツール。Dead Code の客観的な根拠を提供する
- Single Responsibility Principle —— クラスの責務を絞り込むことで、Dead Code の発生自体を予防する
「役目を終えたものには、敬意を持って退場を」
