こんにちは!エンタメ領域のDXを進めるブロックチェーンスタートアップ、Gaudiyでバックエンドエンジニアをしている椿(@mikr29028944)です。
Gaudiyは、まだエンジニア10名、デザイナー2名ほどの開発チームですが、今年の6月からDDDと呼ばれるドメイン駆動設計を開発に取り入れました。
DDDとは、一言で言うとドメインエキスパートと呼ばれる担当業務やシステム設計に最も詳しい人と、エンジニアが共創してソフトウェアを開発する手法です。
今回は、DDDを実践する中での気づきや学び、躓きやすいポイントをどのように乗り越えてきたかについて、ご紹介してみたいと思います。
DDDを検討しているチームや、導入して間もないチームのご参考になれば幸いです!
1.なぜDDDを導入したのか
Gaudiyでは元々、アジャイル開発を進めており、繰り返し小さくサイクルを回していくことで品質の高いプロダクトを作る、という開発スタイルを実践してきました。
また、エンタメ企業に対してブロックチェーンを活用したファンコミュニティサービスを提供している事業特性上、扱うドメインがかなり広いかつ複雑で、追加での機能開発が入ることも多いのが特徴です。
そうした中で、ドメイン知識のある人に開発者がヒアリングして実装する、という進め方は以前から個別では行われていましたが、それを体系的に行う開発スキームがなく、実際にドメインエキスパートと開発者の間で認識齟齬が生まれてしまうことも度々ありました。
そうした中で、コラボレーションを促進し、価値提供する対象のメンタルモデルを探った上でプロダクトの品質を高めていくため、2021年6月にDDDを導入することにしました。
DDDは、ドメインエキスパートがもつ知識をプロダクトに関わる全員がしっかり理解・共有するのに、とても優れたフレームワークだと感じています。
2.GaudiyではどのようにDDDを取り入れているか
DDDには、よく「戦略的設計」と「戦術的設計」と呼ばれる手法がありますが、その本質は、ドメインを理解して適切にコードに反映することで、事業価値の高いソフトウェアを開発することにあると思います。
Gaudiyでは、ドメインエキスパートに対するヒアリングからドメインモデルをつくり、それをソフトウェアの実装に反映する、といったDDDの一連の流れを取り入れています。
特に、ドメインの不確実性が高かったり、複雑なものであったりする場合は、率先してDDDを行うようにしています。逆に機能要件がシンプルでわかりやすいものは、DDDを行わないこともあります。
例えば、ある新機能の開発では、以下のようなチームでドメインモデリングを行いました。
- ドメインエキスパート:プロダクトオーナー
- 参加者:Bizメンバー2名、デザイナー1名、エンジニア5名
進め方は、一般的なDDDと同じく、まずはユースケースを全員で洗い出し、その全ケースを実現するための理想的なドメインモデル図を話し合います。ユースケースに基づいて、様々なステークホルダーの視点から質問していくことで、ドメインエキスパート自身も言語化できていなかったことがクリアになっていきます。
ドメインモデルを作ったあとは、それをどうソフトウェアで実現するかを話すため、ユビキタス言語やドメインモデル図をもとにコミュニケーションを取りながら、実装コードへと落とし込んでいきます。
Gaudiyでは、バックエンドにNestJS(TypeScriptのフレームワーク)やGoを採用しており、オニオンアーキテクチャ構成を取り入れています。
この一連のフローにおいて大事だと思うのが、ドメインモデルをつくるところに必要以上に工数をかけすぎず、ヒアリング→ドメインモデルの作成→実装のサイクルを細かく回すことです。
というのも、ドメインエキスパートが最初からすべてを話せるわけではないし、実装側としてもモックベースで一度作成してから、「こういうフローが必要だよね」「ここの処理どうする?」といった議論に展開しやすいからです。
その中でモヤっとしたら、ドメインエキスパートに再度ヒアリングして、ドメインモデルとコードをアップデートしていく方法が進めやすいと思います。
3.DDDの実践で生じた課題と乗り越え方
DDDを導入したことで、以下のようなメリットが得られました。
- ステークホルダー間で共通言語ベースのコミュニケーションが生まれることで、ドメインへの理解・学習が効率的にできる
- 頻繁な変更に耐えうる拡張性や保守性が高いソフトウェア設計が行える
- 全てのコードがドメインの翻訳になる
- コアドメインを理解し、ビジネス価値を最大化できる
- 多角的な視点からドメインの新たな要素の発見やドメイン同士の重要な関係性を見出すことができる
一方で、チームの学習コストの高さや、モデリング実装の難しさ、抽象化と作り込みの問題など、さまざまな課題も感じています。
ここからは、実際にぶつかった課題と、そのときチームがどう行動したか、そこから何を学んだかを紹介したいと思います。
3-1.チーム全員でDDDを学習する
DDDでは、エンジニアだけではなくBizメンバーも含めてプロダクトに関わる全員が、以下のようなことを学ぶ必要があります。
- ドメインモデリングの手法
- ドメインエキスパートのメンタルモデルを探り、言外の背景まで引き出すスキル
- チーム全員がドメインについての理解を深めるマインドや姿勢
- アーキテクチャ設計やソフトウェア設計原則の理解
これを全員でキャッチアップする学習コストはかなり高いですが、僕たちのチームでは、以下の方法でキャッチアップしていきました。
3-1-1.外部講師を招いた
DDD界隈で有名なログラスの松岡さん(@little_hand_s)をお招きして、自分たちが普段扱っている開発のドメインを題材に、DDDの実践方法を教えていただきました。
オンラインでDDD勉強会を2回ほど開催いただき、実際にユースケース図の書き起こしからドメインモデリング、実装までの一連の流れを実演いただきました。
この勉強会を通じて、どのようにドメインエキスパートのメンタルモデルを探り、知識を引き出すことができるかを知ることができました。
自分が一番学びがあったのは「ドメインエキスパートへのヒアリングの仕方」でした。参考になった質問を以下に記載します。
- このオブジェクトに足りない要素は他にはないか
- この時のユーザーの状態はどういうものがあるか
- オブジェクトの具体的な例が知りたい
- キャンペーンとは期間限定のものなのか、それとも恒常的に開催されてるのか
- このAオブジェクトとBオブジェクトの関係性はどうなのか
- このクラスのルールや制約はどのようなものが存在するか
- 強い整合性を表す集約の範囲はどうするか、それとも一旦実装してから検討する方が良いか
特に「このクラスのルールや制約はどのようなものが存在するか?」
という質問はプロダクト視点で「このサービスで何を実現したいのか」を言語化できる、非常に重要な質問だと感じています。
たとえば「キャンペーン中のミッションをすべて達成した場合に何か副作用がありますか?」というドメインのルールを質問することで、ドメインエキスパートから「実はフルコンプリートミッションというミッションを考えていたのでそれも考慮した設計にしたいです」という発言を引き出せました。
上にも挙げましたが、ドメインエキスパートが最初から何でも知っているというわけではない、という前提に立って、ヒアリングをする姿勢が大事になります。
3-1-2.DDDの書籍や記事、登壇資料などを読み漁る
書籍を読むことで理論を学びました。以下に、学びが多かった書籍を載せます。
最初にこの書籍を読みました。戦術的アプローチ・戦略的アプローチの違いから、モデリング→実装に落とし込むまでの流れがとてもわかりやすく説明されています。
また、ところどころにDDDでつまずきそうなQ&Aが記載されており、DDD初心者でも最後まで読み切れる構成になっています。
現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法(増田 亨)
こちらもドメインモデルの設計方法が手厚く書かれている良書です。またドメイン知識の重要さについての記載もあり、ドメインエキスパートとエンジニアの共創が非常に大事だと改めて実感できました。
さらに書籍だけでなく、DDDの記事や登壇資料を読み漁りました。
特に参考になった記事や資料は、以下になります。
3-2.モデリング実装に実際にどう落とし込むか?
また、ドメインモデル図を作成できても、それをどのようにソフトウェアに実装するか?も実際にやってみると難しかったです。
この際も、外部講師の松岡さんにチャットサポートしていただき、Slackでどんどん質問しました。
DDD導入直後は、モデリングから実装に落とし込む際の懸念などを活発に質問することで、わからないことをわからないまま放置せずに理解を深めました。
後から振り返ってよかったことは、質問することで思考回路が言語化されるということです。
これにより、チームでDDDの振り返りをする際に「どういう判断基準が良かったか」「どういう進め方に改善の余地があるか」といったネクストアクションにつなげることができました。
3-3.「早すぎる抽象化」による不必要な開発の問題
ドメインモデル図の作成では、「いずれこういうユースケースにも対応したい」「きっとこういう使われ方をする」といった未来のユースケースを想定することもあります。結果として抽象化されたドメインモデル図から、いま不必要な開発までしてしまうことがありました。
不必要な開発をした結果、自分たちのチームでは以下の負債が発生してしまいました。
- 複数のパターンに耐えうる汎用的な機能はあらゆるケースを包括的に対応できるが、そのケースが将来存在しなかった場合には、コードが負債に転じる
- 不必要なコードが積もると、後からコードを修正する人がその複雑なコードを扱わなければならない、それよりは追加実装するほうが速い、などの理由で重複したコードが作られる
実際に、週刊少年ジャンプの漫画「約束のネバーランド」の展示会で、アプリでQRコードをかざすとNFTが受け取れる、という体験を開発した際、複雑で不確実性の高いドメインを扱う必要がありました。
コミュニティ内のあらゆる諸条件と、コミュニティ外でのユーザーの活動があり、無数の条件の組み合わせがある中で、複雑なユーザーの状態をあらゆるドメインから情報を集めて、判定を行わなければならないといった状況でした。
さらにNFTに関しては、メタデータを参照するケースも今後は増えてきたり、条件クリアのアイテムを付与するために外部APIやBlockchainとの通信、DBの更新を行わなければならないケースだったりと、様々なケースがありました。
そんな状況下、モデリングしたはいいけれど、将来起こりうる仕様拡張を考慮しすぎて汎用化させてしまった結果、コードを作り込みすぎてしまい、結果的に今も使われてない実装が残ってしまっています。
この反省を踏まえて、汎用的なドメインモデルを扱う際に、不必要に作り込まれたコード実装に陥らないよう、Gaudiyでは「早すぎる抽象化(早抽)」というパターン・ランゲージ(※)を作りました。
パターン化したことで「これって過去に失敗したモデリングの方向に向かってしまっている...?」と、レビュー時などに気付けるようになります。
※パターン・ランゲージとは、組織の中で暗黙知になっている行動様式(パターン)を言語化したもの。過去の複数事例に共通する性質を抽出することで、同じ問題が発生した場合に対処できるよう活用しています。
また、個人的には以下が大事だなと学びました。
- 単一責任原則や高凝集・疎結合を意識し、適切なモデリングを行い、適切なタイミングで抽象化を行うことで「誤った抽象化」を防ぐことができる
- 「仕様は変化し、その将来の姿は予測できない」という現実を受け入れる
一方、逆に「早すぎる抽象化」を意識しすぎると、今度はユースケースの幅を狭めすぎてしまって作り込み不足に陥るという事態も発生してしまいます。
作り込み不足で進めてしまうと、のちにリファクタリングが必要になり、保守・運用が難しくなってしまうため、その解決策のひとつとしてテスト駆動開発(TDD)を取り入れています。
また受け入れテスト駆動開発(ATDD)を導入することで、事前にドメインエキスパートとエンジニア達で決めたユースケースが満たされてるかを確認する方式を取り、作り込み不足になっていないかを確認しています。
4.おわりに
まだまだDDDの実践を始めたばかりではありますが、基本原則を守破離の「守」で学びながらも、自分たちのチームにあうやり方を模索していきたいと思っています。
また今後、DDDでソフトウェアをアップデートをしていく上では、以下のマインドと行動を継続的に実践して、DDDをブラッシュアップしていく予定です。
- 上述した「早すぎる抽象化」「作り込み不足」などに気をつける
- ドメインエキスパートへのヒアリングを通じて設計が再構築されるサイクルを回す
- パターン指向リファクタリングなど、デザインパターンを使って設計を改善する
また、DDDの社内勉強会を開催して、エリック・エヴァンスの書籍もみんなで読んでいきたいと思っています。
もしこの記事を読んで、少しでもDDDの話を聞いてみたい!などご興味を持っていただけたら、ぜひお話しましょう!
Gaudiyの技術選定については、こちらの記事をご参考ください!
毎週水曜、オープン勉強会も開催しています!