每个开发者都应该有自己的判断和品味,所以我通常只分享我用什么,以及某个技术有什么好处。我不喜欢评价别人用什么,搞技术就是要多折腾,有时不折腾不会了解自己需要什么。
Ruby Web 开发有很多 Gems 可以用,这本来是增加生产力的工具,不过最近经常见到有人遇到的问题来自于他们用了某个不必要的东西,这本来是可以避免的。我把它们整理如下,判断留给开发者自己。
这里 unittest 和 rspec,提到的 DSL 的区别在于,rspec 更符合老外的思维和语系。其实对于非 native 的我们来说,用 rspec 并没有占多少优势。
simple_form 里面有大量辅助提示的功能,对于做很多表单的场景非常使用,可以 UI,提示,结构可以统一管理,其实是好用的
如果用 form_for 这些工作要不断的重复,而且可以写出好几种风格
我的 php 代码中整个用户和权限系统(RBAC)都是我自己写的,当时在 rails 里面想找对应的 gems,发现 Devise + cancan,但相对于我原来的系统,实在是太难用了,换句话说,对于我这种初级用户来说,真是太难看懂了,出错只能干瞪眼。
simple_form 和 bootstrap 新版有点时间差,各种 dsl,最后不用了 mongo 在 rails 也是官方的 mongo driver,没加 orm
如果只是要做密码加密,用户登录时候验证一下Devise
的确是很庞大,但是还有一些场景,比如密码找回,邮箱验证,登录失败锁定,这些有时候也是十分必要的,这时候Devise
还是能节省不少时间的。
使用 cancan 的话,基本要遵循 resourse。使用动词或者动词加形容词的组合命名额外 action,这样才能达到使用的目的。不规范的 action 名字,权限控制那些代码读起来简直就是。。。尼玛啊!!这种感觉。。
实际上我一开始觉得 RSpec 的优势在于它能够更好的组织测试代码,因为它的变量作用域划分很灵活,加一层 describe 就是一个新的作用域,然后就可以为这个 example group 新写一个 before :each。
嗯……test unit 也能,但是好像大家并没有都在正确的用。后来在用 test unit 的那段时间里,我总觉得如果用 test unit 写测试的话,应该对某个类的每一个功能(方法)分别写一个 TestCase 类,然后再在这个 TestCase 类里遵守 one assertion per test 的原则。而不是把针对整个类的所有方法的测试都塞到一个 TestCase 类里,因为被测类的不同方法需要的 setup, teardown 可能都不一样。把整个类所有方法的测试都塞到一个 TestCase 类里的话,结果测试代码很容易就是一团乱,比如说你需要在测试方法里做一些本来是 setup 做的事。当然也就只是这么想想,没有去打破团队里大家的习惯自己一个人尝试这么干。
所以我后来一直觉得这两个用哪个都无所谓,用好了都一样,用不好……也都一样。
刚和一个老外讨论了 rspec 和 test unit,他说对于一个新手来说,rspec 明显可读性高多了,陌生的东西基本都可以猜出来,而 test unit 就不行。。
Devise 和 Simple Form 仍然是我的最爱,他们的文档都很棒,常见的需求和问题都非常容易找到。
对于一些业务逻辑相对复杂的应用,simple_form 省事很多。
我对于这些 Gem 的态度是,如果还玩不转,就老老实实造个轮子先。
这让我想起一段话……
但是,当他向曲线上方望去,他不会意识到自己正在看更高层次的语言,而是仅仅觉得自己在看某种奇怪的语言。他可能认为那种语言和 blub 语言一样强大,但是加入了不少怪东西。他觉得 blub 语言已经够用了,不用再考虑那些语言了。这时,他的思维已经被 blub 语言同化了。
下次我如果觉的某个东西“够用了”,不需要 XX 了,虽然别人说 XX 更好——那一定是个危险的信号——除非我想的是“有更牛的一群人说用 OO 比 XX 更好,更符合我的使用场景”,而不是单纯“够用了”
其他情况我没遇到过不好说什么,但是对于这一段,真的没法忍……
当我们想要修改表单的时候,最好的方法是修改 HTML 标签,而不是修改 Ruby 代码。不必要的抽象会增加维护成本
你有真的遇到过这种情景么?修改 HTML 标签的维护成本怎么可能比修改 ruby 代码低……我遇到过好几次了,从 bootstrap2.0 升级到 bootstrap3.0, 从 rails 默认的 server rendering 转到 client rendering,从 jquery-ujs 转移到 angular.js without jquery,再从 angular1.1.5 升级到 angular1.2.1, 各种 breaking change,你可以想像一下这其中修改 HTML 标签和修改 ruby 代码以适应新 api 新 markup 哪个维护成本更高……
请问一下 @Rei ,你在测试时,使用的 Gem 有哪些?有没有先写测试代码的习惯?我感觉如果用先写测试代码的习惯来思考,感觉 Rspec 更符合思维一些。
Rspec 里面的语法在 JavaScript 里面可以对应 mocha/jasmine + BDD + expectjs/chaijs 等等 在 java 世界可以对应 cucumber framework.
以前的几个项目有要求用 cucumber 来写 selenium testcase, 那个语法+annotation 写下来的效果几乎就和 BA 在 backlog 里面写的需求验收标准一样。
说实在的,不是 native speaker 恐怕没法意识某些老外对代码可读性的洁癖。
我刚试跑了一下 minitest,它的 describe 方法好像跟 rspec 的作用一样。
在 rspec 里 context 只是 describe 的一个别名。
#58 楼 @yuan 是一样的,因为有个 https://github.com/thoughtbot/shoulda-context ,说 context 比较容易搜到东西。
业务上大包大揽的,基本不会出现在我的 gemfile 里,比如 devise。 写个自己能用的,也就几个文件,几百行代码而已。别人也容易看懂。 自己写一次,以后基本就是 copy+paste 的事情了。
#32 楼 @Rei 我都没说间隔的时间,怎么就能扯到技术迁移的频率了……这几项技术迁移,根本原因是当时我前端太菜了,原来只听说过 rails 默认的 jquery 那一套东西,为了实现需求折腾过各种 jquery plugin,问题在于用 jquery 那套东西根本没办法做出需要的效果,不得不改,现在再让咱开新项目,前端是绝对不可能用跟 jquery 沾边的任何东西了……还好当时因为是从后端转全端,习惯了用 ruby 弄各种 helper 来写 view,多一层抽象改起来反而相当方便
比方说 angular1.2 的其中一项 breaking change 是重写了动画效果,将 ng-animate 指令移除换成 class base,结果我这只需要在后端改几行,前端统一加个动画定义就完事了,view 基本都不需要动:
--- a/app/helpers/animation_helper.rb
+++ b/app/helpers/animation_helper.rb
@@ -18,13 +18,9 @@ module AnimationHelper
:rotateIn, :rotateInUpLeft, :rotateInDownLeft, :rotateInUpRight,
:rotateInDownRight, :lightSpeedIn, :rollIn].each do |ani|
define_method(ani) do |*args|
- speed = args[0] || ''
- { 'data-ng-animate' =>
- {
- show: "animated #{speed} #{ani}",
- enter: "animated #{speed} #{ani}"
- }.to_json
- }
+ speed = args[0]
+ prefix = speed.to_s.gsub('ani-', '') + '-' if speed
+ { class: "#{speed} a-#{prefix}#{ani}" }
end
end
要是没这一步抽象直接写 HTML 估计就得蹲墙角画圈圈了,一百来处动画,生成的 markup 还不怎么带重样的…… form 也是一样,要不是能给 simple_form 打 monkeypatch,20 来个 form 至少一个 field 一个 button 每个 field 一个 error message,原生态 view 改起来,光写 ng-model 就得手抽筋……实际上一个不到 50 行的 monkeypatch 加一行for i in app/views/**/*.slim; do sed -i "s/simple_form/ng_form/g" $i;done
就搞定了
#62 楼 @aptx4869 看来你们以后也不打算把前端交给前端干了。
“不,你不能改 HTML,要改 Patch!” “不不,你不能只改一个 Form!要不全改要不新建一个 Builder。” “为什么你创建那么多 Builder?!”
另外,Rails 本身就能自定义 FormBuilder:
http://guides.rubyonrails.org/form_helpers.html#customizing-form-builders
#63 楼 @luikore 6 个多月前的事情了,一开始需求简单,先得让程序能继续跑起来,要在每个 field 上面加上相应的 ng-model,于是第一反应就是直接给 simple_form 打了个 monkeypatch,后来更详细的需求定下来后就按照 simple_form 的 Readme 用Custom form builder重构了
但是,当他向曲线上方望去,他不会意识到自己正在看更高层次的语言,而是仅仅觉得自己在看某种奇怪的语言。他可能认为那种语言和 blub 语言一样强大,但是加入了不少怪东西。他觉得 blub 语言已经够用了,不用再考虑那些语言了。这时,他的思维已经被 blub 语言同化了。
有时候,不能理解有些东西的妙处,的确是自己的原因。
當你一直往上把事情弄得太抽象,就會像上太空一樣沒有氧氣。有時候這些聰明的思想家就是停不下來,然後就創造出這些荒唐又無所不包的高層次宇宙景像,這些東西什麼都好,就是完全沒有實際的意義。
我觉得这个还是要看使用场景,大多 gem 是为了解决某个领域的通用问题以简化工作量,所以不可能做到绝对高性能。事情不能一竿子打死了。
比如 devise 不但可以加密,还可以记录登陆 IP,最后登陆时间,email confirm,支持 omnioauth 使用,每一个都是对业务很有帮助的特性,一个个写是不是太麻烦了。
cancan 算不上好的权限控制插件,但做复杂权限管理的时候绝对比自己写 before filter 好。而我也更愿意在一个地方管理所有的权限,这就像一个 map view,可以从业务角度更好的看清权限分配是否合理。
个人觉得 simple form 也是个好东西,至少能让我每次都少些很多 tag,适当的配置下又是一套新的结构了。
RSpec 能做的 MiniTest 都能做,但是 RSpec 代碼真的特別好看…… 而且 MiniTest 現在也不在標準庫裡了,一大優勢沒有了。我反正一直是用 RSpec。
Devise 不能做「前後端分離」的項目,我已經棄用…… 什麼時候做前後端一體的項目,再把他拿出來用。