Clean Architecture with Vue

Clean Architecture with Vue

Attempting Clean Architecture with Vue.js and Vuex.

Event Link: https://kfug.connpass.com/event/90962/
GitHub Link: https://github.com/andoshin11/clean-architecture-example-vue

5c97d6b5611feeebc345c3e4742a05a8?s=128

andoshin11

June 30, 2018
Tweet

Transcript

  1. Clean Architecture with Vue Vue.js / Nuxt.js Meetup Osaka #0

    by andoshin11 Attempting
  2. Who am I ? • Andy (@andoshin11) • Vue.js Japan

    User Group • Frontend Developer @FOLIO • JS, Ruby, Go, Perl, Python, PHP, Rust(?)
  3. None
  4. Vue Fesやります!!

  5. 本日のゴール • Clean Architectureの概要を理解する • 「VueにClean Architectureを導入すべきか」を判断できるようになる

  6. None
  7. Clean Architectureの基本 ・オニオン型のレイヤードアーキテクチャ ・各レイヤーの名前は重要ではない ・依存性の矢印が単方向であることが大切 ・内側のレイヤーは外の世界を知らない

  8. Clean Architectureの特徴 • ビジネスロジックがFWやUI、DB、外部API等に依存しない(Testable) • ビジネスロジックはEntitiesとUsecasesに集約される • 外界(UI等)からのデータの読み書きはInterface Adapter(Presenter, Controller)

    を通して行われる
  9. アプリケーション実装パターンのおさらい • MVC • MVVM • DDD • Flux

  10. MVC(割愛) ・Model - View - Controller ・Railsが採用しているやつ ・ViewがModelをObserve ・Fat Model,

    Fat Controller問題 ・「データの振舞い」を定義する余地がない
  11. MVVM(割愛) ・Vue Componentがやってるやつ ・Modelは生データおよびDomain Model ・ファサードとしてのVM ・ViewとVMにおいてデータバインディングが成立しているので Presenterやイベントを受け 取るControllerが不要

  12. DDD(レイヤードアーキテクチャ) ・業務上の関心事(ドメイン)を中心に据えた 設計手法 ・Domain Layerでデータの振舞を定義 ・責務が分離されているため、フレームワー クやライブラリに依存しづらい ・レイヤー間の依存性は単方向でない

  13. Flux ・Facebook社が提唱 ・Redux, Vuex等 ・CQRS ・Event Sourcing ・単方向データフロー

  14. Flux はClean Architectureに近い?

  15. DDDの観点から見るFlux(Vuex) • UIコンポーネント - Presentation層にあたる。イベントの発火も。 • Action - Application層。API通信だけでなくデータ処理に必要な手続き全般を担うた めDomain層も兼ねることが多い。

    • Mutation - StoreのInput Port。ロジックは持たない。 • Store - オンメモリでデータを永続化。外部への柔軟な Output Portを持つ。
  16. Vuexを利用したFluxパターン(課題) • Actionsにアプリケーションロジックが集約しがち。 • ドメインモデル(振舞いを持ったデータモデル)ってどこに書くんだっけ? • Storeの構造がViewを意識したものになりがち • Gettersを全てのViewに用意するのは厳しい •

    Mutation(≒ Store)にロジックを書く人間が後を断たない (書けてしまうので) • 本当にTestable?
  17. スケールしなさそう・・・

  18. 今回の設計方針 ・より厳密なレイヤー分割を行う ・業務上の関心と技術上の関心を分離 → Domain Modelの活用(DDD Like) ・シンプルなイベント伝達 → 単方向データフロー(Flux

    Like) ・依存性も単方向にしてよりテスタブルに → Clean Architecture ・フレームワークや外部のI/Fに依存しない → Gatewayの活用
  19. スケールさせるぞ!!

  20. Container Controller Use Case Repository Store Entity Presenter UI Components

    Query Command
  21. アプローチ • Controllerからイベントを発火 • Usecaseにビジネスロジックを記述。DI(依存性の注入)はControllerで • データモデルの振舞いを定義する Entity層を用意 • Repository内でStoreにアクセス

    • UIはPresenterで抽出したデータセットの写像である
  22. 実装編 https://github.com/andoshin11/clean-architecture-example-vue

  23. 登場人物 今回はNuxtつかってません!! (土下座)

  24. Store • DomainごとにModule化 • Actionsは持たない • Observableな箱としての用途 • 無理やり型付けしてます

  25. Entity • Interfaceの提供 • Domainロジックの定義 • Data Store Layerへの読み書きを許 容(through

    Vuex API)
  26. Repository • アプリケーション固有のDomainロ ジックを定義 • Data Store Layerへアクセスを持つ (through Vuex

    API)
  27. Container • UIの表示単位 • Atomic DesignでいうPages? • ContainerごとにUse Caseと Presenterを持つ

    • Containerを1つのドメインとみなした DucksなStore実装も可能
  28. Use Case • アプリケーションに必要な手続き を定義 • DIされてはじめて動く

  29. Presenter • 表示要件に必要なデータを Storeから抽出・整形 • 純粋関数として定義し、 Computed プロパティにマッピ ング

  30. Container View • Presenterの値をUI Componentに注入 • Use Caseに依存性を注入する(Domain Injection) •

    現状Controllerも含まれてしまっている
  31. Container Controller Use Case Repository Store Entity Presenter UI Components

    Query Command
  32. Testing • UIコンポーネント - Presenterの写像なので再現が簡単 • Repositories - Data Store

    LayerへのRead & Write APIをテスト • Use Cases - Given ConditionとしてRepositoryとServiceのモックをDIするだけ • Entities- Use Casesと同様
  33. まとめ: • いたずらにレイヤーを増やせば良いというわけではない • 依存の方向性を意識することで変更に強いアプリケーションに近づく • Vuexと周辺のテストツールを信用しきるならデフォルトの API叩く方が楽(今は Gatewayを使っていない) •

    Clean Architectureの導入コストは高いので見極めが大事
  34. これってVueじゃなくてもできるのでは?

  35. We Are Hiring!!

  36. 参考: • https://qiita.com/kondei/items/41c28674c1bfd4156186 • https://speakerdeck.com/takasek/10fen-tezhen-rifan-rusohutoueaakitekutiyafalseli-shi-2017 • http://embryo.hatenadiary.com/entry/2016/12/16/011446 • https://github.com/azu/large-scale-javascript •

    https://qiita.com/Tueno@github/items/705360b357c2a00c9532