どういう記事?
こちらの本 を聖書として DDD(ドメイン駆動設計) を導入してみました。
DDDをどう実装するのかではなく、 今回は導入してみてどうなったか に注目してみます。
何が良かったのか
基本的にこの2つです。
① ドメインモデリングを元に仕様とコードを近づける
② ビジネスロジックを抽出しUTを増やす
① ドメインモデリングを元に仕様とコードを近づける
DDDの開発では、実装前にドメインモデリングということを先にやっていきます。
モデリングを行ってからそのとおりのコードを書くことで、仕様を直感的に表した可読性の高いコードを作ることができます。
たとえばツイッターみたいなアプリの仕様を考えると
- 投稿は140字まで
- 添付画像は4つまで
こんな感じの仕様が思いつきますね。
これをモデリングに落とすと下記のようになります。
【投稿】
- 投稿ID
- 本文
【添付画像】
- 画像ID
- ファイル名
そして、この2つの関係は
【投稿】が複数の【添付画像】を持っている
という関係になりそうです。
また、各々のふるまい(仕様)は、
【投稿】
- 投稿は140字まで
- 添付画像は4つまで
【添付画像】
- 特になし
となります。
これを実装すると、下記のようになるかなと思います。
class Tweet {
id: string;
text: string;
tweetImages: TweetImage[];
constructor(
id: string,
text: string,
tweetImages: TweetImage[]
) {
if (text.length > 140) {
throw new Error("投稿は140字まで")
}
if (tweetImages.length > 4) {
throw new Error("添付画像は4つまで")
}
this.id = id;
this.text = text;
this.tweetImages = tweetImages;
}
}
class TweetImage {
constructor(
public id: string,
public tweetId: string,
public fileName: string
) {}
}
どうでしょうか?
仕様と比べてもかなりそのまま実装しているように見えて可読性も高くなっています。
- 投稿は140字まで
- 添付画像は4つまで
② ビジネスロジックを抽出しUTを増やす
2つ目の利点はビジネスロジック(=仕様)に特化したUTが増やせる点です。
ドメインを意識していないコードだとこんな感じのコードになりがちです。
function(request: Request): Response {
const requestBody = deserialize(request.body); // 割と適当に書いてます。
if (requestBody.text.length > 140) {
throw Error("投稿は140字まで");
}
if (requestBody.tweetImages.length > 4) {
throw Error("添付画像は4つまで");
}
// 割と適当に書いてます。
sql.insert("insert into tweets~");
requestBody.tweetImages.map(images => sql.insert("insert into tweet_images~"));
return new Response(200, "OK");
}
さて、このコードのテストを書くとき何がつらいでしょうか?
正解は
JSONのリクエストとレスポンスをデータとして用意しないといけない
テスト用のデータベースを用意しないといけない(モックでもつらい)
という点です。
一方で先程のDDDのコードでは上記のようなJSONやテスト用のデータベースを用意する必要はなく、ロジックに集中してテストコードを書けます。
describe("投稿が140字を上回る場合", () => {
it("エラーを返す", () => {
expect(() => {
new Tweet(
"1",
"140字だよおおおおおおおおおおおおおおおお(以下省略)"
[
new File("1", "インスタ映え.jpeg")
]
);
}).toThrow();;
});
});
describe("添付画像が4つを上回る場合", () => {
it("エラーを返す", () => {
expect(() => {
new Tweet(
"1",
"おはよー"
[
new File("1", "インスタ映え.jpeg"),
new File("1", "インスタ映え.jpeg"),
new File("1", "インスタ映え.jpeg"),
new File("1", "インスタ映え.jpeg"),
new File("1", "インスタ映え.jpeg"),
]
);
}).toThrow();
});
});
describe("投稿が140字かつ、画像が4つのとき") {
it("正常に投稿できる", () => {
// 略
});
}
どうでしょうか?本文の文字数と添付ファイルの数の仕様に集中してテストがかけています。
このように仕様( = ビジネスロジック)に集中した簡単なテストを増やすことで、より品質の高いコードを生み出すことができます。
まとめ
今回はDDDを導入すると何がいいかをポイントを絞ってまとめてみました。
① ドメインモデリングを元に仕様とコードを近づける
② ビジネスロジックを抽出しUTを増やす
今回はかなりポイントを絞りましたが、他にも色々良いところがあるのでぜひ下記の本などを参考にしてみてください!