Slide 1

Slide 1 text

設計にみる AWA Androidアプリの これまでとこれから

Slide 2

Slide 2 text

新家 亮太 @AWA @r21nomi r21nomi Android / Creative Coding / Anime

Slide 3

Slide 3 text

本⽇話すこと

Slide 4

Slide 4 text

• これまでの設計 • その問題点 • これからの設計

Slide 5

Slide 5 text

これまでの設計

Slide 6

Slide 6 text

これまでの設計 ー ⽴ち上げ期 ー

Slide 7

Slide 7 text

• 2014.10〜 • Androidエンジニア 1 ~ 4⼈ • いわゆるMVC • テストほぼゼロ

Slide 8

Slide 8 text

Model • DB, APIアクセス • ビジネスロジック Activity / Fragment • プレゼンテーションロジック • ビジネスロジック

Slide 9

Slide 9 text

Model • DB, APIアクセス • ビジネスロジック Activity / Fragment • プレゼンテーションロジック • ビジネスロジック

Slide 10

Slide 10 text

Model • DB, APIアクセス • ビジネスロジック Activity / Fragment • プレゼンテーションロジック • ビジネスロジック ビジネスロジックを書く層が必要

Slide 11

Slide 11 text

Model • DB, APIアクセス • ビジネスロジック Activity / Fragment • プレゼンテーションロジック • ビジネスロジック

Slide 12

Slide 12 text

Model •DB, APIアクセス •ビジネスロジック Activity / Fragment • プレゼンテーションロジック • ビジネスロジック

Slide 13

Slide 13 text

Model •DB, APIアクセス •ビジネスロジック Activity / Fragment • プレゼンテーションロジック • ビジネスロジック Modelの責務分割が必要

Slide 14

Slide 14 text

• ビジネスロジックを書く層をつくる • Modelの責務を分割

Slide 15

Slide 15 text

これまでの設計 ー 設計改善期 ー

Slide 16

Slide 16 text

• 2016.4〜 • Androidエンジニア 5⼈ • Clean Architecture Like • data層のテスト充実

Slide 17

Slide 17 text

Model Activity / Fragment Before

Slide 18

Slide 18 text

DbClient / ApiClient Activity / Fragment Model UseCase Model Activity / Fragment Before After

Slide 19

Slide 19 text

DbClient / ApiClient • DB, APIアクセス Activity / Fragment • プレゼンテーションロジック Model • DbClient / ApiClientの操作 UseCase • ビジネスロジック

Slide 20

Slide 20 text

DbClient / ApiClient • DB, APIアクセス Activity / Fragment • プレゼンテーションロジック Model • DbClient / ApiClientの操作 UseCase • ビジネスロジック ビジネスロジックを書く層 ◎ Modelの責務を分割 ◎

Slide 21

Slide 21 text

DbClient / ApiClient • DB, APIアクセス Activity / Fragment • プレゼンテーションロジック Model • DbClient / ApiClientの操作 UseCase • ビジネスロジック だが、まだまだ問題が

Slide 22

Slide 22 text

• 依然として巨⼤なActivity • ⼿続き型の処理多数 • 役割を失ったBase class • 修正困難な巨⼤クラス

Slide 23

Slide 23 text

結局、何が問題だったのか?

Slide 24

Slide 24 text

設計の擦り合わせをしていなかった

Slide 25

Slide 25 text

→ どこに何を書くべきかがバラバラ → 1クラスの責務が⼤きくなりすぎる → ⼀貫性のないコード 設計の擦り合わせをしていなかった

Slide 26

Slide 26 text

v2構想

Slide 27

Slide 27 text

ちゃんと設計の議論をして1から作る

Slide 28

Slide 28 text

• リーダビリティ シンプルに テストが書ける • テスタビリティ • メンテナビリティ 変更に強い 実装時に迷わない

Slide 29

Slide 29 text

設計は可視化しよう

Slide 30

Slide 30 text

新しい設計 ※3/12時点

Slide 31

Slide 31 text

• レイヤードアーキテクチャ + MVVM • CQRS

Slide 32

Slide 32 text

依存⽅向 app data ui domain data

Slide 33

Slide 33 text

ViewModel DataQuery DataCommand ApiClient Repository Activity 依存⽅向 app data QueryUseCase CommandUseCase

Slide 34

Slide 34 text

ViewModel CommandUseCase QueryUseCase ApiClient Repository Activity DataCommand DataQuery UI 画⾯データの管理 永続化データのI/F データ更新・取得処理の組み⽴て ビジネスロジック

Slide 35

Slide 35 text

ViewModel DataQuery DataCommand ApiClient Repository Activity 依存⽅向 app data QueryUseCase CommandUseCase

Slide 36

Slide 36 text

ViewModel DataQuery DataCommand ApiClient Repository Activity 依存⽅向 app data QueryUseCase CommandUseCase

Slide 37

Slide 37 text

ApiClient • Retrofitインターフェース Repository

Slide 38

Slide 38 text

ApiClient • Retrofitインターフェース Repository • ローカルデータソースのインターフェース • DB, Pref, File, Memory • 使う側はデータソースの種類を意識しない

Slide 39

Slide 39 text

APIはRepositoryではない?

Slide 40

Slide 40 text

“リポジトリを使う側からは、 ドメインモデルがあたかもメモリ上にコレク ションとして存在しているかのように⾒える” Martin Fowler

Slide 41

Slide 41 text

Repositoryを使う側はデータソースを 意識すべきではない

Slide 42

Slide 42 text

APIからデータを取得し、DBに保存 interface Repository { fun fetch(): Single fun save(data: T) } repository.fetch() .doOnSuccess { repository.save(it) }

Slide 43

Slide 43 text

← データソース(API)を意識してる ← 保存先は知らない interface Repository { fun fetch(): Single fun save(data: T) } repository.fetch() .doOnSuccess { repository.save(it) } repository.fetch() repository.save(it) APIからデータを取得し、DBに保存

Slide 44

Slide 44 text

interface Repository { fun save(data: T) } apiClient.fetch() .doOnSuccess { repository.save(it) } ← APIからの取得を意識する apiClient.fetch() repository.save(it) ← 保存先は知らない APIからデータを取得し、DBに保存

Slide 45

Slide 45 text

ApiClient • APIのインターフェース Repository • ローカルデータソースのインターフェース

Slide 46

Slide 46 text

ViewModel DataQuery DataCommand ApiClient Repository Activity 依存⽅向 app data QueryUseCase CommandUseCase

Slide 47

Slide 47 text

ViewModel DataQuery DataCommand ApiClient Repository Activity 依存⽅向 app data QueryUseCase CommandUseCase

Slide 48

Slide 48 text

ViewModel DataQuery DataCommand ApiClient Repository Activity 依存⽅向 app data QueryUseCase CommandUseCase Command? Query?

Slide 49

Slide 49 text

CQRS Command Query Responsibility Segregation

Slide 50

Slide 50 text

更新処理 → Command 取得処理 → Query

Slide 51

Slide 51 text

更新処理 → Command 取得処理 → Query • データの変更はしない • 値を返すだけ • データを変更する • 値は返さない

Slide 52

Slide 52 text

「取得 × 更新」が複雑性を⽣む

Slide 53

Slide 53 text

ViewModel UseCase Single 更新・取得

Slide 54

Slide 54 text

ViewModel UseCase Single CommandUseCase QueryUseCase Completable Flowable ViewModel 更新・取得 取得 更新

Slide 55

Slide 55 text

CommandからQueryを分離し、 複雑性を緩和

Slide 56

Slide 56 text

データの流れ

Slide 57

Slide 57 text

ViewModel CommandUseCase ApiClient Repository Activity データの流れ app data QueryUseCase DataCommand DataQuery

Slide 58

Slide 58 text

ViewModel CommandUseCase ApiClient Repository Activity データの流れ app data QueryUseCase DataCommand DataQuery

Slide 59

Slide 59 text

ViewModel CommandUseCase ApiClient Repository Activity データの流れ app data QueryUseCase DataCommand DataQuery

Slide 60

Slide 60 text

データの流れが単⼀⽅向に

Slide 61

Slide 61 text

まとめ

Slide 62

Slide 62 text

• レイヤー分けをし、責務を明確に • 更新と取得を分け、複雑性を緩和 • 曖昧にせずちゃんと議論して決める • 設計は可視化する 設計 進め⽅

Slide 63

Slide 63 text

Thank You @r21nomi r21nomi