この記事は Supership株式会社 Advent Calendar 2016の16日目の記事になります。
Supershipの新規サービス開発室でSunnychat(iOS|Android)というサービスのAndroid版を担当してます @rei-m です。15日目は @tanjo さんによるSlackを監視するBotの話でした。
今回はSunnyChatのアプリの設計について開発開始から現在に至るまでの変遷について書いてみます。このアプリはこういう思想で作ったんだというくらいの雰囲気で見てもらえれば幸いです。
前提
- 新しいサービスの柱を作るという意志を持ったプロジェクトである(簡単には撤退しない)
- Androidエンジニアは2名体制。どちらもAndroid歴は浅め。
- 開発期間は僕が携わり始めたのが2015年の11月で、そこから1年くらいの間の話。
フェーズ1: サービスの立ち上げ期
- とにかく急いでプロトタイプを動く形にする必要があり、中の作りはさておき実機で動かせることが優先。
- 結果としてマッチョなActivityとFragmentがいる、いわゆるSmartUIパターンな状態になる。
- 基本的にはアンチパターンではあるものの、新規サービス開発の初期フェーズでは要件やUIがふわふわしていて、素早いサイクルでプロトタイプを形にすることが優先されるため、設計についてはあまり頑張らない。
フェーズ2: 初期リリース後
- メンテしやすいようにとにかくActivityとFragmentを薄くする方針で、Model層を作ってActivityとFragmentから複雑なロジックを分離。
- アプリの方向性ややりたいことが見えてきたので少しずつマッチョなコントローラを薄くしようとする。
フェーズ3: 二次開発
- サービスの戦略にしたがって必要な機能を追加したり、既存の機能をブラッシュアップしていく時期。
- Presenter層を作って、ActivityとFragmentはViewの管理のみを責務とするようにした。PresenterはActivity/Fragmentからユーザーのイベントを受け取りModel層を操作する責務を負う。
- Model層については、アプリ内でそこそこ多い種類の情報をRealmに保存している事情からDDD的なアプローチでアプリのコンテキスト境界内でのドメインの複雑さの解消を試みている。
フェーズ4: 軽めのピボット中(現在)
- 大きなピボットではないもののサービスの戦略が初期フェーズから変わる。結果、アプリの見た目は似ているが、データのリレーションは変化し、合わせて端末のRealmで管理していたキャッシュ戦略も変更。
- 引き続き継続してメンテしやすい作りになることを目的に、アプリの設計はPresenterとModel層の間にUsecase層を挟んで、Modelの操作はUsecase層で行うようにした。
- Model層については前のフェーズでDDD的なアプローチを取ったが、このフェーズでRealmに保存するデータの種類が少なくなり、アプリのコンテキスト境界内でDDDを採用するメリットが減ったので、やめて、代わりにUsecase層を挟んでそこが具体的なロジックを持つようにした。一部残ったデータについてはModelを永続化するところをそのままRepositoryとして使いまわしている。
現在のレイヤー毎の責務はこんな感じになった
- Activity/Fragment
- Viewの管理
- Presenter
- ユーザーのイベントや非同期で発生するイベントを管理、イベントに対応したUsecaseを呼び出す
- Usecase
- Modelの操作、APIの呼び出しなどの具体的なロジックを書く。ローカルのドメイン層の情報とAPIでサーバーから取ってきた情報をいい感じにマージしてView用のModelに変換してPresentation層へ返す
- Domain
- アプリのコンテキスト境界内で管理するドメインの定義
- Infrastracture
- 通信部分やスキーマ(Realm)の定義など
おわり
- 試行錯誤でしたが、こんな感じでフェーズ毎に作りを見直していくとこでレイヤーを区切り、責務を限定することで、メンテしやすい作りを目指しました。振り返ってみると場当たり的な対応だったような気がしなくもないですが、レイヤー毎の責務を明確にすることでどこに何を書くべきかというのがわかりやすくなったのかなと感じています。
- 反面、レイヤー毎の境界はインターフェースを通しているので、どうしても作るファイル数が多くなったのはやはり煩わしいですね。よりベターな作りを考え続けて、サービスの提供に寄与できるような設計を目指していきたいです。
今回の例は前提として、新しいサービスの柱を作るというプロジェクトで、そこそこの規模の仕様になる、といった感じの条件が揃っていたが故のアプローチです。万能な最強の設計みたいなものは存在しなく、アプリの仕様の複雑さやビジネス的な事情を考慮して、その時に応じた最適な仕様を考えていくとよいのではないでしょうか。
あしたの担当は @knt45 さんです!よろしくおねがいしますー