Suche senden
Hochladen
サービス開発における フロントエンド・ドメイン駆動設計の実践
•
12 gefällt mir
•
41,461 views
T
TakefumiYoshii
Folgen
DeNA TechCon 2018 BLUE Stage
Weniger lesen
Mehr lesen
Ingenieurwesen
Melden
Teilen
Melden
Teilen
1 von 93
Jetzt herunterladen
Downloaden Sie, um offline zu lesen
Empfohlen
イミュータブルデータモデルの極意
イミュータブルデータモデルの極意
Yoshitaka Kawashima
シリコンバレーの「何が」凄いのか
シリコンバレーの「何が」凄いのか
Atsushi Nakada
Mercari JPのモノリスサービスをKubernetesに移行した話 PHP Conference 2022 9/24
Mercari JPのモノリスサービスをKubernetesに移行した話 PHP Conference 2022 9/24
Shin Ohno
「のどが渇いた」というユーザーに何を出す? ユーザーの「欲しい」に惑わされない、本当のインサイトを見つけるUXデザイン・UXリサーチ
「のどが渇いた」というユーザーに何を出す? ユーザーの「欲しい」に惑わされない、本当のインサイトを見つけるUXデザイン・UXリサーチ
Yoshiki Hayama
イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)
Yoshitaka Kawashima
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
Hiroshi Ito
思考停止しないアーキテクチャ設計 ➖ JJUG CCC 2018 Fall
思考停止しないアーキテクチャ設計 ➖ JJUG CCC 2018 Fall
Yoshitaka Kawashima
ドメイン駆動で開発する ラフスケッチから実装まで
ドメイン駆動で開発する ラフスケッチから実装まで
増田 亨
Empfohlen
イミュータブルデータモデルの極意
イミュータブルデータモデルの極意
Yoshitaka Kawashima
シリコンバレーの「何が」凄いのか
シリコンバレーの「何が」凄いのか
Atsushi Nakada
Mercari JPのモノリスサービスをKubernetesに移行した話 PHP Conference 2022 9/24
Mercari JPのモノリスサービスをKubernetesに移行した話 PHP Conference 2022 9/24
Shin Ohno
「のどが渇いた」というユーザーに何を出す? ユーザーの「欲しい」に惑わされない、本当のインサイトを見つけるUXデザイン・UXリサーチ
「のどが渇いた」というユーザーに何を出す? ユーザーの「欲しい」に惑わされない、本当のインサイトを見つけるUXデザイン・UXリサーチ
Yoshiki Hayama
イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)
Yoshitaka Kawashima
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
Hiroshi Ito
思考停止しないアーキテクチャ設計 ➖ JJUG CCC 2018 Fall
思考停止しないアーキテクチャ設計 ➖ JJUG CCC 2018 Fall
Yoshitaka Kawashima
ドメイン駆動で開発する ラフスケッチから実装まで
ドメイン駆動で開発する ラフスケッチから実装まで
増田 亨
アジャイルにモデリングは必要か
アジャイルにモデリングは必要か
Hiromasa Oka
45分間で「ユーザー中心のものづくり」ができるまで詰め込む
45分間で「ユーザー中心のものづくり」ができるまで詰め込む
Yoshiki Hayama
フロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjug
Itsuki Kuroda
テスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるな
Kentaro Matsui
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
mosa siru
ドメイン駆動設計に15年取り組んでわかったこと
ドメイン駆動設計に15年取り組んでわかったこと
増田 亨
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
Takuto Wada
インフラCICDの勘所
インフラCICDの勘所
Toru Makabe
モデリングもしないでアジャイルとは何事だ
モデリングもしないでアジャイルとは何事だ
Iwao Harada
初心者向けMongoDBのキホン!
初心者向けMongoDBのキホン!
Tetsutaro Watanabe
なぜ「マイクロサービス“化”」が必要なのか
なぜ「マイクロサービス“化”」が必要なのか
Yusuke Suzuki
それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?
Yoshitaka Kawashima
正しいものを正しく作る塾-設計コース
正しいものを正しく作る塾-設計コース
増田 亨
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織
Takafumi ONAKA
Redisの特徴と活用方法について
Redisの特徴と活用方法について
Yuji Otani
心理的安全性と、Veinの紹介 Psychological safety and introduction of Vein
心理的安全性と、Veinの紹介 Psychological safety and introduction of Vein
Tokoroten Nakayama
ドメイン駆動設計 本格入門
ドメイン駆動設計 本格入門
増田 亨
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)
Yoshitaka Kawashima
チャットコミュニケーションの問題と心理的安全性の課題 #EOF2019
チャットコミュニケーションの問題と心理的安全性の課題 #EOF2019
Tokoroten Nakayama
ドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解する
増田 亨
BPStudy20121221
BPStudy20121221
Shinichiro Takezaki
Ajax basic
Ajax basic
Katsuyuki Seino
Weitere ähnliche Inhalte
Was ist angesagt?
アジャイルにモデリングは必要か
アジャイルにモデリングは必要か
Hiromasa Oka
45分間で「ユーザー中心のものづくり」ができるまで詰め込む
45分間で「ユーザー中心のものづくり」ができるまで詰め込む
Yoshiki Hayama
フロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjug
Itsuki Kuroda
テスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるな
Kentaro Matsui
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
mosa siru
ドメイン駆動設計に15年取り組んでわかったこと
ドメイン駆動設計に15年取り組んでわかったこと
増田 亨
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
Takuto Wada
インフラCICDの勘所
インフラCICDの勘所
Toru Makabe
モデリングもしないでアジャイルとは何事だ
モデリングもしないでアジャイルとは何事だ
Iwao Harada
初心者向けMongoDBのキホン!
初心者向けMongoDBのキホン!
Tetsutaro Watanabe
なぜ「マイクロサービス“化”」が必要なのか
なぜ「マイクロサービス“化”」が必要なのか
Yusuke Suzuki
それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?
Yoshitaka Kawashima
正しいものを正しく作る塾-設計コース
正しいものを正しく作る塾-設計コース
増田 亨
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織
Takafumi ONAKA
Redisの特徴と活用方法について
Redisの特徴と活用方法について
Yuji Otani
心理的安全性と、Veinの紹介 Psychological safety and introduction of Vein
心理的安全性と、Veinの紹介 Psychological safety and introduction of Vein
Tokoroten Nakayama
ドメイン駆動設計 本格入門
ドメイン駆動設計 本格入門
増田 亨
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)
Yoshitaka Kawashima
チャットコミュニケーションの問題と心理的安全性の課題 #EOF2019
チャットコミュニケーションの問題と心理的安全性の課題 #EOF2019
Tokoroten Nakayama
ドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解する
増田 亨
Was ist angesagt?
(20)
アジャイルにモデリングは必要か
アジャイルにモデリングは必要か
45分間で「ユーザー中心のものづくり」ができるまで詰め込む
45分間で「ユーザー中心のものづくり」ができるまで詰め込む
フロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjug
テスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるな
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
ドメイン駆動設計に15年取り組んでわかったこと
ドメイン駆動設計に15年取り組んでわかったこと
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
インフラCICDの勘所
インフラCICDの勘所
モデリングもしないでアジャイルとは何事だ
モデリングもしないでアジャイルとは何事だ
初心者向けMongoDBのキホン!
初心者向けMongoDBのキホン!
なぜ「マイクロサービス“化”」が必要なのか
なぜ「マイクロサービス“化”」が必要なのか
それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?
正しいものを正しく作る塾-設計コース
正しいものを正しく作る塾-設計コース
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織
Redisの特徴と活用方法について
Redisの特徴と活用方法について
心理的安全性と、Veinの紹介 Psychological safety and introduction of Vein
心理的安全性と、Veinの紹介 Psychological safety and introduction of Vein
ドメイン駆動設計 本格入門
ドメイン駆動設計 本格入門
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)
チャットコミュニケーションの問題と心理的安全性の課題 #EOF2019
チャットコミュニケーションの問題と心理的安全性の課題 #EOF2019
ドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解する
Ähnlich wie サービス開発における フロントエンド・ドメイン駆動設計の実践
BPStudy20121221
BPStudy20121221
Shinichiro Takezaki
Ajax basic
Ajax basic
Katsuyuki Seino
データマイニング+WEB勉強会資料第6回
データマイニング+WEB勉強会資料第6回
Naoyuki Yamada
ドメイン駆動設計という仕事の流儀
ドメイン駆動設計という仕事の流儀
増田 亨
DSL駆動によるクラウド・アプリケーション開発
DSL駆動によるクラウド・アプリケーション開発
Tomoharu ASAMI
Linux 対応だけじゃない!! sql server 2017 こんな機能が追加されています。
Linux 対応だけじゃない!! sql server 2017 こんな機能が追加されています。
Masayuki Ozawa
Object-Functional Analysis and Design : 次世代モデリングパラダイムへの道標
Object-Functional Analysis and Design : 次世代モデリングパラダイムへの道標
Tomoharu ASAMI
ドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみよう
増田 亨
ドメインロジックの実装方法とドメイン駆動設計
ドメインロジックの実装方法とドメイン駆動設計
Tadayoshi Sato
Apexコアデベロッパーセミナー070726 配布用
Apexコアデベロッパーセミナー070726 配布用
stomita
XPages 開発 Tips 百連発
XPages 開発 Tips 百連発
Mitsuru Katoh
Net advantage 2012 volume2 最新情報 xaml プラットフォーム編
Net advantage 2012 volume2 最新情報 xaml プラットフォーム編
Daizen Ikehara
Symfony2でより良いソフトウェアを作るために
Symfony2でより良いソフトウェアを作るために
Atsuhiro Kubo
SQL Server 2016 R Services + Microsoft R Server 技術資料
SQL Server 2016 R Services + Microsoft R Server 技術資料
Koichiro Sasaki
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Yoshifumi Kawai
Seasarプロジェクト徹底攻略
Seasarプロジェクト徹底攻略
takezoe
ADO.NET Entity Framework
ADO.NET Entity Framework
Microsoft
React+redux+saga 01
React+redux+saga 01
TIS Inc
ドメイン駆動設計 の 実践 Part3 DDD
ドメイン駆動設計 の 実践 Part3 DDD
増田 亨
Windows PowerShell 2.0 の基礎知識
Windows PowerShell 2.0 の基礎知識
shigeya
Ähnlich wie サービス開発における フロントエンド・ドメイン駆動設計の実践
(20)
BPStudy20121221
BPStudy20121221
Ajax basic
Ajax basic
データマイニング+WEB勉強会資料第6回
データマイニング+WEB勉強会資料第6回
ドメイン駆動設計という仕事の流儀
ドメイン駆動設計という仕事の流儀
DSL駆動によるクラウド・アプリケーション開発
DSL駆動によるクラウド・アプリケーション開発
Linux 対応だけじゃない!! sql server 2017 こんな機能が追加されています。
Linux 対応だけじゃない!! sql server 2017 こんな機能が追加されています。
Object-Functional Analysis and Design : 次世代モデリングパラダイムへの道標
Object-Functional Analysis and Design : 次世代モデリングパラダイムへの道標
ドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみよう
ドメインロジックの実装方法とドメイン駆動設計
ドメインロジックの実装方法とドメイン駆動設計
Apexコアデベロッパーセミナー070726 配布用
Apexコアデベロッパーセミナー070726 配布用
XPages 開発 Tips 百連発
XPages 開発 Tips 百連発
Net advantage 2012 volume2 最新情報 xaml プラットフォーム編
Net advantage 2012 volume2 最新情報 xaml プラットフォーム編
Symfony2でより良いソフトウェアを作るために
Symfony2でより良いソフトウェアを作るために
SQL Server 2016 R Services + Microsoft R Server 技術資料
SQL Server 2016 R Services + Microsoft R Server 技術資料
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Seasarプロジェクト徹底攻略
Seasarプロジェクト徹底攻略
ADO.NET Entity Framework
ADO.NET Entity Framework
React+redux+saga 01
React+redux+saga 01
ドメイン駆動設計 の 実践 Part3 DDD
ドメイン駆動設計 の 実践 Part3 DDD
Windows PowerShell 2.0 の基礎知識
Windows PowerShell 2.0 の基礎知識
サービス開発における フロントエンド・ドメイン駆動設計の実践
1.
サービス開発における フロントエンド・ドメイン駆動設計の実践 DeNA TechCon 2018
BLUE Stage 2018.02.07
2.
吉井 健文 システムデザイン本部デザイン戦略部 デザインエンジニアリンググループ @Takepepe
@takefumi-yoshii 自己紹介
3.
担当のKenCoMについて 健康リコメンデーションメディア。 健康データの一元管理、利用者の健康度に応じた情報提供。 健康への行動変容を促すサービスへと成長中。
4.
担当のKenCoMが先日リニューアルリリース
5.
担当のKenCoMが先日リニューアルリリース アプリから取得した、歩数・体重・血圧 などのバイタルデータを自動連携。 PCブラウザでも閲覧でき、 手動入力による機能を導入。
6.
React + Redux
という構成は以前から存在したが、 部分的な機能に閉じており、機能追加で Store 乱立が懸念された。 各エンドポイントで、Single Store を維持しつつ 分割統合を柔軟に行いたい。 リニューアル課題
7.
バイタルデータの表示・編集機能など、 複雑な機能は OOPをもって乗り切る必要性を感じた。 モデルも抽象化も無いRedux に、 OOPデザインパターンを統合できるのか? リニューアル課題
8.
小粒度の戦略・アイデアを柔軟に反映可能な、 PDCAサイクルを加速させる フロントエンドの基礎を築きたい。 リニューアル課題
9.
リニューアル課題まとめ 1. エンドポイント毎に異なる、Storeの分割統合 2. 複雑な機能に備え、Redux
に OOP を持ち込む 3. PDCAサイクルを加速するための基礎構築
10.
技術選定の背景 - Hexagonal Redux
-
11.
課題領域(ドメイン)を疎結合にし、再利用・分割統合が容易な 最適解を求めDDDに辿り着く。 エリック・エヴァンスのレイヤードアーキテクチャ(※) 導入を試みるも、 Store と
モデルが分断され、状態の2重管理が発生してしまった。 (※) エリック・エヴァンスのドメイン駆動設計 アーキテクチャ選定背景
12.
そこから、ヴァーン・ヴァーノンの「実践ドメイン駆動設計」(※) で 紹介されているヘキサゴナルアーキテクチャに出会う。(※) 実践ドメイン駆動設計 イベント駆動で表現されたヘキサゴナルアーキテクチャは、 Redux
と相性が良く、多くのコンセプトが一致。 全エンドポイントで Hexagonal Redux を 導入するに至った。 アーキテクチャ選定背景
13.
React + Redux
+ redux-saga + immutable.js flowtype + jest Hexagonal Redux モジュール構成
14.
◼ DomainModel ◼ ReduxAction ◼
Adapter (redux-saga) ◼ Adapter (react-redux) Hexagonal Redux 概念図
15.
Hexagonal Redux 概要 1.
ヘキサゴナルアーキテクチャを模範とした構成 2. Storeの内側に複数のドメインモデルを構える 3. 「イベント・サービス・モデル」で単体ドメイン扱い
16.
`domains` 配下に「イベント・サービス・モデル」== 「Redux +
redux-saga + immutable.js」 `views` には React コード `applications` には エントリーポイント Hexagonal Redux パッケージ構成 ./front/javascripts/ ├── applications ├── constants ├── domains │ ├── achievementQueue │ ├── articles │ ├── healthRecords │ │ ├── stepCounts │ │ ├── weights │ │ └── ... │ ├── recommendedArticles │ │ ├── model.js │ │ └── redux.js │ ├── renderWidget │ │ ├── model.js │ │ ├── redux.js │ │ └── saga.js │ └── ... ├── helpers ├── lib └── views
17.
抽象化の文脈 - 抽象化へのターニングポイント -
18.
バイタルデータ表示・編集機能 - OOP基底クラス
- 項目毎に、表示期間に 応じたグラフリソースの捻 出・不足レコードの fetch
19.
バイタルデータ表示・編集機能 - OOP基底クラス
- 表示期間に応じた 平均値の算出
20.
バイタルデータ表示・編集機能 - OOP基底クラス
- 該当日のレコードの 選択・更新
21.
バイタルデータ表示・編集機能 - OOPファクトリー
- 食前/食後 など、 ドメイン固有の測定値
22.
バイタルデータ表示・編集機能 - OOPファクトリー
- 異なるレコードの扱い (1日に複数の測定値)
23.
バイタルデータ表示・編集機能 - OOPファクトリー
- 1日に複数の測定値を 保持するレコードの 取り扱い
24.
基底クラス・ファクトリーのほか、 表示における関心事の分離など、(値の丸め処理・単位ラベル etc) OOPのデザインパターンが活きる場面が多数見受けられた。 また、今後取り扱うバイタルデータが増えることが想定できた。 抽象化の文脈 -
抽象化へのターニングポイント -
25.
抽象化の文脈 - Redux における抽象化とは?
-
26.
ReduxAction を抽象化することで、構成要素の 全てを同一レベルで抽象化することが可能。 ReduxAction 抽象化の立て役となった、 ボイラープレートジェネレーターを紹介。 抽象化の文脈
- Reduxにおける抽象化とは? -
27.
ReduxAction をモデルに委譲する higher-order-reducer
を生成。 export function createReducer (commands: string[], namespace: string): Function { return (initialModel: immutable.Record) => { return (model = initialModel, action: ActionCreator) => { const fn = action.type.replace(namespace, '') if (model[fn] !== undefined) return model[fn](action.payload) return model } } } 抽象化の文脈 - Reduxにおける抽象化とは? -
28.
ActionCreators と ActionTypes
を生成。 export function createActions (commands: string[], namespace: string) { const types: ActionTypes = {} const creators: ActionCreators = {} commands.map((row: string) => { const type: ActionType = `${namespace}${row}` types[row] = type creators[row] = payload => { return { type, payload } } }) return { types, creators } } 抽象化の文脈 - Reduxにおける抽象化とは? -
29.
ボイラープレートジェネレーターを集約。 このジェネレーターは、状態を変更する Action名を宣言することで、 3種のボイラープレートが一度に出来上がる。(Action名配列の宣言・名前空間の宣言 ) export
function createReduxBoilerplate (commands: string[], namespace: string) { const { types, creators } = createActions(commands, namespace) const reducer = createReducer(commands, namespace) return { types, creators, reducer } } 抽象化の文脈 - Reduxにおける抽象化とは? -
30.
普段の3種のボイラープレート実装は 状態を変化する「コマンド」の StringArray 宣言のみ、 という明快なものとなった。
(要別途 payload 型定義) const { types, creators, reducer } = createReduxBoilerplate([ 'registerAchievement', 'registerAchievements', 'deleteQueueItemByIndex' ], '/domains/achievementQueue/') export { types, creators, reducer } 抽象化の文脈 - Reduxにおける抽象化とは? - 名前空間
31.
export const abstractCommands
= [ 'registerHealthRecordsSrc', 'updateHealthRecordsSrc', 'shiftShowRange', 'shiftCurrentDate' ] const { types, creators, reducer } = createReduxBoilerplate([ ...abstractCommands ], '/domains/healthRecords/stepCounts/') const { types, creators, reducer } = createReduxBoilerplate([ ...abstractCommands, 'setEditorCurrentIndex', 'toggleTimingActive' ], '/domains/healthRecords/bloodSugars/') ReduxAction の抽象コード実体は StringArray。
32.
export const abstractCommands
= [ 'registerHealthRecordsSrc', 'updateHealthRecordsSrc', 'shiftShowRange', 'shiftCurrentDate' ] const { types, creators, reducer } = createReduxBoilerplate([ ...abstractCommands ], '/domains/healthRecords/stepCounts/') const { types, creators, reducer } = createReduxBoilerplate([ ...abstractCommands, 'setEditorCurrentIndex', 'toggleTimingActive' ], '/domains/healthRecords/bloodSugars/') ReduxAction の抽象コード実体は StringArray。 New New
33.
レコードを登録する レコードを更新する 表示期間を変更する 表示日を変更する ReduxAction の抽象コード実体は StringArray。(コード要約) 歩数のレコードを登録する 歩数のレコードを更新する 歩数の表示期間を変更する 歩数の表示日を変更する 血糖値のレコードを登録する 血糖値のレコードを更新する 血糖値の表示期間を変更する 血糖値の表示日を変更する 血糖値の編集測定点を切り替える 血糖値の測定値表示を切り替える バイタルドメインイベント 歩数ドメインイベント 血糖値ドメインイベント 「歩数の」名前空間 「血糖値の」名前空間 New New
34.
状態を変化する「コマンド = ReduxAction」 のリファクタが容易である点も、 運用において大きな利点であると言える。 抽象化の文脈
- Reduxにおける抽象化とは? -
35.
抽象化の文脈 - Redux におけるモデルとは?
-
36.
通常 ReduxStore の状態管理は データソースの保持のみであり、 モデルとしての振る舞いは持ち合わせていない。 ヘルパーモジュールか、view上での処理に 頼らざるを得なかった。 抽象化の文脈
- Reduxにおけるモデルとは? -
37.
この課題を immutable.Record をモデルとして扱う手法で解決。 先ほど宣言した
Action が Dispatch されると、 Reducer から委譲された setter/updater が実行され状態が変化する。 export class BloodSugarsModel extends MultiItemModel(props) { setEditorCurrentIndex (value: number): BloodSugarsModel { return this.set('editor_current_index', value) } toggleTimingActive (index: number): BloodSugarsModel { return this.update('timings', timings => { return timings.update(index, timing => timing.toggleActive()) }) } } 抽象化の文脈 - Reduxにおけるモデルとは? -
38.
Immutable.Record は継承可能。 この抽象レイヤーで、先ほど宣言した Action
と 同一抽象レベルのメソッドを定義。 export const MultiItemModel = (opt: Props) => class extends ItemQueryModel(props(opt)) { updateHealthRecordsSrc (src: RecordProps): MultiItemModel { const { base_date, end_date, records } = src return this._updateRecords(base_date, end_date, fromJS(records)) } } 抽象化の文脈 - Reduxにおけるモデルとは? -
39.
「業務処理・ビジネスロジック・表示上の関心事」を継承階層で分離 抽象化の文脈 - Reduxにおけるモデルとは?
- XHRレスポンスに応じてレコード生成。 全てのレコードが欲しい。 今表示しているレコードの平均は? 次の表示期間に十分なレコードはあるか? 丸め処理済みのラベルが欲しい。 今表示している期間のラベルが欲しい。 継承 継承 バイタル ドメインモデル (抽象モデル) プレゼンテーション層 ビジネスロジック層 業務処理層
40.
「基底クラスメソッド・ファクトリーメソッド」のオーバーライド 抽象化の文脈 - Reduxにおけるモデルとは?
- XHRレスポンスに応じて 血糖値レコード生成。 全てのレコードが欲しい。 今表示しているレコードの 各測定値平均は? 次の表示期間に十分なレコードはあるか? 丸め処理済みのラベルが欲しい。 今表示している期間のラベルが欲しい。 継承 継承 血糖値 ドメインモデル バイタル ドメインモデル (抽象モデル) 継承 override override override プレゼンテーション層 ビジネスロジック層 業務処理層
41.
OOP デザインパターンを FRP
パラダイムに 持ち込むことが可能となった。 課題領域(ドメイン)を分離し、責務に応じて ドメインをスケールさせる、DDD の基礎が出来上がった。 抽象化の文脈 - Reduxにおけるモデルとは? -
42.
コンテキストマップの文脈 - ドメインモデルの粒度 -
43.
ファットモデルを回避するため、 ドメインモデルの課題粒度を細かくした。 粒度が細かいことで、機能同士が疎結合に。 コンテキストマップの文脈 - ドメインモデルの粒度
-
44.
コンテキストマップの文脈 - ドメインモデルの粒度
- バイタルドメイン集約 行動目標記録ドメイン集約 共有ドメイン集約
45.
コンテキストマップの文脈 - ドメインモデルの粒度
- バイタルドメイン集約 行動目標記録ドメイン集約 共有ドメイン集約
46.
ドメインモデルの粒度が細かくなることで、 「横断的関心事」をどの様に参照するべきか、 という点が課題になる。 コンテキストマップの文脈 - ドメインモデルの粒度
-
47.
コンテキストマップの文脈 - 横断的関心事 -
48.
モデル同士が直接参照しあうことは避け、 ドメイン同士が pub/sub する機構上で結合。 モデル外側に位置する「サービス層」に結合点を置くことで、 モデル同士の依存関係は無くなる。 コンテキストマップの文脈
- 横断的関心事 -
49.
コンテキストマップの文脈 - 横断的関心事
- バイタルドメイン集約 行動目標記録ドメイン集約 共有ドメイン集約
50.
コンテキストマップの文脈 - 横断的関心事
- バイタルドメイン集約 行動目標記録ドメイン集約 共有ドメイン集約
51.
サービス層 = redux-saga 非同期処理の
middleware として認知されている redux-saga。 ここで実装する継続的コルーチンをサービス層として機能させた。 コンテキストマップの文脈 - 横断的関心事 -
52.
export function *
mapRequestStateToUI ({ creators }: { creators: ActionCreators }) { // 無限ループをもって継続的コルーチンを起動 while (true) { // requestQueueドメインを購読する yield take(action => { return action.type === RequestQueueTypes.requestSend || action.type === RequestQueueTypes.receivedSuccess || action.type === RequestQueueTypes.receivedError }) const { requestQueue } = yield select() const isProcessing = requestQueue.isProcessing() // 横断的関心事である XHR処理中という状態を、遷移ボタンを押せなくする状態に変換 yield put(creators.setDisabledUI(isProcessing)) } } 【横断的関心事を結合するサービス】
53.
【横断的関心事を結合するサービス】(コード要約) 1. XHRQueueドメインイベントを購読 (イベントが発生するまで loop処理は停止) 2.
XHRQueueドメインの状態を参照 3.「UIが操作可能か?」という状態に変換 4. 付随ドメインに書き込み 5. 1.に戻る 4. 1. ドメインサービスはドメインモデルの一部であるといえる 2. XHRQueue ドメインモデル ドメインモデル 状態変換 サービス 外部
54.
コンテキストマップの文脈 - サービスの抽象化 -
55.
redux-saga は async/await
にデザインが似ており、標準に近い。 分割統合・手続きの差し込み・変更なども容易。 将来的に async/await を利用する様になっても、 設計は変わらないことが期待出来る。 コンテキストマップの文脈 - サービスの抽象化 -
56.
ReduxAction の抽象化はサービス層にも伝播。 継承元が同じドメインは、同名の ActionType
を継承。 名前空間が切り分けられているため、 競合することなく手続きを継承する。 コンテキストマップの文脈 - サービスの抽象化 -
57.
例えば、レコードを fetch するなどの非同期処理。 継続的コルーチン関数起動時に、 ActionTypes
/ ActionCreators / modelName を注入する。 コンテキストマップの文脈 - サービスの抽象化 -
58.
export function activityGoalLogsSagas
() { return [ activityGoalLogsSaga({ types: Daily.types, creators: Daily.creators, modelName: 'activityGoalLogsDaily' }), activityGoalLogsSaga({ types: Weekly.types, creators: Weekly.creators, modelName: 'activityGoalLogsWeekly' }), activityGoalLogsSettingsSaga() ] } 【抽象サービスのコンテキストマップ】
59.
【抽象サービスのコンテキストマップ】(コード要約) 〜の時、状態を取得する 〜の時、記録を変更する 〜の時、記録を取得する 〜の時、日別行動目標の状態を取得する 〜の時、日別行動目標の記録を変更する 〜の時、日別行動目標の記録を取得する 〜の時、週間行動目標の状態を取得する 〜の時、週間行動目標の記録を変更する 〜の時、週間行動目標の記録を取得する 行動目標記録サービス 日別行動目標記録サービス 週間行動目標記録サービス 「日別行動目標の」名前空間 「週間行動目標の」名前空間
60.
コンテキストマップの文脈 - ドメインクライアント -
61.
ドメインクライアント = View
= React ReactComponent の抽象化パターンはこれまで通り。 mapStateToProps・mapDispatchToProps で、 文脈にあった State・ActionCreator を抽象名でマッピングする。 コンテキストマップの文脈 - ドメインクライアント -
62.
Hexagonal Redux では、StateObject
の 代わりにドメインモデルをマッピング。 モデル表層(プレゼンテーション層) の存在で、細かな View の出し分けが 不要になる。 課題領域分割で得られる React.render 最適化 【日別】 【週間】 【月間】
63.
export function HealthRecordPanel
({ model }: { model: HealthRecordQueryModel }) { const ctx = 'c-indexHealthRecordPanel' // model の getter で得られる値は、期間分岐・ラベル・丸め処理・添字付与済み return ( <div className={`${ctx}`}> <div className={`${ctx}__upper`}> <p className={`${ctx}__itemLabel`}>{model.getUpperPanelItemLabel()}</p> <p className={`${ctx}__dateRangeLabel`}>{model.getUpperPanelDateRangeLabel()}</p> <p className={`${ctx}__value`} dangerouslySetInnerHTML={model.getUpperPanelValueLabel()} /> </div> <div className={`${ctx}__lower`}> <p className={`${ctx}__itemLabel`}>{model.getLowerPanelItemLabel()}</p> <p className={`${ctx}__dateRangeLabel`}>{model.getLowerPanelDateRangeLabel()}</p> <p className={`${ctx}__value`} dangerouslySetInnerHTML={model.getLowerPanelValueLabel()} /> </div> </div> ) } 【ビジネスロジックが引き剥がされたコンポーネント】
64.
【ビジネスロジックが引き剥がされたコンポーネント】(コード要約) パネル上部に表示する項目ラベルを取得 パネル上部に表示する日付ラベルを取得 パネル上部に表示する値ラベルを取得 パネル下部に表示する項目ラベルを取得 パネル下部に表示する日付ラベルを取得 パネル下部に表示する値ラベルを取得 モデルに表現力があるため、ReactComponentの仕事は単純
65.
分岐・フィルタリング・ソートなど、 従来 ReactComponent で行われていた処理は、モデルの責務。 View
からビジネスロジックを引き剥がすべきという、 普遍的な最適解が得られた。 課題領域分割で得られる React.render 最適化
66.
ドメインモデルを細かく分割する利点は、 課題領域をシンプルにするだけでなく、 ReactComponent の render
最適化にも繋がる。 render は状態の変化に反応。 各Model が抱える schema が少ない程良い。 課題領域分割で得られる React.render 最適化
67.
分割統合の文脈 - Queue -
68.
各種キューイングを課題としたドメインをそれぞれ設けた。 ReduxActionを通じてキュータスクが積まれるため、各々独立している。 【例】Modal / Achievement
/ Notification / XHR 分割統合の文脈 - 各種キューを司るドメイン -
69.
表示要素毎にキューを構える。 各種表示キューを取りまとめる親キューの存在により、 要素が被るトラブルを回避できた。 ここでも redux-saga による継続的コルーチンが活きる。 分割統合の文脈
- 表示キューを司るドメイン -
70.
export function *
renderAchievementQueue (store: Store) { while (true) { // achievementQueue ドメインモデルを取得 const { achievementQueue } = yield select() // achievementQueue に登録されたの先頭要素を取得 const achievementItem = achievementQueue.getFirstQueueItem() // achievementQueue の要素が無くなったら loop を抜ける if (achievementItem === undefined) break // achievementItem を render yield call(renderAchievementWidget, achievementItem, store) // achievementQueue から 先頭要素を削除 const index = achievementQueue.getQueueItemIndex(achievementItem) yield put(creators.deleteQueueItemByIndex(index)) } // マウント先コンポーネントを空にする disposeReact('[data-react-widget-achievements]') } 【表示キューの継続的コルーチン】
71.
export function renderAchievementWidget
(achievementItem: ItemModel, store: Store) { // Promise に紐づけられた React.render。役目を終えると resolve する return new Promise(resolve => { const selector = '[data-react-widget-achievements]' renderReact(selector, AchievementWidget, store, { resolve, achievementItem }) }) } 【Promise で wrap された表示キューアイテム・レンダラー】
72.
【Promise で wrap
された表示キューアイテム・レンダラー】(コード要約) 1. 先頭のキューアイテムを取得 2. キューアイテムがなければ終了 3. キューアイテムの表示 4. 表示が終わるまで待つ( Promise) 5. キューアイテムを削除する 6. 1.に戻る 3. 2.DONE 1. 4. React 表示キュー サービス AchievementQueue ドメインモデル 外部 Promise.resolve()
73.
分割統合の文脈 - ドメインパッケージ -
74.
「カラダの記録」や 「行動目標記録」などの機能は 複数エントリーポイントで利用。 ドメインをパッケージ単位で集約。 分割統合の文脈 - ドメインパッケージ
-
75.
エントリーポイント毎にモデル層とサービス層は異なるため、 そこで必要なパッケージを統合する。 ヘキサゴナルアーキテクチャ構成要素の内側から 生成・起動・実行する様式は、どのエントリーポイントでも一律。 フレームワークらしき形が表出する。 分割統合の文脈 - ドメインパッケージ
-
76.
export const commonReducers
= { requestQueue: RequestQueueReducer(new RequestQueueModel()), modalQueue: ModalQueueReducer(new ModalQueueModel()), notificationQueue: NotificationQueueReducer(new NotificationQueueModel()), achievementQueue: AchievementQueueReducer(new AchievementQueueModel()), renderWidget: RenderWidgetReducer(new RenderWidgetModel()), pointAccount: PointAccountReducer(new PointAccountModel()), insurancePointAccount: InsurancePointAccountReducer(new InsurancePointAccountModel()) } 【全エントリーポイントに存在するドメインモデル集約】
77.
export const healthRecordsReducers
= { healthRecordsCalendar: CalendarReducer(new CalendarModel()), healthRecordsEditor: EditorReducer(new EditorModel()), healthRecordsSettings: SettingsReducer(new SettingsModel()), healthRecordsStepCounts: StepCountsReducer(new StepCountsModel()), healthRecordsWeights: WeightsReducer(new WeightsModel()), healthRecordsBloodPressures: BloodPressuresReducer(new BloodPressuresModel()), healthRecordsBloodSugars: BloodSugarsReducer(new BloodSugarsModel()) } export const activityGoalLogsReducers = { activityGoalLogsDaily: DailyReducer(new DailyModel()), activityGoalLogsWeekly: WeeklyReducer(new WeeklyModel()), activityGoalLogsSettings: SettingsReducer(new SettingsModel()) } 【機能パッケージ単位のドメインモデル集約】
78.
// create Store const
aggregateRoot = extendReducers( commonReducers, healthRecordsReducers, activityGoalLogsReducers ) const store = createReduxStore(aggregateRoot) // run services runRootSaga(commonSagas(store), [ ...healthRecordsSagas(), ...activityGoalLogsSagas() ]) // view scripts applyCommonViewScripts(store) renderAppReactViews(store) 【集約ルートでStore生成、Service層・View層に注入】 集約ルート生成 Store生成 サービス起動 View起動 全エントリーポイントが この様式に
79.
【集約ルートでStore生成、Service層・View層に注入】(コード要約) /index.js /articles.js /vitals.js /points.js エントリーポイント毎に、必要なドメイン・サービスを採用 共有 ドメイン集約 バイタル ドメイン集約 行動目標記録 ドメイン集約 記事 ドメイン ポイント ドメイン
80.
【集約ルートでStore生成、Service層・View層に注入】(コード要約) /index.js /articles.js /vitals.js /points.js エントリーポイント毎に、必要なドメイン・サービスを採用 共有 ドメイン集約 バイタル ドメイン集約 行動目標記録 ドメイン集約 記事 ドメイン ポイント ドメイン
81.
【集約ルートでStore生成、Service層・View層に注入】(コード要約) /index.js /articles.js /vitals.js /points.js エントリーポイント毎に、必要なドメイン・サービスを採用 共有 ドメイン集約 バイタル ドメイン集約 行動目標記録 ドメイン集約 記事 ドメイン ポイント ドメイン
82.
Store の分割統合は容易になったが、 ユーザーステータスなど、初期状態の注入を行う層が必要に。 分割統合の文脈 -
ドメインパッケージ -
83.
分割統合の文脈 - DI of
HTML to Store -
84.
分割統合された Store は初期状態で
zero value の状態。 rails に載せるうえで、erb から初期値を取得したい。 この課題を jQueryプラグインライクな vanilla plugin で解決。 plugin 適用時に Store を引数に与えることで、 ReduxAction を Dispatch するDOMに変化する。 分割統合の文脈 - DI of HTML to Store -
85.
export function LoadActionDispatcher
(selector, store) { return document.querySelectorAll(selector).forEach(element => { const dataset = JSON.parse(element.dataset.domLoadActionDispatcher) function dispatch (data) { const { type, payload } = data store.dispatch({ type, payload }) } if (Array.isArray(dataset)) { dataset.map(data => dispatch(data)) } else { dispatch(dataset) } }) } 【HTMLにレンダリングされた json を ActionDispatch するプラグイン】
86.
<%= content_tag :div,
nil, class: ctx, data: { 'dom-load-action-dispatcher': [ { type: '/healthRecords/stepCounts/registerHealthRecordsSrc', payload: { base_date: @health_record[:base_date], end_date: @health_record[:end_date], src: @health_record['step_counts'] } } ] } %> 【プラグインが適用されるHTML】
87.
【DI of HTML
to Store】(コード要約) /index.js 共有 ドメイン集約 バイタル ドメイン集約 行動目標記録 ドメイン集約 記事 ドメイン ポイント ドメイン /articles.js /vitals.js /points.js サーバーから得られるインスタンスを Load時に Dispatch /vitals/index.html.erb /index.html.erb /articles/index.html.erb /points/index.html.erb
88.
成果と今後の展望
89.
ReduxAction を抽象化することで、構成要素全てに抽象化が伝搬。 技術選定時の狙いどおり、OOPデザインパターンの恩恵を多く受けた。 ビジネスロジックの再利用で、複雑なユースケースも難なく解を得た。 類似ドメイン間の差異が表面化したため、 新規類似ドメインの受け入れ・機能拡張が容易になった。 KenCoMリニューアルにおける成果 -
抽象化 -
90.
横断的関心事を結合するサービス層を構えることで、 ドメインモデルが純粋になり、 各種関心事が分離された。 組み替えが容易なサービス層の存在で、 機能の追加変更が容易になった。 KenCoMリニューアルにおける成果 -
分割統合 -
91.
1. チーム横断でDDDアプローチを発展(脱軽量DDD) 2. 定量的な効果測定を仕込み、PDCAサイクルを加速 3.
UI/UX を通じて 事業KPI に貢献(デザイン戦略部メンバー全員の課題) 今後の展望
92.
ご静聴ありがとうございました
93.
Reduxにドメイン層を導入する@Qiita 実装 - Hexagonal
Redux - @Qiita MobXは複雑さに耐えられるのか?@Qiita async/await で Modal の Queueing @Qiita redux-ddd-example @github.com immutablejs-record-oop-example @github.com 関連資料
Jetzt herunterladen