[心得] 框架不應該有「MODELS」資料夾

看板Soft_Job作者 (阿川)時間9年前 (2015/03/30 22:02), 編輯推噓9(16747)
留言70則, 32人參與, 最新討論串1/3 (看更多)
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

03/30 22:07, , 1F
最近在看ios的框架,就改使用mvvm中
03/30 22:07, 1F

03/30 22:08, , 2F
你適合 django
03/30 22:08, 2F

03/30 22:10, , 3F
欸..沒看過胖的entity,甚至entity通常都是程式產的
03/30 22:10, 3F

03/30 22:11, , 4F
你對model資料夾的解釋,我換一個角度來講,根本就
03/30 22:11, 4F

03/30 22:11, , 5F
不該有view資料夾,那樣會讓新手以為跟畫面有關的東西
03/30 22:11, 5F

03/30 22:11, , 6F
都放在view資料夾裡面,結果你就會看到一個html
03/30 22:11, 6F

03/30 22:12, , 7F
一大堆css img js,其實不是甚麼該不該的問題
03/30 22:12, 7F

03/30 22:12, , 8F
那只是一個架構的概念,需要拆的人自然會去拆
03/30 22:12, 8F

03/30 22:29, , 9F
竟然有人寫blog的時候會想像別人在請教自己 ...
03/30 22:29, 9F

03/30 22:31, , 10F
03/30 22:31, 10F

03/30 22:34, , 11F
立論薄弱的句讀之學
03/30 22:34, 11F

03/30 22:43, , 12F
農曆七月又還沒到,鬼扯淡沒自己的重點。
03/30 22:43, 12F

03/30 22:55, , 13F
MVC架構,有多種解釋,不過這種Model還是第一次見過,超詭
03/30 22:55, 13F

03/30 22:55, , 14F
03/30 22:55, 14F

03/30 23:07, , 15F
這篇文,部分同意,部分覺得怪怪的。
03/30 23:07, 15F

03/30 23:10, , 16F
有些框架的確把M直接當資料庫,但是做過erp就知道中間還要
03/30 23:10, 16F

03/30 23:11, , 17F
做中間曾,要不然最後會血肉模糊。
03/30 23:11, 17F

03/30 23:12, , 18F
但是,那跟不需要MODEL是兩回事,那也是MODEL
03/30 23:12, 18F

03/30 23:13, , 19F
概念vs實作是兩回事,但這文把實作上的問題當作是概念問題
03/30 23:13, 19F

03/30 23:14, , 20F
,總讓人覺得怪怪的。
03/30 23:14, 20F

03/30 23:27, , 21F
分層寫在modules不是嗎? 為什麼要寫在models裡面?
03/30 23:27, 21F

03/30 23:52, , 22F
把Models內的東西拆出去變成另一個專案就好了啊
03/30 23:52, 22F

03/31 00:00, , 23F
我Model都放Entity的extension method, 用來告知如何
03/31 00:00, 23F

03/31 00:01, , 24F
LaPass 說得沒錯,原po將概念和實作混為一談了
03/31 00:01, 24F

03/31 00:01, , 25F
解讀那entity的. 你可以想一下System.Drawings.Color
03/31 00:01, 25F

03/31 00:02, , 26F
結構, 如何幫助我們方便地解讀32-bit ARGB value.
03/31 00:02, 26F

03/31 00:06, , 27F
GoalBased說得不錯. 那本來就是錯誤學習MVC架構的人
03/31 00:06, 27F

03/31 00:06, , 28F
常犯的錯誤.
03/31 00:06, 28F

03/31 00:34, , 29F
我是把 model 當作 database 的 interface
03/31 00:34, 29F

03/31 00:47, , 30F
我從頭到尾都只認為MVC是架構的概念..就跟3-Tier一樣阿XD
03/31 00:47, 30F

03/31 00:50, , 31F
呃... 沒有被說服,並不同意這篇的看法。
03/31 00:50, 31F

03/31 02:35, , 32F
我在想把 model 改名成 logic 是否能解決原 po 的抱怨...
03/31 02:35, 32F

03/31 02:37, , 33F
我字也是 model 不該跟資料混為一談這一派的
03/31 02:37, 33F

03/31 02:37, , 34F
自己
03/31 02:37, 34F

03/31 02:38, , 35F
不過這算是從根本否定 active record pattern[汗]
03/31 02:38, 35F

03/31 02:39, , 36F
這也是在不同的領域會有不同的需要,商業邏輯不會太複雜的
03/31 02:39, 36F

03/31 02:39, , 37F
時候,寫在一起的 code 其實會優雅不少
03/31 02:39, 37F

03/31 02:40, , 38F
但是商業邏輯開始膨脹的時候,很快就會變成麵團了
03/31 02:40, 38F

03/31 02:41, , 39F
感覺這跟房間該怎麼整理一樣,小孩跟媽媽總是意見不同
03/31 02:41, 39F

03/31 08:31, , 40F
這應該屬於團隊的共識,自己定義清楚就好了吧
03/31 08:31, 40F

03/31 08:54, , 41F
有反省、懷疑就給推,比一堆盲從的人好多了
03/31 08:54, 41F

03/31 10:01, , 42F
原po先去學系統論吧。
03/31 10:01, 42F

03/31 10:03, , 43F
我覺得原PO該問問小朱大,原PO觀念已經偏掉了
03/31 10:03, 43F

03/31 10:05, , 44F
我覺得原PO發表文章可以先從分享程式碼開始
03/31 10:05, 44F

03/31 10:05, , 45F
而且很多事情不要一知半解就拿出來發表,半杯水響叮噹
03/31 10:05, 45F


03/31 10:16, , 47F
kaif 上也有些討論 xd
03/31 10:16, 47F

03/31 11:04, , 48F
models 資料夾最好是會傷害 scalability...
03/31 11:04, 48F

03/31 11:04, , 49F
然後 7 patterns 那篇叫 "refactor" 好嗎? refactor!
03/31 11:04, 49F

03/31 11:56, , 50F
老實說原PO這篇文不一定對 但總也算是個拋磚引玉吧? 不同
03/31 11:56, 50F

03/31 11:57, , 51F
意可以寫一篇反駁他的文讓大家長長知識阿 一擊脫離對架構
03/31 11:57, 51F

03/31 11:58, , 52F
思考也不會有什麼幫助吧? 小弟我老實說還是不太了有M跟沒
03/31 11:58, 52F

03/31 11:59, , 53F
http://bit.ly/1BZAqdO 推薦 ihower 的分享
03/31 11:59, 53F

03/31 11:59, , 54F
題目:從 Classes 到 Objects:那些OOP教我的事
03/31 11:59, 54F

03/31 11:59, , 55F
M真的有差這麼大? 一直以來都以為MVC就只是個方便團隊作
03/31 11:59, 55F

03/31 11:59, , 56F
業的東西 約定成俗就好 如果團隊不想用M 那也OK阿
03/31 11:59, 56F

03/31 12:11, , 57F
我真的看過胖胖entity...所以我還滿認同這部份的
03/31 12:11, 57F

03/31 12:38, , 58F
mvc就是個"概念",不用這麼認真啦...諸多概念中的一個~就醬
03/31 12:38, 58F

03/31 12:46, , 59F
衝blog點擊也不用這樣... 是要強化業務技能樹嗎? :/
03/31 12:46, 59F

03/31 14:43, , 60F
只有我覺得爭這個很沒意義嗎?
03/31 14:43, 60F

03/31 15:55, , 61F
"胖胖"跟叫什麼名字無關啊, 切成 services, helpers 就
03/31 15:55, 61F

03/31 15:55, , 62F
不會胖胖的嗎? 還是會啊, so?
03/31 15:55, 62F

03/31 15:55, , 63F
難道叫 models 你就不會抽像化也不會重構了嗎?
03/31 15:55, 63F

03/31 19:37, , 64F
吵這個就跟吵RMDB要不要跑到3NF一樣, 不過意外地看到
03/31 19:37, 64F

03/31 19:38, , 65F
這居然有「傷害scalability」作為論點就...
03/31 19:38, 65F

04/01 21:13, , 66F
我是另外再細切成Repository、Service 方便分工
04/01 21:13, 66F

04/01 21:14, , 67F
中間再放個ViewModel
04/01 21:14, 67F

04/02 10:57, , 68F
....我都爽叫models,我還會開repository service等等
04/02 10:57, 68F

04/02 13:02, , 69F
我煮味噌湯都只放木瓜和排骨 喝起來有九成像木瓜排骨湯
04/02 13:02, 69F

04/05 22:28, , 70F
MVC是概念,有Model資料夾只是某些語言的約定俗成
04/05 22:28, 70F
文章代碼(AID): #1L6LU7aM (Soft_Job)
文章代碼(AID): #1L6LU7aM (Soft_Job)