Successfully reported this slideshow.
Your SlideShare is downloading. ×

失敗から学ぶAndroid設計話

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Loading in …3
×

Check these out next

1 of 89 Ad

More Related Content

Slideshows for you (20)

Similar to 失敗から学ぶAndroid設計話 (20)

Advertisement

失敗から学ぶAndroid設計話

  1. 1. 失敗から学ぶ設計話 ~Android編~ chigichan24 Android ロボットは、Google が作成および提供している作品から複製または変更したものであり、 Creative Commons 3.0 Attribution ライセンスに記載された条件に従って使用しています。
  2. 2. Agenda • SyncPodについて • 改修の理由 • 様々なアーキテクチャの紹介 • 使用技術 • 構成について • 良かった点 • 悪かった点 • 最後に
  3. 3. Agenda • SyncPodについて • 改修の理由 • 様々なアーキテクチャの紹介 • 使用技術 • 構成について • 良かった点 • 悪かった点 • 最後に
  4. 4. 今日の話 Android版 iOS版 https://github.com/cyder
  5. 5. • 端的にいうと • 同じルームに入った人と動画を同期して再生する. • 動画を見ながらコメントすることができる. • 誰でも入れるルームの作成,人気ルームのサジェストなど. • Androidだけ先行でリリースしていた,iOSをリリース するタイミングでAndroidの技術的負債を一気に改修 (回収)したかった. • 機能追加が常にアドホックで命懸け(?)な状態から いつ不幸にもバズっても運用できるように.
  6. 6. A lot of Problems Copy and Paste No external Library Fat Activity Smart UI Null Pointer Exception Mysterious Bug No ViewModel No Architecture Broken naming convention Broken directory partition No Repository Java
  7. 7. Agenda • SyncPodについて • 改修の理由 • 様々なアーキテクチャの紹介 • 使用技術 • 構成について • 良かった点 • 悪かった点 • 最後に
  8. 8. Agenda • SyncPodについて • 改修の理由 • 様々なアーキテクチャの紹介 • 使用技術 • 構成について • 良かった点 • 悪かった点 • 最後に
  9. 9. • ジェンガ論 • 地盤の段階(ジェンガの下の層)がゆるゆるだと,機能追加や 改修(ジェンガの上に新しく置く操作)はつらい.ジェンガが 崩れる可能性(プロジェクト終了のお知らせ)を秘めている. • 逆に基盤をしっかり作っていれば(下の層がきっちり積まれて いれば),機能追加が少々荒くなっても(上の層に繁雑にジェ ンガを置いても)しばらくは耐えられる. 一から書き直す必要があると判断
  10. 10. どういう構成にしよう 🤔
  11. 11. 様々なアーキテクチャやライブラリ,思想論 いろいろありすぎ とても困った MVC MVP MVVM Flux Redux AAC The Clean Architecture DDD SOLID Jetpack Hexagonal Architecture Onion Architecture
  12. 12. Agenda • SyncPodについて • 改修の理由 • 様々なアーキテクチャの紹介 • 使用技術 • 構成について • 良かった点 • 悪かった点 • 最後に
  13. 13. Agenda • SyncPodについて • 改修の理由 • 様々なアーキテクチャの紹介 • 使用技術 • 構成について • 良かった点 • 悪かった点 • 最後に
  14. 14. 様々なアーキテクチャやライブラリ,思想論 いろいろありすぎ とても困った MVC MVP MVVM Flux Redux AAC The Clean Architecture DDD SOLID Jetpack Hexagonal Architecture Onion Architecture VIPER
  15. 15. ごっちゃになってるので整理する 設計パターン MVC MVP MVVM Flux Redux AAC Jetpack ライブラリ群 DDD SOLID 設計原則 The Clean Architecture Hexagonal Architecture Onion Architecture アーキテクチャ思想
  16. 16. ごっちゃになってるので整理する 設計パターン MVC MVP MVVM Flux Redux AAC Jetpack ライブラリ群 DDD SOLID 設計原則 The Clean Architecture Hexagonal Architecture Onion Architecture アーキテクチャ思想
  17. 17. MVC • Model-View-Controller • rails,ios projectとかがデフォルトで使ってるやつ. • アプリに実装しようとするといろいろ厄介. • 全体的に密結合になる.(Controllerの肥大化) • Androidに適用しようとするとActivityはControllerなの? Viewなの?あれれ...ってなる. View Controller Model
  18. 18. MVP • Model-View-Presenter • 方向を単一方向にする. • ViewとActivity,Fragmentが対応する. • PresenterではViewに依存する処理はinterfaceとしてもらう. • データの更新等の処理はModelに投げる. • ViewではPresenterのメソッドを呼ぶ. View Presenter Model
  19. 19. MVPの雰囲気(iOS × Swift) protocol HogeView: class { func updateLabel(text: String) } final class HogeViewController: UIViewController, HOGEView { @IBOutlet private weak var labels: UILabel! @IBOutlet private weak var button: UIButton! private lazy var presenter = HogePresenter() override func viewDidLoad() { super.viewDidLoad() button.addTarget(presenter, action: #selector(presenter.changeText), for: .touchUpInside) } func updateLabel(text: String) { label.text = text } }
  20. 20. MVPの雰囲気(iOS × Swift) final class HogePresenter { private weak var view: HogeView func changeText() { // ここからmodelをいじりに行く view.updateLabel() } } Presenterが生のViewへの参照を持つのは危なすぎるので, 適宜機能制限した BaseViewClassを継承するべき. MVPの問題点 Presenterがviewを持っていて何やらかされるか分からない.
  21. 21. MVVM • Model-View-ViewModel • MVPと似た構造をしているが,ViewとViewModelは databindingで双方向につながっている. • databindingとは? • protocolやinterfaceでcallback的に層を繋げず, 通知を流す仕組み.viewへの参照を持たない!!! • Android : databinding,ButterKnife,KotterKnife • ios : RxSwift,Bond • C# : WPFにおけるxamlとかの仕組み View ViewModel Model ↑ databinding
  22. 22. Flux Action Dispatcher Store View Action • Flux • MV *ではデータの流れに双方向性があって大変だった問題を 解決した.js由来. • 一方向にデータが流れ,Dispatcherで様々な振り分ける. • (現在FluxアーキテクチャでAndroidアプリ作ってるので作り 上げたら感想がわかりそう)
  23. 23. ごっちゃになってるので整理する 設計パターン MVC MVP MVVM Flux Redux AAC Jetpack ライブラリ群 DDD SOLID 設計原則 The Clean Architecture Hexagonal Architecture Onion Architecture アーキテクチャ思想
  24. 24. ごっちゃになってるので整理する 設計パターン MVC MVP MVVM Flux Redux AAC Jetpack ライブラリ群 DDD SOLID 設計原則 The Clean Architecture Hexagonal Architecture Onion Architecture アーキテクチャ思想
  25. 25. アーキテクチャ思想のキモ • 変更への強さ • 層の数はそれぞれだが,達成したいことは変更に強いこと! • 層の分離はテスタビリティの向上 • 層で分離できる ≈ 層をmockにしてテストができる.
  26. 26. 変更への強さ 偉い人 旧アーキテクチャ編
  27. 27. 変更への強さ あのAPIのレスポンス ちょっと変えます 偉い人 旧アーキテクチャ編
  28. 28. 変更への強さ あのAPIのレスポンス ちょっと変えます 偉い人 え! UIと直接紐付いてるか ら変更は至難の業だ 旧アーキテクチャ編
  29. 29. 怖い話
  30. 30. 昔のアーキテクチャであった怖い話
  31. 31. 昔のアーキテクチャであった怖い話 • 1 画面1 API( 1 エンドポイント )しか叩けない • なぜそんな設計をしたのか... • ごりごり実装メインでやっていたらこうなった.
  32. 32. 昔のアーキテクチャであった怖い話 • 1 画面1 API( 1 エンドポイント )しか叩けない • なぜそんな設計をしたのか... • ごりごり実装メインでやっていたらこうなった. • 使い回しできそうなコードが全部コピペによって生成 されている. • 抽象化して... • 全部に対して変更があったらどうするの...
  33. 33. 昔のアーキテクチャであった怖い話 • 1 画面1 API( 1 エンドポイント )しか叩けない • なぜそんな設計をしたのか... • ごりごり実装メインでやっていたらこうなった. • 使い回しできそうなコードが全部コピペによって生成 されている. • 抽象化して... • 全部に対して変更があったらどうするの... • 謎のマジックナンバーによって管理されるfragment • それfragmentの表示順かえるのでも一苦労やで...
  34. 34. The Clean Architecture
  35. 35. Android10CoderのMVPによる解説
  36. 36. ごっちゃになってるので整理する 設計パターン MVC MVP MVVM Flux Redux AAC Jetpack ライブラリ群 DDD SOLID 設計原則 The Clean Architecture Hexagonal Architecture Onion Architecture アーキテクチャ思想
  37. 37. ごっちゃになってるので整理する 設計パターン MVC MVP MVVM Flux Redux AAC Jetpack ライブラリ群 DDD SOLID 設計原則 The Clean Architecture Hexagonal Architecture Onion Architecture アーキテクチャ思想
  38. 38. 設計原則 • このことばが正しいのかはちょっと怪しい. • 設計手法や実装していく上でのルールの話. • DDDではドメインの世界観をきちんときめてそれを体 現するコードを書く. • SOLID原則はコード実装時のルール SyncPodという世界観を作っているもの(Entity)はなにか? Chatなの?,Roomなの?,Videoなの?,Userなの? これらの関係は?,なにがValueObjectなの? 取り入れた例 publicなmethod名とユビキタス言語を紐付ける. fun post_to_hoge( )とかはありえない.
  39. 39. Agenda • SyncPodについて • 改修の理由 • 様々なアーキテクチャの紹介 • 使用技術 • 構成について • 良かった点 • 悪かった点 • 最後に
  40. 40. Agenda • SyncPodについて • 改修の理由 • 様々なアーキテクチャの紹介 • 使用技術 • 構成について • 良かった点 • 悪かった点 • 最後に
  41. 41. ごっちゃになってるので整理する 設計パターン MVC MVP MVVM Flux Redux AAC Jetpack ライブラリ群 DDD SOLID 設計原則 The Clean Architecture Hexagonal Architecture Onion Architecture アーキテクチャ思想
  42. 42. さて,どういう構成にしよう 🤔
  43. 43. MVVM + The Clean Architecture • 超最新トレンドから一歩引いた感じに落ち着いた. • 使用技術としてやりたかったことはまだまだいろいろあった. • MVVMは実装コストや学習コストは高いが最も堅牢 • MVPにしてもよかったが,可能な限りviewの要素と 切り離したいという思い. • Clean Architectureに載せることで依存を解消 • レイヤー化の恩恵は大きい • 今後様々な変更があることを加味して変更に強く! • 適宜SOLIDやDDDの原則を適用(code reviewで共有) • エンジニア間で意識・アプリの世界観を共有.
  44. 44. 主な使用技術 with KotlinRxJava(RxAndroid,RxKotlin) Dagger2 DI Container Jetpack
  45. 45. Agenda • SyncPodについて • 改修の理由 • 様々なアーキテクチャの紹介 • 使用技術 • 構成について • 良かった点 • 悪かった点 • 最後に
  46. 46. Agenda • SyncPodについて • 改修の理由 • 様々なアーキテクチャの紹介 • 使用技術 • 構成について • 良かった点 • 悪かった点 • 最後に
  47. 47. 構成図 例外的に 呼んでる時ある. View ViewModel Repository SyncPodApi SyncPodWsApi SharedPreference databinding I I II I Interface(抽象)に依存するようにする … Interface Class method call method call stream stream … method call … stream
  48. 48. MVVM的には View ViewModel Repository SyncPodApi SyncPodWsApi SharedPreference I I II View ViewModel Model
  49. 49. 基本的には
  50. 50. 設計・実装時のポイント① • PresenterをViewModelとしてViewとbind • StreamはViewModelまで流れてそれより上はdatabinding • UseCaseをなくした. • 設計時にUseCaseの存在の意味を見いだせなかった. • ViewModelが直接Repository参照して大丈夫でしょ(?) • 抽象に依存する. • 依存関係逆転の法則(DIP) • DI Containerのdagger2で解決 • ViewとViewModelは1対1で. • Viewでは基本的に何も操作しない(smartUIにならないように)
  51. 51. 設計・実装時のポイント② • Rxの型としてObservableは使わない. • 意味がわかりにくくなるので,Single,Compleatable, Flowableのみに. • むやみにFlowable使ったら👊 • ViewModelで使うメソッド名はユーザー目線(ユビキタ ス言語で表現できるもの)に • websocketを扱う部分もなんとかstreamに. • そういうライブラリが存在しないので,websocketでのレス ポンス(listenerで取る形)を全部Rxのstreamに書き直す.
  52. 52. Agenda • SyncPodについて • 改修の理由 • 様々なアーキテクチャの紹介 • 使用技術 • 構成について • 良かった点 • 悪かった点 • 最後に
  53. 53. Agenda • SyncPodについて • 改修の理由 • 様々なアーキテクチャの紹介 • 使用技術 • 構成について • 良かった点 • 悪かった点 • 最後に
  54. 54. 良かった点👍 • 機能追加が楽
  55. 55. 怖い話
  56. 56. リリース初日で機能追加決定
  57. 57. リリース初日で機能追加決定 • コードをどう書くべきか はすぐに思いつく. • ちょっとデザイン考える のがしんどいかなー. • 一週間あれば確実に問題 ないし, ロジックは1時間くらい で実装できた. Android
  58. 58. リリース初日で機能追加決定 • コードをどう書くべきか はすぐに思いつく. • ちょっとデザイン考える のがしんどいかなー. • 一週間あれば確実に問題 ないし, ロジックは1時間くらい で実装できた. • あああああああああああ あああああああああああ あああああああああああ あああああああああああ ああああ • もうどうせ汚いコードだ ししょうがないやろ(最悪 Android iOS
  59. 59. 良かった点👍 • 機能追加が楽
  60. 60. 良かった点👍 • 機能追加が楽 • 身をもって体感.
  61. 61. 良かった点👍 • 機能追加が楽 • 身をもって体感. • 新しいメンバーがjoinしやすい • ファイルごとの役割を明確にしているので どこに何を書くのかがはっきりしている.
  62. 62. 良かった点👍 • 機能追加が楽 • 身をもって体感. • 新しいメンバーがjoinしやすい • ファイルごとの役割を明確にしているので どこに何を書くのかがはっきりしている. • Kotlinで書いてるからJavaの呪いから開放されている.
  63. 63. 良かった点👍 • 機能追加が楽 • 身をもって体感. • 新しいメンバーがjoinしやすい • ファイルごとの役割を明確にしているので どこに何を書くのかがはっきりしている. • Kotlinで書いてるからJavaの呪いから開放されている. • 意味不明なバグも起きなくなった. • バグ数,クラッシュ数が明らかに減った!!!
  64. 64. Agenda • SyncPodについて • 改修の理由 • 様々なアーキテクチャの紹介 • 使用技術 • 構成について • 良かった点 • 悪かった点 • 最後に
  65. 65. Agenda • SyncPodについて • 改修の理由 • 様々なアーキテクチャの紹介 • 使用技術 • 構成について • 良かった点 • 悪かった点 • 最後に
  66. 66. 悪かった点👎 • UseCaseをやっぱり作るべきだった.
  67. 67. 設計・実装時のポイント① • PresenterをViewModelとしてViewとbind • StreamはViewModelまで流れてそれより上はdatabinding • UseCaseをなくした. • 設計時にUseCaseの存在の意味を見いだせなかった. • ViewModelが直接Repository参照して大丈夫でしょ(?) • 抽象に依存する. • 依存関係逆転の法則(DIP) • DI Containerのdagger2で解決 • ViewとViewModelは1対1で. • Viewでは基本的に何も操作しない(smartUIにならないように)
  68. 68. 設計・実装時のポイント① • PresenterをViewModelとしてViewとbind • StreamはViewModelまで流れてそれより上はdatabinding • UseCaseをなくした. • 設計時にUseCaseの存在の意味を見いだせなかった. • ViewModelが直接Repository参照して大丈夫でしょ(?) • 抽象に依存する. • 依存関係逆転の法則(DIP) • DI Containerのdagger2で解決 • ViewとViewModelは1対1で. • Viewでは基本的に何も操作しない(smartUIにならないように) 自分でやってるやん...
  69. 69. UseCaseが無い問題 • Repositoryパターンの肥大化 & やることが多い. • このパターンではそもそもデータのソースを考えず CQRS操作ができるようにするべき.
  70. 70. UseCaseが無い問題 • Repositoryパターンの肥大化 & やることが多い. • このパターンではそもそもデータのソースを考えず CQRS操作ができるようにするべき. Repository UseCase command,queryを投げる データソースを吸収して, → 上に流すだけ データを加工する. ビジネスロジックを委ねる.→ よしなにデータを取ってくる
  71. 71. 悪かった点👎 • UseCaseをやっぱり作るべきだった. • Clean Architectureは正しいなあと痛感. • Repositoryは肥大化してしまっている.
  72. 72. 悪かった点👎 • UseCaseをやっぱり作るべきだった. • Clean Architectureは正しいなあと痛感. • Repositoryは肥大化してしまっている. • ライブラリの選定をミスった.
  73. 73. ライブラリ選定の話
  74. 74. ライブラリ選定の話 リリース直後はAndroid 6.0未満の端末では動かなかった 😱
  75. 75. ライブラリ選定の話 • websocketを扱うために使っていたライブラリの バグだと判明. • ライブラリは全然整備されていない. • star 1で,一年近くなにも更新されていない.
  76. 76. ライブラリ選定の話 • websocketを扱うために使っていたライブラリの バグだと判明. • ライブラリは全然整備されていない. • star 1で,一年近くなにも更新されていない. ライブラリの選定はコミュニティの活発度を見よう!
  77. 77. 悪かった点👎 • UseCaseをやっぱり作るべきだった. • Clean Architectureは正しいなあと痛感. • Repositoryは肥大化してしまっている. • ライブラリの選定をミスった. • 活発なものを選ぼう! • Androidバージョン違いで起きるバグを事前に検証しよう!
  78. 78. 悪かった点👎 • UseCaseをやっぱり作るべきだった. • Clean Architectureは正しいなあと痛感. • Repositoryは肥大化してしまっている. • ライブラリの選定をミスった. • 活発なものを選ぼう! • Androidバージョン違いで起きるバグを事前に検証しよう! • DIコンテナで(dagger)で無理やり依存関係を作ってい る. • なるべく疎になるようにしよう.
  79. 79. 悪かった点👎 • UseCaseをやっぱり作るべきだった. • Clean Architectureは正しいなあと痛感. • Repositoryは肥大化してしまっている. • ライブラリの選定をミスった. • 活発なものを選ぼう! • Androidバージョン違いで起きるバグを事前に検証しよう! • DIコンテナで(dagger)で無理やり依存関係を作ってい る. • なるべく疎になるようにしよう. • MVVMの限界を感じた
  80. 80. MVVMの限界問題 • SnackBarやToast(下からポップアップで出るような通 知バー)は,本来viewmodelで作るべきだがこれらを作 るのにviewが必要. • callback的にやることで解決. ←設計のバイブル本でも むずいと言ってるので多分むずい
  81. 81. Agenda • SyncPodについて • 改修の理由 • 様々なアーキテクチャの紹介 • 使用技術 • 構成について • 良かった点 • 悪かった点 • 最後に
  82. 82. Agenda • SyncPodについて • 改修の理由 • 様々なアーキテクチャの紹介 • 使用技術 • 構成について • 良かった点 • 悪かった点 • 最後に
  83. 83. 最後に
  84. 84. 最後に • いろんな事を考え成功・失敗したが大事なことはエン ジニア・プランナー・利用者のことを考えて設計する こと. • 無理に高尚なアーキテクチャを使ったからといっていい結果 になるとは限らない.
  85. 85. 最後に • いろんな事を考え成功・失敗したが大事なことはエン ジニア・プランナー・利用者のことを考えて設計する こと. • 無理に高尚なアーキテクチャを使ったからといっていい結果 になるとは限らない. • ここで改善点を生かしてiOSを絶賛リファクタ中.
  86. 86. 最後に • いろんな事を考え成功・失敗したが大事なことはエン ジニア・プランナー・利用者のことを考えて設計する こと. • 無理に高尚なアーキテクチャを使ったからといっていい結果 になるとは限らない. • ここで改善点を生かしてiOSを絶賛リファクタ中. • 開発にも活かせることをたくさん学んだ.
  87. 87. 最後に • いろんな事を考え成功・失敗したが大事なことはエン ジニア・プランナー・利用者のことを考えて設計する こと. • 無理に高尚なアーキテクチャを使ったからといっていい結果 になるとは限らない. • ここで改善点を生かしてiOSを絶賛リファクタ中. • 開発にも活かせることをたくさん学んだ. • でも何より,動いているコードは偉い.リスペクトを.
  88. 88. 昨日 • 類似アプリが見つかって絶望してた
  89. 89. ネイティブでの設計の知見を生かして インターンもまだまだがんばります! おわり

×