Slide 1

Slide 1 text

©2024 Kyash Inc. ©2024 Kyash Inc. UI State設計とテスト方針 2024/12/20 rmakiyama(MAKIYAMA Ryo) Ebisu.mobile #8 大忘年会 STORES kubell Kyash asken

Slide 2

Slide 2 text

©2024 Kyash Inc. 2 ● Kyash Inc (2022/10 -) ● Android Engineer ● Engineering Manager ● @_rmakiyama ● @rmakiyama MAKIYAMA Ryo 自己紹介

Slide 3

Slide 3 text

©2024 Kyash Inc. 3 Kyashについて お支払いも お金の管理も かんたんに Visaプリペイドカードとスマホで、いつでもどこでも、かんたんにお支払い。 アプリへのリアルタイムな履歴反映や自動カテゴリー分類で、お金の管理もかんたんに。

Slide 4

Slide 4 text

©2024 Kyash Inc. KyashとJetpack Compose ● 2021年5月から導入開始 ● Fragmentの上にComposeViewを載せる運用 ● 新規実装する画面は基本的にJetpack Composeを利用 ● 大小含め100画面以上を実装 Jetpack Composeがデファクトスタンダード󰚗 4 ※2024年5月現在

Slide 5

Slide 5 text

©2024 Kyash Inc. アジェンダ ● KyashのKotlin Multiplatform構成 ○ Reactor概説 ○ UI Stateのサンプル ● UI Stateの設計で考えていること ● テスト方針 UI State設計とテスト方針 5

Slide 6

Slide 6 text

©2024 Kyash Inc. KyashのKMP構成概略 6 ● ReactorKitを汲んだMVIライクな設計 ○ State/Action/Event ● 各OSでWrapper実装がある

Slide 7

Slide 7 text

©2024 Kyash Inc. KyashのKMP構成概略 / UI Layer 7

Slide 8

Slide 8 text

©2024 Kyash Inc. KyashのKMP構成概略 / UI Layer / Reactor 8 class InputAmountReactor( mainDispatcher: CoroutineDispatcher, ) : AbstractReactor, Action, Mutation, Event>( mainDispatcher = mainDispatcher, initialState = Reactor.LoadState.Loading(), ) { override fun mutate(action: Action): Flow = flow {...} override fun reduce( state: Reactor.LoadState, mutation: Mutation, ): Reactor.LoadState = when (mutation) {...} data class State(...) : Reactor.State sealed class Action : Reactor.Action sealed class Mutation : AbstractReactor.Mutation sealed class Event : Reactor.Event }

Slide 9

Slide 9 text

©2024 Kyash Inc. ©2024 Kyash Inc. UI State設計⚒ 9 9

Slide 10

Slide 10 text

©2024 Kyash Inc. ©2024 Kyash Inc. 簡単なサンプル󰙇 10 10

Slide 11

Slide 11 text

©2024 Kyash Inc. Sample app 11

Slide 12

Slide 12 text

©2024 Kyash Inc. Sample app 12 ● 金額を入力してOKをおしてSubmit ● 金額を入力しないとOKが押せない ● 1000円以上でないとエラーとする

Slide 13

Slide 13 text

©2024 Kyash Inc. Sample app / UI State 13 data class UiState( val amount: Long?, )

Slide 14

Slide 14 text

©2024 Kyash Inc. Sample app / UI State 14 data class UiState( val amount: Long?, ) 🤔

Slide 15

Slide 15 text

©2024 Kyash Inc. Sample app / UI State 15 data class UiState( val amount: Long?, ) : Reactor.State { val hasError: Boolean = amount &= null && amount &= 0L && amount < 1000L val buttonEnabled: Boolean = amount &= null && isError.not() }

Slide 16

Slide 16 text

©2024 Kyash Inc. Sample app / UI State 16 data class UiState( val amount: Long?, ) : Reactor.State { val hasError: Boolean = amount &= null && amount &= 0L && amount < 1000L val buttonEnabled: Boolean = amount &= null && isError.not() } 関心の分離ができている! 仕様・振る舞いが見えてくる!

Slide 17

Slide 17 text

©2024 Kyash Inc. UI Stateの設計で考えていること UI Stateで仕様や振る舞いを表現する ● 見た目(Element)と状態(State)で関心の分離をする ○ Composable関数を簡単にレンダリングできるデータとして定義 ● UIの理解容易性とテスタビリティを高める ● ※ 網羅性を意識しすぎない 17 https://developer.android.com/topic/architecture/ui-layer

Slide 18

Slide 18 text

©2024 Kyash Inc. ©2024 Kyash Inc. テスト方針🧪 18 18

Slide 19

Slide 19 text

©2024 Kyash Inc. 2024年現在のKyashアプリのテスト方針 State Holder / UI Stateの ユニットテストを重点的にやる ● Reactorのユニットテストを最低限行う ○ Actionに対するStateの期待値をテスト ○ 状態遷移のテストはUI Stateに対するテスト ● UIの振る舞いのテストの一部をカバー ○ UI Stateの責務の工夫とセット 19

Slide 20

Slide 20 text

©2024 Kyash Inc. 2024年現在のKyashアプリのテスト方針の背景 問題をできるだけ早い段階で検出し 開発/アウトカムのフィードバックループを早めたい ● KMPだとユニットテストのROIが高い ○ バグの検出コストを最小限に抑える ● UIテストの責務を絞り効果を高める ○ テストの関心を分離 ○ UIロジックや外観のテストにフォーカス 20

Slide 21

Slide 21 text

©2024 Kyash Inc. Thank you!! ● UIを見た目(Element)と状態(State)に分けてUI Stateを設計している ○ UI Stateで仕様や振る舞いを表現 ● State Holder/UI Stateのテストで仕様や振る舞いのテストを一部カバー ● みんなはどうやってる?このあと話しましょう!! まとめ󰢥 21

Slide 22

Slide 22 text

©2024 Kyash Inc. Last one… ● モバイルエンジニアを募集中です! ● 懇親会でも気軽に話しましょう! WE ARE HIRING 󰚗 22 エンジニアの求人一覧 Advent Calendar 2024

Slide 23

Slide 23 text

©2024 Kyash Inc.

Slide 24

Slide 24 text

©2024 Kyash Inc. Appendix 24 https://www.wantedly.com/companies/wantedly/post_articles/300999 https://developer.android.com/topic/architecture/ui-layer?hl=ja https://developer.android.com/topic/architecture/ui-layer/stateholders?hl=ja https://developer.android.com/develop/ui/compose/migrate/other-considerations?hl=ja#prio ritize-splitting-state https://developer.android.com/training/testing/fundamentals/strategies?hl=ja https://developer.android.com/training/testing/fundamentals?hl=ja