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

ドメイン駆動設計入門

uhzz
January 26, 2021

 ドメイン駆動設計入門

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

uhzz

January 26, 2021
Tweet

More Decks by uhzz

Other Decks in Technology

Transcript

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

    View Slide

  2. ●プロジェクト
    - バックエンド担当
    - WEBアプリ基盤サーバーAPI開発/運用
    - WEBアプリインフラ構築/運用
    ●興味
    - ドメイン駆動設計
    - CI/CD
    ●趣味
    - 読書、カフェ巡り
    自己紹介

    View Slide

  3. 1. イントロダクション
    2. ドメイン駆動設計(DDD)とはなんなのか
    3. DDDで使われる専門用語たち
    4. DDDとアーキテクチャの関係
    5. DDDと付き合っていく
    目次

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  8. 書店にて

    View Slide

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

    View Slide

  10. Wikipedia contributors. "ダニング=クルーガー効果
    ." Wikipedia. Wikipedia, 11 Oct. 2020. Web. 12 Nov. 2020.
    1年を通して、コードや書籍を通して
    得た知見をお話しします

    View Slide

  11. 2.ドメイン駆動設計(DDD)とはなんなのか

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  27. type fullname struct {
    firstName string
    lastName string
    }
    type fullname struct {
    firstName name
    lastName name
    }
    どっちも一緒?
    firstName, lastNameはstring型だね!
    えーと、、name型です(そんな型なくね?)

    View Slide

  28. type fullname struct {
    firstName name
    lastName name
    }
    値オブジェクト
    値オブジェクトではname型を定義します!
    値オブジェクトとは、
    「システム固有の値を表現するためのドメインオブジェクト」

    View Slide

  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
    }
    固有の型を定義するメリットは?
    固有の型を定義することで、システムで不要な値を
    初期化するタイミングで削ぎ落とせる!

    View Slide

  30. type name string //name型を定義してます
    func newName(value string) (name, error) {
    // 文字列が0文字以上か
    // 文字列が20字以下か
    // 文字列に英数字が含まれていないか
    return name(value), nil
    }
    つまり?
    ソースコードがドキュメントになる!
    →自己文書化を推進する

    View Slide

  31. そもそも「値」とは?
    - 1, 2, 3, …  → 数字
    - A, B, C, … → 文字
    - りんご, みかん, ぶどう →文字列
    これらには、共通する性質が3つあります。
    - 不変
    - 交換が可能
    - 等価性によって比較される
    値オブジェクトは
    「システム固有の”値”」なので、
    この3つの性質が適用されます。

    View Slide

  32. 不変とは?
    値が「可変」だとすると、、
    "こんにちは".changeTo("今何時?") // こんなメソッドはない
    fmt.Println("こんにちは")
    「こんにちは」という文字列を出力しようとしたのに、「今何時?」が出力される
    「こんにちは」に含まれる別の意味を考えて混乱する
    ことになりかねない、、(言葉のウラをよむ??)
    → 値は「不変」が良さそうですね

    View Slide

  33. 交換が可能って?
    直感的に、普段以下のような「代入」を書いてることでしょう
    var hoge string = "こんにちは"
    hoge = "今何時?"
    何気なく使っている「代入」ですが、無意識にも
    「変数に格納された値を変更(交換)」しているのです(驚)
    ※「こんにちは」という文字列を「今何時?」という文字列に
    上書きしているのではなく、それぞれ格納されている文字列を
    交換している ←この感覚をまんま値オブジェクトでも適用します

    View Slide

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

    View Slide

  35. つまり、、?
    値オブジェクト、「不変」かつ「交換可能」を適用すると、、
    var hogeUser user = user{id: 0, name: "hoge"}
    hogeUser = user{id: 1, name: "fuga"}
    新しいオブジェクトを代入していますね!
    「値」と同じように、「不変」のオブジェクトを「交換」
    しているので、これは値オブジェクトです!

    View Slide

  36. メリットある?
    var hogeUser user = user{id: 0, name: "hoge"}
    // 途方もない処理(hogeUserの中身を変えたりもしてる)
    AllowUser(hogeUser.id, hogeUser.name)
    仮に、userのパラメータにmailAddressなんかがあると、、
    →ユーザの個人情報が別のユーザに送信されるといったバグになりかねない。。
    つまり、状態を変更できないようにするというのは、
    それだけでバグを起こしにくいようにすることができる!

    View Slide

  37. 3−2.エンティティ

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  41. 値オブジェクトと何が違うの?
    type fullname struct {
    firstName name
    lastName name
    }
    type user struct {
    id id
    fullname fullname
    }
    値オブジェクトは、firstName, lastNameが
    同じであれば、まったく同じオブジェクト
    →属性によって識別される
    エンティティは、fullnameが同じでも、
    まったく同じオブジェクトとは限らない
    →属性によって識別されない

    View Slide

  42. エンティティの性質をまとめると
    値オブジェクト エンティティ
    オブジェクト 不変 可変
    属性 区別される 区別されない
    同一性(identify) ない ある

    View Slide

  43. 3−3.ドメインサービス

    View Slide

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

    View Slide

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

    View Slide

  46. ???
    ああ、もちろんだぜ
    もう一人のボク
    ぼく
    ぼくは存在するだろうか?
    「我思う、故に我あり」

    View Slide

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

    View Slide

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

    View Slide

  49. 休憩

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  56. MVCとの違い(個人的意見)
    ユーザー
    インターフェース層
    アプリケーション層
    ドメイン層
    インフラ
    ストラクチャ層
    Model
    Controller
    View
    - Modelが肥大化しがち
    - 役割ぼやけがち

    View Slide

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

    View Slide

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

    インフラストラクチャ層が変更される場合、
    依存しているドメイン層まで変更が入ってしまう

    View Slide

  59. クリーンアーキテクチャでは
    ドメイン層
    インフラ
    ストラクチャ層
    ドメイン層はデータアクセスインターフェースに依存す
    るようになる

    こうする事でインフラストラクチャ層へ変更があったと
    してもドメイン層への影響はない
    何が嬉しいかと言うと、ドメイン層がデータを
    保存する場所(RDSかDynamoDBかRedisか)といっ
    たインフラ部分を気にする事がなくなる
    これを「依存性逆転の原則」と呼びます。
    データアクセス
    インターフェース
    アプリケーション層
    ユーザー
    インターフェース層

    View Slide

  60. 5.DDDと付き合っていく

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  65. まとめ

    View Slide

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

    View Slide

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


    いらすとや. 


    View Slide