Mirrativ Androidエンジニアのmorizoooです。
Mirrativのエンジニアは週4日をプロダクト開発に、週1日を開発体験の向上に時間を割いおり、CTOによる旗振りのもと、エンジニア主導で技術的負債の返済に取り組んでます。
今回は、Androidチームで取り組んだ技術的負債の返済のために行った取り組みについて紹介します。
背景
以前、2019/04に 突撃!!隣のアーキテクチャ - connpass でもお話したのですが、Androidアプリが主に以下の理由でつらい状態なっておりました。
- ロジックが散在
- 今ではあまり使われないライブラリへの依存
- JavaとKotlinの共存
これに対してAndroidチームで以下の取組みを行いました。
- ActivityとCustomViewの再設計
- ライブラリの最新化
- Kotlin化の推進 それぞれのトピックについて説明していきます。
ActivityとCustomViewの再設計
上記スライドにもあるようにMirrativには最凶のBaseクラスが存在しており、全てのActivityがBase継承していました。 このBaseクラスには汎用的なロジックが多数含まれ、実装者がBaseクラス中における処理やデータの流れを理解する必要がありました。 Baseクラスが一概に悪いというわけではないのですが、MirrativのAndroidアプリではこれにより思わぬところでバグが出てしまうなど開発速度を妨げる要因になっていました。
また、CustomView、Helperなどに状態が散り、各々で状態を更新する処理が書かれており、何が正しい状態なのか判断するのが困難になっていました。
やったこと
- Activityをあえて肥大化させて、BaseやCustomView/Helperから状態と状態を更新するロジックをActivityに集約する。
- 状態を更新しないViewを表示するためだけのCustomViewを作りActivityから描画処理を分離する
CustomViewはViewの拡張ではなく
FrameLayoutを継承して、以下のようなViewのコンポーネントとして作成しています。
class EventBannerView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : FrameLayout(context, attrs, defStyleAttr) { private val binding = DataBindingUtil.inflate<ViewEventBannerBinding>( LayoutInflater.from(getContext()), R.layout.view_event_banner, this, true ) // ActivityからEventBannerを描画するための情報を渡す fun bind(iconUrl: String, title:String) { GlideApp.with(this) .load(iconUrl) .into(binding.imageView) binding.titleTextView.text =title } }
ライブラリの最新化
MirrativのAndroidアプリはリリースから5年目のため、当時最先端だったライブラリもいまではlegacyになっているものが多数あります。 そのようなライブラリに対しては学習コストが高く、そもそもメンテされていなかったりでライブラリそのものに苦しめられることがありました。
Mirrativでは業務委託や副業の方のサポートを受けながら開発しており、Join後にすぐにバリューを出してもらえる環境を作るために、Android Architecture ComponentsとKotlinで置き換えできるライブラリを削除しました。
やったこと
以下のライブラリを書き換え
Before | After |
---|---|
AndroidAnnotations | Data Binding Library |
DBFlow | Room |
bolts | Coroutines |
guava | Kotlin標準API |
ライブラリの置き換えは変更量が多く検証も大変なのですが、 QAチームのおかげでユーザー影響がなくリリースすることができました。
MirrativのQAフローについて、そのうち書きたいと思ってます。
Kotlin化の推進
もともとは開発効率を考えて新規機能開発についてはKotlin化されていましたが、既存機能改修の場合はJavaのファイルを変更する流れになっていました。
Kotlin⇔Java間のコンテキストスイッチを避けたいのと、非同期の処理をCoroutinesに変更したかったため、Kotlinへの書き換えを行いました。
やったこと
昨年4月にはJavaとKotlinを比べるとKotlinの割合が3割ほどでしたが、今では8割ほどになりました。
現状では普段触るファイルでJavaがでてくることは少なくなりました。
Before(2019/4)
After(2020/01)
書き換えている当初は、直接内容を変更してCommitしていましたが、 Git上での変更履歴と手動で変更したところが分からなくなってしまったため、以下の流れで対応していきました。
- git mv でjavaからktにRenameしてCommit
- Convert Java to Kotlin を実行してCommit
- 修正内容をCommit
やってみて
やっていることに目新しいことはないのですが、開発速度は改善していると実感できています。また、開発速度だけでなくUI刷新をスムーズに行えたり、クラッシュの発生率を昨年4月と比べると1/3以下まで低下するなど、プロダクトに対しても直接ポジティブな影響を出せています。
その影響もあると信じているのですが、Google Play ベストオブ 2019で「エンターテイメント部門」大賞を受賞することができました!
技術的負債の返済は開発者のためだけではなく、ユーザーに価値を届けるために続けていきます。
また、上記の改善により、次のステップとしてアーキテクチャの刷新を行うことができました。 次回は現在どのようなアーキテクチャで開発しているか書きたいと思います。
We are hiring!
こんなAndroidチームです!!
チームだからできることを、もっと大きく・速くしていきたい「Androidエンジニア」もりぞーさん ―ミラティブの中の人|ミラティブ|note
一緒に開発してくれるエンジニアを募集中です!! speakerdeck.com