一部分だけを、この呪文は許してくれない
私はセイラ。職人組合で、入会の受付係をしている。新しい職人が組合の門をくぐるたびに、その人を迎え入れる「入会の儀」を、一手に取り仕切るのが私の仕事だ。窓口に立って、日がな一日、人を見ている。派手さはないけれど、手続きが滞りなく回って、新入りが安心した顔で工房へ向かっていく——それを見届けるのが、私のささやかな誇りだった。
入会の儀は、一本の大きな呪文でできている。新入りが一人来るたびに、私はこの呪文を頭から唱える。すると、四つのことが順番に起きる。まず、名簿にその人を載せて会員の札を発番する。次に、見習い部屋と、その職種に合った初期道具を割り当てる。それから、歓迎の触れ状を送る。最後に、入会の統計を本部の簿冊へ計上する。登録して、設定して、通知して、計測する。この四つが、一本の呪文の中に、上から順に、ぜんぶ書き込まれている。
魔導式で言えば、こういう一つの魔法体——一つのクラスだ。
| |
data class は、いくつかの値をひとまとめに運ぶための器だ。入会を申し込む人を Applicant、登録された会員を Member、割り当てた部屋と道具を Profile として持つ。そして、入会の儀そのものが、こうだ。
| |
見慣れない書き方に、先に触れておく。LinkedHashMap は、入れた順序を覚えている連想配列(マップ)だ。名簿に登録した順を、そのまま保ってくれる。"M%03d".format(seq) は、番号を三桁の0埋めで文字にする書き方だ(1 なら M001)。when (applicant.craft) { … } は、値によって結果を選ぶ書き方で、ここでは職種に応じて初期道具の一覧を選び、そのまま tools に入れている。firstOrNull { it.name == ... } は、条件に最初に合う一人を返し、いなければ空(null)を返す——波かっこの中の it は、いま調べている一人ひとりを指す、仮の呼び名だ(ラムダに渡される値を、名前を省いて it と呼んでいる)。?.let { return it } は、その人がすでにいたら、そこで儀式を切り上げて帰る、という意味だ。
長らく、これで回っていた。だが組合が大きくなるにつれ、「触れ状の文面を今風にしたい」「新しい職種の初期道具を足したい」という直しの注文が増えてきた。そのたびに私は、この一本の呪文の、真ん中に手を入れることになる。
先日、肝を冷やした。歓迎の触れ状の文面を、一語だけ今風に直そうとして、呪文の真ん中の「通知のくだり」に手を入れたときだ。ところが、そのすぐ上に書いてあった「部屋割りのくだり」まで、一緒に手が触れてしまった。私は、新入りを一つ違う部屋へ案内してしまった。触れ状を直したかっただけなのに、隣に書いてあったというだけの部屋割りが、巻き込まれたのだ。困った顔で戻ってきた新入りに、私は平謝りした。その日のうちに気づけたから収まったが、指先が冷えた。応対の一つを直すのに、どうして、別の応対まで巻き添えにしなければならないのか。
それ以来、たとえ一語直すだけでも、私は入会の儀を頭から丸ごと唱え直して、登録も通知も計測も、ぜんぶ一緒に走るのを見届けないと、落ち着かなくなった。通知の文面を一度試したいだけでも、本物の名簿に登録が入り、本部の簿冊に計上が積まれてしまう。一つの働きだけを、独りで試せたら。いつも、そう思っていた。四つが一本に融け合っていて、一部分だけを、この呪文は、どうしても許してくれなかった。
窓口はそのまま、奥を分けたらしい
きっかけは、他の組合の受付係たちと集まる、月に一度の寄合の席だった。
隣の組合の受付係が、こんな話をした。「うちの入会の儀を、丘のアカデミーの見習いに直してもらったんだ」。彼女が言うには、その見習いは、受付の使い勝手はそっくりそのままに——つまり窓口は前と同じなのに、奥の作りだけを、役目ごとにきれいに分けてくれたのだという。「窓口はそのまま、奥を分ける、っていうのがね。受付を預かる身には、妙に引っかかる直し方でね」。
私も、その言い回しに引っかかった。窓口はそのまま、奥を分ける。それに、と彼女は付け加えた。「あの見習いには、傍らでずっと黙って見ている、年寄りの師がいるらしい。マグナスさま、と呼ばれていた」。
丘のルーク、そして師のマグナス。私は、あの一語直して部屋割りを巻き込んだ日のことを思い返しながら、その二人の名を覚えて帰った。翌日、私は入会の儀の呪文の写しを抱えて、アカデミーの丘を上った。
工房は、宙に浮かぶ光の粒と、古い書物の匂いで満ちていた。奥の机で、若い見習いが手を動かしている。見ると、一枚の紙に、ごちゃごちゃに絡まった一本の長い線が描いてあった。その子は、色の違う筆を何本か手にして、その絡まった線を、まず役目ごとに——ここは赤、ここは青、と塗り分けている。塗り分けたあとで、色の変わり目のところで、別々の紙へ一本ずつ、線を写し取っていく。
「切ってから分けるんじゃない……役目で分けてから、切るんだ」。そう手元で独りごちながら。
その傍ら、卓の隅に、年寄りが一人座っていた。卓上に、小窓が一つだけ空いた小さな衝立を立てて、その奥に、木でできた小さな人形を数体、並べている。そして、窓の内側で、人形を一体ずつ、順に前へ送り出しては、また引っ込める。表の小窓からは、いつも一体しか見えない。それをまた繰り返している。私には、その手すさびが、退屈しのぎにしか見えなかった。何をしているのかは、気にも留めなかった。
私が声をかけると、見習いは筆を置いて顔を上げた。「あ……入会の儀の、ご相談ですか」。これがルークか。私は呪文の写しを卓に広げ、事情を語った。四つの働きが一本に詰まっていること。先月、通知を直そうとして部屋割りを巻き込んだ一件。今も、一語直すだけで儀式を丸ごと唱え直している綱渡りのこと。
ルークは写しをじっと見て、静かに言った。「これは……四つの違う働きが、一つの呪文に、上から順に、ぜんぶ詰め込まれていますね。だから、通知を直そうとすると、すぐ上の部屋割りに、手が触れてしまう」。
そのとおりだ、と私は頷いた。「一部分だけ、を、この呪文は許してくれないんだよ。ぜんぶが、一本に融けてる」。
こういう、一つのクラスが、変更する理由の違う働きをいくつも抱え込んで、一箇所の直しが広い範囲に響いてしまう魔導式を、神クラスと呼ぶのだそうだ。ひとつの魔法陣に、攻撃も回復も飛行も詰め込んだような、欲張りな陣。まさに、私の入会の儀のことだった。
手が、先に走る
ルークは、写しをもう一度見つめると、宣言もぼやきもせず、いきなり手を動かし始めた。呪文の並びを目で追いながら、紙にクラスを次々と描いていく。私には、その勢いが、少し前のめりに見えた。
呪文は、登録して、設定して、通知して、計測する、という手順で並んでいる。ルークは、その区切りごとに、クラスを一つずつ立てていった。登録するやつ、設定するやつ、通知するやつ、計測するやつ。そして、そのクラスの間に、「これが済んだら、これを呼んで」と、依存の矢印を描き足していく。登録の次に設定、設定の次に通知、通知の次に計測。一本の手順が、そのまま、クラスの鎖になっていく。
ルークが描いていたのは、こういう形だった。
| |
これは、ルークが盛りかけて捨てた案なので、細部まで追わなくていい(TODO() は「まだ中身を書いていない」という印だ)。目で追ってほしいのは、next.run(...) という一手が、後ろのクラスを呼ぶために入っていることだ。登録のクラスは「次に設定を呼ぶ」ことを自分で知っていて、設定のクラスは「次に通知を呼ぶ」ことを自分で知っている。登録・設定・通知の三つは、それぞれ、自分の次を呼ぶ責任まで抱えている(末尾の計測だけは、鎖の終わりなので次がない)。こうして、四つのクラスが、一本の鎖につながっていく。
最後の、通知から計測へと向かう矢印を引いたところで、ルークの筆が止まった。私にも、紙の上で、矢印がひと続きの鎖に入り組んでいくのが見えた。組み立てるにも、後ろから順に相手を渡して、RegisterStep(ConfigStep(NotifyStep(MeasureStep()))) と、数珠つなぎにするしかない。ずいぶん、こみ入った形だ。
(また、ややこしくする気か。奥を片付けると聞いて、来たんだが)。私は思わず、眉をひそめた。ルークの手が止まったのを見て、私の中で、あの部屋割りを巻き込んだ日の、指先の冷たさが、ふっと蘇る。やっぱり、そう簡単に、切り分けられるものじゃないのか。声には出さなかった。ただ、期待した分だけ、肩に力が入った。
ルークの向こうで、隅の老人は、あいかわらず衝立の奥の人形を、一体ずつ順に送り出していた。私は、それが目に入っても、やはり気に留めなかった。
切る場所が、逆だった
ルークは、鎖だらけの紙から、筆を離した。そして、さっき役目を塗り分けていた、あの色筆を、もう一度手に取った。
縺れた矢印が走る紙の上に、今度は、線ではなく「役目」を、色で塗り直していく。登録の働きを一つの色、設定を別の色、通知を、計測を。すると、手順の矢印は色の下に沈み、代わりに、同じ色でまとまった島が、いくつか浮かび上がってきた。役目の島だ。そして、島と島の間には、一本の窓口だけが、ぽつんと残った。
「……切る場所が、逆だった」。ルークが、低く呟いた。「手順で切ってた。役目で、切るんだ」。
そして、自分の手元の島を見つめたまま、言葉を継いだ。「手順の区切りでクラスにしたから、それぞれが『次に誰を呼ぶか』を抱え込んで、鎖になった。通知を直したくても、通知のクラスが、計測を呼ぶ責任まで持っている。だから、独りにできない。……役目で分ければいい。登録は登録だけ、通知は通知だけ。互いに、呼ばせない。呼ぶ順番のほうは、窓口ひとつに、預ける」。
私は、その様子を、ただ見ていた。誰かに問われたわけでも、急かされたわけでもない。あの見習いは、自分で盛りかけて、自分で手を止めて、自分で引き返した。受付を預かってきた私には、途中で引き返すのが、どれだけ難しいかが、身にしみて分かる。
「分ける、が悪かったんじゃない」。ルークは、自分に言い聞かせるように言った。「どの向きで分けて、順番を誰に持たせるか、だ」。
このとき私は、まだ半信半疑だった。手順で切っても、役目で切っても、結局できあがるのは「登録・設定・通知・計測」の同じ四つの箱だろう。何がそんなに違うのか。——だが、あとで分かる。同じ四つでも、その四つが互いを呼び合って一本の鎖になるのか、それとも、順番を窓口ひとつに預けて、めいめいが独り立ちの島になるのか。違うのは、箱の顔ぶれではなく、箱と箱をつなぐ配線のほうだった。
ルークは手元の羊皮紙に、青と金の光で描かれた二つの魔法回路を並べてみせた。それは、彼が今しがた頭の中で組み立て直した、新しい「配線」の blueprint(設計図)だった。

「ね?」とルークは二つの魔法回路を順に指さした。
「左側が、さっき僕が手順順に作りかけた『鎖』です。一見するとクラスに分かれていますが、自分の仕事を終えたクラスが、次のクラスを自分で呼んでいます。これだと、隣り合うクラス同士が直接結ばれてしまって、結局は一本の太い呪文だった頃と変わらない。通知だけを独りで試そうとしても、その先にある計測まで連動して走ってしまいます」
彼は次に、右側の魔法回路を指でなぞった。
「でも、右側の形なら、四つのクラスは互いのことを一切知りません。自分がやるべき『役目』だけを静かにこなして、次の人を呼ぶ手札も持っていない。その代わり、順番をコントロールする『窓口』をひとつだけ上に立てて、段取りはすべてそこに預けるんです。これなら、一本の鎖を完全に解きほぐせます」
役目で、分ける
ルークは、色分けした紙をそっと机に置くと、新しい魔導式に取りかかった。「四つの役目を、それぞれ独りで働ける専門家にします。そして、順番を取り次ぐ窓口を、一つだけ立てます」。
まず、四つの専門家から。
| |
ここでルークが言った「役目」というのが、設計の言葉で言う責務だ。そのクラスが受け持つ役目のことで、言い換えれば、そのクラスを「直したくなる理由」のことでもある。関係する働きを一つにまとめ、関係ない働きは別に切り離しておく——これを、関心の分離という。
「登録は登録の名簿だけ、通知は触れ状の控えだけを持ちます」とルーク。「それぞれが、自分の役目に要るものだけを持っていて、他の役目のことは、何も知りません」。
私は、その「役目」というのが、まだ少しつかめなかった。「その役目というのは、どう見分けるんだ。登録も通知も、同じ入会の儀の一部だろう」。
「どういうときに直したくなるか、で見分けます」とルークは言った。「触れ状の文面を今風にしたい——これは、通知を直したい理由です。新しい職種の初期道具を足したい——これは、部屋割りを直したい理由。直したくなる理由が別なら、それは別の役目なんです。理由の違うものを一つに混ぜて書いていたから、通知を直そうとして、隣の部屋割りまで巻き込まれた」。
私は、あの一語直して部屋割りが巻き込まれた日を、思い出していた。「……直す理由が違うものを、別々にしておく、ということか」。
「そうです」とルーク。「では、通知の文面だけ直したいとき、登録まで走らせずに、済むのか」——私が知りたかったのは、そこだった。ルークは頷いた。「済みます。通知のクラスは、他の誰も呼びません。通知だけを、独りで試せます」。
関係ないところが、巻き込まれない。私は、ようやく胸のつかえが少し降りるのを感じた。
順番は、窓口ひとつに
「そして、この四人の専門家を束ねる、窓口を立てます」。ルークは、島と島の間に残った、あの一本の窓口を、魔導式にした。
| |
こうして、複雑になった奥を、一つの窓口の裏に隠し、使う側には簡潔な入口だけを見せる定石を、Facade(ファサード)と呼ぶのだそうだ。建物の正面を意味する言葉らしい。使う側は、奥に四人の専門家がいることを知らなくていい。ただ onboard という窓口の一手を叩けば、あとは窓口が、登録・設定・通知・計測を、順番に取り次いでくれる。
見慣れない書き方に、触れておく。窓口の頭にある class OnboardingService(private val registry: MemberRegistry, …) は、使う四人の専門家を、自分の中で勝手に作るのではなく、外から渡してもらって、自分の中に持っておく、という書き方だ。こうしておくと、あとで試すときに、たとえば通知役だけを独りで取り出して確かめる、といったことがしやすくなる。
私は、ここで一つ、引っかかった。「さっき君が鎖にしかけた書き方も、クラスに分けてはいたよな。あれと、今のこれは、どう違うんだ。どっちも、分けているだろう」。
ルークは、捨てた案の紙を、もう一度こちらに向けた。「さっきの通知役は、こう書いていました」。
| |
「next.run で、自分で次の計測役を呼んでいます。次を呼ぶ責任を、通知役が、自分で抱えていた」。そして、採用した形を指す。
| |
「今度の通知役は、次を呼びません。呼ばれもしません。順番は、窓口の onboard だけが持っています」。ルークは、二つの紙を並べた。「分けるかどうか、じゃなかったんです。どの向きで分けて、順番を誰に持たせるか、でした。手順で切って、互いに呼ばせれば、鎖になる。役目で切って、順番を窓口ひとつに預ければ、はじめて、解ける」。
各クラスが、次に誰を呼ぶかを知っているか、いないか。似た四つのクラスの、たった一つの違いは、そこにあった。通知役が次を呼ばないから、通知役は、独りで立てられる。独りで、試せる。
私は、念のため確かめた。「では、この窓口さえ立てれば、片付くのか」。
「いえ、逆です」とルークは、はっきり言った。「先に、役目で分けたから、窓口が『順番を取り次ぐだけ』の、薄いもので済むんです。もし、分けずに、この窓口の中へ、四つの働きの中身を全部書き込んだら——窓口が、名前を替えただけの、元の神クラスに戻ります。分けるのが先で、窓口は、後なんです」。
(ちなみに、Kotlinには、別の部品へ処理を丸ごと横流しする委譲の書き方もある。だが窓口の値打ちは、四つの段取りを組み立てることにあって、ただ横流しするのとは違う。だから onboard は、普通のメソッドとして書く。)
仮の受付で、独りずつ試す
「本物の入会名簿に手を入れる前に」とルークは言った。「結界の中に、仮の受付を立てて、登録・設定・通知・計測が、それぞれ別々に、独りでちゃんと働けるかを確かめます」。
模擬詠唱——本番の前に、安全な結界の中で試しに詠唱して、確かめる作法だ。ルークは、こんな三人の申込者を、試しの元にした。
| |
会員の札は登録順に M001、M002、M003。部屋は、割り当てた順に101号室から。道具は職種ごとに決まっていて、石工のように表に無い職種には、既定の「汎用道具箱」が渡る。
まず、窓口経由で三人を迎えると、名簿も部屋も触れ状も計上も、狙いどおりに揃うこと。次のコードに出てくる assertEquals は、狙いどおりの形と、実際にそうなった形とを、照らし合わせる詠唱だ。profileOf(id)!! の !! は、「ここは必ず値がある」とみなして中身を取り出す書き方で、もし空(null)ならその場で止まる。
| |
次に、私がいちばん確かめたかったこと——通知役を、たった独りで働かせられること。
| |
登録役も、設定役も、計測役も、一つも用意していない。それでも、通知役は独りで、ちゃんと触れ状の控えを残した。名簿を汚さず、本部の簿冊に計上を積むこともなく、通知だけを試せる。あの、一部分だけを許してくれなかった呪文が、嘘のようだった。
三つ目は、私が本当に念を押したかったところだ。奥を分けても、書き換える前の一本の呪文と、寸分同じ入会の儀になること。
| |
「これが、いちばん大事なところです」とルーク。「奥を役目で分けても、書き換える前の呪文と、まったく同じ結果になる。受付のやり方も、出来上がる名簿も、触れ状も、一文字も変わっていない——それを、機械の目で照らして確かめます」。
前と寸分同じ。私が心配していた一点に、この三行がそのまま応えていた。設計を整えただけで、中身は変えていない。だから、事故にはならない。最後に、同じ人が二度来ても、二重に迎え入れないこと。
| |
すでに名簿にいる人なら、窓口はそこで儀式を切り上げる。触れ状が二重に飛ぶことも、計上が二重に積まれることもない。これは、書き換える前の呪文と、まったく同じふるまいだ。結界の中の仮の受付は、すべて、狙いどおりに通った。
通知だけ、独りで触れる
役目ごとに分けられ、一つの窓口で束ねられた入会の儀を、私は受け取った。窓口は一つ。その奥で、登録・設定・通知・計測が、それぞれ独立した専門家になっている。
「これなら、触れ状の文面を直したいとき、通知役だけを開けばいいんだな」と私は言った。「登録も、計測も、走らせずに」。
「はい」とルーク。「窓口の中の順番は変わりませんから、受付のやり方は、前とそのままです。奥の一人だけを、独りで直せます」。
私は、念のため確かめた。「では、この窓口さえあれば、この先どんな直しも、安全なのか」。
ルークは、正直に答えた。「いえ。役目で分けたから、一つを直しても、隣に手が届きにくくはなりました。でも、窓口の中の『順番』そのものを書き替えれば、儀式の流れは変わります。何でも安全になる魔法ではなく、どこを触れば、何に響くのかが、はっきり見えるようになった、ということです」。
「それで、十分だよ」と私は言った。「どこに響くのか分からないのが、いちばん怖かったんだ」。
私は、「試しに、私の手でやってみていいか」と切り出した。まず、通知役だけを独りで呼んで、前から気になっていた触れ状の文面を、一語だけ変えて、控えを確かめる。登録も、計測も、走らない。指先が、拍子抜けするほど軽かった。次に、窓口経由で新人を一人迎えて、名簿と部屋と触れ状と計上が、ちゃんと揃うのを見る。一部分だけを触る、というのが、こんなに当たり前にできるとは。あの日の指先の冷たさは、もう無かった。
私が帰り支度をしていると、それまで衝立の奥で人形を送り出すばかりだった隅の老人が、その手を、ふいに止めた。そして、こちらへ——ルークにではなく、私に——ゆっくりと視線を向けた。何か確かめたいことがある、という、穏やかな目だった。
「あの子の引いた線、あなたにはどう映ったね」。
詰めるでも、試すでもない、静かな問いだった。私は面食らいながらも、受付柄、思ったままを返した。「……分ける前より、どこに何があるか、はっきり見えました。窓口は一つのまま、奥が、役目でちゃんと片付いていて」。
老人は、小さくうなずいただけで、また人形へ手を戻した。その所作を見て、私はようやく腑に落ちた。ああ、この方が、あの子のお師匠さまか。ルークが去り際に「マグナスさま、失礼します」と会釈したのが、それを確かめさせた。あの黙って見ていた人は、この日、口を開いたのは、その一問きりだった。
組合へ戻った私は、さっそく、通知役だけを独りで開いて、前から気になっていた触れ状の文面を、今度こそ直してみた。登録も、計測も、走らない。直して、試して、また直して。関係ないところが、もう、巻き込まれない。一つずつ、独りで触れる。ただそれだけのことが、私の受付を、こんなに軽くするのか。窓口はひとつのまま、私は今日、奥の一人と、ようやく落ち着いて向き合えた気がした。
📖 見習い魔術師ルークの魔導書メモ(Luke’s Spellbook Notes)
- 修復した呪文(クラス/モジュール名):
MemberRegistry(登録)/ProfileInitializer(初期設定)/WelcomeNotifier(通知)/SignupMetrics(計測)=役目ごとに分けた四人の専門家。OnboardingService(窓口=Facade。呼ぶ順番の取り次ぎだけを持つ) - 乱れの要因(アンチパターンの課題):
- 入会の儀の
OnboardingWizardが、登録・初期設定・通知・計測という、変更する理由の違う四つの働きを、一つのメソッドに手順順で抱えていた(神クラス)。現状は正しく動くが、通知を一語直すだけでも、すぐ上の部屋割りに手が触れて壊す危険があり(実際に一度、部屋割りがずれた)、通知だけを独りで試すこともできなかった。
- 入会の儀の
- 過剰設計の反省(背伸びの過ち):
- 神クラスの手順の並びを見て、その区切りごとにクラスへ分け、各クラスが次のクラスを自分で呼ぶ鎖(
next.runの数珠つなぎ)にしかけた。だが、段取り(呼ぶ順番)の知識が各クラスに散り、一つを直すと前後まで巻き込む——神クラスを「小さな神クラスの鎖」に切り分けただけだと気づき、手を止めた。分けるのが悪いのではなく、手順で切って互いに呼ばせたのが、逆だった。
- 神クラスの手順の並びを見て、その区切りごとにクラスへ分け、各クラスが次のクラスを自分で呼ぶ鎖(
- 魔術の定石(学んだ設計パターン):
- 責務分割 + Facade。変更する理由(役目=責務)ごとに専門クラスへ分け、各クラスは互いを呼ばず、自分の役目だけを持つ。複雑になった奥を、
OnboardingServiceという一つの窓口(Facade)で隠し、窓口だけが呼ぶ順番を持つ。使う側は、窓口だけを知ればよい。手順で切って互いに呼ばせると鎖になり、役目で切って順番を窓口ひとつに預けると解ける——違いは、どの軸で分け、段取りを誰に持たせるか、だった。
- 責務分割 + Facade。変更する理由(役目=責務)ごとに専門クラスへ分け、各クラスは互いを呼ばず、自分の役目だけを持つ。複雑になった奥を、
- 模擬詠唱の記録(検証のポイント):
- 窓口経由で入会の儀が通ること、通知役などの専門家が単独でも独りで働けること(=一部分だけを試せる)、書き換える前の一本の呪文と寸分同じ結果になること(=設計を変えても中身は変わらない)、同じ人を二度迎えても二重に迎え入れないことを確かめた。
- ちなみに:
- 複雑な奥を一つの窓口で隠す定石を Facade と呼ぶ。ただし窓口は「取り次ぎ(段取りの合成)」に徹すること。奥を役目で分けずに、窓口へ中身を全部書き込むと、窓口が「ラベルを替えただけの神クラス」になる(Fat Facade)。だから、分けるのが先、窓口は後。似た定石に、相手を共通の形へ変える Adapter、同格の面々の相互通信を集める Mediator があるが、いずれも狙いが違う。
- 師匠マグナスの格言:
- 「あの子の引いた線、あなたにはどう映ったね」(この日、マグナスさまは終始無言で、衝立の奥の木偶人形を順に送り出すばかりだった。口を開いたのは、依頼人セイラへの、この一問だけ。師の答えではなく、依頼人が持ち帰った言葉を、格言の代わりに記しておく——「分ける前より、どこに何があるか、はっきり見えました。窓口は一つのまま、奥が、役目でちゃんと片付いていて」)
