51
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

CrowdWorksAdvent Calendar 2017

Day 14

DDDで考えるマイクロサービスのバリデーション

Last updated at Posted at 2017-12-14

この情報は古いです。リライトしました。
http://hikouki.hateblo.jp/entry/2019/05/31/164944

この記事は CrowdWorks Advent Calendar 2017 の14日目です。

エンジニアリーダーの @hikouki です。

0からDDDでアプリケーションを立ち上げ中ですが、バリデーションの壁にぶち当たったので、
「バリデーション」はどう扱えばいいのか考えてみました。

バリデーション

ここでは、ユーザー(外部システム)入力値に対する検証に限定します。

どこでユーザー入力値を検証するべきか

ユーザー入力値のバリデーションは全て、Presentersion層で行うべきだと考えました。

理由は、「Application層に来た時点でユーザー入力値ではない」からです。
なので、Application層の引数が不正な場合は、例外(内部エラー)として扱うようにします。

どこにバリデーションルールを定義するべきか

バリデーションルールには、業務知識を含むものと含まないものがあります。

例えば、以下のような感じです。

業務知識

  • 注文番号は15桁
  • emailは一意
  • 名前は必須

業務知識でないもの

  • 入力値Aの状態によって、入力値Bのルールが変わる(Presentersion層の都合)

まず、業務知識は ValueObject に定義して、
業務知識でないものはPresentation層に定義することを考えました。

業務知識をDomain層に書くことは正しいし、そうすべきです。

ですが、チームで話した結果、Domain層にバリデーションルールを定義しないことにしました。

理由は以下のような感じです。

  • Presentation層と、Domain層でバリデーション定義が散らばる
  • 場合によって、バリデーションルールが変わる(記事が下書きの時は、内容は空でも良いなど)

業務知識がドメイン層から染み出してしまうので、かなり悩みました。
ただ、コードの見通しや変更しやすさを優先しています。

DBにアクセスする必要があるものはどう検証するか

これもどの層で検証するか議論が分かれます。

なるべく各層の依存関係をシンプルにしたいので、Presentation層からInfrastructure層を呼び出すことは避けたいです。

そこで、Application層で検証することにしてみます。

Application層で検証する場合、それはユーザー入力値ではないので、検証に失敗した場合、例外(内部エラー)を返します。

なので、APIの呼び出し元で事前に値を検証する必要がありそうです。

値を検証するためだけのAPIを用意して、検証した後で、呼び出してもらうような設計にしました。

重複しやすい値が高頻度で入力されるシステムの場合は、耐えられない気もしますが、
今のところ、そのようなデータを扱っていないので、この設計に落ち着いています。

バリデーションエラーをどう表現するか

不正な入力値の場合、バリデーションエラーである旨、APIの呼び出し元に返す必要があります。

この記事では、「ある特定の社内サービスからgRPCで通信するマイクロサービス」を前提にします。

Viewを持たないので、リッチなメッセージを返す必要はなさそうです。

また、UXを良くする為に、エンドユーザーには早い段階で入力値の検証を行いたいことがあります。

その為、エンドユーザーへの入力値バリデーションは、マイクロサービスを使う側の責務としました。

マイクロサービス側は、期待していない値が入力された場合、例外(INVALID_ARGUMENT)として扱い、適切に障害通知して必要な情報をログに保存します。

APIの呼び出し元は、例外を受け取った場合、処理が継続不可能な状態として 「500エラー」の画面を表示させます。

まとめ

チーム内でも意見が分かれる部分があり、かなり熱く議論しました。

DDD的な考え方から行くと、やっぱりDomain層にバリデーションルールを定義した方がいい気もしています。

ただ、メンバーの経験や、すでにある事例を参考にして意思決定を行いました。

バリデーションや例外の扱い方はアプリケーションの要件によって大きく変わる部分なので、一つの参考資料として見て頂けると幸いです。

51
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
51
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?