ユースケースとドメインモデリングに思いを馳せる
背景とかとか
今メインで開発しているサービスのアーキテクチャが色々辛くなってきた。元々は少人数で始まったプロジェクトでありAmplify x AppSyncを使っていたが、開発規模が大きくなることにつれて(特に)バックエンドのリソースが大変なことになってきた(大量のAWS Lambda群が出来上がってしまったのだ...)。
個々のLambdaはClean ArchitectureベースとしてGolangで書かれており、且つテストもあるので機能の観点ではそこまで致命的なことはないのだが、問題は サービスの全体像が埋もれつつあること だった。個々のLambdaそのものは良いのだが、そのLambdaが自分以外に与える影響範囲がわからなくなってきていたのだ。またデータフローの認識もチーム内でバラバラになりつつあった。
このままだとヤバいということで、共通認識の再構築も兼ねて数日間ユースケースとドメインモデリングの洗い出しをした。
この記事ではこの取組を通して得た知見をまとめる。
*Lambda間での処理のフローがあるのであればStepFunctionでまとめられるだろうが、1リクエスト1Lambdaといった構成となっているのでそいいったワークフローも作れなかった。
前提
- この記事ではドメインモデリングやユースケースそのものの説明などはしない
- 詳しくはその分野の強い人達の記事や書籍を読んでほしい
- あくまでも経験上の話をまとめており、技術書に載っているような系統だった情報ではない
- これが絶対的な正解といったものではない
1. ユースケースは兎にも角にも目的を考える
兎にも角にもここれが大事なんだ。そもそも我々エンジニアがソフトウェアを作る目的は、それなしでは達成できない(または達成できるが苦労が多い)何らかの目的を達成すること なんだ。そのユースケースを実行することの目的をチームで明確に言語化出来ないとユースケースもクソもない。
ユースケース定義がガバガバだと、そこから生まれるドメインモデリングも中途半端になってしまい、ユーザーが本当に解決したいことが解決出来ないかもしれない。または解決できるがその後の度重なる変更で砂上の楼閣と化すかもしれない。
だから、このユースケースでは本質的には、誰/何がどうする/なることを目的としているのか? を常に問いかけることが重要なんだ。チームでシックリくる目的を設定しよう。
2. ユースケースの動作主体は誰/何だ?振る舞いは何だ?
2-1. 動作主体は誰/何だ?
既述の通りユースケースは「特定の誰か/何かが何らかの目的を果たすための一連の行動」である(少なくとも僕はそう思っている)。ここでいう「特定の誰か/何か」というのは具体的には何だろう?よく見る例としては「ユーザーが○○する」といったものだろう。
ユーザーとは一体誰のことだろう?ユーザーという言葉で現実世界の行動を表現出来ているだろうか?その言葉でチーム全員(エンジニアはもちろんのこと、PO、ドメインエキスパート、デザイナーなどそのプロダクトに関わる人全員)が共通認識を持てるのだろうか?
僕個人としては、ユースケースの主体は ユーザー なんていう生ぬるいガバガバな主体でいい訳がないと考えている(それでもいいけど、それであればユーザーの定義についてチームで共通認識が取れている必要がある)。そのユーザーというのが具体的にはどういう人達のことを意味しているのか、そこを考えることが重要だ。
また、動作主体は人じゃないかもしれない。普段の生活ではモノが主体的に動作するというのはあまりイメージがつかないかもしれないが、本質的には何らかの役割を担っているのかもしれない。
本質的にそれを達成したいのは誰/何なんだろうか? ということをまずはチームで話し合ってみるのが良いと思う。
2-2. 振る舞いは何だ?
ユースケースでは動作主体が何らかの振る舞いを行うんだが、その振る舞いとは何だろう? 表面的に見えている振る舞いは、本質的に実施したいことを表しているのだろうか?
例えば「登録する」といった振る舞いがあるとするが、それは本当に登録なのだろうか?「既に持っているAとBを紐付ける」といった行為ではないのだろうか?
また、そもそも登録がしたいのだろうか?本質的には他の動作をすることが主目的であり、登録というのは便宜上使っている言葉なのではないだろうか?
こういった「動作主体は 本質的には何を達成したい のだろうか?」を考え抜いた先に、より自然な振る舞いが見えてくるのではないだろうか。
3. 曖昧な言葉を紐解く
これも既に話していることと被るが、曖昧な言葉をそのままにしておいてはいけない。その曖昧さは様々な意味を含んでおり、使用者と聞き手で微妙にニュアンスが異なっていることが多い。
なんとなく抽象的な言葉を置いておけばそれっぽくは聞こえるが、本質を見逃してしまっているかもしれない。「○○というのはつまりどういうことなんだ?(例えばユーザーというのは具体的にはどんな人達なんだ?どんな目的を持っているんだろう?)」というのをチームで議論するべきだ。
また、 ユースケースやドメインモデルで使う言葉は本来、ユビキタス言語となるはずだ 。つまりこの言葉がチーム内での共通言語であり共通認識となるんだ。ここで「とりあえず〜」といってテキトーな名前を使ってしまうと、少し時間が経つだけでメンバー間で別の用語を同じ意味で使い始めてしまうようになるだろう。これでは意味がない。
どんな名前付をしてもいいが、チームで共通認識を持てるように設定すべきだ。
4. DBのことは忘れろ
悪いことは言わない。 ユースケースやドメインモデリングの話をしているときはDBのことは一旦忘れてしまえ。この世界には中間テーブルも正規化も存在しないんだ。 ユースケースやドメインモデリングの議論において重要なことは「現実世界の出来事をモデリングすること」であり、データベースなんていう物自体出てくることはそもそもおかしいんだ。
確かにエンジニアは既存のDB構成などをイメージして会話したいかもしれない。特にRailsなどのフルスタック入りのwebフレームワークを使っていた人(私のことだ!)ならなおさらだろう。
なぜかというと、その方がデータの取り扱いが楽だからだ。ドメインやユースケースというトラエドコロのない概念をDBに無理やり対応させることで(もちろん対応など出来ていないのだけれど)安心感が得られるのだ。
でも待つんだ。DBに引っ張られた実装をしても本当に必要なものは出来上がらない。
DBは最終的なデータの永続場所の一つであり、あくまでも結果しか転がっていないのだ。 そこにはユーザーの行動も背景も含まれていない。
だからひとまずDBの話をするのはやめるんだ。現実世界に目を向けて、動作主体とそのふるまいに着目するんだ。
5. 正解は無いし常に改善を重ねていくしかない
残念なお知らせだが、設計に正解(100点の設計)というものはない。 僕たち人間が一度に考慮できることなんてたかだかしれているし、そもそもドメインエキスパートでさえ最初の議論ですべてを説明仕切ることも出来ないだろう(彼/女らには自明すぎて見えていないことだってあるんだ)。
どれだけ凄腕のエンジニアとドメインエキスパートが集まっても、最初の設計で完璧なユースケース/ドメインモデルというのは作れないし、それでいいんだ。これらはアプリケーションが進化するにつれてチームの中に構築されていく知識によって成熟していくんだ。
だから、 「最初に頑張ってモデリングしたから、あとはそれに沿って実装するだけ!」というとは全然ないし、その脳死は絶対にやめるべきだ 。実装しながらも「本当にこれで良いのか?」というのは考え続けなくてはならない。
そうして思考を繰り返した先に、より良いモデリングが見えてくるんだ。
Discussion