蒼時弦也
蒼時弦也
資深軟體工程師
發表於

複雜的操作 - 重新思考 Rails 架構

這篇文章是 重新思考 Rails 架構 系列的一部分。

現代大部分的軟體都會考慮到使用者體驗(User Experience)因此都會盡量設計成簡單易懂的操作,然而仍有一些例外的狀況,像是有高度專業需求的系統,或者一些傳統產業長久以來的習慣,當時客戶就屬於這一類型。

難以使用

當我們得知畫面上必須一次性的處理四到五種資訊時,就明顯的感受到操作是非常困難的。這是因為在舊系統中,客戶會在同一個畫面中處理出發、抵達時間、運送的貨物等等資訊。

正常狀況下,我們可能會很直覺的拆分成數個小步驟來進行處理,這樣每一個步驟就會變得相對簡單使用起來也會比較容易,然而就當時的狀況而言,因為每個站點的業務量基本上是相當龐大的,比起簡單花時間的操作,能夠一次性完成處理更加適合。

也因此,這就造成了在一個動作中我們需要有大量的檢查確認使用者的行為,裡面還需要根據使用者當地的時區做出不同的呈現,讓整個行為變得非常複雜。

Form Object

在 Rails 中,只靠 Controller 以及 Model 上的一些驗證機制,是很難解決這樣的問題,因此 Form Object 這一個技巧很常會被 Rails 的開發團隊使用。

比較常見的應用案例,通常會是一些資料上的檢查在不同情境下無法適用。

 1class CreditCard < ApplicationRecord
 2  validate :sufficient_balance
 3
 4  private
 5
 6  def sufficient_balance
 7    return if balance.positive?
 8
 9    errors.add(:balance, :insufficient_balance)
10  end
11end

以上面的「餘額」情境,假設我們要增加一個「預借」功能時,這個檢查就會在另一個功能造成問題,因此會用兩個不同的 Form Object 處理。

1class PayWithCashForm < ApplicationForm
2  validate :sufficient_balance
3
4  # ...
5end
6
7class PayWithCreditForm < ApplicationForm
8  # no balance check
9end

這個情境也適用於上述的複雜表單,因為同樣的資料在不同畫面的檢驗條件可能是不一樣的(如:角色不同)使用 Form Object 就能很好的做出區分。

自動化

設計一個系統應該是要有更多的「自動化」在大部分的時候只需要提供足夠的資訊,系統就能夠完成適當的判斷並把事情做完。

也因此,雖然上述的情境我們可以用 Form Object 把使用者輸入的檢查自動化,最後還是仰賴使用者完成大部分的資料輸入,假設驗證發生錯誤時,提示訊息不完整還是會卡住使用者。

因此,延伸上一篇提到的「脈絡」概念,在這階段的設計上,我們也沒有去考慮到整個系統的運作流程,因此錯失了許多可以改善、簡化的地方,也讓「檢查」這件事情變得複雜。

舉例來說,在 Rails 中提供了一種 accepts_nested_attributes_for 的機制,可以讓我們針對多層 Model 同時賦予數值,然而不少文章都不推薦使用。更恰當的方式,應該是在操作的對象身上,提供一些方法根據設計好的行為修改這些相關的物件。

這樣一來,一部分的「驗證」也就不需要再去處理,因為這些檢查是根據行為判斷是否能被執行,另一方面根據這些可用的行為,我們也能設計更多輔助使用者處理的機制,來讓工作更輕鬆,而不是用複雜的表單畫面操作以及以輸入的資料做檢查。