Advertisement

More Related Content

Slideshows for you(20)

Similar to Python におけるドメイン駆動設計(戦術面)の勘どころ(20)

Advertisement

Recently uploaded(20)

Advertisement

Python におけるドメイン駆動設計(戦術面)の勘どころ

  1. Python における ドメイン駆動設計(戦術面)の 勘どころ 2017-09-09 @ PyCon JP 2017 林 淳哉
  2. 自己紹介 ● 林 淳哉 (@loose_agilist) ● GROOVE X でロボット開発 ● 「実践ドメイン駆動設計」 Reviewer ● Qiita に DDD の記事書いてます
  3. 今日おはなしすること ● ドメイン駆動設計とは ● ドメイン駆動設計の悩みどころ ● Todo List を例にしたドメイン駆動設計の実践 ○ https://github.com/ledmonster/ddd-python-inject
  4. $ git clone https://github.com/ledmonster/ddd-python-inject $ cd todolist $ python setup.py develop $ ./bin/todo --help
  5. ドメイン駆動設計とは何か ● Eric Evans が提唱した設計手法 ● モデリング技術 や オブジェクト指向設計 を抽象化し、 問題領域の抽出から、アーキテクチャ設計、モデリング、 実装に至る全工程を 一貫性のある体系 として整理したも の
  6. おすすめ書籍 エリック・エヴァンスのドメイン駆動設計 (2011) “Domain Driven Design” Eric Evans (2003) DDD 信者の聖書。その難解さから「鈍器」と呼ばれる。抽象度が高く、分厚いので 読み通すの大変だが、何回読んでも発見がある。ここで整理されている概念は、 10 年以上経った今も色褪せない。  実践ドメイン駆動設計 (2015) “Implementing Domain Driven Design” Vaughn Vernon (2011) Evans 本の中身は本質を突いているが、その実践は容易でない。本書は、 Evans 本以降の10年間に発表された新しい開発技法を取り込みながら、 DDD の考え方 を実践に移すにはどうすれば良いかを記述した指南書。 ※ 読むのに挫折しても、鈍器としてなら使えます ※ ※ 翻訳レビューに参加しました。
  7. ドメイン駆動設計を構成する要素 ● 「戦略」的側面 ○ 将棋でいう「定跡」 ○ プロダクト全体を俯瞰するための考え方 ● 「戦術」的側面 ○ 将棋でいう「手筋」 ○ 個々の実装のための考え方
  8. ● ユビキタス言語 ○ プロダクト全体で統一された言葉 を使おう ● コアドメイン、サブドメイン、汎用 ドメイン ○ 問題領域を整理しよう ● 境界付けられたコンテキスト ○ 実装するシステムを整理しよう ● コンテキストマップ ○ システム間の関係を整理しよう ドメイン駆動設計の 「戦略」的側面
  9. ドメイン駆動設計の 「戦術」的側面 ● アーキテクチャ ○ MVC, MVVM などの実装パターン ● ドメインモデル ○ エンティティ ■ 識別子を持つもの ○ 値オブジェクト ■ 値に型を与えたもの ○ サービス ■ 振舞いだけを提供するもの ○ リポジトリ ■ 永続化の仕組み ○ ファクトリ ■ オブジェクトを生成する仕組み ○ 集約 ■ 不変条件を管理する単位 ○ ドメインイベント ■ エンティティの変化を表現したイベント ● アプリケーション ○ コンテキスト全体の調整役
  10. ヘキサゴナルアーキテクチャとは ● 依存性逆転の原則(DIP)を用いて、 ドメインモデルから外部システム(DB・UIなど)への 依存を排除したアーキテクチャ手法 ● 古い方法 ○ 商品管理のロジックが Redis に依存する ● ヘキサゴナルアーキテクチャ ○ 商品管理ロジックにストレージのインタフェースを定義し、 インタフェースに合うように MySQL アダプタを実装する
  11. CQRSとは ● Command and Query Responsibility Segration ○ コマンドクエリ責務分離 ○ Greg Young (2010) ● クエリ(副作用なし)とコマンド(副作用あり)を分離する考え方 ○ 一貫性 ■ 「コマンド」では整合性が求められる ■ 「クエリ」ではあまり気にしない ○ ストレージ ■ 「コマンド」では正規化してデータを保存したい ■ 「クエリ」では非正規化して効率的にデータを取得したい ○ スケーラビリティ ■ 「コマンド」は負荷が大きくなりづらい ■ 「クエリ」は負荷が大きくなりやすい ● ドメイン駆動設計は、コマンドと相性が良い
  12. いざ実践しようとすると悩む・・・
  13. 悩みどころ ● 参考になる Python 実装がない ● ソースコードが肥大化しがち ● リポジトリの実装が複雑になってしまう ● 値オブジェクトの不変性を表現できない ● ヘキサゴナルアーキテクチャの使い方が分からない ● CQRS を適用したいけど、分からない ● 名前の付け方で悩む ● OR Mapper を使って良いのか悩む
  14. というわけで サンプルを作りました
  15. $ git clone https://github.com/ledmonster/ddd-python-inject $ cd todolist $ python setup.py develop $ ./bin/todo add --name 発表資料を作る #1: 発表資料を作る $ ./bin/todo list [ ] #1: 発表資料を作る $ ./bin/done 1 [x] #1: 発表資料を作る
  16. Task TaskRepository TaskStatus User UserService TaskRedisR epository TaskMemory Repository Redis Memory Simple UserService app/cliConsole (app/http) Web 未実 装 Domain Model Adapters Read Model TaskQuery TaskDto Todo List
  17. 考え方
  18. ● 名前を大切にする ● テストを書く ● ヘキサゴナルアーキテクチャを活用する ● DI コンテナを活用する ● DBアクセスライブラリを活用する ● CQRS で読み出し専用ロジックを分離する ● 値オブジェクトを活用する
  19. 名前を大切にしよう ● 違和感を感じたら直す ○ 始めから適切な名前がつけられるとは限らない ○ 良い名前を思いついたら、チームで合意して、直す ○ 適切な名前をつけると、モデルの中身も整理される ● 長過ぎる名前を避ける ○ 経験上、長すぎる名前は活用されづらい ○ 時には略称を活用する ■ 例: decision making → dm ● 曖昧な言葉は、ドメインに対する理解不足のサイ ン
  20. テストを書こう ● メンタルモデルとソースコードを合わせることが大切 ● テストがないと、違和感のあるコードを修正できず、 ドメイン駆動設計の効果が半減する
  21. ヘキサゴナルアーキテクチャを活用しよう ● ドメインモデルを中心に置くことで、 テストのしやすい、柔軟なシステムが構築できる ● アプリケーションは、「アダプタ」+「設定」 ○ HTTP / CLI アダプタ ○ 各種設定 Task TaskRepositor y TaskStatu s User UserService TaskRedis Repository TaskMemor yRepository Redis Memor y Simple UserService app/cliConsole (app/http) Web 未実装 Domain Model Adapters
  22. DI コンテナを活用しよう DI コンテナを使わない場合 ● コンストラクタで依存性を注入 ● 依存関係が増えると悪夢
  23. DI コンテナを活用しよう DI コンテナ(inject)を利用 ● https://pypi.python.org/pypi/Inject/3.1.1 ● DI コンテナで依存関係を一元管理
  24. DI コンテナを活用しよう DI コンテナ(inject)を利用 ● https://pypi.python.org/pypi/Inject/3.1.1 ● DI コンテナで依存関係を一元管理 ● コンストラクタが汚染されない
  25. DB のアクセスライブラリを活用しよう ● リポジトリの実装に OR マッパーなどの ライブラリを使っても構わない ● Todo List での実装 ○ adapter/redis 以下にスキーマ定義 ○ adapter/repo/redis でスキーマを利用
  26. DB のアクセスライブラリを活用しよう https://github.com/groove-x/gxredis todolist.adapter.redis.task todolist.adapter.repo.task.redis
  27. CQRS で読み出し専用ロジックを分離しよう 失敗談 ● 検索要件が増えると、リポジトリが肥大化 ● リポジトリの入出力はエンティティや値オブジェクトのため、 ○ 入出力のオーバーヘッドが大きい ○ 書式の最適化がしづらい ○ ドメインモデルと整合性を取りながらメンテナンスするのが大変 ○ DB 固有の最適化がしづらい
  28. CQRS で読み出し専用ロジックを分離しよう 改善案 ● 読み出し専用の処理は read_model として分離する ○ リポジトリをシンプルに保てる ○ 読み出し処理を最適化できる
  29. 値オブジェクトを活用しよう ● エンティティが増えがち ● コンテキスト内で属性を変更しないなら、 値オブジェクトにできる ● 例 ○ 外部のコンテキストで管理している オブジェクトを参照する場合
  30. Task TaskRepository TaskStatus User UserService TaskRedisR epository TaskMemory Repository Redis Memory Simple UserService app/cliConsole (app/http) Web 未実 装 Domain Model Adapters Read Model TaskQuery TaskDto Todo List
  31. まとめ ● Python でドメイン駆動設計を実践しました ○ 名前の付け方を大切にしよう ○ テストを書こう ○ ヘキサゴナルアーキテクチャを使って ドメインモデルと外部依存の実装を分離しよう ○ DIコンテナ(inject)で依存性を管理しよう ○ DB のアクセスライブラリを活用しよう ○ CQRS で読み出し専用ロジックを分離しよう ○ 値オブジェクトを活用しよう
Advertisement