Controller - 重新思考 Rails 架構
有了第一個 Cucumber 撰寫的測試後,我們對於更新運送狀態的行為有一定的概念,那麼就可以針對這個機制來進行 Controller 的實作。
路由
首先,要讓 POST /shipments/:id/routes
這個端點可以被存取,因此需要在 Rails 的路由設定中加入以下的內容。
1Rails.application.routes.draw do
2 # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
3
4 # Defines the root path route ("/")
5 # root "articles#index"
6 resources :shipments, module: :shipments do
7 resources :routes, only: [:create]
8 end
9end
這樣一來 Rails 就會知道要使用哪個 Controller 來處理,這是大多數開發者很直覺能實踐的事情,然而在 Clean Architecture 的角度分析,這是一個低階元件,也就是描述細節的資訊。
因此會被分類在最外圈 Framework & Drivers 這一階段,這類型的物件通常會跟環境有很深的連結,因此當我們要改為使用 gRPC 之類的方式互動時,這些實作就無法繼續使用,就 Rails 的角色,就只能針對 Web(HTTP 協定)的情境。
控制器
Controller 想必也不需要特別討論,在這個階段我們要先讓 Cucumber 的測試通過,因此可以直接將輸出寫死。
1module Shipments
2 class RoutesController < ApplicationController
3 def create
4 render json: {
5 id: 1,
6 state: 'shipping',
7 routes: [
8 {
9 route_id: 'OKA',
10 shipment_id: 1,
11 delivered_at: Time.utc(2024, 3, 19, 0, 0, 0)
12 },
13 {
14 route_id: 'TPE',
15 shipment_id: 1,
16 delivered_at: Time.utc(2024, 3, 19, 2, 0, 0)
17 }
18 ]
19 }
20 end
21 end
22end
在應用到 Clean Architecture 時,可能就會有一些爭議出現。因為我們以往的經驗,會把處理的行為設計在 Controller 中,那麼這樣算是一種 Use Case(使用案例)的類型嗎?
然而,在 Clean Architecture 由外向內的第二圈舉例中有 Controller 並且歸類為 Interface Adapter(介面轉接器)的類型,這是否表示我們不該在 Controller 中有實際的商業邏輯呢?
反思
意識到這個問題後我做了不少思考,大致上來說這件事情並沒有一個絕對正確的答案,或者說他是一個系統發展過程中的一個階段。
在 Clean Architecture 中並沒有限制切分的層級數,書中以四層為例子確實是大部分情境都通用的情況,那麼 Rails 採用的 Model View Controller(MVC)設計,我認為可以看作是只有兩層的情況,也就是指具備 Framework & Drivers 和 Interface Adapter 的情境。
從另一個角度來看,當下的 Interface Adapter 因為跟實際的 Use Case 處理的內容非常一致,因此也沒有特別要做 Adapt(適應) 的必要,只需要直接使用即可。
然而,從職責的角度來看,隨著在 Controller 中實作的邏輯增長,會開始出現需要拆分職責的情況,剛開始可能會用 Fat Model 的模式來做,然而不論怎樣處理最後還是會有職責過多的狀況,進而需要切分出新的物件類型,而 Service Object 這類 Rails 常見的物件也因此而生。
直到這個階段,才開始出現更向內的第三、第四層級,也才開始有明確的 Use Case 和 Entity(實體)的劃分跟界定。
如果對這篇文章有興趣,可以透過以下連結繼續閱讀這系列的其他文章。
- 軟體架構的挑戰 - 重新思考 Rails 架構
- 資料驅動設計 - 重新思考 Rails 架構
- 複雜的操作 - 重新思考 Rails 架構
- 時區換算 - 重新思考 Rails 架構
- 報表機制 - 重新思考 Rails 架構
- 通用化功能 - 重新思考 Rails 架構
- ActiveRecord 的限制 - 重新思考 Rails 架構
- 領域驅動設計 - 重新思考 Rails 架構
- 從架構到設計 - 重新思考 Rails 架構
- 重復使用的反思 - 重新思考 Rails 架構
- 釐清脈絡 - 重新思考 Rails 架構
- 劃分邊界 - 重新思考 Rails 架構
- 職責劃分 - 重新思考 Rails 架構
- 架構規劃 - 重新思考 Rails 架構
- 驗收測試 - 重新思考 Rails 架構
- Controller - 重新思考 Rails 架構
- Form - 重新思考 Rails 架構
- Use Case - 重新思考 Rails 架構
- Entity - 重新思考 Rails 架構
- Repository - 重新思考 Rails 架構
- Output - 重新思考 Rails 架構
- Query - 重新思考 Rails 架構
- 可能性 - 重新思考 Rails 架構