有效結構化你的 Rails 專案

有效結構化你的 Rails 專案

將使用數種實際的範例,講述如何結構化專案邏輯與 UI 畫面。

建議使用多層的 Namespace 來結構化專案的業務邏輯,每個業務流程須講究獨立運作。

當不同角色的業務邏輯 UI 畫面不一樣時,該如何使用前後端技術有效率實作,並保留容易擴充的彈性,將是本次探討的重點。

使用 Rails 開發專案,務必不要死守 MVC 架構,Presenter、Form Object、Query Context 等都是你的好朋友。Rails 的 Form Builder 是很有彈性的,可以串接 ActiveRecord 以外的物件,重點是如何做好表單驗證、錯誤處理、巢狀表單。將會示範如何靈活運用這些物件。

最容易將專案越搞越複雜的方式,大多發生於

1. 相似的業務流程,直接使用同一個流程,加上很多 if else 條件。
2. 不同的角色,有類似的 UI,使用很多 if else 條件去 render 不同的 patial 檔案。

以上無視眾多的小差異積累的威力,就會造成牽一髮動全身,讓專案變得難以維護。將會示範幾項手法來處理這問題。

使用 Rails view 或 React 實作 UI 端(Server / Client Side Render)的基本守則是類似的,因此可以做到遊走於兩種實作方法的。將會示範基本做法。

61b55110e7f363bff43bcab8789930fb?s=128

tsechingho

August 02, 2020
Tweet

Transcript

  1. 何澤清 TSECHINGHO, 2020-08-02, COSCUP TAIWAN 有效結構化你的 Rails 專案 改變思維很重要! 不斷調整思維更重要!!!

  2. 何澤清 tsechingho ⿈碼科技

  3. 邏輯需求

  4. 複合式商店 - 購物⽅式 • 購物⾞ • 可放置多樣商品+型號 • 可移除商品 •

    可選數量 • 可放置加購商品 • 所有商品⼀起結帳 • 智能購物⾞ • 主動折扣(符合條件) • 即時拆單(分批結帳)
  5. ⼀⾴式商店 - 單品購物 • 單品+立即結帳 • 各型號獨立 • 不可選數量 •

    不可搭配加購商品 • 樣式:按鈕 • 單品選購+立即結帳 • 型號可單選 • 可選數量 • 可搭配加購商品 • 樣式:選項+按鈕
  6. ⼀⾴式商店 - 系列商品購物 • 系列商品+立即結帳 • 各商品+型號獨立結帳 • 不可選數量 •

    不可搭配加購商品 • 樣式:分區(按鈕) • 例:劃位售票 • 系列商品選購+立即結帳 • 可多選商品+型號⼀起結帳 • 可選數量 • 可搭配加購商品 • 樣式:分區(選項+按鈕) • 例:冷凍鍋物(⽺⾁爐 )
  7. ⼀⾴式商店 - 綑綁商品購物 • 綑綁商品+立即結帳 • 各綑綁商品獨立結帳 • 不可選數量 •

    不可搭配加購商品 • 樣式:分區(按鈕) • 例:限量公仔 • 綑綁商品選購+立即結帳 • 可複選綑綁商品⼀起結帳 • 可選數量 • 可搭配加購商品 • 樣式:分區(選項+按鈕) • 例:募資商品
  8. 線上商店 - 結帳流程 • 折扣 • 抵⽤(點數) • 優惠(合作) •

    ⾦流 • ATM、超商條碼 • 信⽤卡、線上⽀付 • 發票、電⼦發票 • ⼆聯式、三聯式、捐贈 • 載具 • 物流 • 超商取貨、超商付款取貨 • 郵寄、宅配、貨到付款
  9. 複合式商店 - ⾏銷 + 結帳 • 免費領取 • 零元兌換 •

    等價兌換 • 折價兌換 • 全站折扣碼 • 指定商品折扣碼 • 分類(館)折扣碼 • VIP 卡 • 活動折扣 • 經常性、季節 • 特惠、廠商合作 • 加購優惠
  10. Flow chart

  11. UI 設計需求

  12. 依照角⾊ - 所需⾴⾯組成不同 • 線上課程平台 • 訪客 • 學員 •

    講師 • 學院 • 平台 • 外送平台 • 顧客 • 外送員 • 店家 • 平台
  13. 依照流程 - 呈現元素排列不同 • 貨運單(送件 -> 收件) • 空運 -

    ⾶機, 空港, 轉運站 • 海運 - 貨船, 海港, 海關 • 陸運 - 卡⾞, 集貨中⼼, 收貨點 • 購物 • 購物⾞ • ⼀⾴購物
  14. N 角⾊ x N 流程 =

  15. UI Mockup

  16. Client / Server Side Render !?

  17. SEO + Page Speed 兼顧 !?

  18. 突破舊思維

  19. 學會 Rails 不只是 … • 只會 MVC 架構 • 只會在

    Model 做 Validation • 只會寫⼀⼤串 ActiveRecord 的 where 條件查資料庫 • 只會⽤ view helper 簡化 view 取得資料的複雜度 • 只會拿 Form Builder 串接 ActiveRecord 或 Ransack 物件 • 只會⽤ if … else … 切割流程
  20. 至少要活⽤ … • ActiveHash / ActiveYaml / ActiveJson 當作資料物件 •

    Query Context 作為跨資料物件查詢的仲介層 • Presenter / Decorator 作為 view 的資料來源 • Form Object 作為表單驗證的把關者 • Service Object 作為串接外部服務的⿊盒⼦ • Operator / Flow Object 作為控制流程的中⼼物件
  21. 最好再加碼 ... • React.js / Vue.js • Webpack / ?

    • AMP • PWA
  22. 迎接新思維

  23. 善⽤ Route 切割業務邏輯 • Admin 和 API 都知道要切成 namespace,為何其他功能不切 namespace?

    • 除了切出 namespace,也能切成 subdomain 做到獨立。 • 既然會掛 rails engine 的 routes 到專案,為何 routes.rb 不切割成數個檔案?
  24. Rails View 層越簡潔越好 • 多點 Layout 不是壞事,仿照 AMP 只放該⾴⾯需要的 JS、CSS

    和資料 • 同個 namespace 的 partial file 不要放到其他 namespace 資料夾 • 改⽤ Presenter 為主、Decorator 為輔,少⽤ view helper • 資料要遵守 Single Source of True 原則 • 避免多層的 if … else …,儘量只⽤ if 就好 • 最後⼤概只剩 HTML + CSS classnames + methods + Loops + if 的結構
  25. Namespace 是業務邏輯⼿段 • 每個業務邏輯都要有⾃⼰的 module ( namespace ) • 流程控制邏輯

    / UI 呈現邏輯 / 資料存取邏輯 • Controller / View / Model => web page • Operator / Presenter / Query Context => page section (components) • 放 app 或 lib 資料夾 • 寫成 rails engine 放專案內,或發佈成 ruby gem
  26. Namespace 依類型區分 • app/contexts • carts/query_context.rb • orders/query_context.rb • app/forms

    • carts/update_form.rb • orders/create_form.rb • app/presenters • carts/popup_presenter.rb • orders/details_presenter.rb • app/services • payments/create_service.rb • callbacks/update_service.rb
  27. Namespace 依需求區分 I • app/learning • carts • query_context.rb •

    update_form.rb • popup_presenter.rb • app/teaching • orders • query_context.rb • create_form.rb • details_presenter.rb
  28. Namespace 依需求區分 II • app/components/learning • carts • popup_presenter.rb •

    app/objects/learning • carts • query_context.rb • update_form.rb
  29. golden-objects https://github.com/goldenio/ golden-objects

  30. React.js + Rails • 不做需要 SEO 的 web page 或

    page section 才⽤ React • 需要 SEO 的⾴⾯⽤ AMP (in rails view) • React 資料夾切割以⾴⾯為單位 • API 端點依需求 namespace 切割 (例:learning vs teaching) • Presenter -> json.jbuilder -> React component props
  31. 挑戰

  32. 程式範疇 -> 架構範疇 Namespace -> Micro service