可能是過去求學時,學的是《Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development》和《Object-Oriented Modeling and Design with UML, 2nd》書中描述的方式做物件分析與設計,從 use case 描述中抓出名詞成為 domain model,從動詞找出類別的行為和物件間的關聯,用 GRASP 原則將責任分配到合適的類別身上,但這個 domain model 離實際的 implementation model 還有段距離,畢竟還要跟使用的框架打交道。
就業後,對於 Model 這字眼總是特別小心,有趣的是,Model 其實沒什麼嚴格的定義,所以每個人對 Model 的解讀也不盡相同,有人覺得資料怎麼儲存屬於 Model 的一部份 (受 ORM 工具的影響),有人覺得工作流程 (workflow) 是 Model 的一部份,我個人也有自己的想法,而且隨專案的規模和特性,也不是總是一樣的。
若看 Wikipedia 對 Multitier architecture 的描述,會發現常見的架構分成四層,每一層的責任似乎明確卻又有一點模糊,而我自己的見解是:
雖然這樣看起來,四層很明確啊!但實際在寫程式時,還是會有一些模糊的空間,有時候還是要思考這一段程式應該放在哪一層,特別是 application layer 和 business layer 之間更是如此;因此,也可以說,每個人對於 Model 到底是包含 application layer 還是 business layer 的哪些部分看法不太一致,對我來說,二者都是 Model,但若分成四層,二者不會是同一個物件。
程式的結構 (以目錄或其他方式呈現) 上,有時也不容易看出結構與分層的對應關係。有時候,強制分成四層也會讓程式架構變複雜,所以我在桌面應用程式或 Mobile App 中,我可能選擇讓 application layer 與 business layer 合併,簡化成三層,或是讓 application layer 非常的薄。
在 Web 應用中,原則上還是分成四層,但個人偏好 client-rendering,因此 presentation layer 通常在 client,不過,為了方便測試,有時候 Web server 端還是會有負責提供 presentation model 的 presentation layer。例如用 Spring 框架來撰寫,application layer 的程式有時會散在 filter (身份認證或權限控管)、interceptor (稽核) 和 request controller (直接當成 system event controller) 中,但原則上 request controller 的程式大多很短,主要邏輯還是在 business layer 裡。
或許,事情不用這麼複雜,在設計每個 class 時或是想將功能加到一個 class 時,用 single responsibility 的原則來思考,適合放在這個 class 嗎?若不合適,應該放在哪裡呢?這時候參考軟體的架構思考應該放在哪一層。在層與層之間的 dependency 該如何管理或注入時,多想想 interface segregation 原則,不要直接依賴實作,甚至可以想一下 dependency inversion 原則,降低上層程式與下層程式的依賴,盡可能讓每一層都能維持獨立,此時,要進行測試就容易多了。
總結來說,對 Model 的解讀可以各自不同,沒什麼標準答案,但不論用什麼方式解讀,只要能讓程式易讀好維護,就是好的設計。