こんにちは! マネーフォワードクラウド確定申告アプリ のテックリードを勤めている須田です。
本記事では2020年3月〜本格開発開始して8月にリリース。現在継続運用中である、Androidアプリの設計方針を共有します。
設計方針を定めることで実現したいこと
関心の分離がされている
- ビジネスロジックの関心事と、技術的な関心事が適切に分離されるようにします。特に、Androidにおいては、UIの表示ロジックと、その他のビジネスロジックが適切に分離されていなければ、クラスの肥大化などの問題が発生します。
テストのしやすい設計にする
- テストをしやすい状態であれば、コンポーネントの粒度が適切に保てている可能性が高く、疎結合に実装できています。新規立ち上げの段階なので、TDDは実践しませんが、グロースフェーズ、成熟フェーズになった際にいつでもTDDに移れるようにします。
複数人でも素早く開発できる
- 複数人で開発する際、設計方針がバラバラだとコードレビューにとても時間がかかり、ユーザーに価値を届けるまでの時間が長くなってしまいます。方針がある事で、コードを書く際にも読む際にも考える事を減らし、スピードを持って開発する事を可能にします。
設計の方針
Googleが勧めている設計があれば、原則それを採用する
- AndroidアプリはGoogleが提供してくれたSDKのAPIを使用して作成するため、Googleが勧めているものを使用します。現時点ではMVVM + Repositoryパターンが推奨されてますので、それに従います。今回、参考にしたGoogleの推奨アーキテクチャはこちらです。
- 上記の推奨アーキテクチャに合わせて Android Architecture Components を提供をしてくれているので、積極活用します。
Android Studio上でエラー表示される実装は原則NG
- エラーとして表示される実装は安全性、メンテナンス性に乏しいと考えています。
使用するライブラリーの方針
- Googleが勧めている物があれば、そちらを原則優先する
- 設計方針と同様です。AndroidアプリはGoogleが提供してくれたSDKのAPIを使用して作成するため、長期にわたりメンテナンス性が高いと考えています。
- stableの物を使用する
- 理由や動作確認がしっかりとできていれば、alphaやBetaの物でも認めます。breaking change等があったり、動作が不安定である可能性があるため、原則使用しない方針です。
- 長期間に渡ってメンテナンスされると考えられる物を使用する
- starが多く注目度が高いものや、メンテナンスが定期的に行われているもの、著名な開発元の作者のものや、Facebook等が提供している実績のあるライブラリー等を使用します。
実際の設計
- google が推奨しているMVVM + RepositoryパターンにAppEnvironmentを足す
- AppEnvironmentはkickstarter社のiOSのOSSから命名の参考をしました。中身はEncryptedSharedPreferencesをラップしたシングルトンになっています。SharedPreferenceにいれるような内容をわざわざViewModel, Repositoryと取得するのはコードが必要以上に冗長になってしまう可能性が高いと考えており、それを防ぐ目的で導入しました。
- 頑張らないMVVM == AppEnvironmentがあるという意味になります。
マルチモジュールの構成はどうするか
マルチモジュールのメリット
- ビルドが早くなる
- 全てのビルドが早くなるわけではないですが、単一モジュールの様に毎回全てリビルドするよりは、キャッシュされる分ビルドが早くなります。
- モジュールで強制的に参照を制限するので、依存関係を強制することが可能
- 構成によっては、アーキテクチャを強制する事が可能になります。MVVMレポジトリーパターンで例えると、VIewの層が直接Repositoryを参照する事が不可能になり、強制する事に成功します。
確定申告Androidアプリで受けたいマルチモジュールの恩恵
- 見た目(MVVMの部分)の差分ビルドを早くしたい
- ただの肌感覚ですが、確定申告Android開発でビルドする回数の8割以上は、見た目修正のビルドであると考えています。既にWebサービス, iOSがあるので、基本的にアプリケーションロジックはサーバーに持たせます。その様にバックエンドのAPIを設計するため、必然的に見た目の部分の改修作業が多くなると考えています。
- MVVM, Repositoryの依存関係を強制したい
- 既に上述していますが、Viewが直接Repositoryの先のAPI参照する等を不可能にする事ができます。
- 機能毎に依存関係を強制したい
- A機能とB機能があった際、A機能はB機能の事をお互い知らなくて済む構成にしたいと考えてます。A機能とB機能でモジュールが別れていればそれが実現できるため、コンフリクトが少なくなり複数人での開発がスムーズになったり、Stringのresourceファイルがスリムにする事が可能です。
マルチモジュールの組み方例の考察
①MVVM、Repository、Data の層でのみ切る
メリット
- MVVM+Repositoryパターンの依存関係を強制
- Repositoryより右の部分のビルドが省けるため、見た目の差分ビルドを早くできる
- モジュールが少なく簡単
- 実現するための障壁がほぼ無い。
デメリット
- 機能毎に依存関係は切れていない
- 見た目の差分ビルドの早さがそこまで変わらなさそう
②機能毎の層でのみ切る
メリット
- 機能毎に依存関係が切れる
- 差分ビルドが機能毎になり高速になる
デメリット
- MVVM+Repositoryパターンの依存関係を強制できない
- 見た目の差分ビルドの早さがそこまで変わらなさそう
サンプル
③MVVM、Repository、Data × 機能毎の層で切る
メリット
- 機能毎に依存関係が切れる
- 見た目のビルドが早い
デメリット
- モジュールが増えすぎて、モジュール管理をするという新しい難しさが発生する可能性がある。
- モジュールが増えすぎて、最後にマージする箇所が重くなる可能性がある。
実際に採用した構成
プレゼンテーション層は機能毎に切り、Repository層は一つにまとめる
- 上述した3つの受けたい恩恵を全て受けれる
- 見た目(MVVMの部分)の差分ビルドを早くしたい、MVVM, Repositoryの依存関係を強制したい、機能毎に依存関係を強制したいを享受できそうでした。
- repository層を細かく分けるメリットが薄い
- アプリの特性上、機能によって共通で使うAPIやDB 等多そうであったためです。あまり細かく分けるとcore_repositoryなどと共通のrepositoryを作ったりしてどんどん複雑になるため、repositoryより下のモジュールに関してはApi,DBなど機能事にモジュールを切りました。
- 見た目のビルドと全体のビルドを最大限早くできる。
- 上述しましたが、モジュール数が多くなってしまうと、最後にマージする時間が長くなってしまいます。それは防ぎたかったので、全体のモジュール数は最小限で済む様にしました。
立ち上げ、運用してみてどうだったか
早く立ち上げる事ができた
- iOSを立ち上げた際にかかった人員と期間を単純計算すると10分の1の工数でできました。仕様が決まっていた場合の開発と、仕様を模索しながらの開発での違いはありますが、成功した考えています。
プルリクエストの指摘が少なく、スピードを持って開発できている
- 書き方が統一されているので、レビューの指摘事項が少なく済んでいます。また、どこに何を書けばいいかで悩む事が少ないため、書くスピードも早いです。狙っていたMVVM層のみの差分ビルド時間も短くてすみ、見た目の開発の際のビルド待ちの時間を短くする事に成功しました。
経験の浅いメンバーでもスピーディに立ち上がれた
- 20新卒のフレッシュな人もチームに参加してくれましたが、直感的で読みやすく書けるとコメントを貰えた。実際に早期戦力化できております。もちろん新卒の方が優秀というのも一因にあります。
確定申告される方へアピール
電子証明書の登録不要、JPKI利用者ソフトのアプリインストールも不要、マイナンバーカードがあれば簡単に電子申告ができる機能を2021年2月中にリリースします。今年の確定申告は弊社のアプリを是非使ってみてください。ダウンロードはこちらからお願いします。
おわりに
マネーフォワード確定申告チームでは確定申告のペインを一緒に解消する仲間を募集しています。 少しでも気になる、話が聞きたい方は是非こちらまでご連絡お願いします。 カジュアル面談を優先度高めに実施させていただきます。 チームの募集事項はこちらです。 以前取材していただいた記事も参考になるかもしれません。チームの雰囲気を掴めると思います。
【サイトのご案内】 ■マネーフォワード採用サイト ■Wantedly ■京都開発拠点
【プロダクトのご紹介】 ■お金の見える化サービス 『マネーフォワード ME』 iPhone,iPad Android
■ビジネス向けバックオフィス向け業務効率化ソリューション 『マネーフォワード クラウド』
■だれでも貯まって増える お金の体質改善サービス 『マネーフォワード おかねせんせい』