[經驗談] 無招勝有招

Design Patterns 或 MVC 都是用來解決架構與設計上的相關問題,它給你的是方向,但真正實作出來的,其實並不是一定要 "依樣畫葫蘆",只要在設計上有滿足 Design Patterns 或 MVC 的精神:職責分明,並且能解決你要解決的問題領域,就夠了。當你學習夠多的時候,自然而然就會有想法,而且自然會植基於 Patterns 之上來思考。Design Patterns 或 MVC 其實只是教你該如何去思考,是概念上的作法,但實作要靠自己實踐,打出一套能夠滿足 Design Patterns 的精神,並能完成問題解決的拳法,才是王道。

其實我是想回應這篇:https://www.ptt.cc/bbs/Soft_Job/M.1427724167.A.916.html,被 cue 的時候我人在日本,沒辦法直接回應,今天有點時間,就來回應這個 cue 吧。

現在網路上到處都是 Framework,也到處都在強調 Design Patterns 的重要性,是的,Design Patterns 很重要,Frameworks 也很重要,學習 Design Patterns 是為了要解決特定的設計問題 (例如策略樣式),學習 Framework 是為了要在一個既有的框架架構下開發出自己需要的東西,不過可能有些人會覺得有點弔詭的是,為什麼 Design Patterns 有些很像,Frameworks 也是一樣,似乎應有的功能都是各自表述,像是 Spring Framework 本身就有實作 MVC,Ruby on Rails 也有 MVC;Hibernate 則是 ORM,但 Entity Framework 也是 ORM,大家都很像,選擇也很多,每一個 Framework 都有其背景與設計目的,因此當看到一些固定的規則時,根本就不需要覺得奇怪。

以 ASP.NET MVC 來說好了,為什麼它會有 Controllers, Views 和 Models 資料夾,其實它只是想要貫徹習慣取代配置 (Convention over Configuration) 的精神而已,在 .NET 的世界,當在一個專案內存在資料夾時,其內部的程式碼的命名空間會自動由資料夾來產生階層,例如 MVC1 專案內有 Controllers 資料夾時,裡面新增的程式碼就會自動使用 MVC1.Controllers 命名空間,同樣的,Views 資料夾內會存放所有的 View,而 ASP.NET MVC 也會自動在 Controller 新增 View 時,在 Views 資料夾內產生相應的 Controller 資料夾以及以 Action 為命名的 View 檔案,日後當接手的維護人員只要了解 MVC 的習慣,就能快速的理解整個專案的配置,減少摸索的時間。

但是,初學者很容易中了這些 Framework 的招,就是 "我一定要這樣做才行"。

其實沒有這種事,習慣取代配置是為了要解決團隊專案中交互開發時的溝通問題,當團隊所有成員都使用相同的語言溝通時,錯誤率自然會下降很多,當一個專案變大,或是需要導入像 DDD (Domain Driven Design) 的設計架構時,團隊可以自由將 Models 資料夾的內容移到其他的專案去,例如另外新增 Domains 或是 Repository 專案,將必要的 Model 與資料存取功能移置到那裡,再於 MVC 專案加入參考就行了,並沒有實質的硬性規範說一定要怎樣怎樣才算。

由這個部份,其實可以再衍生出一些議題,例如要怎樣怎樣才算是 MVC。

image

照這張圖來看,MVC 不過就是由 Controller 去拉 Model 出來,再用 Model 更新 View 來讓 User 看結果,如此簡單不過的事情為什麼會有人去解讀出 MVC 是一個巨大誤會 ... 或許有人說我這樣解讀太過武斷,那咱們來看看 1979 年的定義好了 (Trygve Reenskaug 的定義):

image

Model 的用意其實很簡單,就是為了要去定義出問題的可識別部份 (Identifiable Part),例如 POS 系統內要定義出產品,客戶,銷售等資料,這些資料都會是 Model 的一部份,而這些資料會由各種地方來,可能是資料庫也有可能是外部服務,所以現代的 MVC 應用程式會用一個 Repository Pattern 去切割 Provider 和 Model 的相依性。

image

View 的用意只是視覺化後的 Model,也就是 Model 的資料要如何呈現,大多數的 MVC Framework 通常會由 Controller 來擷取 Model,再交給 View 來負責呈現,這樣的動作也再簡單不過了。但這裡會有個爭議點,這裡的 View 定義提到它可能會以送出適當訊息的方式來更新 Model,這句話在當時 1979 年的時空是很平常的,但到了 Web 時代,這樣做會很奇怪,但 Web 上已經提出了 MVVM (Model-View-ViewModel) 的解法來解決這個問題,所以在 MVVM 架構下,View 有能力回應更新給 Model

image

Controller 的角色也是十分單純,作為使用者和系統之間的連結,處理使用者的輸入並選擇適當的 View 來輸出,這裡並沒有看到 Model 的影子,是因為前面已經把 View 和 Model 給綁在一起,但拉資料的責任在 View,而現代的 Web MVC,拉資料的責任會回到 Controller,這就是 Model 2 的架構。因為在 HTTP 的協定限制下,View 無法像在 Local 端一樣可以連接到 Model (後期才有 AJAX,但 AJAX 也無法直接連到 Model,中間還是會有一個 API),所以才將職責轉移給 Controller 來處理,變成現在大家看到的 Web MVC 的實作基礎。

所以我覺得 MVC 根本沒有什麼誤會,只是時代的改變,讓它適應時代環境而有的些許變化罷了。

(這裡也有很棒的解釋:http://www.ithome.com.tw/node/77330)

另一個有趣的議題是,框架不應該有「models」資料夾

如同我前面所提的,Model 資料夾只是個習慣取代配置的結構而已,Model 本來就沒有任何限制,只要是問題的可識別部份都能變成 Model,各家 MVC Framework 好像也沒說 Model 一定要擺在 Models 資料夾吧,或許是因為教學的因素,Model 通常會放在 Models 資料夾,而不明究理的初學者,就順理成章的在以後的專案都把 Model 放到 Models 資料夾了。但是只要寫多了 MVC 專案的人,應該就會知道 Model 其實並沒有限制要擺在哪,完全是依專案和系統,以及團隊的規範來定義的,一個大型專案的 Model 可以移到單一程式庫,或是由多個程式庫共同組成 Model,都可以,並沒有任何硬性規定。所以我不知道在質疑 Model 資料夾是在質疑什麼 ... 我也是第一次看到 "Model 資料夾會影響 Scalability" 的說法,或許他的 Scalability 和我們的定義不同吧 (笑),Scalability 也可以利用 Refactor 來解決。

但是 Model != Database 是肯定的,Model 也不應該只是指單一資料 (除非你的應用程式就只有那麼一種資料),Model 應該是應用程式所需要用來解決問題的各種資料,而且資料來源可能不只是 Database,還有可能是來自 FB 或是 File System。

Design Patterns 或 MVC 都是用來解決架構與設計上的相關問題,它給你的是方向,但真正實作出來的,其實並不是一定要 "依樣畫葫蘆",只要在設計上有滿足 Design Patterns 或 MVC 的精神:職責分明,並且能解決你要解決的問題領域,就夠了。當你學習夠多的時候,自然而然就會有想法,而且自然會植基於 Patterns 之上來思考。Design Patterns 或 MVC 其實只是教你該如何去思考,是概念上的作法,但實作要靠自己實踐,打出一套能夠滿足 Design Patterns 的精神,並能完成問題解決的拳法,才是王道。

無招勝有招,才是學習 Design Patterns 和 MVC 等軟體架構的最高境界。