あえて軽量DDDを採用した話
NE株でJavaを書いている谷口(@taniguhey)です。
弊社では、EC一元管理システムである「ネクストエンジン」以外にもいくつかサービスを展開しており、2024年1月にβ版をリリースした「encer mall」(エンサーモール)という仕入れと卸のマーケットプレイスがあります。
8月1日にこれらの2つのサービスを連携するアプリ「encer mall連携 for 卸会員」をリリースしましたので、この記事は「encer mall連携 for 卸会員」(以下、連携アプリ)の開発の裏側を語る記事になります。
- 大きな泥団子から抜け出すための軽量DDD
- 軽量DDDを持ち込むにあたって気をつけたこと
について書いていきます。
あえて軽量DDDを採用した話
ここでいう軽量DDDとは、ドメイン駆動設計における"戦術的設計"と呼ばれる部分のことです。
ドメイン駆動設計は"戦略的設計"の部分も併せて行うことで本来期待している効果が100%発揮されるため、ソフトウェア内だけに焦点を当てた戦術的設計のみ行うことは、状況によってはアンチパターンであると語られがちです。
アプリケーションと開発チームの背景
連携アプリを開発したチームは、「encer mall」を開発しているチームと同じです。「encer mall」を開発していたバックエンドエンジニアは、連携アプリ開発を始める前の段階では4人で、連携アプリを開発すると同時に2人追加となり、自分はそのうちの1人でした。
「encer mall」は、仕入れと卸のマーケットプレイスなのでBtoCのECモールが備えているような「商品」「在庫」「注文」「決済」などの基本的なドメインを備えつつ、仕入れ・卸特有の「商品の掛率」「取引の承認」のような複雑な概念・ビジネスロジックを抱えています。
競合サービスに比べると後発になるので、新規事業らしくローンチ前から需要や差別化できるポイントを設計したりするものの、ローンチしない限りはその仮説を実証できないためアプリケーションとしては荒削りなままローンチまで進んできました。
そのため、上述した基本的・複雑なドメインは整理されておらず、開発においては"方針"と呼べるものはあっても"設計"と呼べるものはあまりなく、ローンチのために開発スピードに重きを置き、密結合だったりテストがないコードなどがある程度の割合を占めていました。
これから「encer mall」を素早く改善していくにあたって、これらが整理されていない状況では障壁になると感じていました。
例えば、service
ディレクトリ配下には直下にXxxService
と名付けられたクラスが約60個並んでいるというような状況でした。ローンチまで開発してくれたメンバーは少し入れ替わりはすれども、ある程度ずっと同じメンバーで進んでいたためその時点ではこれはきっと大きな問題ではなく、チーム状況が変わったためコード理解などで認知に負荷がかかる問題と浮き彫りになった形ではあります。
私が参画した時点での仲間5人は、例えばこのような60ファイルをどのようにすれば中長期的に素早く開発を進められるかあまりピンと来ていなかったため、自分が舵取りをすることにしました。
獅子は我が子を千尋の谷に落とす
連携アプリの開発はちょうどタイミングが良く、「encer mall」のリファクタではなく0から始められるため、目指す形を覚えるのにちょうど良い題材とすることができました。
まずはエンジニアメンバー内に向けて、コードのどの部分がビジネスにとって重要で、そうでない部分はどこなのかをはっきりさせるため、
さらにいうと、アプリケーションの実装はそのように分類・分離できることから理解してもらうために、「ビジネスロジック」や「エンティティ」などを導入しました。つまりはドメイン層を分離しようという提案です。
必然的に、分離されたドメイン層とそれ以外を分ける必要があるため、結果的にはレイヤードアーキテクチャを導入することになり、軽量DDDとなりました。
メンバーにとっては学習コストがあるわけですが、すぐにでもサービスは成長させなければならず、ゆっくり時間をかけて成長していく時間はなかったので、獅子🦁となることを決めました。
具体的には、設計規約(Design Doc)を書きGithubのDiscussionsに公開しました。この時点ではメンバーにとっては、「ビジネスロジック」や「エンティティ」という言葉自体が初見のものもあったと思いましたが、「わからないことある?」という質問で谷に落とすところから始めました。
もちろん、設計規約読んでもらいつつDiscussions上で質問を貰ったり、口頭でも質問を受け付けながらメンバーの疑問に答えていきました。
実装に入ってからも疑問に思った時点で口頭で呼び出してもらい、例えば「この判定処理ってXXXクラスに入れてdomain
パッケージ配下でいいんですよね?」というような質問などにも答え、徐々にドメイン層とそれ以外についてを実装しながら覚えてもらいました。
追記(2024-10-22)
DDD的な要素が薄いため、どのような規約にしたかについて追記しておきます。
規約は、レイヤードアーキテクチャに出てくる「プレゼンテーション層」「アプリケーション層」「ドメイン層」「インフラ層」に分けてディレクトリを切るよう求めることから始めています。
「ドメイン層」にはこういったオブジェクトを置きましょうという規約に軽量DDDの手法を盛り込んでいて、「ビジネスロジックを書く」「操作の単位となるEntityを決める(集約)」「リポジトリパターンを使って永続化を行う」ことなどを明記しています。
規約上だけでは具体例を表現しづらい「ドメインサービス」のような概念は口頭でレクチャーしたり、ある集約がエンティティのインスタンスを持つのか、IDだけを持つのかなども都度相談に乗っていました。
結果的にレイヤードアーキテクチャとなったのは、上記により今まで「XxxService
」に書いていた手順的な処理をどこに書くのかに迷うと判断したため、アプリケーション層などが明示されていた方が良いと考えたためです。
アプリケーション層については依存方向のコントロールのため、コントローラー(Web)だったりバッチ処理だったりに関わらず、再利用可能な形が望ましいという風にレクチャーしました。
気をつけたこと
軽量DDDを導入すると言いつつ、軽量DDDではなくできるだけ汎用的な力と考え方を身につけてもらうように心がけました。
例えば、増田さんの「大きな泥団子に立ち向かう」では、「計算を分離する」という形で説明されており、ここで紹介されているような実践技法をDDDの枠組みに当てはめることで身につけてもらうように考えました。
そのため、設計規約の目的には下記を明文化してあります。
メンバーが実装をベースに戦略的なDDDの概念を理解することで、単純なMVCのアプリケーションから思考方法やパラダイムの変化をもたらすことを目的にする。
なんかイケてるクラス設計をするのが目的ではなく、現実の制約や課題とコードを結びつける思考を身につけること、それを計算として分離できることが目的となるように説明しました。
加えて、一般的にはフレームワークや外部システムから距離を置くこと、つまり、インターフェースでラップして技術的な実装詳細を隠蔽することがベターとされていますが、プロジェクトのステージを考えそこまでは求めないようにしたりもしています。
メンバーの声と結果
この軽量DDDを導入してからメンバーの声を紹介します。
- タスク分解がしやすくなった
- これはレイヤードアーキテクチャやドメイン層を導入したおかげで、ファイル配置やクラスの分類が明確になり、タスク分解の時点で何を行うかの解像度を上げやすくなったとのことです。
- コードが読みやすくなった
- ドメイン層やアプリケーション層を明確に決めたおかげで凝集度が高くなったり、集約のメソッド名などに直感的な命名をつけられるようになったおかげのようです。
- 語彙が伝わりやすくなった
- 「サービス」は実質的に定義がなく神クラス的な立ち位置だったので、軽量DDDで出てくる言葉のおかげでどのようなものを指しているのかがメンバー間ではっきりしました(ユビキタス言語のことではないです)。
そうして、無事「encer mall連携 for 卸会員」連携アプリはリリースすることができました。
メインとなるサービスである「encer mall」側にはこの規約を持ち込んだわけではなく、どこに適用していくかは見えていないので大きな変化はないのですが、少なくとも、エンジニアメンバーが連携アプリの開発を通して、DDDの戦術的な部分の具体例を知ったので、戦略的な部分の話ができる土台に立てたと思います。
戦略的な話をできるようになれば、実装とビジネス上大事なことや競合優位な部分を考える思考の反復ができるようになるかもしれないので、さらに良いサービス作りに進めると期待しています。
まとめ
軽量DDDだけを導入してうまくいくという例は再現性がないことかもしれません。ただ、引っ張っていく人がいる上で、大きな泥団子から設計と呼べるものへのステップアップとして、軽量DDDの概念を持ち込むという捉え方であれば上手くいくケースになるかもしれません。
入門書として有名な「ドメイン駆動設計入門 ボトムアップでわかる! ドメイン駆動設計の基本」も実装パターンから入るもので、とても参考にさせていただきました。
デザイナー目線でプロジェクト進行やデザインについて書いたブログ記事もありますので、こちらもご覧ください。
👀デザイナー目線で振り返る!アプリ開発|NE株式会社・デザイン
NE株式会社のエンジニアを中心に更新していくPublicationです。 NEでは、「コマースに熱狂を。」をパーパスに掲げ、ECやその周辺領域の事業に取り組んでいます。 Homepage: ne-inc.jp/
Discussion