前言
上一章中,我們介紹了Presenter的概念,View是HUMBLE OBJECT(謙卑物件)模式的一種形式,它能幫助我們辨識和保護架構的邊界,事實上,上一章中充滿了HUMBLE OBJECT的實作。
HUMBLE OBJECT模式
HUMBLE OBJECT模式是一種設計模式,最初是用來協助單元測試人員將難以測試與容易測試的行為做分離,例如,GUI是難以被測試的,但GUI所呈現的資料與行為大多容易測試,所以我們將這兩種行為分為兩種不同的類別,分別稱之為Presenter與View。
備註: 換個方式說,要測試到Presenter要做整合測試,但要做到View的測試,就是E2E測試了,當然整合測試比起E2E更簡單些。
Presenter及View
Humble Object是指那些難以被測試的元件,所以View是一個Humble Object,其程式碼應盡可能地保持簡單,它將資料移到GUI但不處理資料。
Presenter是可測試的物件,它的工作是接受來自應用程式的資料,並將其格式化以便View可以簡單將之移動到螢幕上。用一個例子來說明,你有一個財務系統,當人的資產總額是負的時候,在該人名上面標示紅色做HL,此時,Presenter會在View Model中設置好人名、資產總額、是否HL等標示,View則是根據View Model的內容作GUI上面的呈現即可,由於View除了將View Model的資料載入到螢幕上之外,它沒做任何事情了,所以View是謙卑的(Humble)。
測試和架構
現在你知道可測試性是良好架構的一個屬性,HUMBLE OBJECT就是一個很好的案例,將行為分為可測試與不可測試的兩個部分,其實也就定義了一個架構的邊界,Present/View邊界就是這樣的邊界之一,但還有許多其他的邊界。
資料庫閘道
Interactor和資料庫之間的是資料庫閘道,這些閘道是多型介面,包含新(C)增、查詢(R)、修改(U)、刪除(D)等操作的方法。我們也不允許SQL出現在Interactor層,閘道是由資料庫層的類別來實作的,這些實作是一個humble object,相反地,因為Interactor封裝了業務規則,所以它們並不是humble object,因此是可測試的,而閘道可以用適當的替身樁(stub)和test-double(Mock Object也是其中一種)來取代。
備註: 上一章中DataAccess物件就是阿宏為了Demo隨意寫的Mock Object,它並沒有連接資料庫,但還是可以提供一些資料讓Interactor被測試。
資料映射器(ORM)
大家覺得ORM應該是哪一層呢?
ORM(Object-Relational Mapping)應該是不存在的,物件裡面某些資料是不可見的,能見的只有那些設定公有(public)的屬性或函式,對用戶來說,物件是一些操作的集合,並非簡單的數據集合,所以物件不是數據集合。
但數據集合恰恰相反,它沒有隱藏任何東西,,所以ORM命名為資料映射器(data mappers)會更洽當些,因為他的職責就是從RDB table中將資料載到數據集中。
所以ORM應該放在哪層呢? 當然是放在資料庫層,ORM其實就是在閘道介面(Gateways)與資料庫(DB)之間建構了另一種HUMBLE OBJECT的邊界。
服務監聽器
如果你的程式必須與其他服務通訊,或者你的程式本身就提供了服務,那在相關服務的邊界也會看到HUMBLE OBJECT嗎?
答案是肯定的,輸出的部分,當你的程式將資料載入簡單的資料結構中,並將之跨越邊界傳遞給那些可以「格式化並傳遞至外部環境」的模組;輸入的部分,服務監聽器會負責從port拿取資料,並將其格式化成可以讓程式使用的形式。
整理: 服務監聽器是一個HUMBLE OBJECT的邊界,如同大部分框架的controller,在Unittest中你不會去測試controller是不是正常,而是只會測試use cases層拋出的資料結構是不是符合商業邏輯與API協議。
總結
架構中的每個邊界中,你會處處發現潛伏在某處的HUMBLE OBJECT,跨越邊界的通訊幾乎透過傳遞某種簡單的資料結構(格式)來達成,這些邊界很自然的將系統分成容易測試與難以測試的部分,因此,在邊界處運用HUMBLE OBJECT模式,可以大大提升系統的可測試性。
整理: 還記得嗎? 良好架構其中一個衡量的標準就是可測試性,因此,在邊界定義好HUMBLE OBJECT,會讓你的架構更上一層樓!