この記事は導入編の続きになります。
こっちは文字ばっかです。
実施してみて
まず、そもそも私のDDDに対する理解がまだまだなので、本来の効果が発揮できているか怪しいですがNon知識から導入してみたらどうなったかということを書いてみます。
メリット1:保守性が上がった
レイヤーがきれいに分かれておりレイヤー間の結合度が低いので、互いの干渉が少なく仕様変更には強くなりました。
画面単位でのロジックが一切ないので、この画面のこの処理を変更してさらにこの画面の同じ処理を…というリファクタリングはかなり減ったと感じました。
メリット2:ファットコントローラーの解消
MVCの一番の悩ましい点だったファットコントローラーが解消されたと感じます。
アニメーションがもりもりの画面などは相変わらずViewControllerの記述量は多いところもありますが、少なくともUIの描画(ViewController)とイベントのハンドリング(Presenter)やロジック周り(UseCase)のコードが混在してカオス化することは防げているので、その点では大いに効果がありました。
メリット3:テストしやすい
一番恩恵をうけるのはテストだと思います。
ロジックのテスト、UIのテスト、DBアクセスのテスト等、分離してテストが出来るのでテストコードが書きやすく、バグの原因追求も容易です。
例えばドメイン層のロジックのみをテストしたい場合は、スタブとドライバを用意すればおkです
デメリット1:工数増えるしぶっちゃけめんどくさい
ViewControllerから保存されている値を取り出そうと思った場合、最短だと
ViewController→UserDefaults
のようにアクセスすると思いますが、DDDに則って取り出しを行うと
ViewController→Presenter→UseCase(インターフェース)→UseCase(実装クラス)→Repository(インターフェース)→Repository(実装クラス)→UserDefaults管理クラス→UserDefaults
とかなり長いクラスを経て取得しに行くことになります。メンドクサイです。
この場合途中のUseCaseクラスは次のクラス処理を依頼しているだけなので書いてる途中に「このクラス挟んでる意味あるのか…?」という気分に陥ります。
デメリット2:Realm等の一部のライブラリとの相性が悪い
DDDを導入する上で一番困ったことの一つがRealmデータベースをどう扱うかという問題で、Realmはプロパティアクセス時に初めて値がDBから呼び出されるライブオブジェクトと呼ばれる仕組みを用いて高速化を行なっています。
Realmの概念は本来Data層のみに留めるのが理想ですが、RealmオブジェクトはそのままUIに適用するのを想定されているため、ほかの層でもRealmの存在を強く意識する必要があります。
Data層でRealmオブジェクトを取り出してDomainオブジェクトへの変換してしまうとせっかくのライブオブジェクトの利点がなくなってしまうのが悩ましいところです。
今回は悩んだ末、DomainオブジェクトをそのままRealmオブジェクトとして扱うことにしました。
つまりDomain層やPresentation層の中にもがっつりRealmの概念が入り込んでおり、Domain層にあるRealmオブジェクトをData層やPresentation層でもそのまま使っています。
デメリット3:途中参入メンバーの学習コスト高い(かも?)
私のプロジェクトでは途中参入はありませんでしたが、途中からプロジェクトへ参入された方は苦労するかもしれません。
ちゃんと設計を理解した上で同じように実装して貰う必要があるので、プロジェクトが炎上しているからと行って説明を省いて作業に取り掛かるとお互い不幸になりそうです。
自分なりの結論:効果は大いにあるが銀の弾丸ではないのでTPOに応じて使おう
元々があまり良い設計で開発していなかったので、それに比べればクラス設計に一定のルールが設けられ、クラス間の疎結合も保たれるのでMVCより設計が改善されたと感じることが出来ました。
その反面、かけるコストは大きいためスピーディな開発には向いていません。
特にiOS・Androidアプリだと一人のエンジニアがスピード重視で作ることも多いため、そのような場合にかけたコストに見合った効果が得られるかは微妙なところです。
ただ開発の途中からDDDのような概念を導入することは大変なので、プロジェクトが肥大化することを見越して最初から考慮しておくのはありだと思います。
ポイントは適度にユルめにやること
DDDのような設計手法をガチガチにやってしまうとコストが掛かりすぎてしまう事もあるので、概念を一部適用するのもありだと思います。
たとえばData層のRepositoryパターンだけを採用してデータ入出力処理を一箇所にまとめるだけでも効果があるでしょう(既にやってる人多いと思いますが。。。)
UIに近い部分は特にOSフレームワークの影響を受けやすく設計概念をそのまま適用するのが難しいことがあるので、そこは厳密にはやらないという選択肢もあります。
また定数ファイルの置き場所一つでData層に置くかPresentation層に置くか悩んだりもしてくるのであまり厳しくやりすぎないのがコツです。
私自身も一部端折ったり妥協したりしながら試行錯誤して作業したので、自身のプロジェクトにあったやり方を見つけるのが一番ですね。
参考
SwiftでDDD(ドメイン駆動設計)
まだMVC,MVP,MVVMで消耗してるの? iOS Clean Architectureについて
[ Android ] - これからの「設計」の話をしよう
Clean Architecture + DDD + Redux + RxJavaをAndroidでやるときにどこまで分割するか問題
AndroidではMVCよりMVPの方がいいかもしれない