Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ドメイン駆動設計入門

Avatar for uhzz uhzz
January 26, 2021

 ドメイン駆動設計入門

社内勉強会で使用したドメイン駆動設計のスライドです

Avatar for uhzz

uhzz

January 26, 2021
Tweet

More Decks by uhzz

Other Decks in Technology

Transcript

  1. Wikipedia contributors. "ダニング=クルーガー効果 ." Wikipedia. Wikipedia, 11 Oct. 2020. Web.

    12 Nov. 2020. 1年を通して、コードや書籍を通して 得た知見をお話しします
  2. type fullname struct { firstName string lastName string } type

    fullname struct { firstName name lastName name } どっちも一緒? firstName, lastNameはstring型だね! えーと、、name型です(そんな型なくね?)
  3. type fullname struct { firstName name lastName name } 値オブジェクト

    値オブジェクトではname型を定義します! 値オブジェクトとは、 「システム固有の値を表現するためのドメインオブジェクト」
  4. type name string //name型を定義してます func newName(value string) (name, error) {

    // 文字列が「hoge」であるか、初期化のタイミングでチェックできる! if value != "hoge" { return "", errors.New("value is not hoge") } return name(value), nil } 固有の型を定義するメリットは? 固有の型を定義することで、システムで不要な値を 初期化するタイミングで削ぎ落とせる!
  5. type name string //name型を定義してます func newName(value string) (name, error) {

    // 文字列が0文字以上か // 文字列が20字以下か // 文字列に英数字が含まれていないか return name(value), nil } つまり? ソースコードがドキュメントになる! →自己文書化を推進する
  6. そもそも「値」とは? - 1, 2, 3, …  → 数字 - A, B,

    C, … → 文字 - りんご, みかん, ぶどう →文字列 これらには、共通する性質が3つあります。 - 不変 - 交換が可能 - 等価性によって比較される 値オブジェクトは 「システム固有の”値”」なので、 この3つの性質が適用されます。
  7. 交換が可能って? 直感的に、普段以下のような「代入」を書いてることでしょう var hoge string = "こんにちは" hoge = "今何時?"

    何気なく使っている「代入」ですが、無意識にも 「変数に格納された値を変更(交換)」しているのです(驚) ※「こんにちは」という文字列を「今何時?」という文字列に 上書きしているのではなく、それぞれ格納されている文字列を 交換している ←この感覚をまんま値オブジェクトでも適用します
  8. つまり、、? 値オブジェクト、「不変」かつ「交換可能」を適用しないと、、 var hogeUser user = user{id: 0, name: "hoge"}

    hogeUser.name = "fuga" 確かにこのコードは正常に動作しますし、なんならよく見慣れた方もいるはず ※便宜上、idとnameをint/string型にしています ですが、残念ながらこのコードは、 「値は不変」というルールを適用してないので 「値オブジェクト」ではありません。 →やりがちなパターンです。。
  9. つまり、、? 値オブジェクト、「不変」かつ「交換可能」を適用すると、、 var hogeUser user = user{id: 0, name: "hoge"}

    hogeUser = user{id: 1, name: "fuga"} 新しいオブジェクトを代入していますね! 「値」と同じように、「不変」のオブジェクトを「交換」 しているので、これは値オブジェクトです!
  10. メリットある? var hogeUser user = user{id: 0, name: "hoge"} //

    途方もない処理(hogeUserの中身を変えたりもしてる) AllowUser(hogeUser.id, hogeUser.name) 仮に、userのパラメータにmailAddressなんかがあると、、 →ユーザの個人情報が別のユーザに送信されるといったバグになりかねない。。 つまり、状態を変更できないようにするというのは、 それだけでバグを起こしにくいようにすることができる!
  11. type user struct { id id fullname fullname } エンティティ

    値オブジェクトと同じように、 固有のid型、fullname型を定義するよ! エンティティとは、 「属性でなく同一性によって識別されるドメインオブジェクト」
  12. 値オブジェクトと何が違うの? type fullname struct { firstName name lastName name }

    type user struct { id id fullname fullname } 値オブジェクトは、firstName, lastNameが 同じであれば、まったく同じオブジェクト →属性によって識別される エンティティは、fullnameが同じでも、 まったく同じオブジェクトとは限らない →属性によって識別されない
  13. 不自然な振る舞い? var hogeUser user = user{id: 0, name: "hoge"} //

    ユーザーの重複チェック var isExist, _ := hogeUser.IsExists(hogeUser) hogeUserがhogeUserの存在チェックをする? ※便宜上、idとnameをint/string型にしています 一見すると普通のコードに見えますが、コードから読み取れるのは 「自身と同じオブジェクトが存在するかを自身に問い合わせて 確認している」 という情報のみで混乱を招く恐れがあります
  14. ドメインサービスを活用すると var userService := NewUserService() var hogeUser user = user{id:

    0, name: "hoge"} // ユーザーの重複チェック var isExist, _ := userService.IsExists(hogeUser) ここから分かることは、ドメインサービス(userService)というロジックを通して エンティティの存在チェックを行っているということです! つまり、ドメインサービスとは 「エンティティ(値オブジェクト)を利用して、 ビジネスルールを記述するオブジェクト」 と言うことができます。
  15. クリーンアーキテクチャでは ドメイン層 インフラ ストラクチャ層 ドメイン層はデータアクセスインターフェースに依存す るようになる ↓ こうする事でインフラストラクチャ層へ変更があったと してもドメイン層への影響はない 何が嬉しいかと言うと、ドメイン層がデータを

    保存する場所(RDSかDynamoDBかRedisか)といっ たインフラ部分を気にする事がなくなる これを「依存性逆転の原則」と呼びます。 データアクセス インターフェース アプリケーション層 ユーザー インターフェース層