往診
金曜の夕方は、戦場が静まる時間だ。
周りのデスクは空っぽで、蛍光灯の薄ぼんやりした明かりだけが残っている。私はモニタの前で、もう2時間も同じ関数を睨み続けていた。process_ringi()——200行超の、私の手作り稟議書承認フローだ。
来週月曜から、監査ログ機能を追加しなければならない。部長は「付け足すだけでしょ?」と軽く言ったけれど、この200行のif文の海に、いったいどこから手をつければいいのか。
「ヨリコさん」
隣のデスクの若手——新卒2年目の佐野くんが、帰り支度の鞄を肩にかけたまま、こちらを覗き込んでいた。
「あの……コード診療所って、知ってます?」
「コード……何?」
「往診もしてくれるらしいですよ」
佐野くんがメモを置いて去った後、私はしばらくそれを眺めていた。コード診療所。プログラムのお医者さん。冗談みたいな名前だ。でも、この200行を前に途方に暮れている今、藁にもすがりたい気分だった。
半信半疑で電話をかけた。30分後、フロアの入り口に2人の人影が現れた。
長身の男が、黒い鞄を片手にまっすぐこちらに向かってくる。その後ろから、白い上着を羽織った助手らしき人が穏やかな足取りでついてきた。
「どちら様——」
言いかけた私の声を遮るように、その助手が微笑んだ。
「大丈夫ですよ、ここはコード診療所です……あ、いえ、往診ですね」
ナナコさんと名乗った助手が自己紹介をしている間に、男はもう私のデスクの横まで来ていた。断りもなくモニタを覗き込んでいる。
不躾な人だ、と思った。でも、その目はモニタに釘付けではなかった。
視線が止まったのは、デスクの横の壁だ。
私が総務部時代から使っている、手書きの稟議回覧ルート図。B4の紙に回覧ルートを描いて、条件ごとに色分けした付箋をびっしり貼ってある。「10万以上→係長+課長」「50万以上→部長も」「100万以上→役員決裁」。紙の稟議書を20年さばいてきた、私の虎の巻だ。
男——先生らしき人物が、その図に右手を伸ばした。指先が付箋の1枚を辿る。
「……これが、本体か」
低い声。ぶっきらぼうを通り越して、独り言にしか聞こえなかった。
「あ、それは前の部署のときの……紙の稟議書の回し方のメモで」
「……コードは?」
「こ、これです」
モニタを指すと、先生はゆっくりと壁の図とモニタのコードを見比べた。何かに気づいたらしく、わずかに目を細めたように見えた。
触診
「座っていいか」
先生が私の椅子を指した。私が慌てて立ち上がると、先生はするりと座り、ものすごいスピードでコードをスクロールし始めた。200行の関数を——20秒で読み切ったように見えた。
そして、顔をしかめた。
「……巻きすぎだ」
「え?」
ナナコさんがすっと私のそばに来た。
「傷口の上に包帯を何重にも巻いてしまっている状態です。最初はちゃんと傷を保護できていたんですが、新しい傷ができるたびに上から包帯を足して……もうどこが元の傷口なのかわからなくなっているんです」
包帯。確かに、この関数には「あとから足した」処理がいくつもある。メール通知機能。部門別の分岐。フラグ変数。全部、仕様が追加されるたびに上から被せてきたものだ。
先生がさらにスクロールした。そして、止まった。
$needs_buchou_hanko, $needs_yakuin_hanko, $hanko_count, $ringi_status——
「……判子(hanko)」
ナナコさんが少し目を丸くした。
「変数名が……判子ですね」
顔が熱くなった。
「だ、だってそう考えないと分からないじゃないですか。部長の判子が要るか要らないか、って考えた方が直感的で……」
先生は答えない。代わりに、画面上のフラグ変数を4つ、指で順番に差した。$needs_buchou_hanko、$needs_log、$needs_mail、$needs_audit。
「4つ。……組み合わせ16通り」
ナナコさんが補足した。
「フラグが4つあると、組み合わせは2の4乗——16パターンになります。今はif文で全部書き分けていますが、新しいフラグが1つ増えるたびに……」
「倍……に、なる……?」
「はい。来月の監査ログ機能を入れると、5つのフラグで32パターンです」
胃がきゅっと縮んだ。
診断
ナナコさんが、私に向き直った。
「先生の診断をお伝えしますね。病名は 包帯過剰巻着症候群(Excessive Bandage Wrapping Syndrome) です」
「ほ、包帯……?」
「はい。傷口——つまり稟議の基本承認処理——の上に、ログ記録、メール通知、部長承認、役員承認という包帯を場当たり的に巻き重ねてきた結果、もはやどの包帯がどの傷に対応しているのかわからなくなっている状態です。包帯を1枚剥がそうとすると、別の傷口から出血——つまりバグが出るんですね」
まさに、そのとおりだった。先月、メール通知のタイミングを直そうとしたら、部長承認の分岐が壊れた。
「処方は Decorator(デコレーター) ——包帯解体・再巻着術です」
外科手術
先生がおもむろに立ち上がった。そして、壁に貼ってある私の稟議回覧ルート図の前に立った。
「ちょ、ちょっと、それは私の——」
先生は聞いていない。右手で付箋を1枚、ぺりっと剥がした。
「え?」
もう1枚。もう1枚。
「ちょっと! それ20年分のメモが——」
ナナコさんが私の肩にそっと手を置いた。
「大丈夫ですよ。先生は今、付箋を 役割ごと に分類しているんです」

見ると、先生はデスクの上に付箋を5つの山に並べていた。
1つ目の山——「係長承認」「起案者確認」。基本承認フロー と先生がペンで走り書きした。 2つ目——「記録」「タイムスタンプ」。ログ記録。 3つ目——「部門メール」「経理CC」。メール通知。 4つ目——「監査証跡」。監査ログ。 5つ目——「部長判子」「役員判子」。上位承認。
「この図のほうが、正しい」
先生が、モニタではなく付箋の山を指していた。
ナナコさんが説明を続けた。
「紙の稟議書では、承認ステップを付箋で追加したり外したりできましたよね? プログラムでも同じことをしましょう——包帯を1枚ずつ、必要なだけ巻く んです」
「……付箋を貼るように?」
「はい。これを Decoratorパターン と呼びます。基本の処理をラッピングして、上から機能を重ねていくんです。付箋を貼る順番で、承認フローが変わる——紙の世界でやっていたことと、考え方はまったく同じです」
先生がデスクの上に自分のキーボードを置いた。黒くて小さな、変わった形のキーボード。乾いた打鍵音が、静かなオフィスに響き始めた。
ナナコさんが、画面の横に立って解説を始めた。
「まず、すべての承認処理が共通で持つ インターフェース を定義します。process() メソッドだけのシンプルなものです」
| |
「次に、稟議の基本承認処理だけを行うクラスを作ります。これが 裸の傷口 ——包帯を全部剥がした状態です」
| |
ナナコさんが付箋の山を指した。
「そして、ここからが Decorator です。包帯の型紙 を1つ作ります」
| |
「inner というのが、包帯の 内側 にある処理です。この型紙を使って、1枚ずつ包帯を作っていきます」
ナナコさんが付箋の2つ目の山——「ログ記録」を指した。
「まずは、ログ記録の包帯です」
| |
「内側の処理($self->{inner}->process())を呼んで、その結果にログ記録を 追加 しているだけです。内側の処理には一切手を触れていません」
ナナコさんが3つ目の山を指した。
「メール通知も、同じ型紙から作ります」
| |
「部長承認も、役員承認も、監査証跡も——全部同じ型紙から、1枚20行足らずの包帯として作れます」
先生の打鍵が止まった。画面には、6つの小さなファイルが並んでいた。
ナナコさんが、一番大事なところを見せてくれた。
「組み立て方を見てみましょう。金額が100万以上の稟議なら——」
| |
「逆に、10万未満の軽い稟議なら——」
| |
「付箋の数を変えるだけです。if文は1行もありません」
私は画面を食い入るように見つめていた。あの200行の関数が消えている。代わりに、それぞれ20行足らずのファイルが並んでいる。
「……来月の監査ログ機能は?」
「もう入っていますよ。WithAuditTrail という包帯——いえ、Decoratorを1つ作っただけです」
「……200行のif文に手を入れなくていい?」
「はい。既存のコードは1行も触っていません」
目の奥がじわっと熱くなった。紙の世界でやっていたことが、コードでもできる。付箋を剥がしたり貼ったりするだけで、承認フローが変わる。
術後経過
テストが走った。すべて緑。
「……試せ」
先生が椅子を横にずらした。
私は座って、新しいファイルを1つ作った。WithEmergencyFlag——緊急フラグの付与。来月、総務部長が「緊急稟議にもフラグ立てて」と言い出すのが目に見えていたやつだ。
20行。テスト1つ。——通った。
以前なら、全部のif文に $is_emergency フラグを追加して、既存の32パターンのどこに入れるか悩んで、3箇所直して、別の2箇所が壊れて——。
今は、包帯を1枚巻くだけだ。
先生が帰り支度を始めた。鞄の中から黒い小さな箱を取り出した。
——上等な印鑑ケースに見えた。
この人も、判子を使うんだ。プログラマーの世界にも「判子」があるのだろうか。……なんだか、親近感がわいた。
ナナコさんがドクターの横に立ち、小声で言った。
「先生、USBアダプタのケース、印鑑ケースに見えますよ」
先生が首を傾げて、ケースを見つめている。何が問題なのかわかっていない顔だった。
先生が鞄を閉じ、出口に向かった。振り返らずに一言。
「……判子。変数名」
ナナコさんが少し申し訳なさそうに、でも確かな口調で言った。
「あの……$needs_buchou_hanko は……さすがにリネームしていただけると」
「……はい。$needs_manager_approval にします」
苦笑しながら答えた。
2人がオフィスのドアを抜けて去っていった。廊下に消える白い上着の背中を見送りながら、私は自席に戻った。
壁を見る。付箋が5つの山に分類されたままだ。20年間、紙に貼り続けてきたこの付箋たちが、今日初めて「パターン」という名前をもらった。
包帯を巻き直す。付箋を貼り直す。……やっていることは同じだったんだ。紙でもコードでも。
モニタには、6つの小さなクラスファイルが並んでいる。200行の巨大なif文はもう、どこにもない。
来週月曜の朝、部長が何を言い出しても——包帯を1枚、そっと巻くだけだ。
処方箋まとめ
| 症状 | 適用すべき | 経過観察 |
|---|---|---|
| 機能追加のたびに既存コードを直接書き換えている | ✓ | |
| フラグ変数の組み合わせで条件分岐が爆発している | ✓ | |
| 既存の処理に「非破壊的に」機能を追加したい | ✓ | |
| 実行時に動的に機能の組み合わせを変えたい | ✓ | |
| 追加する機能が1つだけで、今後も増える見込みがない | ✓ | |
| 処理の前後に機能を挟むのではなく、処理自体を完全に差し替えたい | ✓ |
治療のステップ
- 傷口の露出 — コアとなる処理(今回は基本承認フロー)を特定し、付加機能から切り離す
- 共通インターフェースの定義 — すべての処理(コアもDecoratorも)が
process()を持つようにする - 包帯の型紙の作成 —
Decoratorベースクラスを作り、内側の処理をinnerとして保持する委譲構造にする - 個別の包帯の作成 — ログ記録、メール通知、監査証跡など、各機能を独立したDecoratorクラスとして実装する
- 動的な巻着 — 稟議の条件に応じて、必要なDecoratorだけを組み合わせて巻き付ける
助手より
紙の付箋で承認フローを管理してきたご経験は、そのままDecoratorパターンの理解に繋がっていましたね。「必要な付箋だけ貼ればいい」という発想を、コードの世界でも活かしてください。
あの先生はこう言うと思います——「命名。直せ」。でも、それは技術への敬意の表れなんですよ。$needs_buchou_hanko が $needs_manager_approval になる日を、楽しみにしています。
——ナナコ
