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

ドメイン駆動設計入門

Ab8c85abd123fc26817fad242cf4ad4c?s=47 uhzz
January 26, 2021

 ドメイン駆動設計入門

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

Ab8c85abd123fc26817fad242cf4ad4c?s=128

uhzz

January 26, 2021
Tweet

Transcript

  1. ドメイン駆動設計(DDD)入門 2020/11

  2. •プロジェクト - バックエンド担当 - WEBアプリ基盤サーバーAPI開発/運用 - WEBアプリインフラ構築/運用 •興味 - ドメイン駆動設計

    - CI/CD •趣味 - 読書、カフェ巡り 自己紹介
  3. 1. イントロダクション 2. ドメイン駆動設計(DDD)とはなんなのか 3. DDDで使われる専門用語たち 4. DDDとアーキテクチャの関係 5. DDDと付き合っていく

    目次
  4. 1.イントロダクション

  5. ドメイン駆動設計(DDD)を知ったきっかけ このプロジェクトのアプリは「ドメイン駆動」に沿って作ら れてるよ(チームリーダー) なるほどですね! ←ぼく

  6. ネットで調べてみた https://www.amazon.co.jp/dp/479813161X/ref=cm_sw_em_r_mt_dp_XBoRFb1D9HGH7

  7. 書籍購入申請にて この本は、基本的なソフトウェアデザインパターンの経験と十分な理解を持つ 中堅から上級のエンジニアを対象としています。(社内リード) なるほどですね! ←ぼく

  8. 書店にて

  9. なにもわからない。。。

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

    12 Nov. 2020. 1年を通して、コードや書籍を通して 得た知見をお話しします
  11. 2.ドメイン駆動設計(DDD)とはなんなのか

  12. ドメイン駆動設計(DDD)におけるドメインとは、 「プログラムを適用する対象となる領域」 のこと! そもそもドメインって?

  13. システムが対象とするモノや領域によって変化する それってどういうこと? 物流システム 車両管理システム 貨物 倉庫 輸送手段 車両 ドライバー 企業

  14. ドメイン駆動設計(DDD)とは、 「ドメインの知識に焦点を当てた設計手法」 のこと! つまり、、?

  15. 技術指向の開発者であればあるほど疎かにしやすい このモデルを使えば、万事解決 うーん。。 実際の業務内容イマイチよく分かってないけど、ト レンドのこの技術使お

  16. そもそもソフトウェアって、 「利用者の抱えている問題の解決」←大前提

  17. とすると、 開発者は、「利用者が直面している問題」を 正しく理解しなければいけない つまり、 「利用者を取り巻く環境(ドメイン)に向き合う」 必要がある

  18. 言い換えると、 ドメインの概念や事象を理解して、問題解決に 役立つものを抽出する そして、 「抽出した知識を、ソフトウェアに反映する」

  19. それって、、 結局のところ、ドメイン駆動設計(DDD)ってのは 当たり前を当たり前に実践するための開発手法 という側面もある

  20. 3.DDDで使われる専門用語たち

  21. ドメインモデル 車両管理システムにおいて、車両とは 「走行記録を送信する」 ことを表現できれば十分です。 車両には他にも、 「レバーを操作するとワイパーが出る」 「ボタンを押すとサイドミラーが開く」 といった操作もありますが、 システムにおいて表現する必要がありません。

  22. ドメインモデル 抽象的な なにか 事象、概念の洗い出し 洗い出した要素の抽象化 (モデリング) ドメインモデル(抽象的ななにか)とは、 「ドメインから事象、概念を抽象化して得られるモデル」 ドメイン

  23. ドメインモデル 抽象的な なにか ドメインモデル ソースコード (ドメインオブジェクト) 役立つモデルを選別 (すべてを実装するわけではない) 実装! ドメインオブジェクトとは、

    「ドメインモデルをソフトウェアとして表現したもの」
  24. ドメインモデル 抽象的な なにか ドメインモデル ソースコード (ドメインオブジェクト) ドメイン ドメインモデルを媒介して、ドメインの変更が連鎖的に ソースコードへ反映される仕組みができる

  25. ドメインモデル(知識)を表現する ここからは、コードもちょこちょこ挟んでいきます 抽象的な なにか ドメインモデル 値オブジェクト エンティティ ドメインサービス ドメインオブジェクト

  26. 3−1.値オブジェクト

  27. type fullname struct { firstName string lastName string } type

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

    値オブジェクトではname型を定義します! 値オブジェクトとは、 「システム固有の値を表現するためのドメインオブジェクト」
  29. 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 } 固有の型を定義するメリットは? 固有の型を定義することで、システムで不要な値を 初期化するタイミングで削ぎ落とせる!
  30. type name string //name型を定義してます func newName(value string) (name, error) {

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

    C, … → 文字 - りんご, みかん, ぶどう →文字列 これらには、共通する性質が3つあります。 - 不変 - 交換が可能 - 等価性によって比較される 値オブジェクトは 「システム固有の”値”」なので、 この3つの性質が適用されます。
  32. 不変とは? 値が「可変」だとすると、、 "こんにちは".changeTo("今何時?") // こんなメソッドはない fmt.Println("こんにちは") 「こんにちは」という文字列を出力しようとしたのに、「今何時?」が出力される 「こんにちは」に含まれる別の意味を考えて混乱する ことになりかねない、、(言葉のウラをよむ??) → 値は「不変」が良さそうですね

  33. 交換が可能って? 直感的に、普段以下のような「代入」を書いてることでしょう var hoge string = "こんにちは" hoge = "今何時?"

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

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

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

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

  38. どっちも一緒? 名前:たかし(仮名) 年齢:20歳 2020年 名前:たかし(仮名) 年齢:70歳 2070年 〜50年後〜

  39. ソフトウェアにおいて、属性(年齢とか身長とか体重など) によって区別されないオブジェクトを、同一性(identify)によって 識別します。 → 要するにIDで管理するということ! どうやって区別するの?

  40. type user struct { id id fullname fullname } エンティティ

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

    type user struct { id id fullname fullname } 値オブジェクトは、firstName, lastNameが 同じであれば、まったく同じオブジェクト →属性によって識別される エンティティは、fullnameが同じでも、 まったく同じオブジェクトとは限らない →属性によって識別されない
  42. エンティティの性質をまとめると 値オブジェクト エンティティ オブジェクト 不変 可変 属性 区別される 区別されない 同一性(identify)

    ない ある
  43. 3−3.ドメインサービス

  44. そもそもサービスとは 色々な文脈でつかわる言葉ですが、 - 相手のために尽くすこと - 奉仕、勤務、接客、提供 の意味で使われることが多いと思います。 ドメイン駆動設計におけるサービス(ドメインサービス)とは、 「値オブジェクトやエンティティに記述すると不自然な振る舞いを解決す るオブジェクト」

  45. 不自然な振る舞い? var hogeUser user = user{id: 0, name: "hoge"} //

    ユーザーの重複チェック var isExist, _ := hogeUser.IsExists(hogeUser) hogeUserがhogeUserの存在チェックをする? ※便宜上、idとnameをint/string型にしています 一見すると普通のコードに見えますが、コードから読み取れるのは 「自身と同じオブジェクトが存在するかを自身に問い合わせて 確認している」 という情報のみで混乱を招く恐れがあります
  46. ??? ああ、もちろんだぜ もう一人のボク ぼく ぼくは存在するだろうか? 「我思う、故に我あり」

  47. 不自然にならないのは はい、登録されております 役所職員 ぼく ぼくは存在するだろうか? 現実世界の役割をドメインサービスが担う

  48. ドメインサービスを活用すると var userService := NewUserService() var hogeUser user = user{id:

    0, name: "hoge"} // ユーザーの重複チェック var isExist, _ := userService.IsExists(hogeUser) ここから分かることは、ドメインサービス(userService)というロジックを通して エンティティの存在チェックを行っているということです! つまり、ドメインサービスとは 「エンティティ(値オブジェクト)を利用して、 ビジネスルールを記述するオブジェクト」 と言うことができます。
  49. 休憩

  50. 4.DDDとアーキテクチャの関係

  51. ぼくの誤解 「ドメイン駆動設計」ってアーキテクチャが あって、その他にも - レイヤードアーキテクチャ - クリーンアーキテクチャ っていうアーキテクチャがあるんだよね! ←ぼく

  52. ぼくの誤解 「ドメイン駆動設計」ってアーキテクチャが あって、その他にも→ない - レイヤードアーキテクチャ - クリーンアーキテクチャ っていうアーキテクチャがあるんだよね!→ある ←ぼく 「ドメイン駆動設計」はアーキテクチャではない!

  53. アーキテクチャとは、「方針」です つまり、開発者がアーキテクチャに従うことによって、 「何をどこに書くのか」に振り回されないための決まりごと ドメイン駆動設計とセットで出てくるアーキテクチャ - レイヤードアーキテクチャ - ヘキサゴナルアーキテクチャ - クリーンアーキテクチャ

    アーキテクチャ
  54. 先ほども述べた通り、ドメイン駆動設計がアーキテクチャに求めることは、 「何をどこに書くのか」→「ドメインを隔離すること」 が重要であるため、必ずいずれかのアーキテクチャに従う必要はありません! ただし、 いずれかのアーキテクチャに従ったからといって、 ドメイン駆動設計を実践したことにはなりません! アーキテクチャについての注意

  55. 伝統的なアーキテクチャ 矢印の方向に依存することを許可する ※上位のレイヤーから下位のレイヤーを コントロールするようなイメージ ドメイン層が一番重要! 他の層からドメインオブジェクトを隔離する事が目的 レイヤードアーキテクチャ ユーザー インターフェース層 アプリケーション層

    ドメイン層 インフラ ストラクチャ層
  56. MVCとの違い(個人的意見) ユーザー インターフェース層 アプリケーション層 ドメイン層 インフラ ストラクチャ層 Model Controller View

    - Modelが肥大化しがち - 役割ぼやけがち
  57. よく見るやつ ビジネスルール(ロジック)を 中心にするのがコンセプト 依存性を内側に向けている クリーンアーキテクチャ https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

  58. レイヤードアーキテクチャの場合 ユーザー インターフェース層 アプリケーション層 ドメイン層 インフラ ストラクチャ層 レイヤードアーキテクチャの場合、ドメイン層 がインフラストラクチャ層に依存している ↓

    インフラストラクチャ層が変更される場合、 依存しているドメイン層まで変更が入ってしまう
  59. クリーンアーキテクチャでは ドメイン層 インフラ ストラクチャ層 ドメイン層はデータアクセスインターフェースに依存す るようになる ↓ こうする事でインフラストラクチャ層へ変更があったと してもドメイン層への影響はない 何が嬉しいかと言うと、ドメイン層がデータを

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

  61. ドメイン駆動設計は決して開発者だけでは実現しません これまで紹介したパターンやアーキテクチャを導入する事でそれっぽく作る ことはできます → 「軽量DDD」と呼ばれます ドメインの本質に向き合うための手段として以下の概念が存在します。 - ドメインエキスパート - ユビキタス言語 - 境界付けられたコンテキスト

    振り返ってみて
  62. ドメインエキスパート ドメインエキスパートとは、ドメインの実践者のこと! 開発者はドメインエキスパートとのコミュニケーション が不可欠です ドメイン エキスパート

  63. ドメインエキスパートから見えている世界(ドメイン)が どういったものなのか知る必要がある ドメインの概念を捻じ曲げないための共通の言葉が 必要になってくる コミュニケーションを取るには ドメイン エキスパート hello へ、へロー

  64. ユビキタス言語とは、「プロジェクトにおける共通言語」 ドメインエキスパートと開発者はユビキタス言語で 話し、また改良していく事が求められます。 ユビキタス言語 ドメイン エキスパート hello 読めるぞ!!

  65. まとめ

  66. DDDは、今後のエンジニアリングに対するスタンスを変えうる ビジネスの問題を解決するために、ビジネスへの理解を深め ビジネスを表現する ビジネスとコードを結び付けて反復的な改良ができるような 枠組みを作る 「ソフトウェア開発にとっての”当たり前”を徹底しましょう」 まとめ

  67. 参考 成瀬 允宣. 「ドメイン駆動設計入門 ボトムアップでわかる! ドメイン駆動設計の基本 」. 翔泳社, 2020
 


    いらすとや. <https://www.irasutoya.com/>