はじめに
きっかけは、ふと浮かんだ一文だった。
ドメイン駆動設計を夫婦の関係に置き換えるととても面白いのでは。お互いに好きなドメインを好きなだけ大きくできるし、インターフェイスを持つことでお互いが適切にハンドシェイクできる。
ただの思いつきの比喩だ。ところが書き出してみると、DDD(ドメイン駆動設計:業務領域の言葉を中心にソフトウェアを設計する手法)の語彙が、気味が悪いほどそのまま当てはまる。境界づけられたコンテキスト、ユビキタス言語、共有カーネル、腐敗防止層、結果整合性。どれも、家庭で実際に起きていることの名前になっている。
とはいえ、当てはめて遊ぶだけなら 5 分で終わる話だ。この記事で書きたいのはその先で、テーマは二つある。
- 境界は「制限」ではなく「自律の前提」:境界を切るのは相手を締め出すためではない。相手の承認なしに自分の領域を育てられるようにするためだ。マイクロサービスを切る動機と、まったく同じ理屈になる。
- そして、この比喩は最後に壊れる:ソフトウェアの設計は「インターフェイスを固定して、内部を自由に変える」ためにある。ところが人間は、内部が変わるとインターフェイスのほうを作り直さないといけない。この壊れ方が、そのまま DDD 側への示唆になる。
順に解いていく。
1. 出発点:境界があるから、好きなだけ大きくできる
元ネタの直感を要約すると、こうなる。
「相手の領域に口を出さない代わりに、自分の領域は好きなだけ広げていい」
これを DDD の言葉に翻訳すると、境界づけられたコンテキスト(Bounded Context)になる。あるモデルが有効な範囲を線で囲い、その中では中の言葉と中のルールだけが正しい、と決める考え方だ。
ここで大事なのは、境界の目的が「隔離」ではないことだ。目的は自律にある。
境界が切られていない領域では、何かを変えるたびに相手の合意が要る。カメラを 1 本買うのに家族会議が必要な状態を想像すればいい。合意そのものが悪いのではない。合意が律速になるのが問題だ。判断の回数だけ、待ち時間が増えていく。
境界を切ると、この待ち時間が消える。趣味のドメインの中で完結する変更は、相手にレビューを頼まなくていい。ソフトウェアで言えば、他チームのリリース列に並ばずに自分のサービスをデプロイできる状態だ。マイクロサービスを切る一番の動機も、性能ではなく、この独立デプロイ可能性にある。
そして、境界を切ったうえで必要になるのがインターフェイスだ。内部を見せ合うのではなく、公開された窓口越しに合意する。「詳細は聞かないけど、何時に帰るかだけ教えて」は、実装隠蔽と契約の話そのものだ。
相手の内部実装を隅々まで理解しようとする努力は、善意であってもしばしば報われない。ときには越境にもなる。DDD が教えてくれるのは、理解ではなく契約でつなぐという選択肢がある、ということだ。
2. 語彙はどこまで効くか
主要な概念の対応を、先に一覧にしておく。
| DDD の概念 | 家庭での対応物 |
|---|---|
| 境界づけられたコンテキスト | 相手の仕事や趣味。何が正しいかは当人が決める |
| ユビキタス言語 | 「片付けた」「あとでやる」の定義 |
| 共有カーネル | 家計・予定・子ども |
| 腐敗防止層 | 職場のストレス、実家の価値観の持ち込み方 |
| 結果整合性 | 「決まったら共有」で足りる領域 |
2-1. ユビキタス言語 ― 「片付けた」の定義がズレる
ユビキタス言語とは、そのコンテキストの中で意味が一つに定まった言葉のことだ。開発者と業務担当が同じ語を同じ意味で使う。DDD の中核にある考え方になる。
家庭で最初に事故るのは、たいていここだ。「片付けた」「あとでやる」「もうすぐ着く」。どれも定義がズレる。
型で書くと、ズレの正体が見える。
// コンテキスト A の「片付いた」
type Tidied = {
floorIsClear: true; // 床にモノがない
};
// コンテキスト B の「片付いた」
type Tidied = {
floorIsClear: true;
everyItemHasItsPlace: true; // すべて定位置に戻っている
surfaceIsWiped: true; // 天板を拭いてある
};
同じ名前、違う型。これは「よくある不注意」ではなく、構造的に必ず起きることだ。コンテキストが違えば言葉の意味は違う。それが境界の定義そのものなのだから。
だから対策は「言葉を統一しよう」ではない。統一は、たいてい片方の意味をもう片方に押しつける形になって失敗する。正しいのは翻訳を用意することだ。コンテキストをまたぐときに、明示的にマッピングする。「片付けた(床だけ)」と言い直すだけで、障害の半分は消える。
2-2. 共有カーネル ― 強い整合性が要る唯一の領域
共有カーネル(Shared Kernel)は、複数のコンテキストが同じモデルを共同所有する統合パターンだ。DDD では「便利だが危険」と扱われる。片方が勝手に変えると、もう片方が壊れるからだ。だから共同所有する範囲は小さく保ち、変更は必ず合意のうえで行う。
家庭でこれに当たるのが、家計・予定・子どもだろう。ここだけは結果整合性では足りない。片方が知らないうちに大きな支出を決めたら、それは共有カーネルへの無断コミットになる。
重要なのは、共有カーネルは小さいほど良いという原則がそのまま効くことだ。「夫婦なんだから全部共有すべき」は、設計としてはカーネルの肥大化にあたる。後述する密結合は、たいていここから始まる。
2-3. 腐敗防止層 ― 外の価値観を、そのまま通さない
腐敗防止層(Anticorruption Layer)は、外部システムのモデルが自分のモデルを侵食しないよう、境界で変換をかます層だ。歪んだデータ構造を持つレガシー API を扱うとき、それを自分のドメインに持ち込まないために置く。
家庭に流入してくる「外部システム」は多い。職場のストレス、実家の価値観、SNS で見た他人の暮らし。どれも別のコンテキストのモデルであり、無変換で流し込むと自分たちのモデルが壊れる。
「実家ではこうだった」をそのまま要求として通せば、それは外部モデルの直結だ。翻訳が要る。「自分はこういう理由でこうしたい」という、自分のドメインの言葉に直してから通す。これが腐敗防止層の仕事になる。
2-4. 結果整合性 ― 全部を同期しなくていい
分散システムでは、すべてを常に一致させようとするとコストが跳ね上がる。だから多くの領域は結果整合性で運用する。今この瞬間ズレていてもいい、いずれ揃えばいい、という割り切りだ。
家庭も同じだ。相手の仕事の進捗も、読んでいる本も、リアルタイムに同期する必要はない。「決まったら共有」で足りる領域のほうが多い。
そして、たぶん一番よくある事故は、どこが結果整合性でよくて、どこが強整合性なのかを取り違えることだと思う。旅行の日程を「決まったら言うね」で運用すると壊れる。逆に、趣味の買い物を毎回同期していたら、今度は速度が死ぬ。
3. アンチパターン ― 切りすぎと、つなぎすぎ
比喩の面白さは、うまくいく話より失敗の形のほうに出る。ここが本題だ。
3-1. 分散モノリス(切りすぎ)
分散モノリスは、サービスを分けたのに互いに依存し合っていて、結局まとめてしか動かせない状態を指す。境界を引いたコストだけ払って、自律のメリットを得られていない。
家庭版はこうなる。役割はきれいに分けたはずなのに、何をするにも確認と調整が必要で、分ける前より遅い。「私の担当なので勝手にやります」と「でも報告と相談は毎回します」が同居すると、これになる。
判定は簡単で、分けたのに速くなっていないなら、それは分散モノリスだ。
3-2. 密結合(つなぎすぎ)
逆に、共有カーネルを広げすぎるとどうなるか。あらゆる変更に相手のレビューが必要になる。すべてを共有した状態は、一見すると仲が良さそうに見える。だが設計としては、変更容易性が最悪の状態だ。
3-3. 両者に共通する失敗
切りすぎも、つなぎすぎも、症状は正反対に見える。だが原因は同じところにある。一度引いた線を、固定してしまったことだ。
そして、この「固定」こそが、比喩が壊れる場所につながっていく。
4. 比喩が壊れる場所 ― インターフェイスのほうが動く
ここまでは、DDD の語彙が気持ちよく効く話をしてきた。だが、正直に書いておきたい破綻点がある。
ソフトウェアの設計における境界は、インターフェイスを固定して、内部を自由に変えるためにある。契約さえ守れば、中身は好きなだけ作り替えていい。安定した契約こそが、自律の土台になる。
人間関係は、そうならない。内部が変わると、インターフェイスのほうを作り直さないといけない。
転職して働き方が変わる。子どもが生まれる。体調を崩す。価値観が変わる。そのたびに、家事の分担も、お金の決め方も、「これは相談すること/しないこと」の線も、すべて意味が変わる。契約は動かないまま、実態だけが動いていく。
つまり、契約の再締結のほうが運用の本体なのだ。安定したインターフェイスを設計して、あとは中身を自由にやろう、という発想でいくと、いずれ破綻する。というより、破綻したときに「相手が契約を破った」という誤った診断をしてしまう。実際に起きているのは、契約が現実に追いつかなくなっただけなのに。
ソフトウェアで言えば、これは破壊的変更が発生し続けるドメインだ。そんな相手とバージョン固定の契約を結んでも、意味がない。
5. だから、本番はコンテキストマップの描き直し
コンテキストマップは、どんなコンテキストがあり、それらがどう繋がっているかを一枚に描いた図だ。DDD ではこれを、あるべき姿ではなく「現状の記述」として描く。
比喩から実務に戻ってくると、示唆はここに落ちる。マップは成果物ではなく、運用対象だ。
一度描いて壁に貼って終わり、というのが、いちばんよくある失敗だと思う。組織は動く。人は入れ替わり、事業は変わり、去年の境界は今年ズレている。にもかかわらず、更新されないマップだけが正しい顔をして残る。
だから本番は、定期的に描き直す作業のほうになる。点検する項目は、この記事でたどってきた三つで足りる。
- 変更のたびに他チームの合意が要るようになっていないか(=密結合が育っていないか)
- 分けたのに速くなっていない場所はないか(=分散モノリスになっていないか)
- 同じ言葉が、チームをまたぐと違う意味になっていないか(=翻訳が要る箇所はどこか)
コンウェイの法則(システムの構造は、それを作る組織のコミュニケーション構造に似る)を持ち出すまでもなく、組織が動けば境界も動く。だから、描き直しの頻度がそのまま設計の鮮度になる。
夫婦の話と、まったく同じ構造だ。
描き直しを、イベントではなく運用にする
とはいえ「定期的に描き直そう」は、たいてい実行されない。リアーキテクチャという大きなイベントとして構えるからだ。もっと軽くしたほうがいい。
- トリガーを決めておく:カレンダーで半年に一度、もしくは「人が増えた」「事業の柱が変わった」といったイベント駆動にする。人間関係なら、転職・引っ越し・体調の変化がそれにあたる
- 成果物を軽くする:清書した図を作ろうとすると腰が重くなる。ホワイトボード 1 枚と、前回との差分メモで十分だ
- 見るのは差分だけ:全部を描き直すのではなく、「前回から動いた線」だけを探す。三つの点検項目は、そのための質問になっている
大事なのは、描き直しを失敗の兆候が出てから始める作業にしないことだ。密結合も分散モノリスも、ある日突然できるものではない。少しずつ育つ。定点観測がないと、手遅れになってから気づく。
おわりに
最後に、比喩の限界を書いておきたい。
パートナーはシステムではない。設計対象として扱った瞬間に、いちばん大事なものが抜け落ちる。この記事も、実生活の運用マニュアルとして書いたものではない。
それでも、この遊びには収穫が二つあった。
一つは、境界を語る言葉が手に入ること。「なんとなく息苦しい」は議論にならないが、「共有カーネルが大きすぎるかも」なら議論になる。名前がつくと、問題を人格から構造へ移せる。
もう一つは、逆方向の学びだ。夫婦に当てはめてみると、DDD が「安定した契約」を暗黙の前提にしていることがくっきり見える。その前提が成り立たない領域では、設計の本体は境界を引くことではなく、引き直し続けることに移る。
境界は成果物ではない。運用対象だ。家庭でも、組織でも、たぶん同じだと思う。