DDDの実装順序を見直したら、開発速度が向上した話
こんにちは。赤い色素です🍅。
とある企業にてGoを使ってバックエンド開発をしている、新卒エンジニアです。
配属されて3ヶ月が経ち、まだまだわからないことばかりで大変な毎日を過ごしていますが、日々先輩方に学びながら仕事に励んでいます。
私のチームでは、ドメイン駆動設計(DDD) を採用しています。しかし、配属当初はDDDの概念を理解するのに必死で、先輩の見よう見まね、教えていただくままに実装を進めていました。
本記事では、この手順によって私が直面した課題とその改善により、いかにして新人メンバーの私が開発速度を向上させることができたかについて、実体験を交えてお話しします。
対象:DDDによる開発を初めて間もないバックエンドエンジニア👶🏻
直面していた課題:終わらない手戻りのループ
教わった手順は以下の通りでした。
- テーブル設計
- エンティティ作成 (Domain)
- リポジトリ実装 (Infrastructure)
- ユースケース実装 (Application)
- ハンドラ実装 (Interface)
単純なCRUD機能であればこの手順でも問題ありませんでした。しかし、少し複雑なビジネス要件が入ってくると、途端に手戻りの嵐に見舞われることになります。
テーブルとドメインの混同
🍅「テーブル設計した!seeder作った!ドメインを作るぞ!」
🍅「テーブルとドメイン、ほぼ一緒やん まあええか、PR提出」
レビューにて:👨🏻💻「DBの都合とビジネスの関心事を混同していますね」
→エンティティ作り直し orz
実装中の仕様変更
ユースケース層実装中
for _, e := range エンティティ+リポジトリメソッドの数 {
🍅「このデータ、必要なのにエンティティになくね?」
🍅「このデータ、エンティティにいらんくね?」
🍅「このエンティティ、やっぱり一つにまとめられるな…」
→ ドメイン層やインフラ層にまで遡って修正PR orz
}
途中までは順調に行っていたのに、途中で設計ミスが次々発覚し、何回も手戻りを繰り返してしまいました。「今日も手戻りが発生して作業目標未達です。。。」と報告する日々が続き気持ち的にもしんどかったです。。。
なぜ問題が起きたのか?DDDの基本と原因の探求
この手戻りの原因は、DDDの思想とは逆のアプローチを取っていたことにありました。
DDDの基本思想
ここで、DDDの基本を改めて振り返ってみましょう。DDDは、ビジネスの関心事(ドメイン)こそがソフトウェアの中心であるべきという設計思想です。
- モデル駆動の実装:設計の主役は、データベースのスキーマやUIではなく、ドメインモデルです。
- ユビキタス言語:開発者とドメインの専門家が共有する言語で、ビジネスの概念をコードに直接反映させます。
- 関心の分離:アーキテクチャを層(レイヤー)に分け、各層が自身の責務に集中します。
理想的な依存関係は、外側の層が内側の層に依存する形です。つまり、ドメイン層はどの層にも依存しない、最も中心的な存在でなければなりません。
根本的な原因
私の失敗の原因は、この原則に反してドメインの前にインフラ(データベース)の都合を考えてしまったことでした。
-
ドメインエンティティと永続化エンティティの混同
- ドメインエンティティ:ビジネスのルールやロジックを表現するもの。
- 永続化エンティティ:データベースのテーブル構造に合わせたデータ格納用のもの。
無知だった私はこの2つを同一視してしまい、ドメインがデータベースの構造に引きずられてしまいました。
-
ビジネスロジックの全体像が不明確なままの実装
ユースケース(アプリケーションが何を実現するのか)を具体的に考える前に実装を進めたため、「何のためのデータか」「どういう手順で処理されるのか」が曖昧なまま、手探りでドメインやリポジトリを作ってしまっていました。
改善策:実装の順序を「ドメインファースト」へ
これらの反省から、私は実装の順序を以下のように変更しました。
-
ドメイン層 (Domain)
- ビジネスの関心事を表現するエンティティ、値オブジェクト(VO)を定義する。
- これらの永続化をどう行うかの「仕様」として、リポジトリのインターフェースを定義する。
-
ユースケース層 (Application)
- ドメイン層で定義したモデルとリポジトリインターフェースを使い、「何を、どの順で行うか」というビジネスロジックの手順を記述する。
-
インフラ層 (Infrastructure) & プレゼンテーション層 (Interface)
- ユースケースで定まった要件に基づき、リポジトリの具体的な実装(DBアクセス処理)や、ハンドラ(リクエスト受付、レスポンス返却)を実装する。
改善による効果
-
ドメインの独立性
最初にドメインを実装してしまうことで、物理的に他の層に依存できなくなります。これにより、純粋なビジネスロジックをコードに落とし込むことに集中できました。 -
ユビキタス言語の徹底
ドメイン層で固めたビジネス用語(ユビキタス言語)が、後続のすべての層で一貫して使われるようになり、コードの可読性や不適切なユビキタス言語の使用について指摘される頻度が(少しだけ)減りました。 -
全体像の把握と工数見積もりの精度向上
「ビジネスロジック(ドメイン)を、どのような単位で扱い(リポジトリインタフェース)、どのような手順で実行するか(ユースケース)」が先に決まるため、必要なデータベース操作やAPIのインプット、アウトプットが明確になります。これにより、実装の全体像を把握しやすくなり、工数の見積もり精度も上がりました。
結果として、実装終盤での大幅な手戻りは劇的に減少しました。これにより先輩にヘルプを求める頻度も少しずつ減っていきました。
また、レビュワーである先輩も、ドメインやユースケースが最初に出来上がっていることで全体像がわかり、レビューがしやすいと話していました。
結果的にチームのベロシティも少しずつ向上したのではないでしょうか。
終わりに:全体像の把握って大事
今回の経験を通じて、DDDの責務への理解を深めることができました。
ドメインが全体の中核!ということは教科書の知識レベルでは知ってはいたのですが、実際に開発業務に関わってみて初めてビジネスの関心事をソフトウェアの中心において設計・実装することの重要性を学びました。
加えて、ただ闇雲に手を動かすのではなく、「自分たちが何を作ろうとしているのか」という、行動に対するゴールをいかに明確にイメージできるかが、業務の生産性を大きく左右するということを学びました。
私は構造化があまり得意では無いなあ、、と日々課題に感じているので、まだ苦戦中です。
ですがこれからも、自分が把握できる単位まで見立てを立ててから行動することを大切にして、日々の開発業務はじめ社会人生活に励んでいきたいと思います。
Discussion