新卒研修でドメイン層のテストカバレッジ100%にした話

この記事は [株式会社サイバー・バズ Advent calendar 2021](https://qiita.com/advent-calendar/2021/cyberbuzz) 2日目になります！

## 概要

『うっしゃー！新卒研修で**サーバーをDDDで実装**がてら**ドメイン層でテスト網羅**してやるぞ〜〜！』

というキラキラした心で挑んで、苦しかったこと、気づいたことを共有いたします。


## 忙しい方へ、1分で分かるこの記事の結論

- そもそもDDDがまず難しかった(未だに理解したとか到底言えない)
- 異常系をちゃんと書くことで、そのリクエストは想定済みと胸をはれた
- **ドメイン層のテストをガチガチに書けたのは、自分がプロダクトオーナーだったから(仮)**
- 余談: 目標(100%)故に重要度の低いテストも書かなきゃいけない煩わしさを感じる
- 新卒研修という学べる時間はとてもありがたかった

## そもそもDDDがまず難しかった

DDDとはドメイン駆動設計を指す言葉です。
よく以下のエリックエヴァンンス本が挙げられたりしています。

https://www.amazon.co.jp/dp/4798121967

### 取り入れれる技術の範囲は時間との勝負

いくら研修といえども、リミットが設けられているので、
何でもかんでも採用はできません。

ですがこの機会に**【【新卒でも耳に入ってくるDDDという設計思想】】**を
是非とも学んでおきたく、採用いたしました。

### そしてぶつかるDDDの概念量と難しさ

一言でDDDといっても、さまざまな概念が存在しています。

- ドメインモデル
- ユビキタス言語
- 値オブジェクト
- エンティティ
- 集約
- レイヤードアーキテクチャ(domain,interface,infra,usecase)
- リポジトリ
- etc...

上記で挙げた項目全てに対して、

1. まずは実装例を見る
1. 概念を眺める
1. 先輩へDDD雑談しにいく
1. 雰囲気がなんとなく掴める
1. **自分の中で落とし込んだ理解を基に実装してみる(Go)**

これの繰り返しでした。

⑤DDDの実装例などJavaがほとんどなので、Goで書く場合、
ある程度自分で考える部分も多くありました。

ただし、
*「逆にそんな状況だったからこそ得られたものも大きかったんじゃないかな〜」*
と勝手に思ってます。

### いま振り返ってみると

:::note info
苦しかったこと: 学ぶべきことが多すぎて、ある程度取捨選択をしなければいけなかったこと
気づいたこと: 新卒の研修にして設計思想の一つを少しでも学べたのは、今後とても生きていきそう！
:::

## 異常系をちゃんと書くことで、そのリクエストは想定済みと胸をはれた

自分だけかもしれないですが、5xx系ではないステータスコードを返すのはとても意義を感じます！

場合によって、もちろん5xx系を返すべき時はありますが、
「4xxなはずなのに〜」という文脈においては絶対に4xx系を返すべきです。

### 執拗にエラーハンドリングを責めれるのはテストだけ

フロントの制御によって、
あまり日の目を見ないサーバーサイドのエラーハンドリング達ですが、、、

テストにおいては、
**ありとあらゆるハンドリングに対して、執拗に責めることができる**ので、
**テストが動いている時にこそ、エラーハンドリングし甲斐をとても感じました**。

#### 余談

実際のプロダクトでどうするとかは抜きにして、
僕はgoのテストコマンドに、`-d`オプションをつけるのが好きです。

### 機能を壊す破壊衝動と境界値

どこで読んだか/聞いたか忘れましたが、
テストを書くコツは**【サービスを破壊してやる】**という強い意志だと学びました。

もちろん壊すためじゃなく、サービスを安定稼働させるためですが！

**境界値を決定**して、大きく外れ値、スレスレ値、nil系などのモックデータを用意し、
そしてモックデータがハンドリングを走る度に安堵や、
たまに何かのミスで弾けない時に*「なんでだー」*と叫んでいました。

### 真価を発揮するのはリグレッションテスト

実際にちゃんと**デグレしていた**ことがあり、そこに**ちゃんと検知してくれた**ので、
感動しました。

### いま振り返ってみると

:::note info
苦しかったこと: ある意味仕様がガチガチに決めていくので、脳が溶けそうになりました。(後述)
気づいたこと: 境界値の話やリグレッションテストの有効性について、実際に経験して意味を感じられたのは大きかったです。
:::

## ドメイン層のテストをガチガチに書けたのは、自分がプロダクトオーナーだったから(仮)

一番メインな話です！

今までのテスト話はレイヤードな形で説明すると、下記画像のdomainで実装した話をしていました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436088/5507a096-e5a0-713d-6d4e-5b8ca65843ea.png" width="500">
[ドメイン駆動設計で保守性をあげたリニューアル事例 〜 ショッピングクーポンの設計紹介より引用](https://techblog.yahoo.co.jp/entry/2021011230061115/)

### ドメイン層とは何か

**【主にサービス本体に関わるロジックが集結した層】**と捉えて頂いて構いません！

### 「ドメイン層のテストカバレッジ100%にする」が意味すること

他の層でテストカバレッジを100%にするのとは、訳が違うと思います。

先ほども書いた通り**【【主にサービス本体に関わるロジックが集結した層】】**で、
**正常系/異常系コードの境界値を定義して、全てのコードをテストで網羅**しているので、
いわば**サービスの仕様を厳密に細部まで決めている**ようなものです。

もちろん大まかに決めるのはあたりまえですが、
**DBに入る限界値ではなく、サービスとしての境界値を決定するのがドメイン層**
です！

ここで感じたことは、
*「研修という自分だけで意思決定できるからこそ、100%になるまでやりきれたんじゃないかなぁ」*
でした。

### 実際に動いているサービスだと、、、？

**プロダクトオーナーと要件を詰めるための綿密な会話を、
必ず挟む必要がある**と思います。

1人のエンジニア自身が勝手に仕様書となっては、
今後の運用で支障がでるのは間違いないですし、、、
いざ認識違いがあった時に、テストまで改修しなければいけません。

なので工数が膨らむこと考慮して、綿密な合意の上で進めなければならないと感じました。

そこでよく
*「ユースケース層のテストをしっかり書くべきだ」*
みたい話が出てきますよね、、。

### いま振り返ってみると

:::note info
苦しかったこと: 脳が溶けるような仕様決めを、プロダクトオーナーと共に決定していかなければいけないので、難しさを悟りました。
気づいたこと: 「テストが仕様書になる」という文章を深く理解できました。
:::

## 目標(100%)故に重要度の低いテストも書かなきゃいけない煩わしさを感じる

少し余談です！w

目標を掲げてしまったので、やりとげるのですが、
*「100%はやりすぎたなぁ」*と今は感じています。
(それなら*「他層のテストをもっと書きたかった」*など、諸説あり)

例えば、goでメソッドチェインを実装して、
構造体の値をはめていく値オブジェクト辺りを書いていて、
エラーハンドリングの際に、構造体にエラーを埋め込んで、伝搬するような形をとっていました。

そして
**既にエラーが入ってるなら無条件で次のチェーンに渡す**
ような処理を書いていて、、、

*「「こんなところもテストを網羅しなければいけないのか」」*と、
虚無と戦いながら書いていました。

### いま振り返ってみると

:::note info
苦しかったこと: 100%にするより重要な実装あるのに、そこに時間取られること
気づいたこと: 「100%」を目標とするのは、しんどいし、間違ってる
:::


## 新卒研修という時間はとてもありがたかった

研修期間を終えると、ここまで技術に対して調べ、学び、実装する時間はないので、
あの期間はとても有意義なものでした。

特にインターンの時期などはGraphQL公式ドキュメントの日本語訳とかしてたので、
今考えてみるとすごい期間だったと感じます。

### いま振り返ってみると

:::note info
苦しかったこと: 分からないことだらけだったので、闇雲にもがいていることも時間も長かった気がします。
気づいたこと: 多くを学び、多くを知れる機会だったので、とても良い経験になりました！
:::

### これから研修期間を迎える方へ

ここまで学べる機会は研修期間を抜けると、中々とれないものです！
なので精一杯学べること/吸収できることを我が物にしていってください！！！