知道嗎?MVC的定義就已經夠令開發者頭痛了,竟然還有MTV、MVP、MVVM……,令開發者揣摩半天,然後爭吵不休。創造更多新名詞,除了引發好奇、吸引開發者目光之外,這些名詞,真的有實質的溝通意義嗎?想表達什麼?採用MV*架構或框架時,該思考的是什麼?

事情總是這樣,開發者好不容易吵完了某個名詞,不久就又冒出新名詞,要命的是,新舊名詞之間概念很像,卻又有那麼點關鍵性的不同?老一輩的程式人,稍微搞懂了差別,新入門的程式人,才正要進入伸手不見五指的五里霧中。

新的名詞可以吵,舊的名詞也可以吵,老實說,引發爭吵也是創造名詞的目的之一,特別是那些還可以縮寫成幾個字母的名詞,我相信,吵得越兇,有人越高興,畢竟這是免費的好行銷,不用可惜!

如果我兩年前寫好〈MVC與Model 2的變異與結合〉的整理之後,就可以翹腳樂看MVC的演變就好了,不過,總是會冒出一些名詞,說它們跟MVC確實不一樣,像是Classic MVC、Web MVC,還有什麼主動MVC、被動MVC之類的……,等一下!那個被動MVC,該不會就是在說Model 2吧?都是Model-View-Controller嘛!

有次突然看到MTV,是Music Television縮寫?不!這出現在Python的Web框架Django,代表Model-Template-View,MVC少了Controller多了Template。

乍看有點新鮮感,細看之下,原來是Django框架認為,Controller的職責都被框架完成了,開發者實際上在views.py中撰寫的Python程式碼,都只是在準備畫面呈現時必要的資料,然後轉發Template頁面處理。但在我看來,這本質上還是Web MVC,只不過Controller這層很薄弱。對不起!我還是得用個Web MVC名詞,以便表示我在講哪種MVC。

就這麼安穩地過了幾年,又冒出MVP、MVVM、MVW了。我想,大概又是那些玩意兒吧!沒特別理它們,直到有次在網路上看人吵架時,突然雙方就開始吵起MVP、MVVM了,呃……,因為我在〈技術名詞紛爭多〉中說過,名詞是用來溝通用的,為了看懂他們在演什麼戲碼,還是認真瞭解好了。

箭頭方向不一樣,對吧?

MVP代表Model-View-Presenter,MVVM代表Model-View-ViewModel,跟MVC都有Model與View,不過Controller換成Presenter與ViewModel。

在MVP中,Presenter會接受View的命令,對Model進行操作,Model會通知Presenter取得狀態變更,然後再由Presenter去更新View;而MVVM的話,View的變化會直接影響ViewModel,而ViewModel的變化也會反映在View上,ViewModel必要時會處理Model,而Model的變化會通知ViewModel……,對於手邊可查到的文件,文字描述上大多就是這麼寫的,看得霧煞煞。

一圖解千文,還是看圖解吧!畢竟還是與MVC有關。第一眼可看出最大差別是,MVP與MVVM的View與Model之間沒有箭頭,而MVC有,這表示前兩者的View與Model不知道彼此存在;第二個差別是,MVP、MVVM的Presenter或ViewModel,與Model間的箭頭是雙向的,而MVC中是Controller至Model的單向關係。到網路上搜尋MVC、MVP、MVVM的文件,看到的圖示也許箭頭畫法不同,但箭頭方向八九不離十。

單看這些描述與圖解,不少人一定也是模模糊糊,會想找程式碼或支援的框架來看看,但這不會有多少幫助,一般也不建議從程式碼來理解這類架構名詞,從程式碼上多半也只能看到箭頭方向怎麼實現,像是註冊、事件、通知,有些框架還用神奇的魔法將這些隱藏起來,開發者只加上約定好的掛勾(hook)就好,因此看不到實質的物件如何互動。

為何箭頭方向不同?好處是?解耦合、可測試性、分離View與Model……,MVC不也是這麼說?

此外,我想要有份像〈NotRxJava guide for lazy folks〉的文件,能告訴我非同步需求所為何來,因而產生了RxJava框架,我想要知道,是何種需求驅動了MVP、MVVM架構的產生,而不是告訴我最後箭頭方向,彼此之間是不一樣的結果。

Separation of concerns

在維基百科〈Model View Presenter〉條目,提到「分離關注點(Separation of concerns)」概念。想想,MVC最初是為了解決視窗程式中,程式碼全夾雜在一起而產生,但實際上,不少視窗框架的View與Controller是合併的,反映出View與Controller通常是一對一,因此重點在Model的分離,讓「同一個Model可以有多種的呈現方式」,到了Web時代,請求的處理更複雜了,將Controller分離出來變得重要,Model、View、Controller的職責切割更為清楚,各自關注在不同的邏輯處理。

前端技術的興起,使得MVC的職責分配,也從伺服器移轉到瀏覽器,前端也有一些支援MVC的框架,實際上這類框架中Controller,如同過去視窗程式一樣,並非一定與View分離,然而,前端對頁面操控靈活度的要求越來越高,因此MVC中,被Model通知狀態有異的View,在提取Model狀態後更新畫面的這個職責,越來越厚重,因此,將「指導頁面如何呈現」的關注點分離出來,由於轉發請求的Controller職責變少,指揮頁面如何呈現的職責變多了,因此被改稱為Presenter。

實際上,這樣的關注點分離,跟Martin Fowler在2006年提過的〈Passive View〉(http://goo.gl/fp0smD)極為類似。Martin Fowler提到,Passive View模式可將UI元件的行為減到最少,令測試集中在Controller(相當於MVP的Presenter)而不是View,因而可避免直接對View測試的問題。

至於MVVM,可視為MVP下更特定的一個模式,一個ViewModel就像是更專用的Presenter,這個Presenter針對某個特定的View,之所以稱為ViewModel,是因為View上某個UI狀態,就對應於ViewModel某個狀態,其中一方變化,另一方必然跟著變化,在這樣的情況下,開發者只要關注「ViewModel的狀態變更」,指導頁面呈現的部份,可以設計通用或直接採用現成的框架來完成。

採用MV-Whatever

瞭解MVC、MVP、MVVM的過程中,我看過更多名詞,像Application Model MVC、ASP.NET MVC、Web MVP等,1996年左右也出現MVP(http://goo.gl/QdZ01L),這麼多名詞實在令人厭煩,更別說分清楚,最後,我最懂的只有MVW了!

MVW是什麼?AngularJS自稱是MVW框架,也就是Model-View-Whatever,Igor Minar在2012年解釋過為什麼AngularJS是MVW框架(https://goo.gl/Gs3D7l)──Whatever是指開發者對哪個名詞爽,就用哪個(whatever works for you),Igor Minar認為將框架加以分類有好處,開發者在使用框架或API時會比較清楚正在建立的概念,也有助於開發者建立共同的詞彙;但他也認為,與其將時間浪費在MV*的爭論上,更重要的,是在建立應用程式時有良好設計,以及隨時保持Separation of concerns。

確實如此,那麼多MV*的文件,都集中在職責分配、優缺點分析、流程走向的探討,還有一堆圖片試圖清楚畫分彼此不同,卻沒看到Separation of concerns的討論,無怪許多開發者更加迷惑,也終於能理解,為什麼上次看著人們拿著一堆圖吵來吵去,我看了老半天,卻覺得只有箭頭畫法與方向不同。

不管開發者打算採用哪種MV*架構或者框架,重要的是知道應用程式的需求在哪,是否能說出這類架構或框架,能帶來什麼樣的Separation of concerns,以及團隊中哪些人或是否有人,能來擔任相關職責的實現,而不是爭論這個元件應畫分到哪個名詞之下。若能如此,那麼架構或框架是MV*,對開發者來說,就真的是MV-Whatever了!

作者簡介


Advertisement

更多 iThome相關內容