刚刚才 Twitter 上面和 @xdite 讨论到这个话题,顺便也拋出来聊聊 以之前 zheye 这个项目为例,比如这个页面: https://github.com/huacnlee/quora/blob/master/app/views/logs/_log.html.erb
业务需求就是有这么多的逻辑,而且是由于项目不断变化带来愈来愈多的逻辑,有些页面就必然会变得这么复杂,后面维护起来就成问题了。
大家有没有什么好的方法处理复杂的页面?
#2 楼 @huacnlee 我也是从 railscast 上学的 (http://railscasts.com/episodes/286-draper ),概念很简单,就是把 view 里的逻辑全部独立出来。大哥去看看就明白了
Hi, 我當時是這樣 refactor zheye 的 code 的
https://github.com/techbang/q17/blob/master/app/views/logs/_log.html.erb https://github.com/techbang/q17/blob/master/app/views/logs/_asklog.erb
當然還沒有接下去拆的太乾淨。因為光拆到這樣就很費力了 XD
光 model 裡的 Type 就花了一些時間切....
老實說我反對 Decorator 的觀念(尤其是 Draper 的實作)。
在 台灣 Rubyconf 時,我有跟 Cell 的作者討論到 view 的寫作方式。 其實 Controller 和 View 本來就要切的很開,所以我們都討厭 Presenter 這樣的東西。
何況是把 Model 和 View 混的更深的 Decorator。
我們 team 的標準 practice 是
我用过 draper,会明显增加 view render 的时间。 对于 view 代码的复用,我还是比较喜欢用 cells http://rails-bestpractices.com/posts/89-use-cells-to-abstract-view-widgets
之前曾經寫過的 MVP 與 Cells 的文章 http://wp.xdite.net/?p=3063
其實就是 MiniController 與 Partial View 的組合
只要你不要在 partial 裡 query something,其實就不會慢。
真的得要 query something,我就會用 cell 再起一個 mini controller 去解這件事。
因為 partial 速度其實都算蠻快的,大家在抱怨慢是慢在 query in view 這一段。而 Draper 根本沒有「解決」這件事...反而把事情弄的更糟了。
我是這樣整理 code 的。
比如說
<% if current_user || current_user.is_admin ? %>
<%= link_to("EDIT", edit_post_path(@post) %>
<% end
<% if editable_by?(current_user) %>
<%= render :partial => "post_toolbar" %>
<% end
而 editable_by? 會抽去放在 posts_helper。 為什麼要抽出成 editable? 。因為可以管理者也許權限需要擴增。 到處都是硬寫死的邏輯,將來就要去把整個 project 到處挖來看
def editable?(user)
user && user.is_admin?
end
中間這一段又可以拆成 cancan 的 method 去做....。因為 Rule Engine 式清晰很多。
找不回來的。因為 heat cache 還是有成本,就看誰倒楣剛好碰上當那個去 heat 的人。
而 query in view 一次的代價是幾百 ms,同樣的 query 在 controller 可能只要幾 ms。詳見我的 http://wp.xdite.net/?p=3063
會換上 cells 就是因為當初我們也是用 cache 去解 heavy view 的問題。但是 heat cache 實在太沈重,於是就轉變成想要 background heat cache 的方式。
但 Rails 原始的 cache 架構很難實做 background heat cache,於是我們找阿找的,找到 cells,這一套就能讓我們實作 background heat cache。
本來我們用 cells 也是這個原因而已。後來我找到時間仔細讀 Cells 的架構,才發覺他其實就是 MiniController + View 的實作。本來我最痛的就是無法把 View 裡面的 query 拆出去,尤其是三層邏輯 View,拆無可拆,只好 cache。
我把三層邏輯 View 拆成三層 MiniController 後,速度從 500ms 變成了 15ms...。連 Cache 都不必上了。
在开发稍微大的 project 就会遇到这个问题。看了 railsconf 2011, Fat Models Aren't Enough slide(http://assets.en.oreilly.com/1/event/59/Fat%20Models%20Aren_t%20Enough%20Presentation.pdf) 介绍的 presenter pattern. 这一招经过我的实战,发现在处理复杂逻辑时还是不理想,因为我真不知道如何布局越来越多的代码,它们虽然已经是 abstract class 了,但还没有组成一个个组件。 所以后来把@xdite说过的 cell 再仔细阅读,发现却是一个很好的解耦的方法。
之前一直会担心 partial 过细后面回头看会很麻烦,现在这么一回头看,其实相比之下,将复杂的页面细分成多个 partial 确实会让 view 干净很多(实际上是,之前担心 partial 性能的问题,汗)
看起来 @xdite 似乎将 Cells 用得很广泛,我目前得项目里面顶多一两个 Cells 都是也写常用的功能,比如 Commentable, AttachmentList