$30 off During Our Annual Pro Sale. View Details »

Baby steps to improve architecture in Study Sapuri Android

chiiia12
February 05, 2020

Baby steps to improve architecture in Study Sapuri Android

chiiia12

February 05, 2020
Tweet

More Decks by chiiia12

Other Decks in Programming

Transcript

  1. #sapurimeetup
    Baby steps to improve architecture
    In Study Sapuri Android
    @chiiia12
    Study Sapuri/Quipper Product Meetup #4

    View Slide

  2. #sapurimeetup
    @chiiia12 / 横尾千明
    2
    ● Mobile Engineer at Quipper
    ○ 2018.4 Study Sapuri Android team join
    ○ Quipper Product Team Blogの運営
    ● 2015年新卒でエンジニアとしてリクルート入社
    ○ お小遣い稼ぎサービスでサーバーサイド開発
    ○ 人材領域でAndroidアプリ開発
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  3. #sapurimeetup
    今日お話しすること
    ➔ 歴史ある大規模 Android アプリにおけるアーキテクチャ改善
    ◆ 案件開発・リリースを止めずに進める戦略
    ◆ リファクタリングを進めていく中での試行錯誤
    ◆ アーキテクチャ改善で得た思わぬ恩恵?
    3
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  4. #sapurimeetup
    Agenda | 01
    02
    03
    04
    Androidチームの現状と技術的課題
    どのように実践していくか
    Try & Error
    振り返り・まとめ
    4
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  5. #sapurimeetup
    Androidチームの
    現状と技術的課題
    01
    5
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  6. #sapurimeetup
    Androidチームについて
    ● EM1名、メンバー4名
    ● メンバーは全員Quipper歴2年以内
    6
    @daisukefuji @chiiia12 @padobariya @aruke @geckour
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  7. #sapurimeetup
    ● 小中高大学受験生向けの学習アプリ
    ● ユーザータイプ: 5タイプ
    ● ソースコード:135,125行
    ● 現ソースコードでの開発:5年以上
    ● 歴史と複雑さを持つアプリ
    Study Sapuri について
    7
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  8. #sapurimeetup
    手をつけられていなかった課題感
    ● 2017年から開発停止しているGreenDaoがまだ使われている
    ● 時代ごとに違うアーキテクチャ
    ○ MVPとMVVMが混ざっている状態
    ● Kotlin率 10%
    ● データ操作をすべてまとめる1800行のFatクラス
    ● RxJava部分で頻発する不具合の調査に時間がかかる
    ○ 今のメンバーのスキルセットと合っていない技術選定
    8
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  9. #sapurimeetup
    New architecture : to be
    ● データ操作を担当するFatクラス -> DataごとのRepository作成
    ● JavaからKotlinへ
    ● MVP → MVVMへ
    ○ EventBusからLiveDataへ
    ○ RxJavaからCoroutineへ
    ● GreenDao → Room
    9
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  10. #sapurimeetup
    “やっていき”の機運
    ビジネス案件が落ち着いた頃
    数ヶ月後に大規模な案件が待っていた
    ➔ “今やるべき案件”として優先度が高まった
    10
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  11. #sapurimeetup
    考慮すべき事項
    案件を完全に止めることはできない
    数ヶ月後から大規模案件の開発ができるようにしておくこと
    もちろん大きな障害が出ないように…
    ➔ 進め方に工夫が必要
    11
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  12. #sapurimeetup
    どのように実践するか
    02
    12
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  13. #sapurimeetup
    New architecture : to be
    ● データ操作を担当するFatクラス -> DataごとのRepository作成
    ● JavaからKotlinへ
    ● MVP → MVVMへ
    ○ EventBusからLiveDataへ
    ○ RxJavaからCoroutineへ
    ● GreenDao → Room
    13
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  14. #sapurimeetup
    技術選定のポイント
    ● Google公式/推奨のものを基本的に採用
    ○ MVVM, LiveData, Kotlin etc...
    ● チームメンバーに馴染みがあるか
    ○ RxJavaは難しい…
    ● 学ぶのにモチベーションがあがるか
    ○ Kotlin, Coroutine etc...
    14
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  15. #sapurimeetup
    Before
    15


    Fragment.java
    Activity.java
    Presenter.java ModelManager.java
    DB(GreenDao)
    Network
    EventBusで通知
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  16. #sapurimeetup
    After
    16


    Fragment.kt
    Activity.kt
    ViewModel.kt Repository.kt
    DB(Room)/Network
    LiveDataで通知

    LiveDataで通知
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  17. #sapurimeetup
    タスクへの分解
    17
    Migrate
    GreenDao to
    Room
    - GreenDaoを廃止しRoomを採用
    - データごとのDaoを作成しモデル層をまとめる Fatク
    ラスを廃止
    アプリ全体
    Convert to Kotlin - JavaからKotlinへ変換 各画面
    Migrate to MVVM - ViewModelの追加
    - EventBusからLiveDataへ変更
    - RxJavaからCoroutineへ変更
    各画面
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  18. #sapurimeetup
    ビジネス案件を止めずに改善を行う戦略
    18
    ● タスクを特性によって分解
    ○ 一気に進めないといけないもの
    ○ 大規模案件の開発に影響のあるもの
    ○ 複数画面に影響のあるもの
    ○ 独立して進められるもの
    ● 先にやるもの、後でも問題ないものに分解しスケジュール化
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  19. #sapurimeetup
    ビジネス案件を止めずに改善を行う戦略
    19
    ● Phase1: Migrate GreenDao to Room
    ○ 小さくリリースができないのでまとまった時間を使って進める
    ● Phase2: 大規模案件に影響する画面のKotlin化、MVVM化
    ○ 見通しの良い状態で大規模案件を始めたい
    ● Phase3: その他の画面のKotlin化、MVVM化
    ○ 誰でも独立して進められる。期限の制約がない
    ○ MVVM化は最低ViewModelの追加とLiveDataへの導入は行う
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  20. #sapurimeetup
    Try & Error
    03
    20
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  21. #sapurimeetup
    試行錯誤した点
    21
    ● スコープの調整
    ● 新導入したLibraryでのベストプラクティス探し
    ○ Kotlin Coroutine
    ○ LiveData
    ● 開発プロセスの改善
    ○ コードレビュー
    ○ タスクのアサインと知見共有
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  22. #sapurimeetup
    スコープの調整
    22
    ● 一部、改修時の変更に先送りしたこと
    ○ RxJavaからCoroutineへ移行
    ○ LiveData経由でローカルのデータを返す
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  23. #sapurimeetup
    Kotlin Coroutine
    23
    ● [Before] ExceptionHandlerを使ったエラーハンドリング
    val scope = viewModelScope + CoroutineExceptionHandler { _ , _->
    Timber.d("failure clickDebugButton ")
    }
    var count = 0
    fun clickDebugButton() = scope.launch {
    count++
    if (count % 2 == 0) {
    throw AssertionError("count%2 is 0")
    }
    Timber.d("success clickDebugButton")
    } ViewModel.kt
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  24. #sapurimeetup
    Kotlin Coroutine
    24
    期待値は success と failure が交互に出る
    clickDebugButton: success clickDebugButton
    clickDebugButton: failure clickDebugButton
    clickDebugButton: success clickDebugButton
    clickDebugButton: failure clickDebugButton Logcat
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  25. #sapurimeetup
    Kotlin Coroutine
    25
    実際は一度エラーが出るとcatchし続けてしまう
    clickDebugButton: success clickDebugButton
    CoroutineExceptionHandler: failure clickDebugButton
    CoroutineExceptionHandler: failure clickDebugButton
    CoroutineExceptionHandler: failure clickDebugButton Logcat
    Baby steps to improve architecture In Study Sapuri Android
    ※ version 1.2.1

    View Slide

  26. #sapurimeetup
    Kotlin Coroutine
    26
    ● [After] runCatching, onFailureを使ったハンドリングに変更
    var count = 0
    fun clickDebugButton() = viewModelScope.launch {
    runCatching {
    count++
    if (count % 2 == 0) { throw AssertionError("count%2 is 0") }
    }.onSuccess {
    Timber.d("success clickDebugButton")
    }.onFailure {
    Timber.d("failure clickDebugButton")
    }
    }
    ViewModel.kt
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  27. #sapurimeetup
    LiveData
    27
    [Before] 一つのError fieldに複数の種類のErrorを非同期で通知
    private var _errorDebug: MutableLiveData = MutableLiveData()
    val errorDebug: LiveData
    get() = _errorDebug
    fun clickDebugButton() = viewModelScope.launch(IO) {
    _errorDebug.postValue(Error.Hoge)
    }
    fun clickDebugButton2() = viewModelScope.launch(IO) {
    _errorDebug.postValue(Error.Fuga)
    }
    ViewModel.kt
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  28. #sapurimeetup
    LiveData
    28
    期待値は Hoge も Fuga も通知してほしい
    onCreateView: error is observed Hoge
    onCreateView: error is observed Fuga
    binding.debugButton.setOnClickListener {
    viewModel.clickDebugButton()
    viewModel.clickDebugButton2()
    } Fragment.kt
    Logcat
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  29. #sapurimeetup
    LiveData
    29
    実際は Fuga のみ通知される(場合がある)
    ● ほぼ同時に postValue が呼ばれると値が抜ける
    ● delay() などでタイミングをズラすと呼ばれる
    onCreateView: error is observed Fuga
    Logcat
    Baby steps to improve architecture In Study Sapuri Android
    ※ version 2.1.0-alpha02

    View Slide

  30. #sapurimeetup
    LiveData
    30
    [After] Error種類によってLiveDataを分けるように変更
    fun clickDebugButton() = viewModelScope.launch(IO) {
    _errorHoge.postValue(true)
    }
    fun clickDebugButton2() = viewModelScope.launch(IO) {
    _errorFuga.postValue(true)
    }
    ViewModel.kt
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  31. #sapurimeetup
    コードレビュー
    31
    ● Convert to Kotlinのコードレビューがしにくい
    ○ 自動変換のものとマニュアルの変更のコミットを分ける
    ● 細かいコーディングスタイルは進めながら議論
    ○ どの単位でRepositoryを切るか
    ○ nonnullにできるところ/lateinit,lazyが使えるところ
    ○ スコープ関数何を使うか
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  32. #sapurimeetup
    タスクのアサインと知見共有
    32
    ● DBのマイグレーションなど複数人作業に効率の悪いタスクは専任を決める
    ○ 開発途中でブランチを移動するとBuildに時間がかかる
    ● 勉強会を開き知見を共有
    ○ e.g) Roomの導入
    ○ e.g) RxJavaのコードで起こしやすい不具合の共有
    ● 特に複雑度の高い画面はペアプロで進める
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  33. #sapurimeetup
    振り返り・まとめ
    03
    33
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  34. #sapurimeetup
    取り組みの結果
    34
    ● Phase1: Migrate GreenDao to Room
    ○ 完了
    ● Phase2: 大規模案件に影響する画面のKotlin化、MVVM化
    ○ 完了
    ● Phase3: その他の画面のKotlin化、MVVM化
    ○ Kotlin化 49%
    ○ MVVM化 44%
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  35. #sapurimeetup
    アーキテクチャ改善は必要か?
    35
    ● Yes.
    ● 当時考えられて作られたアーキテクチャでも開発メンバーも変わればアーキ
    テクチャの良さも変わる
    ○ 開発する自分たちに合うものに変える
    ○ 自分たちが開発していて気持ちいい環境にする
    ● ドメイン知識の伝承
    ○ 知らない仕様で起きる不具合が多かった
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  36. #sapurimeetup
    ドメイン知識の伝承が役立った場面
    36
    ● 大規模案件の開発のとき
    ○ データ構造が複雑に絡み合っている
    ○ 複数の条件/状態を前提に開発しなければいけない
    ○ 元々不具合がとても多かった画面
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  37. #sapurimeetup
    大規模案件を担当したメンバーの声
    37
    ● “正直アーキテクチャ改善でできたところは周辺の部分”
    ● “だけどリファクタでドメイン知識のキャッチアップができたので開発に入りや
    すかった”
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  38. #sapurimeetup
    アーキテクチャ改善が進められた要因
    38
    ● 最新の技術を習得したいDeveloperのモチベーション
    ● ビジネス案件が落ち着いていた
    ● リファクタリングにコストを払う価値がある考えがQuipper全体に浸透してい

    ● 技術選定に関してエンジニアチームに一任されている環境
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  39. #sapurimeetup
    まとめ
    ● Study Sapuri Androidチームは地道なアーキテクチャ改善を続けてきまし
    た…!!
    ● リファクタによる恩恵
    ○ ”複雑な仕様の伝承”
    ○ 開発スピード/品質の改善
    ● 今のアーキテクチャに固執しすぎない、常に良い形を模索していくチーム
    39
    Baby steps to improve architecture In Study Sapuri Android

    View Slide

  40. #sapurimeetup
    ご清聴ありがとうございました
    40
    Baby steps to improve architecture In Study Sapuri Android

    View Slide