2020-08-13
ドメイン駆動設計を試した話
ReactNativeを使ってアプリを作っている。データベースを操作する非同期関数をMobxのモデルで書き始めてからプログラムの構造が破綻していた。アーキテクチャ設計を適当にやると機能追加できなくなる。mobxにメリットを感じなくなったので、よりデファクトスタンダードなReduxを導入し、ついでにドメイン駆動開発の考え方も勉強した。
やったこと
- mobxやめてreduxにした
- runInActionが本末転倒
- modelをRedux store + serviceに分けた
- 非同期処理なし
- daoがentityではなくdtoを返すようにした
- そのほかいろいろ
Javascript
-
const Func と function()の違い
-
interface generic function
-
interface IGetter { get<T>(): T } class GetA implements IGetter { get<A>(): A {...} // Wrong } class GetA implements IGetter { get<T>(): T {...} // OK }
- read here: https://www.typescriptlang.org/docs/handbook/generics.html
- 謎エラー
- 'xxx' could be instantiated with an arbitrary type which could be unrelated to 'yyy'
- '' is not assignable to the same property in base type
-
-
Promise.prototype.finally => ES2018.promise
-
Array.prototype.forEachの第3引数で元の配列をいじれるよ
- c++のイテレータの感覚だと不思議
OOP
- Dependency Injection
- 依存関係をコンストラクタを通して渡し、コンポーネントを疎結合に保つデザインパターン
- インターフェイスを介せば実装を差し替えられる
- コンストラクタの引数が多くて初期化が面倒
- DIContainer, ServiceLocatorなどを使ってインスタンスの組み合わせを事前に定義
- DI Container
- Dependency Injectionを実現するためのフレームワーク?
- @injectableみたいなアノテーションはちょっと苦手
- ServiceLocator
- DependencyInjectionを使ったはいいものの、その実体はどこで生成するの?
- ServiceLocatorに登録しておいて、利用者がここから取り出す
- DIコンテナがやっていることと同じでは?
- ServiceLocatorへの依存性が発生する。
- 不要な依存性が発生する、依存性が分かりにくくなる、テスト困難になる
- https://www.nuits.jp/entry/servicelocator-vs-dependencyinjection
DIコンテナを利用する場合は、同様のジレンマが発生しますが、DIコンテナを利用 せずにDIパターンだけを利用する事も出来ます。つまりDIを採用した場合、選択権は利用者にありますがServiceLocatorでは利用者に選択権がありません。
- ここの説明が一番しっくりきた
- AbstractFactoryと何が違うん?
- ほぼ同じ。Factoryは単一インスタンスの生成を責務とする。
- Inversion of Control
- SOLID原則におけるDependency inversion principle
- DependencyInjection, ServiceLocatorなどがこれを実現するパターン
DDD
- DDD vs OnionArchitecture vs CleanArchitecture
- DDDのやり方が複数あり、それぞれ登場する言葉が違う。これがややこしい。
- 大きく分けると
- ドメイン
- インフラ(Network, Database, Presentor/UI...)
- 二つを繋ぐもの(Applocation Service, Adapter...)
- DAO vs DTO vs Entity
- Entityはドメインロジックの中に登場する存在
- DAO(DataAccessObject)はデータベースかのデータにアクセスする責務を果たす。
- データベース操作を素直に実装すればヨシ
- ORMよりも単純。RelationalMappingしない。
- Entity>DTO>DAO>IDatabase
- 最初Infrastructureレイヤに置いたけど、途中からDTOと同じレイヤに置いた。
- 結局どこのレイヤに置くのが正しいんだろう?
- DDDで登場するRepositoryはドメインレイヤのものだが、実装はInfrastructureっぽい。
- 結局どこのレイヤに置くのが正しいんだろう?
- DTO(DataTransferObject)はレイヤを跨いでデータを渡すときに使うもの
- DAOはEntityを返すよりもDTOを返すべき。DTOからEntityを構築する。
- 元々はDAOのバッチ処理に使われていたが、シリアル処理を使うために使われることがふえたとかなんとか
- DDDのEntityとCAのEntityはどう違う?
- ほぼ同じものだと思う
- 違う派 vs 同じ派
Redux
- globalInstanceはstoreに入れる?それとも外部モジュールを使ってアクセスする?
- 手っ取り早いので外部モジュールを作りました。setInst()/getInst()できるGlobalProvider。
- リクエストごとに異なるメモリを割り当てたければ別の方法がいいかも
- 当たり前の話
- Storeが更新されたらStoreを更新する処理を書いたら無限ループする。
- アプリケーションが固まりはしなかった。非同期処理だったからかな?
ReactNative
- SQLite.enablePromise(true);
- Database
- 使うときにだけ接続し、使い終わったら切断するパターンが多い
- インスタンスを使うときにnewして接続し、使い終わったら解放する
- c#(.NET)はコネクションプールがあるのでオーバヘッド少ない(using ...)
- Webアプリもコネクションプールを使い、リクエスト毎に借用・解放する
- ReactNativeも同じことできるのかな?
- 使うときにだけ接続し、使い終わったら切断するパターンが多い
失敗したこと
- ReactNativeでProjectRootからimportする
- 調査不足
Links
- What is the general difference between DAO and ORM?
- https://softwareengineering.stackexchange.com/questions/351884/should-a-domain-service-have-dependencies
-
The domain service (facade) would have a dependency on the external service.
- ドメイン層でインフラ層を使ってもいいの?って思ったんだけど、よく考えたら注入は必須。誰がどこで注入するの?という問いにつながる。
-
- DDDでバリデーションはどこで行うの?
- https://stackoverflow.com/questions/5818898/where-to-put-global-rules-validation-in-ddd
- 普通はドメイン層。でもバリデーションの目的によって異なる。
- DTOはどこのレイヤで実装するの?
- DTOとEntityの相互変換は誰がやるの
- Entityかな
- Entityにメソッドいっぱい生やすのは嫌い
- DTOと1:1変換できるならいいんだけど、そうじゃない場合は?
- javascriptは関数のオーバーロードをサポートしてないから、変換関数が増えがち
- DAOはEntityとDTOどちらを返すべきか
- データをEntityに変換する作業の責務の話
- 最初はデータから手動でEntityを構築していた。型変換が複雑。
- 多分ORMの仕事なんだけどORM使ってない。上手く分けたければORM使うべきなんだろう。
- DTOって目的ごとに異なるものを作ってもいいの?
その他
- 業を暴く