2024年1月15日
株式会社スタメン
ミノ駆動(仙塲大也)
電子機器メーカーや大手精密機器メーカー、クラウドワークスを経て、2021年4月にREADYFORに入社。アーキテクチャの変更容易性や機能性を促進する設計構造を目指し、リファクタリングやドメインモデリングを主軸としたシステム設計に従事する。現在は、組織改善のためのエンゲージメントプラットフォーム「TUNAG」を擁するスタメンに在籍。ITエンジニア本大賞2023技術書部門大賞を受賞した『良いコード/悪いコードで学ぶ設計入門』著者としても知られる。
ドメイン駆動設計(以下、DDD)に注目が集まりだしてしばらく経ちますが、いまだに捉えづらさを感じている人も多いのではないでしょうか。
「技術的負債解消」をエンジニア人生のテーマとするミノ駆動さんこと仙塲大也さんは、「(所属している株式会社スタメンでの)技術的負債解消のために、DDDを用いる」と発信しています。
ミノ駆動さんは、技術的負債を解消するための手段としてなぜ「DDD」を採用しようと思ったのか。聞いてみると、「DDDは、ソフトウェア開発の本質を捉えるカギとなる」とのこと。一体どういうことなのか、詳しくお話を聞いてみました。
ミノ駆動:ソフトウェアの技術的負債解消においては、DDDが最適だと考えたからです。
そもそも技術的負債とは「あるべき姿」と「今」の差のことであり、負債解消はこの差分をなくしていくこと。つまり、技術的負債解消において最も大切なのは、この「あるべき姿」を定義することです。
技術的負債を解消するぞ!と動き出してみたものの、なんだかうまくいかない…ということ、よくあると思います。その原因は往々にして、負債解消における「あるべき姿」、つまり「何がどうなったら、負債が解消された状態だと言えるのか」がハッキリと定義できていないことでしょう。「今こうして書き直したコードも、時が経てばまた負債になってしまうかもしれない」と思うと、何を目指せばいいのかわからなくなってしまうんです。
DDDは、僕たちがつくっているような「ビジネスとして、利益を生み出し続けることを前提としたソフトウェアのあるべき姿」を定義するのに、最も適した手法だと考えています。
ミノ駆動:ソフトウェアの内部品質の中でも「機能性」と「変更容易性」が高い状態、といえるでしょう。
ソフトウェアは、ユーザーが目的を達成するための手段です。たとえば通販アプリにおいては、「そのアプリ上で商品を売買すること」が果たすべき目的であり、アプリなどのソフトウェアがその目的を達成するための手段になります。ユーザーの目的を達成できてはじめて、その対価として利益を生み出すことができます。つまり、ソフトウェアをつくり、使ってもらうことで利益を生まなくてはならない僕たちは、「ユーザーの目的を達成できるソフトウェア」をつくる必要がある。
そのために最優先で満たすべきは、ユーザーの目的を達成できる「機能性」と、ユーザーやその目的が増えたり変わったりしても、それに合わせてすぐに形を変えられる「変更容易性」です。これらを同時に満たせる姿こそ、ビジネス手段としてのソフトウェアの「あるべき姿」だと考えています。
ミノ駆動:過去に積み重なった技術的負債に初めて直面したとき、頻発するバグをなんとか減らすために、負債解消に関するあらゆる書籍を読み、様々なメソッドを使いました。当時読んだ技術書、特にマーティン・ファウラー氏の「リファクタリング」には、バグを埋め込まない構造をつくるノウハウが豊富に盛り込まれていて助かりました。
でも、最終的にどういう構造になればいいのかについてはあやふやなように感じていました。できあがった構造も、なんだかいびつに感じて、最適な構造にできた!と言えるほどの「自信」はなかったんです。
「負債を解消できた」と自信をもって言い切れる構造をつくるためには、何を目指したらいいんだろう。そう考えてさらにたくさんの技術書を読んだ結果、「機能性」と「変更容易性」を担保するための設計手法であるDDDにたどり着いたんです。
ミノ駆動:DDDとは、「ビジネスとして利益を上げ続けられるソフトウェアをつくるために、目的に合った設計をしよう」という考え方に則った設計手法だと、僕は解釈しています。
ミノ駆動:「そのソフトウェアが果たすべきユーザーの目的に合った設計」といえるでしょう。
そもそもソフトウェアは、ユーザーの目的を果たすための手段です。先程の通販アプリでたとえるならば、ユーザーの主目的は「モノを売買したい」ということです。
ただ、ひと言で「ユーザー」といっても、様々な人がいますよね。買う人、配送する人、在庫を管理する人など。しかも、それぞれのユーザーは、主目的の「売買したい」からブレイクダウンした別々の目的を持っています。買う人の目的は「商品を買うこと」、配送する人の目的は「正しい商品を正しい住所に送ること」。在庫管理する人の目的は「正しい在庫数をリアルタイムで把握すること」。目的が異なると、達成方法や条件も目的ごとに違います。
ミノ駆動:このようにユーザーごとに異なる目的を、それぞれ別のモジュールで達成するような設計をしよう、というのがDDDの考え方のひとつです。
ミノ駆動:ユーザーごとの目的の違いを認識できずにコードを書くと、負債になってしまうからです。
たとえば、通販において、どのユーザーも「商品」というモデルを使うでしょう。「どのユーザーも使うなら、共通した1つのモデルを使えばいい。それなら1個のモデルで済むから手間が少ないだろう」と、「商品」という1つのモデルをつくったとします。
ミノ駆動:でも、ユーザーごとにその通販アプリを使う目的が違います。すると「商品」モデルに果たしてほしい役割も違う。にも関わらず、無理やり1つのモデルでまかなおうとすると、ロジックがぐちゃぐちゃになり、負債となってしまいます。
ミノ駆動:まず、「このユーザーと、このユーザーの目的は違う」という境界線を整理しなくてはいけません。
先ほどお話した「買う人」「配送する人」「在庫管理する人」は、それぞれやりたいことが違いますよね。この「やりたいこと(=目的)の違い」を見極めて、境界線を引く必要があります。そして、この境界線の範囲内を、DDDでは「境界づけられたコンテキスト」と呼んでいます。
そうして「境界づけられたコンテキスト」がいくつもできたら、それぞれの境界内の目的を達成できるシステムを、それぞれ分けてつくっていくのです。買う人用、配送する人用、在庫管理する人用のシステムをそれぞれつくる。もちろんモデルも分けます。それらのシステムの中に、そのシステムのユーザーの目的を果たすためだけのモジュールやクラスが入ってくるわけです。
ミノ駆動:これなら、それぞれのシステムが、それぞれの目的を達成できます。つまり高い「機能性」が担保できます。また、あるシステムの一部に変更が必要になっても、システムが目的ごとに分けられていれば、目的を飛び越えて影響しあうことはありません。必要なところだけ変更でき、それ以外に意図しない影響が出ることはなくなり、高い「変更容易性」も担保できるのです。
ミノ駆動:そう思います。DDDで明確にそう言っているわけではありませんが、僕は「機能性と変更容易性が高いコード」=「DDDが目指す、目的に合った設計ができているコード」だと解釈しています。
ソフトウェアは、個別の目的を達成できる構造の集合体です。大きな目的を達成するためのソフトウェアの中に、細かい粒度の小さな目的を達成するためのシステムがたくさんある。そうした構造であらゆるユーザーの課題を解決できるソフトウェアをつくろう、というのがDDDの考え方なのです。
ミノ駆動:そうですね。ビジネスとして利益を生み出せる、つまり目的を達成できるソフトウェアをつくるなら、その目的をちゃんと把握して適切にコードに反映するべきだ、というのは、至極当たり前で本質的なことだと思います。
だからDDDというのは、「ビジネスとして利益を生み出せるソフトウェアをつくるために、当然やるべきこと」が書いてあるだけなんですよ。DDDの中で出てくる用語が特殊だから、特殊なことを言っているように思えてしまうかもしれません。本質的には、利益を出せるソフトウェアをつくるために当然やるべきことを、「ソフトウェアが果たすべき目的」にフォーカスして説明しているだけなのです。
ミノ駆動:DDD独自の用語がたくさんあるので、そう思っても仕方がないでしょう。しかし、DDDでよく聞く「ドメイン」「ユビキタス言語」「コアドメインとサブドメイン」などの言葉も、当たり前のことを言っているだけなんですよ。
最も基礎的なところでは、「ドメイン」という言葉。これをより直感的に理解しやすくするために、僕は「目的」と表現しています。ドメインは「ソフトウェアが解決しようとしている現実世界の複雑な問題」と言われていますが、そもそも「問題」というものは、ユーザーの「目的」を達成するまでの過程の中に生じるものです。なので、「問題」にフォーカスするためにまず「目的」を明らかにするべき、というのが僕の解釈です。
また、「ユビキタス言語」が意味するのは、CSや営業、ユーザー本人などのあらゆる関係者とエンジニアの間で、ユーザーの目的や意図を齟齬なく共有するために、同じ言葉を同じ意味で使おう、ということです。提唱者であるエリック・エヴァンスさんの通称「DDD本」内『意図の明白なインターフェース』では、ユビキタス言語が目的を表現する言葉である旨が明確に記述されています。
同じ言葉でも、ユーザーごとに意味や解釈が違うことはよくあります。たとえば、通販でいうところの「商品」は、買った人にとっては「自分が買ったもの、そして家に届くもの」であり、配送する人にとっては「買った人に送るもの」です。また、在庫管理する人にとっては「残っている在庫」。「商品」っていう言葉が意味するものが、ユーザーごとに違います。
ミノ駆動:これを「商品」というひとことでまとめてしまうと、どのユーザーのどんな目的の話をしているのかの認識が食い違い、話がかみ合わなくなっていきます。
であれば、買った人にとっての商品は「購入品」、配送する人にとっては「配送品」など、そのユーザーが果たしたい目的が直感的に理解できるように言葉を分けたら、何の話をしているのかがグッとわかりやすくなりませんか?
ミノ駆動:ユビキタス言語というのはそういうことなんですよ。目的と、その目的達成のためにつくるシステムがずれないように、関係者同士の目的の齟齬が起きないようにすることが、ユビキタス言語が存在する理由です。
「ドメインモデル図」もこれに似ていますね。誰が使う?その人は何がしたい?システムでどう実現する?などを図式化して視覚的におこしたものが、ドメインモデル図です。それを一緒に見ながら何をつくるのかを議論できれば、「誰が、何の目的を果たすために、どんなシステムをつくるのか」を、もっと齟齬なく認識を合わせられます。また、視覚化によって、議論の中で「目的が違うユーザーが混ざってないか?」など、目的やユーザーの混同に気づきやすくもなりますね。
「コアドメインとサブドメインの疎結合化」もビジネスにおける「選択と集中」をソフトウェアでもできるように、アーキテクチャレベルでも「コアドメイン」と「サブドメイン」として分けておこう、ということを言っています。
ビジネスインパクトが大きい機能を「選択」し、それを「集中」して磨き込むことでビジネスインパクトを最大化しよう、とよく聞きますよね。ただ、ソフトウェア開発における「選択と集中」は、アーキテクチャレベルで「コアドメイン」と「サブドメイン」に分けられていないと、物理的に実現不可能なんです。
ミノ駆動:ソフトウェアには絶対に果たすべき、そして、競争優位性が高く、強化し続けていきたい「主目的」と、それ以外の「副目的」があります。この「主目的」はつまりコアドメインであり、「副目的」はサブドメインのことです。
この両者のロジックが混ざらないように、アーキテクチャを分けて構築しないと、後々大変なことになります。コアドメインを改善しようとしてコードを書き換えたら、サブドメインで不具合が起き、それを直そうとしたら今度はコアドメインで不具合が起き…と、コアとサブそれぞれの変更が相互に影響し合ってしまう。これではとても「集中」なんてしていられなくなってしまいますよね。
逆に、コアドメインとサブドメインでアーキテクチャが分かれていれば、コアとサブがそれぞれ独立していて、変更が相互に影響し合うことはありません。コアドメインの開発に技術力の高いエンジニアをアサインするなどして新規開発や改善を高速に回し、集中して磨き込むことができるでしょう。
これをDDDでは「コアドメインとサブドメインの疎結合化」と言っているんです。
ミノ駆動:その通りです。「ビジネス側の都合を考慮したうえでアーキテクチャの設計をする」という考え方はDDDの特徴であり、唯一無二のユニークなところだと思います。
結局、どんなにすごいフレームワークを使おうと、どんなに革新的な技術を使おうと、ユーザーの目的を達成できるソフトウェアをつくれなければ、顧客から報酬をもらえないんですよ。
だったら、ユーザーの目的をちゃんと達成できて、ちゃんと報酬をいただけるように、ユーザーの目的に合わせてシステムをつくりましょう。そうすれば、ビジネスとして利益を生み出し続けられるソフトウェアをつくることができるでしょう。これがDDDの根幹をなす考え方なんだと、僕は解釈しています。
ミノ駆動:「DDDを実践していない」というわけではなく、DDDに出てくる言葉を使っていないだけであって、ほとんどの企業はDDDと同じようなことをしていると思いますよ。
たとえば「ユビキタス言語」は「要求定義」と近いです。ユーザーの要求、つまり目的をはっきりさせるためにやり取りするのが「要求定義」ですが、そのとき使う言葉をDDDでは「ユビキタス言語」と言っていますよね。また、「うちの会社は選択と集中でプロダクトをつくっています」というのも、DDDでの「コアドメインとサブドメイン」と同じ話です。
でもその場合の多くは、DDDの「目的ごとにアーキテクチャを分ける」という考え方を知らないまま開発していますから、できあがるコードの構造と、そのソフトウェアやシステムが達成したい目的が一致しません。やりたいこと、つまり目的とコードが食い違ってしまい、負債が生まれます。
そうした組織も、設計におけるDDDでの考え方を深く理解できていれば、目的とアーキテクチャを一致させることができたかもしれません。それができていれば、発生しなくてよかった負債もあるかもしれませんし、もったいないことだと思います。
ミノ駆動:DDDの中でも、アグリゲートやエンティティなど「戦術的設計」だけをやろうとする、いわゆる「軽量DDD」ではうまくいかない場合もあるでしょうね。
そもそも「戦術的設計」にある手法は、あくまでも提唱者であるエリック・エヴァンスさんが、DDDの考え方に基づいて開発を進める中で、経験上うまくいったものを体系化したものだと考えられます。
だから、DDDやその戦術が何のためにあるのかを理解できていないまま、ある特定の戦術だけ採用しているとしたら、意図していた形にならなくて当然だろうと思います。DDDの「戦略」、つまりDDDが一番大切にしてる「目的に合うシステムをつくろう」っていうのをすっ飛ばして「戦術」だけ実践する、いわゆる軽量DDDが無意味だといわれる理由の1つでもありますね。
「戦術」だけやってみてたまたまうまくいってしまうことも、もちろんあるでしょう。実際に、「軽量DDDをやってみてうまくいった」という声もあります。けれどそれはたまたまであって、再現性はないと思います。
ミノ駆動:いや、そんなことはありませんよ。ソフトウェアが満たすべき内部品質の定義の中で、DDDによって担保できるのはごく一部です。ただ、利益を生み続けられるソフトウェアをつくりたいなら、「変更容易性」「機能性」は備えているべきで、それを担保するためにDDDはまずやるべきだろう、と僕は思います。
それに、「変更容易性」「機能性」以外のソフトウェア品質特性の担保については、DDDには書いてないんです。それらはまた別の手法で補ってね、ということなんじゃないでしょうか。
ミノ駆動:今は色々な開発手法があって、それぞれに得意分野があります。1つだけ完璧に実践できていればいいなんて、夢みたいな開発手法などないと思いますよ。
ミノ駆動:まず、「理想的なコードとはどんな状態か」を知ることからはじめるべきでしょうね。
良いシステムをつくるための「課題」は、「理想」のイメージがあって、それと現状を比べることではじめて明らかになるだろうと思います。「何が正解なんだ?これが最適なのか?」という不安から抜け出したいなら、まず「理想」を知ることです。そのために、ソフトウェア設計や開発手法にまつわる書籍を手当たり次第に読んでみるといいと思います。
目指すべき理想と現実の間にどんなギャップがあるのか分かれば、ぼんやりとした不安に対して、自分がやるべきことが見えてくるはずです。そこから一つひとつの課題と向き合い解決することで自分を成長させていくほかないだろうと、僕は思っています。
取材:武田敏則(グレタケ)
構成・編集:光松瞳、王雨舟
関連記事
人気記事