こんにちは、Androidアプリエンジニアの藤樫(とがし)です。OpenWorkのAndroidアプリをどうやって作っているかざっとご紹介します。
自己紹介
新卒で某半外資系携帯電話メーカーに入社し、Android端末の開発に携わっていました。もともとアプリ屋さんではなく、オシロスコープ片手にC言語を駆使してLinuxカーネルやデバイスドライバなどを弄り回したり、時には中国の工場に出張して試作のサポートなどをしていました。
7年半ほど勤めた後にAndroidアプリエンジニアとして某セキュリティベンダーに転職し、その後1人目のAndroidアプリエンジニアとしてオープンワーク(当時のヴォーカーズ)にジョインしました。最近子どもが生まれて毎日がサバイバルです。
アプリ概要
OpenWorkのAndroidアプリはフルKotlinで立ち上げました。Clean Architectureを念頭に置きつつ、データレイヤー、ドメインレイヤー、プレゼンテーションレイヤーに分け、レイヤー間の依存を原則ドメインレイヤー方向のみへと制限しています。
データ構造とそれを操作/判定するロジックをエンティティにまとめてユニットテストを書いていくという、基本的なモデリングを粛々とやっています。非同期処理は基本的にRxKotlinで書いています。
アーキテクチャ
現在Androidチームは少人数で、時にはビジネス要求の兼ね合いで外部パートナーと開発することもあるため、複雑に作り込んだアーキテクチャで最初の理解に時間がかかったり、画面やウェブAPI定義追加時にボイラープレートをたくさん書かなければならない状態は避けたいと考えていて、自分なりにバランスを探りながら開発を進めています。
例えば、各レイヤーの制約は後述する程度にとどめたり、本来定義すべきレイヤー間のインターフェース群などは端折っています。これがベストかはわかりませんが、幸い今まで大きな問題を起こさず、かつ開発効率を維持できています。
データレイヤー
リポジトリパターンを採用し、APIリポジトリ、DBリポジトリ、SharedPreferencesリポジトリなど詳細の実装と、必要に応じてそれらをまとめてドメインレイヤーにRxでデータを流すリポジトリを用意しています。
ドメインレイヤー
バックエンドサーバーのAPIのレスポンスやリクエストに対応するデータ構造を表現するエンティティを定義し、エンティティ自身にデータ整形関数やバリデーションロジックなどを持たせています。また、複数のリポジトリをまとめるユースケースを定義しています。
基本的にAndroidフレームワークに依存は持たず、ホストマシンでユニットテストを実行可能にしています。
プレゼンテーションレイヤー
Activity、Fragment、ViewModel、カスタムView、Androidフレームワークに依存するViewに対応するモデルなどを置いています。Data Bindingを利用し、ActivityやFragmentは出来るだけ画面遷移や表示データの紐付けだけを行い、表示に必要なデータやロジックはViewModelに書いています。
単純にデータをバインディングできない場合は、レイアウトXMLに複雑な条件式を書かずにBindingAdapterを自作して、Robolectricでユニットテストを書いています。
ViewModelはコンストラクタでユースケースを受け取るようにして、モックでユニットテストが書けるようにしています。
採用しているライブラリ
JetPack(ViewModel、LiveData、Data Binding、Navigation、Room、WorkManager)など出来るだけ公式のものを採用しつつ、デファクトスタンダードであるOkHttp、Retrofit、RxKotlin/RxJava、Glideというのが基本構成です。
また、準公式(?)のFlexboxLayoutは動的なタグ表示などで大変重宝しています。RecyclerViewのライブラリは日本だとGroupieの解説記事が多い印象ですが(DroidKaigiアプリに採用された影響?)、カルーセルなど多様なリストのサポートを見据えてEpoxyを採用しました。Groupieでもできそうですが、Epoxyは公式Wikiにカルーセルの説明があったり、ちょっと使ってみた感じ割とスムーズに使い方を理解できたので。
We are hiring!
OpenWorkアプリは新機能追加や機能改善やリファクタリングなどまだまだやることが盛りだくさんです。
少人数のため担当範囲が広く、改善のアイディアもどんどん提案して議論していける環境です。少しでも興味を持ったら話を聞きに来てください!
(※本記事は2019年9月18日にWantedlyに掲載した記事を移行したものになります)