あとで書く
-
-
Save podhmo/ac0e3f650b589e82700a9187cad71618 to your computer and use it in GitHub Desktop.
どうも。今回はソフトウェア設計における「PDS (Presentation Domain Separation)」について、私がどう捉えているか、少しばかり語ってみようと思う。別に誰かに教えを説くつもりはないんだ。ただ、長年この世界でコードを書いてきて、色々と試行錯誤する中で、自分なりに「こういうことなんじゃないかな」と感じていることを、思考の整理がてら書き留めておきたい、というだけだ。
もし、この長話の中から何か一つでも持ち帰ってもらえるとしたら、それは「PDSはシステムをどう分けるかの境界線と依存の向きの話であって、分けられた中身をどう作るかの具体的な方法論とは少しレイヤーが違うんだ」ということかもしれない。
PDS。プレゼンテーション・ドメイン分離。言葉だけ聞くと難しそうだが、要はソフトウェアを作る上で、「見た目や操作の部分」と「それ以外の仕事をする部分」をちゃんと分けようぜ、という、まあ、基本中の基本みたいな原則だ。
P (Presentation)
: ユーザーさんが直接触れるところ。UIだね。画面のデザイン、ボタン、入力フォーム、そういった表層の部分。D (Domain)
: P以外の部分。アプリケーションが本来やるべき処理、ビジネス上のルール、扱うデータ、そういったシステムの核となる部分。
なぜ分けるのか?単純な話で、UIのデザインを変えたいだけなのに、裏側の計算ロジックまで書き直す羽目になったり、逆に大事なビジネスルールを修正したら、なぜか画面表示がバグったりしたら、開発も保守も大変になるからだ。分けておけば、それぞれ独立して変更・テスト・再利用がしやすくなる。いわゆる「関心の分離」ってやつだ。
そして、大事なルールが一つ。「PはDの機能を使ってもいい。でも、DはPのことを知っていてはいけない」。依存の向きは P -> D の一方通行。これが基本だ。
私がPDSを捉える上で大事にしているのは、これが特定のクラス設計パターンとかではなく、もっと大きな視点での「地図」や「方針」に近いものだということだ。システム全体を俯瞰して、「ここがUIの領域、ここがそれ以外の領域」と、大まかな境界線を引くための考え方。
どこに川が流れていて、どこに山があるか、みたいな。その地図があれば、自分が今システムのどの部分に関わっていて、他の部分とどう繋がっているのか、迷子になりにくい。
ここが、私がちょっと独特な捉え方をしているかもしれない点だ。PDSにおける「D」とは何か?一般的には「ビジネスロジック」とか「ドメインモデル」を指すことが多い気がする。でも私は、もっとシンプルに、システム全体というジグソーパズルから、P(UI)というピースを取り除いた、残りの全部だと考えている。つまり、Pの「補集合」だ。
だから、この「D」の中には、ビジネスロジックだけでなく、
- データベースとやり取りするコード (データアクセス層)
- 外部のAPIを呼び出す処理 (インフラストラクチャ連携)
- ログを出力したり、設定ファイルを読み込んだりする仕組み
- 場合によっては、アプリケーション全体を制御するようなロジック (アプリケーション層/ユースケース層)
なんかも、最初は全部含まれると考える。UIでなければ、それは「D」なんだ、と。1
だからこそ、PDSにおける「D」と、例えばドメイン駆動設計(DDD)で語られる「ドメインモデル」は、イコールじゃない。ここを混同すると、話がややこしくなる。
DDDのドメインモデルは、ビジネスの核心的な概念やルールをオブジェクトとして豊かに表現しようとする、Dの中身をどう設計するかの素晴らしい手法の一つだ。でも、PDSのDは、もっと大きな枠組みで「UIじゃない部分全部」を指している。
PDSは「境界線」の話。DDDはその境界線の内側、特にビジネスの核心部分をどう作るかの「設計手法」の話。レイヤーが違うんだ。
さて、じゃあ設計を始めるぞ、となった時。「よし、まずは最も重要なドメインモデルから定義するぞ!」と意気込む人がいる。立派な心がけだと思う。でも、正直に言って、私はこのアプローチには少し懐疑的だ。
プロジェクトの初期段階で、そのシステムの「最も重要なドメイン」なんて、本当に正確に分かるものだろうか?ヒアリングを重ね、分厚い仕様書を作ったとしても、それは往々にして「存在しない仮定」の上に成り立っていたり、関係者の思い込みが含まれていたりする。
そんな不確かなものを「これがコアだ!」と定義して突き進むのは、まるでドン・キホーテが風車に突撃していくようなものじゃないか、と思うことがある。本来戦うべき相手(ユーザーの真の課題)ではなく、自分で作り出した架空の敵(理想化されたドメインモデル)と格闘して時間を浪費し、結果として柔軟性を欠いた「不要な檻」を作り上げてしまう。そんな経験、ないだろうか?2
完璧なドメイン定義から始めるのが難しいなら、どうするか。私が現実的だと思うのは、まず P (UI)
のプロトタイプから作ってみることだ。ユーザーが直接触れる、具体的な画面や操作感から入る。
見た目だけでもいい。動きはダミーでもいい。とにかく「ユーザーはシステムとどう対話するのか」を形にしてみる。
このUIプロトタイピング、注意点もある。よくあるのが、イベントハンドラとかにビジネスロジックをベタ書きしちゃって、PとDがぐちゃぐちゃになることだ。そうなったプロトタイプは、まあ、コードとしては「捨てる」ことになるだろう。大抵の場合、そうなる。
でも、その「捨てる」ことになったプロトタイプにも、大きな価値がある。それを作る過程で、ユーザーや関係者から具体的なフィードバックが得られる。「このボタン押したら、こういうデータが見たい」「この操作、もっとこうしたい」とかね。
この試行錯誤を通じて、自然と「PがDに何を求めているのか」が浮かび上がってくるんだ。UIを実現するためには、その裏側(D)がどんな情報を提供し、どんな操作を受け付ける必要があるのか。PとDの間の「やり取りの雛形」、つまりDが外部に公開すべきインターフェースの輪郭が見えてくる。
PとDの間の「やり取りの雛形」(Dのインターフェース)がある程度見えてきたら、ようやくDの中身を本格的に設計する段階だ。
- このインターフェースを満たすために、どんなビジネスルールが必要か?
- どんなデータ構造が適切か?
- ロジックやデータをどう整理・構造化するか?
ここで初めて、DDDの手法を適用してリッチなドメインモデルを作るのもいいし、もっとシンプルなトランザクションスクリプトを選ぶのもいい。データアクセス層やインフラ連携部分をきれいに分離するのもいい。PDSの原則(境界線と依存方向)と、Pから要求されたDのインターフェースさえ守っていれば、Dの内部をどう構築するかは、状況に応じて自由に選べる。これが「補集合」としてのDの良さだと思う。
これは本当に余談で、過言かもしれないが、リーンスタートアップで言う「まずLP作って、問い合わせが来たら裏側は人手で対応しろ!」ってやつ。あれも、PDSのアナロジーで捉えられないかな、なんて考えることがある。
LPがP(プレゼンテーション)。人手対応が、自動化される前のD(ドメイン機能)の一時的な実装。まずPで価値を検証し、OKならD(システム)を作る。Pの有効性を確認してからDに投資する流れ。…まあ、ソフトウェア内部の話と事業開発の話をごっちゃにしすぎか。3
もちろん、経験を積んだ開発者なら、こんなまどろっこしいことを考えなくても、頭の中には定石やパターンがある。「認証ならこのライブラリだな」「ここは後で複雑になりそうだから、最初からインターフェース切っておこう」みたいに、暗黙のうちに良い設計をしていることも多い。そういう「勘」は大事だ。
でも、だからこそMVP(Minimum Viable Product)を作るのが難しい。価値検証のために機能を「枝刈り」しないといけないけど、何が本当に「最小限」で「実行可能」なのかを見極めるのは至難の業だ。技術的な判断だけじゃなく、ビジネスの判断も必要になる。
長々と語ってしまったが、結局、PDSについて私が大事だと思っているのは、
- PDSは「UI (P)」と「それ以外 (D)」を分ける境界線と、P -> D という依存の向きを定める原則だということ。
- PDSのDは、一般的に言われる「ドメインモデル」よりずっと広く、「Pの補集合」として捉えると、設計の自由度が増すんじゃないかということ。
- 最初から完璧なDを目指すより、P(UIプロトタイプ)から始めて、PとDの「やり取りの雛形」を見つけてから、Dの中身を設計していく方が、現実的なんじゃないかということ。
このあたりだろうか。
まあ、こんな風に偉そうに語ってはみたものの、言うは易し行うは難し、だ。実際のプロジェクトでは、納期や予算、チームのスキル、様々な制約の中で、常に理想的な設計ができるわけじゃない。私自身、今でも試行錯誤の連続で、完璧にできているなんて、とても胸を張って言えるもんじゃない。
それでも、このPDSという考え方を頭の片隅に置いておくだけで、少しはマシなコードが書けるようになるんじゃないか、と信じている。そんな、ある開発者の独り言だと思って、聞き流してもらえれば幸いだ。
脚注
Footnotes
今日は一日、昔から頭の片隅にある「PDS」っていう設計原則について、改めて考えを巡らせていた。プレゼンテーション・ドメイン分離。もう何年もこの業界にいるけど、いまだに「完全に理解した」とは言えない、奥が深いテーマだ。この考えを忘れないうちに、日記に書き留めておこうと思う。誰かに見せるわけじゃない、自分のためのメモだ。
もし、未来の自分がこのメモを読み返して、何か一つでも思い出すことがあるとしたら、「PDSはシステムをどう分けるかの境界線と依存の向きの話であって、分けられた中身をどう作るかの具体的な方法論とは少しレイヤーが違うんだ」ってことかな。
PDSって、結局のところ、ソフトウェアを二つの大きな塊に分ける考え方だよな、と思う。
- P (Presentation): ユーザーさんが触るところ。画面とか、ボタンとか、見た目の部分。
- D (Domain): それ以外の全部。システムがやるべきこと、ビジネスのルール、データとか。
なんで分けるかって?そりゃまあ、ごちゃ混ぜだと後で大変だからだ。UIちょっと直したいだけなのに、裏側のロジックまで影響が出たり、逆も然り。分けておけば、変更しやすいし、テストもしやすい。依存の向きは P -> D で、DはPを知らない。この基本は変わらない。
最近特に思うのは、PDSって具体的な設計パターンの名前じゃなくて、システム全体の「地図」みたいなものだってこと。どこがUIの領域で、どこがそれ以外の領域かを示す、大まかな境界線。その地図があれば、自分が今どこにいるのか、少しは分かりやすくなる気がする。
そして、この地図における「D」の領域。これをどう捉えるか。一般的には「ビジネスロジック」とか「ドメインモデル」って言われることが多い気がするけど、私はもっと大雑把に、システム全体からP(UI)っていうピースを取り除いた、残りの全部って考えるのがしっくりくるんだよな。Pの「補集合」。1
だから、この「D」の中には、
- DBアクセス
- 外部API連携
- ログ出力
- アプリ全体の制御ロジック
なんかも、最初は全部含まれる。UIじゃなければ、それは「D」だ、と。
この捉え方をすると、DDD(ドメイン駆動設計)で言う「ドメインモデル」とは、やっぱり意味合いが違うことになる。DDDのドメインモデルは、ビジネスの核心をリッチに表現するもので、Dの中身をどう設計するかの素晴らしいアプローチの一つだ。
でも、PDSのDは、もっと大きな枠で「UIじゃない部分全部」。PDSは「境界線」の話、DDDはその内側をどう作るかの「設計手法」の話。この区別は大事だと思う。
設計を始めるとき、「よし、完璧なドメインモデルから作るぞ!」って意気込むのは、なんだか危うい気がしてしまう。だって、最初からシステムの「核心」なんて、本当に分かるんだろうか?
頑張ってヒアリングして仕様書を作っても、結局は不確かな仮定の上に立っていたり、本質じゃない問題にリソースを割いてしまったり。まるでドン・キホーテが風車に挑むみたいにね。自分で作り出した「理想のドメインモデル」という架空の敵と戦って、時間を浪費するだけかもしれない。そんなの、虚しいじゃないか。2
だったら、どうするか。最近よくやるのは、まず P (UI)
のプロトタイプから作ってみることだ。ユーザーが直接触るもの、具体的な画面から入る。見た目だけでも、動きがダミーでもいい。
このUIプロト、作ってるうちにロジックが混ざってぐちゃぐちゃになって、結局コードは「捨てる」ことになるかもしれない。でも、それでいいんだと思う。その過程で、「ユーザーは本当は何をしたいのか」「このUIを実現するには、裏側(D)に何が必要なのか」が見えてくるから。
PとDの間の「やり取りの雛形」、つまりDが外部に公開すべきインターフェースの輪郭が、プロトタイピングを通じて浮かび上がってくる。この発見が大事なんだ。
Dが満たすべきインターフェースが見えてきたら、ようやくDの中身を設計する段階だ。どんなビジネスルールが必要か?どんなデータ構造がいいか?どうやって整理するか?
ここでDDDを使うもよし、もっとシンプルな方法を選ぶもよし。PDSの原則(境界線と依存方向)と、Pからの要求(インターフェース)さえ守っていれば、Dの内部設計は、プロジェクトに合わせて自由に選べるはずだ。
これは本当にただの思いつきだけど、リーンスタートアップの「まずLP作って、裏は人手で!」ってやつ。あれも、見方によってはPDSっぽい気がする。LPがP、人手が一時的なDの実装。Pで価値を検証してからDを作る流れ…。まあ、こじつけか。3
もちろん、長年やってれば、「ここはこうするのが定石だな」とか「この部分は後で சிக்கそうだな」とか、経験から来る「勘」みたいなものはある。そういう暗黙知は、確かに開発を助けてくれる。
でも、だからこそMVPを作るのが難しい。機能を「枝刈り」しないといけないけど、何を残して何を削るか。技術だけじゃなく、ビジネスの判断も必要になる。本当に難しい。
PDSについて、今日考えたことをまとめると、
- PDSは「UI (P)」と「それ以外 (D)」を分ける境界線と、P -> D という依存の向きの原則。
- Dは「Pの補集合」と広く捉えると、設計の自由度が増すかも。
- P(UIプロト)から始めて、PとDの「やり取りの雛形」を見つけてから、Dの中身を設計する方が、現実的かも。
ってことかな。
まあ、こんなことをつらつらと考えてはいるけど、実際のプロジェクトはいつも綺麗事では済まない。納期、予算、人間関係…いろんな制約の中で、妥協もたくさんしてきた。理想通りにできたことなんて、ほとんどないかもしれない。
本当はさ、こんな風にプロダクトの全体構造とか、ビジネス要件とか、そういう大きな話に向き合い続けるよりも、もっとこう、細々と技術的な興味を探求してたいんだよな。誰に頼まれたわけでもない、自己満足のライブラリとか、盆栽みたいに手塩にかけて育てるOSSとか、そういうのを書いて静かに暮らしたかった。なんてね。
まあ、明日もコードを書くんだろうけど。少しでもマシなものが作れるように、また考えるとするか。
脚注
強弁したところに弱気な脚注というのは良い気がした