釐清脈絡 - 重新思考 Rails 架構
我們繼續用「物流系統」作為案例,來探討將軟體架構設計完善時所需的前置準備,也就是去了解整個系統的脈絡(Context)或者說學習該領域(Domain)的知識。
這個過程大多還未進入到開發階段,因此不論語言、框架都是通用的,甚至可以說是否要使用某個語言或者框架,可能要再確認後才決定更加適合。
從案例學習
不論是設計文件(Design Document)或者產品需求文件(Product Requirement Document)如果只描述功能、規格層面的問題,對所有閱讀文件的人來說都是非常大的心理負擔,對新成員、初次接觸的領域來說,都會變得容易出錯。
舉例來說,在物流系統中有對於時區的特殊需求,以規格來描述會像這樣
當從站點出發時時,在 ATD 欄位以
MMdd
格式紀錄出發時間。抵達目標站點時,在 ATA 欄位以MMdd
格式紀錄抵達時間,所有時間皆以當地時間表示。
以一份規格來說,已經算是相當清楚的資訊,將要填寫的數值、格式、換算等資訊都有描述出來,然而對於開發團隊仍要花時間理解完整的運作。
如果以案例的方式描述,那麼會像這樣
假設有一筆運送紀錄單號 O-1234 當從桃園(TPE)出發,在 ATD 欄位以當地時間(UTC+8)
1600
填入。 當抵達沖繩(OKA)時,在 ATA 欄位以當地時間(UTC+9)1830
填入。
上述的案例看起來就會比規格容易理解很多,同時也會發現「規格」跟「案例」一定程度是互補的,我們可以從多個案例中推導出一個可能的規格,而案例也可以幫助對於規格的理解更加清楚。
除此之外,這些案例的撰寫方式實際上也很將近使用者故事(User Story)的描述方式,通常也會是描述使用者需求的一種呈現。
客戶下了一筆運送訂單 O-1234 從桃園(TPE)出發 當機場人員確認出發後,在 ATD 欄位以當地時間(UTC+8)
1600
填入後送處 那麼在報表上可以看到 O-1234 的 ATD 呈現16:00
客戶下了一筆運送訂單 O-1234 從桃園(TPE)出發 當機場人員確認抵達後,在 ATA 欄位以當地時間(UTC+9)
1830
填入後送出 那麼在報表上可以看到 O-1234 的 ATA 呈現18:30
出發跟抵達可能是兩個不同的流程(不一樣的步驟)因此我們會將使用者故事拆成兩件事情獨立描述,而且正好涵蓋了我們對於規格的理解。
這類型的案例就很適合用 Cucumber 撰寫文件進行測試
分類脈絡
正常狀況下,我們會不斷蒐集到各種需求、規格上的描述,然而如果只作為「單一系統」來看待,就可能把各種行為混合在一起處理,因此需要將脈絡釐清。
舉例來說,空運、海運等等都會是集中運輸的方式進行,也就是說我們除了透過案例了解系統時,也會發現一些預期外的資訊。
以大多數人的生活經驗來看,寄送包裹會是一個訂單加上貨品的組合。
1class Order < ApplicationRecord
2 # 一筆訂單可以同時運送多個貨品
3 has_many :products
4end
5
6class Product < ApplicationRecord
7 belongs_to :order
8end
然而,在空運或者海運的狀況下,運送的規模不會是一台車子,而是一整個貨櫃,因此還需要知道這些被寄送的商品被怎樣組合到其他運送單位上。
1class Shippment < ApplicationRecord
2 # 一個運輸單位有多個「貨櫃」
3 has_many :containers
4end
5
6class Container < ApplicationRecord
7 # 每個貨櫃以「棧版」為單位集裝
8 has_many :pallets
9 belongs_to :container
10end
11
12class Pallet < ApplicationRecord
13 # 商品被打散到不同棧版上
14 has_many :products
15end
加入了運送資訊後,是否開始覺得整個系統變得複雜,如果要再加入不同類型的運輸單位(如:貨車可能是單一貨櫃或者棧版)我們可能還要做更多的處理。
同時,你可能還會發現 Order
和 Pallet
同時都管理 Product
那麼其中一邊的物件做了修改後,是否會影響到另一邊的資料正確性,都會需要考量進去。
根據需求不同,會有不一樣的分類方式。在這個情境來看,我會選則分成三個不同的情境。
- 訂單(Order)
- 運送(Shipment)
- 集裝(Container)
判斷的依據通常會根據使用者故事的描述可以找到線索,通常有對應的操作就表示我們會有類似的分組出現,至少在「運送」這件事情上我們可以從文章一開始的案例看出來。
那麼,訂單跟分配貨品,就有蠻高的機率是兩件不同的事情。
印象中當時「集裝」是被設計在運送的畫面上,不過那個畫面非常複雜,實際操作設定哪些貨櫃被送出去應該是可以在另外的畫面被處理的。
如果對這篇文章有興趣,可以透過以下連結繼續閱讀這系列的其他文章。
- 軟體架構的挑戰 - 重新思考 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 架構