[爆卦]MVC Model 資料庫是什麼?優點缺點精華區懶人包

為什麼這篇MVC Model 資料庫鄉民發文收入到精華區:因為在MVC Model 資料庫這個討論話題中,有許多相關的文章在討論,這篇最有參考價值!作者poopoo888888 (阿川)看板Soft_Job標題[心得] 框架不應該有「MODELS」...


HI! 小弟最近對web back-end MVC框架有些想法

跟各位分享一下

<( _ _ )>

網頁好讀版

框架不應該有「MODELS」資料夾

http://blog.turn.tw/?p=1541

--------------------------------------------

各大back-end framework幾乎都採用了「MVC」架構。

它們至少會有「views」、「 controllers」、「 models」三個資料夾。

「views」跟「controllers」沒太大問題,但是「models」資料夾根本不該存在。

我要對這些框架提出嚴厲指控:

「models」資料夾的存在是一種錯誤的架構設計。它不但阻礙新手學習,還會傷害

scalability。

任何back-end framework都不應該有「models」資料夾。

我會在這篇文章解釋理由,並且提出改善架構設計的幾個方向。

哪些框架有「models」資料夾?

光是我接觸過的Ruby、PHP框架,就至少有:

Rails(Ruby)
CodeIgniter(PHP)
Yii(PHP)


除此之外,像是Java, Python還是什麼語言,

一定也有框架做這種事:放一個「models」資料夾在那邊。

這真是大錯特錯。

你到底要放什麼東西到「models」資料夾裡面?你覺得Model是什麼?

Model是什麼?

撇開我之前提到的MVC正名爭議不談,光是MVC的M該如何解釋就已經是個大哉問。

看看這則出色的Stack Overflow問答:

How should a model be structured in MVC?

Model是layer、它包羅萬象、它涵蓋你全部的business logic。

眾說紛紜中,這是我們唯一能有的共識。

Model難以定義、沒有絕對正確的架構設計。聽起來真令人洩氣,對吧?

不!這樣很好!這樣才對!軟體架構本來就是大哉問,有無限種可能的方法,

這也是我們所有人應該要一起討論和嘗試的地方。

而「models」資料夾卻嚴重妨礙我們討論、阻止我們思考,

它不但阻礙新手學習,還會傷害scalability。

「models」資料夾如何阻礙新手學習?

說明這段之前,我先定義一個名詞:「entity」。

我將entity定義成「代表現實生活中的一種事物」。

以常見的Active Record pattern來說,


// user.rb
// Rails
class User < ActiveRecord::Base


// user.php
// Laravel
class User extends Eloquent


// post.php
// Yii
class Post extends CActiveRecord
類似這樣的東西,你一定看過。

user.rb、user.php、post.php,這些就是我所謂的「entity」。

也就是這些「entity」,讓新手容易誤以為「entity」就是MVC裡面的M。

錯!M是layer,entity只是M裡面的組成元素之一而已。

「models」資料夾的存在本身,會讓新手以為「弄幾個entity類別丟進去就搞定架構了」


然後entity的行為、對entity做出的行為、關乎兩個以上entity的行為,

管他什麼logic,管他什麼行為,全部想辦法塞進entity類別。

下場通常就是:那些entity類別最後變得超肥胖、難以理解、動輒達到上千行程式碼。

我稱之為「胖胖entity」。

「models」資料夾帶給新手「model == entity」錯覺!

「models」資料夾誘惑新手去做出一堆胖胖entity!

「models」資料夾如何傷害scalability?

看看Rails社群這篇出名的文章:

7 Patterns to Refactor Fat ActiveRecord Models

幹得好!它點出「胖胖entity」的問題,並給出7個patterns去協助你設計軟體架構。

抽出行為邏輯變成Service Objects、抽出表單驗證邏輯變成Form Objects、抽出資料庫

查詢邏輯變成Query Objects、抽出呈現邏輯變成View Objects…聽起來真棒,也確實很

有幫助,不是嗎?

問題來了:抽出來的這些類別,到底要放哪裡?

我們看看文章下面comments提到的範例:GItLab

它的檔案結構如下:


/lib
/gitlab
/tasks
/...
/app
/assets
/controllers
/finders
/helpers
/mailers
/models
/services
/uploaders
/views
/workers

新的問題來了:那個「models」資料夾到底代表什麼?它是我們包羅萬象的偉大Model

layer嗎?那finders、services、uploaders為什麼跟models在同一層,而不是在models

裡面?lib/底下的gitlab/又是怎麼回事?難道GitLab的商業邏輯也出現在lib?

這就是我想說的:「models」資料夾的存在從一開始就污染了架構設計。

它引誘人們把entity全丟進去。結果除了entity以外的東西,像是前面的Service

Objects、 Form Objects、Query Objects、View Objects,還有後面的finders、

services、uploaders、gitlab全都不知道放哪了。只好隨便亂放。

GItLab原始碼中的models有代表MVC的M嗎?怎麼不改名叫entities?

就算改了又如何?Model layer到底在哪裡?四分五裂、結構鬆散。

一團混亂的設計、難以理解的命名、與MVC的M不相容的檔案結構。

所以我說,「models」資料夾傷害scalability!

那該怎麼辦?

要解決這個問題,首先得要了解MVC是三個極度不對稱的存在。

V: 負責呈現UI
C: 負責接受request、請M處理、回傳response
M: 負責全部的business logic

M幾乎是你的整個application。

你可以在框架底下,找地方建一個空資料夾,用公司名稱或是專案名稱替它命名,

然後開始煩惱軟體架構這件事。

好好煩惱entity要放在哪裡、Service Objects、 Form Objects、Query Objects、View

Objects、finders、services、uploaders這些要放哪裡,彼此又要怎麼分門別類。

MVC不是萬靈丹,只是軟體架構的入門磚。

架構設計本來就是這麼難,OOP本來就是這麼難。

恭喜你,至少你跨出第一步了:

你不再把一堆胖胖entity丟進「models」資料夾,然後覺得設計完軟體架構了。

Q&A

Q1: 「models」資料夾毫無優點嗎?

「models」資料夾還是有少數優點。

它是一種quick and dirty作法,鼓勵你眼中只看見entity,然後把所有business logic

全塞進裡面。

換句話說,它在小型的專案可以幫你節省時間。但它的優點也僅此而已。

Q2: 你的結論好空泛,什麼建一個公司名稱空資料夾啊。拜託給點方向?

沒問題,我給你兩個架構設計的參考方向。

第一個來自這篇文章:

Rails is Not Your Application

引用作者的話,核心精神如下:

Rails不是你的application。它可以是你的views還有資料來源,但不是你的application

。把你的application放在Gem裡面或是lib/資料夾底下。

我不覺得這樣有很優雅,但至少點出一個可能方向,並且至少不再有models資料夾。

我第二個要給你的,是Laravel官方論壇的原始碼。

這個Laravel.io專案簡稱為Lio,結構如下:

/app
/controllers
/views
/Lio
/Core
/...
/Accounts
/User.php
/UserPresenter.php
/UserRepository.php
/UserCreator.php
/....
/Articles
/Article.php
/ArticlePresenter.php
/ArticleRepository.php
/ArticleCreator.php
/....
/Comments
/...
光看檔案結構就很優雅。也正是我前面所說的:建一個空資料夾,用公司名稱或是專案名

稱替它命名,然後開始煩惱架構設計這件事。

想想看Laravel官方論壇的原始碼為什麼長這樣吧。

Q3: 講得好像多有道理!我覺得你只是在鬼扯!框架的製作團隊都是業界大神,既然他們

決定要有「models」資料夾,必定有它的正當性!

不,你錯了。那些業界大神只是背負了行銷框架的壓力。

他們為了滿足用戶的錯誤期待而委屈地放了個「models」資料夾在那。

但還是有高尚的人存在。PHP最被推崇的框架Laravel就沒有「models」資料夾。

向Laravel的Taylor Otwell致敬吧!

他不願成為殘害新手的幫凶,硬是把「models」拿掉了,

強迫你去思考:「軟體架構到底該長怎樣」。

你要自己在Laravel裡面做一個「models」資料夾,

然後把那些entity class全丟進去嗎?

那你是自願把entity當成整個Model,真遺憾,

但別說是Laravel鼓勵你這麼做。Laravel盡力了。

Q4: 少自以為了解Taylor Otwell了!你憑什麼代替他發言!

Reddit上有一則 Why would anyone choose Laravel over Symfony or Silex?

Taylor Otwell本人親自做出回答。下文擷取自第四段:

我個人在開發Laravel 4的早期階段就想把「models」資料夾整個移除了。因為我不覺得

它有用,也不覺得它能協助你設計軟體架構。而且它還會引誘人們掉入「model ==

database」的陷阱裡。所以,我希望你不要覺得我對架構設計很無知。我花了點時間才想

清楚我到底想在PHP世界打造什麼。

Laravel實作Active Record Pattern,資料表映對到entity class。他指的「model ==

database」陷阱就是我說的「model == entity」錯覺。我並沒有代替他發言。

Q5: 我還是覺得,你沒有資格批評那麼多框架。「models」資料夾就是有某種正當性。

除了Taylor Otwell,我看也沒有其他權威支持你的說法!

前面提到的出色Stack Overflow問答:

How should a model be structured in MVC?

作者是teresko

Stack Overflow上關於MVC的幾個最高分討論,全都是由teresko解答。

下文擷取自那篇出色問答的段落「What a model is NOT」:

model不是一個class,也不是任何一個單一物件。這是一個超級常見錯誤,因為大部分的

框架都在助長這種誤解。

他選擇這樣帶過。我選擇正面指控。

然後我建議你討論事情的時候,不要太在乎權威還是前輩怎麼講。

不如專注於討論事情本身。

Q6: 好啊!那來啊!照你的說法,「models」資料夾底下多放個「entities」資料夾不就

搞定一切問題了?你果然是不切實際的理想主義者!最好是有框架幹這麼囉唆的事情!

有!它就是Cake(PHP)框架!

看看Cake在Model底下放了什麼:


/View
/Controller
/Model
/Behavior
/Entity
/Table
看到了嗎?

Cake怕你把entity當成整個model,直接擺好幾個資料夾,

逼你去思考entity跟model是什麼。

替這些用心良苦的框架歡呼吧!

Q7: 專注於討論事情本身是不是!那Cake的「models」資料夾就沒問題啊!你還說任何框

架都不能有!

你看錯了,Cake沒有「models」資料夾,也沒有「Models」資料夾。它只有「Model」資
料夾。

資料夾、package、資料庫table命名,都有一個關於單數/複數的原則可以參考:異質性
與同質性。

你的「models」資料夾底下不再是同屬entity的class了,而是分為behavior、entity、

以及其他你設計的分類,也就是異質,所以應該用單數命名。

參考這個連結:

Should package names be singular or plural?

簡單地說,既然model代表的是layer而非多個entity,資料夾命名上就應該用單數而非複

數。

好吧,我這樣說有點太嚴苛了。

如果你知道自己在幹嘛的話,就繼續用你的「models」資料夾吧,我勉強可以接受。

Q8: 等等,不對勁…你整篇文章流露一股氣息…我覺得你不但反對「models」,你幾乎在

否定MVC的價值?你怎麼可以覺得偉大的MVC沒有價值?

我前面提過,Taylor Otwell在Laravel 4移除了「models」資料夾,逼迫大家去思考「軟

體架構」到底應該是什麼。

我告訴你第二件事。

你去逛Laravel官網,翻遍官網你都找不到「MVC」三個字。

MVC名氣多麼響亮!哪個framework不想打著MVC當作賣點?但Laravel拒絕這麼做。

我再告訴你第三件事。

2015年最新出爐的Laravel 5,它的views在resources/底下,controllers在app/Http/底

下。一樣沒有models。

所以你神聖的MVC在Laravel 5底下長這樣:


/resources
/views
/lang
/assets
/app
/Commands
/Console
/Events
/Exceptions
/Handlers
/Http
/Providers
/Services
/Https
/Controllers
/Middleware
/Requests
你推崇的V跟C不再佔據檔案結構的核心位置了。你最愛的MVC現在看起來是如此渺小,

小到沒有討論價值,小到毫無意義可言。

「MVC是三個極度不對稱的存在」,這是個太過客氣的說法。

MVC這個觀念已經無法協助我們討論和思考了。放下它,往前走吧。

我來自Laravel社群。我們不聲稱自己擁戴MVC。

來把時間花在真正值得討論的概念上吧:你正在用的框架,架構合理嗎?框架有沒有擋住

你的路?你在框架之下設計出的專案架構漂亮嗎?大中小型專案通用的架構存在嗎?如何

分辨使用時機?怎麼做會最彈性?該怎麼描述某個框架才不會對新手揠苗助長?

放下你凡事都要套進MVC的執著,請直接思考「軟體架構」的本質。

啊,我看到MVC粉絲對Laravel 5的分析了:


MVC依然發揮重要的討論價值!我看到Controllers資料夾了!我看到views資料夾了!

剩下的十幾個資料夾全部統稱為Model!果然是豐富又厚重的layer!

我們來討論Model是什麼吧!MVC萬歲!


朋友,祝福你能得出有意義的結論。

--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 114.37.93.112
※ 文章網址: https://www.ptt.cc/bbs/Soft_Job/M.1427724167.A.916.html
Ghosso: 最近在看ios的框架,就改使用mvvm中 03/30 22:07
readonly: 你適合 django 03/30 22:08
GoalBased: 欸..沒看過胖的entity,甚至entity通常都是程式產的 03/30 22:10
GoalBased: 你對model資料夾的解釋,我換一個角度來講,根本就 03/30 22:11
GoalBased: 不該有view資料夾,那樣會讓新手以為跟畫面有關的東西 03/30 22:11
GoalBased: 都放在view資料夾裡面,結果你就會看到一個html 03/30 22:11
GoalBased: 一大堆css img js,其實不是甚麼該不該的問題 03/30 22:12
GoalBased: 那只是一個架構的概念,需要拆的人自然會去拆 03/30 22:12
CaptainH: 竟然有人寫blog的時候會想像別人在請教自己 ... 03/30 22:29
milonga332: 推 03/30 22:31
CaptainH: 立論薄弱的句讀之學 03/30 22:34
pttworld: 農曆七月又還沒到,鬼扯淡沒自己的重點。 03/30 22:43
motestg: MVC架構,有多種解釋,不過這種Model還是第一次見過,超詭 03/30 22:55
motestg: 異 03/30 22:55
LaPass: 這篇文,部分同意,部分覺得怪怪的。 03/30 23:07
LaPass: 有些框架的確把M直接當資料庫,但是做過erp就知道中間還要 03/30 23:10
LaPass: 做中間曾,要不然最後會血肉模糊。 03/30 23:11
LaPass: 但是,那跟不需要MODEL是兩回事,那也是MODEL 03/30 23:12
LaPass: 概念vs實作是兩回事,但這文把實作上的問題當作是概念問題 03/30 23:13
LaPass: ,總讓人覺得怪怪的。 03/30 23:14
jack0204: 分層寫在modules不是嗎? 為什麼要寫在models裡面? 03/30 23:27
mapleone: 把Models內的東西拆出去變成另一個專案就好了啊 03/30 23:52
leicheong: 我Model都放Entity的extension method, 用來告知如何 03/31 00:00
seamanku: LaPass 說得沒錯,原po將概念和實作混為一談了 03/31 00:01
leicheong: 解讀那entity的. 你可以想一下System.Drawings.Color 03/31 00:01
leicheong: 結構, 如何幫助我們方便地解讀32-bit ARGB value. 03/31 00:02
leicheong: GoalBased說得不錯. 那本來就是錯誤學習MVC架構的人 03/31 00:06
leicheong: 常犯的錯誤. 03/31 00:06
ROCKandROLL: 我是把 model 當作 database 的 interface 03/31 00:34
a926: 我從頭到尾都只認為MVC是架構的概念..就跟3-Tier一樣阿XD 03/31 00:47
appleway: 呃... 沒有被說服,並不同意這篇的看法。 03/31 00:50
GALINE: 我在想把 model 改名成 logic 是否能解決原 po 的抱怨... 03/31 02:35
GALINE: 我字也是 model 不該跟資料混為一談這一派的 03/31 02:37
GALINE: 自己 03/31 02:37
GALINE: 不過這算是從根本否定 active record pattern[汗] 03/31 02:38
GALINE: 這也是在不同的領域會有不同的需要,商業邏輯不會太複雜的 03/31 02:39
GALINE: 時候,寫在一起的 code 其實會優雅不少 03/31 02:39
GALINE: 但是商業邏輯開始膨脹的時候,很快就會變成麵團了 03/31 02:40
GALINE: 感覺這跟房間該怎麼整理一樣,小孩跟媽媽總是意見不同 03/31 02:41
talenttb: 這應該屬於團隊的共識,自己定義清楚就好了吧 03/31 08:31
csfgsj: 有反省、懷疑就給推,比一堆盲從的人好多了 03/31 08:54
liddle: 原po先去學系統論吧。 03/31 10:01
StupidGaGa: 我覺得原PO該問問小朱大,原PO觀念已經偏掉了 03/31 10:03
StupidGaGa: 我覺得原PO發表文章可以先從分享程式碼開始 03/31 10:05
StupidGaGa: 而且很多事情不要一知半解就拿出來發表,半杯水響叮噹 03/31 10:05
qrtt1: kaif 上也有些討論 xd 03/31 10:16
hSATAC: models 資料夾最好是會傷害 scalability... 03/31 11:04
hSATAC: 然後 7 patterns 那篇叫 "refactor" 好嗎? refactor! 03/31 11:04
strlen: 老實說原PO這篇文不一定對 但總也算是個拋磚引玉吧? 不同 03/31 11:56
strlen: 意可以寫一篇反駁他的文讓大家長長知識阿 一擊脫離對架構 03/31 11:57
strlen: 思考也不會有什麼幫助吧? 小弟我老實說還是不太了有M跟沒 03/31 11:58
qrtt1: http://bit.ly/1BZAqdO 推薦 ihower 的分享 03/31 11:59
qrtt1: 題目:從 Classes 到 Objects:那些OOP教我的事 03/31 11:59
strlen: M真的有差這麼大? 一直以來都以為MVC就只是個方便團隊作 03/31 11:59
strlen: 業的東西 約定成俗就好 如果團隊不想用M 那也OK阿 03/31 11:59
pennymarkfox: 我真的看過胖胖entity...所以我還滿認同這部份的 03/31 12:11
gname: mvc就是個"概念",不用這麼認真啦...諸多概念中的一個~就醬 03/31 12:38
typiacalcat: 衝blog點擊也不用這樣... 是要強化業務技能樹嗎? :/ 03/31 12:46
remmurds: 只有我覺得爭這個很沒意義嗎? 03/31 14:43
bibo9901: "胖胖"跟叫什麼名字無關啊, 切成 services, helpers 就 03/31 15:55
bibo9901: 不會胖胖的嗎? 還是會啊, so? 03/31 15:55
bibo9901: 難道叫 models 你就不會抽像化也不會重構了嗎? 03/31 15:55
leicheong: 吵這個就跟吵RMDB要不要跑到3NF一樣, 不過意外地看到 03/31 19:37
leicheong: 這居然有「傷害scalability」作為論點就... 03/31 19:38
vn509942: 我是另外再細切成Repository、Service 方便分工 04/01 21:13
vn509942: 中間再放個ViewModel 04/01 21:14
takasaki: ....我都爽叫models,我還會開repository service等等 04/02 10:57
manaup: 我煮味噌湯都只放木瓜和排骨 喝起來有九成像木瓜排骨湯 04/02 13:02
psliurt: MVC是概念,有Model資料夾只是某些語言的約定俗成 04/05 22:28

你可能也想看看

搜尋相關網站