その日、「レガシー・コード・インベスティゲーション(LCI)」のドアは、同時に二度ノックされた。
「すみません、コードの相談を——」 「すみません、コードの相談を——」
私たちは顔を見合わせた。双子の姉妹が、同じタイミングで同じ事務所のドアを叩き、同じセリフを口にする。……まあ、よくあることだ。
私はアオイ。隣にいるのは妹のミドリ。同じ会社のバックエンドチームで、それぞれ別のデータのCSVエクスポート機能を担当している。
事務所の奥から、例のヨレヨレのトレンチコートが現れた。
「ほう。双子か」
コード探偵——自称——ロック。エナジードリンクを片手に、私たちを値踏みするように見つめている。
以降、私は心の中でこの男を「トレンチコート」と呼ぶことにした。だってそれ以外に印象がない。
「私はアオイです。こちらは妹の——」 「ミドリです」 「問題ない。2人ともワトソン君だ」
……いいえ、それは問題です。
「で、ワトソン君たち。何があった?」 「CSVエクスポートのバグを直したんですが——」 「直したら、もう片方にも同じ修正が必要で——」
トレンチコートが片眉を上げた。
「2人が同時に同じセリフを言うだけでなく、同じ悩みまで持ち込むとは。なかなか面白い事件だ」
現場検証:瓜二つの指紋
トレンチコートは2つのモニターに、それぞれのコードを映し出した。
| |
| |
2つのコードが横に並んだ瞬間、トレンチコートの口元が緩んだ。
「ほう……依頼人だけでなく、コードまで双子とは。これは興味深い」
「え? 全然違うコードですよ!」ミドリが身を乗り出す。 「そうです、扱うデータが違いますし……」私も続けた。
トレンチコートは人差し指を立てて、2つのコードを交互に指した。
「いいや。骨格は同じだ。彼らは変装しているだけさ。ほら、ここを見たまえ——データ取得、ヘッダー生成、行の整形、出力の結合。手順は完全に瓜二つだ」
言われてみれば、確かに——1、2、3、4のステップは、テーブル名やカラム名が違うだけで、流れは同じだ。
「……でも、それぞれ動いてはいるんです」 「ああ、今はね。だが君たちはさっき言ったはずだ——バグを直すたびに、もう片方にも同じ修正が必要だと」
トレンチコートはエナジードリンクを一口飲んだ。
「これは『コピペコード(Duplicated Code)』の典型的なにおいだよ、ワトソン君たち。そしてこのにおいは、放っておくと増殖する」
推理披露:家族の再統合
「解決策はシンプルだ。双子の『同じ部分』を親に引き上げ、『違う部分』だけを子に残す」
トレンチコートのキーボードが鳴り始めた。
1. 骨格の抽出
「まず、この2つのコードに共通する『手順書』を基底クラスに定義する。これが Template Method ——つまり『処理の骨格=テンプレート』を親が持つということだ」
| |
「あ、全部のメソッドをサブクラスに移せばいいんですね!」ミドリが声を上げた。
トレンチコートは首を振った。
「いいや。共通部分は親に残すんだ。export メソッドの流れ——データを取り、ヘッダーを作り、行を整形して結合する——この骨格は1箇所に集約する。差分だけを子に委ねる。それがTemplate Methodだよ、ワトソン君」
2. 差分の定義
「そして、双子それぞれが『自分だけの個性』を持つ部分——データの取り方、ヘッダーの中身、行の整形方法——だけを、サブクラスで定義する」
| |
「……待って」
私は画面を凝視していた。何かが引っかかる。
「この export メソッドの中で fetch_data や header_line を呼んでいますけど……これって、親クラスが子クラスのメソッドを呼んでいるってこと……ですか?」
「いい質問だ、ワトソン君A」

——Aは余計です。
「その通り。親クラスは手順だけを知っている。具体的にどんなデータを取るか、どんなヘッダーにするかは、子に任せる。つまり——」
「骨格は一つ、中身は自由に差し替えられる……!」
「ご名答。そしてもう一つ。バグが見つかったとき、骨格の修正は——?」
ミドリと私は同時に答えた。
「親クラスの1箇所だけ!」
……また声が揃ってしまった。トレンチコートがニヤリと笑う。
「双子というのは、コードにも伝染するらしいね」
事件の終わり:2つのテストが通る日
テストがすべてグリーンに変わった。Before版とAfter版の出力は完全に一致し、振る舞いは何も壊れていない。
「これで……片方を直してもう片方を忘れる、なんてことはなくなるんですね」
「私たちは双子だけど、コードまで双子にする必要はなかったのね」ミドリが溜息をついた。
「初歩的なことだよ、ワトソン君たち」
トレンチコートはコートの襟を立てた(室内は相変わらずPCの排熱で暑いのに)。
「さて、報酬だが——同じブレンドだが焙煎度だけ違うコーヒー豆を2袋いただこうか。骨格は同じ、差分は細部。まさにTemplate Methodだろう?」
私とミドリは顔を見合わせた。
「……ロックさん、それ普通にコーヒー豆が2袋欲しいだけですよね」 「失敬な。これはパターンの本質を体現したメタファーだよ」
私たちは呆れながらも、後日きっちり2袋を届けることになるのだった。 双子の依頼人と双子のコード。解決してみれば笑い話だが、あの瞬間のトレンチコートの推理は——悔しいけれど、鮮やかだった。
探偵の調査報告書
| 容疑(アンチパターン) | 真実(パターン) | 証拠(効果) |
|---|---|---|
| コピペコード(Duplicated Code)。ほぼ同じ処理が複数箇所にコピペされ、バグ修正も二重に必要になる。 | Template Method パターン。処理の骨格(テンプレート)を親クラスに定め、差分だけをサブクラスでオーバーライドする。 | DRY原則の達成。共通ロジックの修正は1箇所で済む。新しいエクスポート形式の追加もサブクラス1つで完了。 |
推理のステップ
- 共通骨格の発見: 複数のコードに共通する「手順」(データ取得→ヘッダー→整形→出力)を特定する。
- 基底クラスへの抽出: 共通の手順を
exportメソッドとして基底クラスに集約する。このexportが Template Method。 - 差分のオーバーライド: 各サブクラスは
fetch_data、header_line、format_rowだけを定義すればよい。
ロックより
瓜二つに見えるものほど、その違いにこそ価値がある。 君たちの双子のコードは、実は「同じであるべき部分」と「異なるべき部分」の区別がついていなかったんだ。Template Methodは、その境界線を引くための推理の道具さ。
今度コピペしたくなったら、まず自分に問いかけたまえ——「この骨格は、本当に2つ必要か?」
