こんにちは、安部です。Androidアプリを担当しています。今回はおそらくAndoidアプリ開発者は常に頭を悩ませる問題である、設計の話です。私もずっと試行錯誤を繰り返し、現在進行系で悩んでる問題でもあります。見えてきた部分があるので現在の状況を共有したいと思います。抱えてる問題Androidアプリ開発していくうえで、よくぶつかる壁です。ライフサイクルAndroidのライフサイクルは複雑でViewの状態をどのように管理すればよいのか難しいです。今はActivityだけではなくFragmentもあるので、更に複雑にしていると思います。非同期にしなければいけません。そのためUI側もそれを意識しなければいけなくなり、Viewの状態管理も複雑になっていきます。テストContextなどAndroid固有のものを必要とするクラスが自然と増えてしまうので、すぐにテストがしにくくなってしまいます。最近はこのあたりはDagger2でDIすることでだいぶ改善されつつありますが、まだまだコストが高い印象です。チーム等で検証してバランスを取ってやっていくのが良いかなと。DDDDDDをやらなきゃと思って、どこに何を書けば良いのかわからない状況に陥りやすいです。いざやってみると頭を抱えることが多くなります。現在はMVVM+DDDみたいな形でやっています。現在のレイヤーの分け方は次のようになっています。PresentationViewに対しての操作や状態管理、イベントハンドリングを行います。ApplicationDomainの直接のクライントになります。ここはPresentationから呼び出され、Domainへ処理を移譲するものになります。DomainモデルやビジネスロジックやリポジトリとAPIアクセスのインターフェースなどがあります。Infrastructure詳細な実装を記述します。DBアクセスやAPIアクセスなどの詳細な実装になります。InfrastructureについてはDIを使って依存を解決するので、他のレイヤーに直接でてくることはありません。packageも同じような分け方になります。PresentationレイヤーここではUIに関するものを処理します。現在はDataBindingを使った、MVVMっぽい感じにしています。改善の余地があると思っていますが。MVPでもMVVMでもやることは変わりません。UIなどの表示とイベントに関する責務を負います。それ以外のことはしないようにします。逆に他のレイヤーにこれらの関心ごとが漏れないようにします。ここではビジネスロジックを処理しませんが、おそらく一番コード量が多いレイヤーになるかと思います。Viewの状態を管理したりするのはライフサイクルなども絡んできてかなり複雑になると思います。私の場合ですが、ここから直接Domainレイヤーの処理を呼ばずに、後述のApplicationレイヤーを経由するようにしています。このあたりのDataBindingとMVVMについては来年のDroidKaigiで話す予定です。ApplicationレイヤーここはDomainの直接のクライアントになります。Presentationレイヤーから呼び出されDomainレイヤーへ処理を委譲します。Domainレイヤーに受け渡すためのデータの加工を少しやったりもします。Domainレイヤーここが一番どうしたら良いのかが分からなくなることが多いと思いますが、最近思うのはAndroidアプリではDomainレイヤーはビジネスロジックがそこまで多くない気がします。アプリの性質にもよりますが、だいたいAPI経由で処理をサーバーに移譲している思うので、ほぼサーバー側にビジネスロジックが実装されていることになります。そのためDomainレイヤーにはAPIに対するインターフェースとモデルが多い感じなっています。モデルを設計する必要はあるので、そこまで単純ではないと思います。ここではAPIやDBの実装の詳細は記述しません。API通信の処理についてはインターフェースのみを定義して、実装はInfrastructureレイヤーに記述するようにします。リポジトリの場合は次のような感じのみです。getUser();}APIのインターフェースは私はGateWayと命名しています。ここでは戻り値をRxJavaのObservableにすることで非同期を扱いやすくしています。getUser();}また、ドメインモデルにも実装の詳細が入り込まないようにします。Realmを使ってる場合でRealmObjectを継承したりはしないようにします。DBテーブル情報はInfrastructureレイヤーのほうで定義してあげて、それからドメインモデルに変換してあげるようにします。android.*がない)が理想だと思います。一部Parcelなどは例外にしています。最初はPresentationレイヤーでDTOみたいなのを作って対応していたのですが、ごちゃごちゃしてきてしまったので、Parcelは例外的にOKにしました。InfrastructureレイヤーDomainレイヤーに定義されたインターフェースを実際に実装します。ここはPresentationレイヤーの次にコード量が多くなる気がします。APIやDBから取得したレスポンスをドメインモデルへの変換もここで行います。}}DIInfrastructureレイヤーにおいたものは基本的に他のレイヤーで直接依存するようがないことが重要です。そのためDIで依存を解決してあげます。変更に強くなったり、テストしやすくなったり、BuildVariantごとに差し替えたりできるようになります。可能であれば初めから導入しておくことをおすすめします。あとから導入すると結構大変なので。すべては書きませんが、Dagger2の場合は次のような感じのモジュールを使う感じなります。}}これをApplicationレイヤーでInjectしてあげます。}}このようにすればInfrastructureレイヤーの詳細な実装が他のレイヤーに漏れることはありません。まとめ現在の設計の状況をざっくり書いてみました。本当はサンプルを用意できればよかったのですが...実際に試さないとわからない部分も多くあるので、最初は多少オーバーキル的な箇所があっても良いと思います。時間をかけすぎるのも駄目なのでバランスを取りながらやっていくと良いと思います。設計に正解はないと思っています。今の設計もまだまだ改善すべきところはあります。このあたりは随時改善していきたいです。