Rails RoR 新人报到,Java 出身,正开始学 Ruby 和 Rails,特此感慨,欢迎前辈们批评指正

dylanninin · 2013年11月12日 · 最后由 yfractal 回复于 2013年11月14日 · 9160 次阅读

RoR 新人报到,Java 出身,正开始学 Ruby 和 Rails,特此感慨,欢迎前辈们批评指正。

Markdown 格式可能有点乱,见谅!

原文:http://dylanninin.com/blog/2013/11/11/for_rails.html

我是一枚 Java 攻城狮,工作两年多,主要做 Java Web 开发,期间转去做了一年多的Oracle DBA,维护Oracle EBS,也当过Linux Administrator

Sun 早就被 Oracle 收购了,Java 和 MySQL 成了 Oracle 的小儿子;Oracle Database 和 EBS 自不必说,Oracle 的亲亲亲生孩子,庞然大物,组件众多;Oracle 推出了基于 Redhat 的 Oracle Linux, 号称 Unbreakable,所以 Linux Administrator 就成了 Oracle Linux Administrator。看这趋势,一路朝 Oracle 走来一路坑,深有被 Oracle 绑架的感觉,所以希望能够从 Oracle 中解脱出来,呼吸下 新鲜空气。

最近王垠新写了一篇博文再见 Voxer,你好 Sourcegraph,讲述他最近的一段经历和想法,顺便小议了下 Oracle:“想当年 Oracle 的那些烂东西也是用同样的方式发家的吧”。 这是不是在黑 Oracle,我想不是的。在公司刚结束的一个由华南地区 Oracle ACS 的 team 主导的 Oracle EBS 升级项目中,有一位技术深厚、经验丰富的顾问(专攻 Oracle Database,经历过 8i, 9i, 10g, 11g,现在 12c 开始着火了)半开玩笑的说道:Oracle Database 就是一堆 Patch 堆积起 来的。这是在食堂排队前的一点闲谈,但不无道理,以不才一年之误尚不足以体会这么深,可顾问该是有些说服力的。

甲骨文叫 Oracle,而不取类似 “Apache” 的名字,是不是很神秘?即使这样,公司每年还是要签 Oracle 的 License,为 Oracle 测试、提 Bug。

在做 Oracle DBA 时看了阮一峰的Java 语言学校的危险性 (译文),似乎识迷途其未远;偶尔碰见Lisp 的永恒之道,编程语言真的会影响人的思维方式;昨天还看了下 Hacker News 上的提问Ask HN: Is Java still worth learning?又验证了 某些想法。现在开始觉得是时候换种语言了,在同学、朋友的影响与帮助下,开始了RoR之旅。


##Java

先简单总结下个人 Java Web 开发的经历。基本有三个阶段:

  • 四叶草网上书店:大二数据库课程设计的项目,用到的技术很基础,JSP, Servlet, JavaBean, 数据库为 MySQL。 现在早已不知道代码在哪里,好在当时开了新浪博客四叶草团队,还留有一些可寻的印象,现在看过去文字好生硬。
  • 俱乐部会员管理系统:一个暑期的项目,应该是大二结束后的暑假,由 IBM 教育学院派人进行培训,为其 40 天。从这起就是开始接触 Java Web 开发框架 (Struts2, Hibernate, Spring,合称 SSH);那时啥也不知道,学会了一点 SSH 的使用技巧后,就开始抛弃纯 JSP, Servlet, JavaBean 的开发了。
  • 生活信息分享系统:大四毕业答辩的项目,分微博 (集成新浪微博)、房产 (模仿搜房)、景点 (不记得模仿哪个系统了) 和天气预报 (集成雅虎天气) 四大子系统, 因为那时 LBS 渐热,所以这些模块都要结合 Google Maps,根据我们的想法就把它们硬生生地扯在一起了。技术框架自然是 SSH,但需要整合的第三方系统实在太多, 新浪微博 (OAuth 和开放 API),雅虎天气 (Web Service,XML 或 JSON),还有 Google Maps(开放 API);因为种种原因,系统完成得并不理想,庆幸的是并没有影响大家正常毕业。

工作中接触的 Java Web 项目,都是采用 SSH 的基础框架。偶尔还有点变化,前端从 Adobe Flex 到 Ext JS3,Java FX 也曾一度惊现,但缺少纯 HTML 和 JavaScript;开始集成 Lucene 做简单的站内搜索, 或者干脆使用 Solr;最近又要集成 IM,做基于 Openfire、Spark、FastPath 的开发;用够了 Hibernate,终于开始调研 MyBatis;听说 PHP 和 Java 可以强强联合,所以又开始尝试 Quercus 及 php-java 的桥接... ...

以个人有限的知识和经历,我认为对中小型企业来说 SSH 框架已经基本够用。作为补充,上个月整理了一份Java Resource可供参考。


##Rails

以上是从大学到工作至今接触过的一些 Java Web 开发的技术或框架,它们堆积在一起很吓人,说不上完全掌握,但理解还是有一点的;要说是啃老族,那我啃的还是大学的底,只是不再认为 “Java Web == SSH”。

在回头审视这些项目或阅读源代码时,我有经历过一些想法的摩擦和碰撞,而这些想法又体现在 Rails 中,但 Rails 做得很好,也很优雅,当之无愧的"魔幻"。

看 Rails 的第一本书是Agile Web Development with Rails 4,它除了教你如何认识和使用 Rails,也讲了敏捷开发的流程,不得不说让人感受和启发良多。如果要说一句话,我想那会是相见恨晚。

##Java vs Rails

下文将说说这几天学 Rails 时脑海中时而涌现的念头,作为对 Java Web 开发的一次小结,也算是对 Rails 的一种拥抱。

这些想法很基础,可以说任何一个项目都会遇到;但也很重要,我认为只有理解和解决了它们,一个项目的基石才是可靠的。

主要包括:

  • 项目结构:Top directory and packages in Java, Rails and Django;
  • 命名规范:Naming Conversion; NamingStrategy in Hibernate and why plurals for tables in Rails;
  • 日志处理:Log4j in Java and Logger in Rails
  • 单元测试:jUnit, DbUnit in Java and Fixtures in Rails
  • 构建工具:Ant in Java and Rake in Rails

特别说明:

  • Ask HN: Is Java still worth learning?中看到基于 Java 和 Scala 的框架Play Framework,对以上问题似乎解决得也很不错,具体如何,需要试用、与 Rails 对比才知道;
  • 为方便引用,Agile Web Development with Rails 4 以下简称 AWDR4;
  • 因为啃老,下文可能停留在 “Java Web == SSH” 的水平,欢迎拍砖和评论;
  • 个人知识水平有限,若有错误还请大侠们不吝赐教;

## 项目结构

### 目录结构

####Java

Java Web 应用并没有明确规定该采用怎样的目录结构,唯一可寻的规范似乎是WAR file format中提及的web.xml, 其中 web.xml 的具体内容又由web-app_2_5进行定义。

一个打包好的 Java Web 应用应有如下的目录结构,以便部署到 Tomcat、Weblogic 等容器中。

WebRoot/
css/
images/
js/
logs/
META-INF/
WEB-INF/
classes/ lib/
web.xml
index.jsp 404.jsp 500.jsp

项目开发的目录结构就真没有规范可寻了,最简单的只需要一个 src 目录和一个 WebRoot 目录即可搞定;但随着时间推移,或许是半年,一年,也或许是两年,这样的目录结构并不能满足需求。 于是经过调整,可能会发展成这样:

my_project/ src/ java 源码包,一般按域名继续划分,防止包冲突,如 com.egolife.ssh; test/ java 测试源码包; resource/ 各类资源或配置文件,如 struts, spring, system properties, freemarker templates, jbpm processes; doc/ 项目文档目录; lib/
测试时需要的额外的库,如 jsp,servlet,junit,spring 等;运行时需要的 lib 在 WebRoot 下; 单独列出此 lib,方便正式部署时排出这些包; reports/ 报告目录,如单元测试报告; WebRoot/ Web 根目录,包含运行所需的 web.xml,lib,classes 等; build.xml - Ant build 文件;

但也可能会是这样:

my_project/ src/ java 源码包,一般按域名继续划分,防止包冲突,如 com.egolife.ssh; test/ java 测试源码包; config/ 各类资源或配置文件,如 struts, spring, system properties, freemarker templates, jbpm processes; lib/
测试时需要的额外的库,如 jsp,servlet,junit,spring 等;运行时需要的 lib 在 WebRoot 下; 单独列出此 lib,方便正式部署时排出这些包; sql/ 数据库 schema,或者实用的 script; WebRoot/ Web 根目录,包含运行所需的 web.xml,lib,classes 等;

####Rails

Rails 框架已经约定好了项目的目录结构,你只需要输入 rails new my_app,它就会自动帮你生成,每个文件/目录的定义清晰可见。

my_app/ app/ Model, view, and controller files go here. bin/ Wrapper scripts config/ Configuration and database connection par config.ru - Rack server configuration. db/ Schema and migration information. Gemfile - Gem Dependencies. lib/ Shared code. log/ Log files produced by your application. public/ Web-accessible directory. Rakefile - Build script. README.rdoc - Installation and usage information. test/ Unit, functional, and integration tests, fixtures tmp/ Runtime temporary files. vendor/ Imported code.

### 包或模块结构

除了项目的顶级目录结构,包或模块结构的划分往往是一件令人头疼的事儿。

最早开始注意到这个问题,还是在 11 年工作后开发第一个 Java Web 应用时。那是四个人的小团队针对老系统进行再次开发,抱着动大刀的心态, 总觉得原有项目的包结构十分别扭,修改一个模块时经常需要跨越多个包,而且前端还使用了 Adode Flex 3 的框架,IDE 提供的 Refactor 功能顿 时失灵了,在修改 service 的一个方法名、model 的一个属性时别提会有多么恶心(深受其害之后动手写了一个小工具,可以批量将 Java 的 Model 映射成 Flex 的 valueObject,copy->paste->fix 这种方式实在太 ugly)。当然,很有可能是再次开发增强了这种恶心感,手里拿着锤 子什么的,那自然一切都成了钉子。不过,开发第二个 Java Web 项目时,还是沿用了原有 的包结构,SSH 框架,前端由 Adobe Flex 3 换成了 Ext JS3,但明显没有以前那种恶心感。如果这个系统再由一批新人去维护,很有可能他们也会受罪,正如我们一样,只不过这次是我们制造的。

言归正传,还是谈谈 Web 项目的包或模块结构,先引一篇老文,JavaEye新闻月刊 2008 年 07 月总第 05 期四个有害的 Java 习惯之包的命名和划分

#### 包的命名和划分

包 (package) 的命名和划分按照行为和层次划分 (package-by-layer),而不是根据特征和功能划分 (package-by-feature)

这个问题在我刚学 java 的时候就遇到了,在看了众多的网上开源程序后,我也慢慢习惯了按层次命名包。

作者举了个例子:

com.blah.action com.blah.dao com.blah.model com.blah.util

我们已经习惯了按照层次分类或者叫按照行为分类,model 一个包,dao 一个包,service 一个包,action 一个 包。这样就把具有同样特征或者功能的类划分到了不同的包里。这样的习惯,把 java 的包内私有 (package- private) 这个作用域给完全扔掉了,而包内私有是 java 的默认作用域(ps:我学 java 来好像很少用过 java 的包内 私有这个作用域,汗一个)。

这种包的划分习惯也违反了面向对象编程的核心原则之--尽量保持私有以减少影响,因为这种习惯强迫你必须扩大类的作用域.

下面的包命名方式是按照特征划分命名:

com.blah.painting com.blah.buyer com.blah.seller com.blah.auction com.blah.webmaster com.blah.useraccess com.blah.util

举个例子,在一个 web 应用中,com.blah.painting 包可能包含下面的成员:

Painting.java: model 对象 PaintingDAO.java: dao 对对象 PaintingAction.java: controller or action 对象 statements.sql: SQL 文件 view.jsp: JSP 文件

值得注意的是这种情况下,包里包含的不仅仅是 java 源码文件,同时也包含其他与该特征相关的文件。这点上好像违反大多数 java 程序员的习惯,并且如果要打包为 jar 好像也不方便,真实环境中如何应用,有没有别的麻烦,还要待实践一下。

作者列举了这种包划分方式的优点:

  • 包是高内聚的,并且模块化,包与包之间的耦合性被降到最低。
  • 代码的自文档性 (或自描述性 self-documenting) 增强. 读者只需看包的名字就对程序有些什么功能或特 征有了大概的印象。在《代码大全》中, Steve McConnell 将自文档化 (self-documenting) 的代码比作 "the Holy Grail of legibility."(不知道怎么翻译)
  • 把类按照每个特征和功能区分开可以很容易实现分层设计。
  • 相关的成员在同一个位置。不需要为了编辑一个相关的成员而去浏览整个源码树。
  • 成员的作用域默认是包内私有。只有当另外的包需要访问某个成员的时候,才把它修改为 public. (需要 注意的是修改一个类为 public,并不意味着它的所有类成员都应该改为 public。public 成员和包内私有 (package-private) 成员是可以在同一个类里共存的。)
  • 删除一个功能或特征只需要简单的删除一个文件夹。
  • 每个包内一般只有很少的成员,这样包可以很自然的按照进化式发展。如果包慢慢变的太大,就可以再 进行细分,把它重构为两个或者更多新的包,类似于物种进化。而按照层次划分的方式,就没办法进化 式发展,重构也不容易。

作者引用了一句 Effective Java 中的名言:

"The single most important factor that distinguishes a well-designed module from a poorly designed one is the degree to which the module hides its internal data and other implementation details from other modules."

-- Joshua Bloch, Effective Java

####Java, Rails and Django

在按照行为和层次划分还是根据特征和功能划分的争论上,我们的 Java 项目优先选择了前者,在 MVC 层级的结构之下再按特征和功能划分模块;Rails 与之类似。那么,有没有反过来的呢,即正如上文作者提到的建议,先按特征和功能划分,再按行为和层次划分。答案是 Django,在 Django 1.5.3 Documentation 中提到的项目结构:

tutorial/ mysite/ init.py settings.py urls.py wsgi.py polls/ init.py urls.py views.py models.py admin.py tests.py static/ polls/ style.css templates/ 404.html 500.html polls/ detail.html index.html result.html hn/ init.py urls.py views.py models.py admin.py tests.py static/ hn/ style.css templates/ 404.html 500.html hn/ detail.html index.html result.html templates/ admin/ base_site.html manage.py

目录结构,包结构十分重要,它们从文件、模块的层次体现着项目的设计水平和权衡,在这方面感觉 Ruby 和 Django 要略胜一筹,因为设计或不设计,它就在那里。


## 命名规范

对程序猿来说,Coding 并非是最难的事情;那是什么?命名!!!对,是命名偷走程序猿的大把时间和精力。

记得在一个 OA 项目开始初期,整理过一分 Java 和 Ext JS 的编码规范,其中命名规范是重点,实践起来实际上是困难重重。想一想,单是找出一个合适的英文单词 似乎就要绞尽脑汁,随意和不杀脑细胞的后果是瞅瞅国内一些开放平台的 API 就知道他们的英语水平和设计素养;当然,如果你直接使用中文编程就另当别论了。

###Java

Java 命名规范举例(参考了 AWDR4)

Model Naming

Table image_sprite
Package com.egolife.ssh.po.media Class ImageSprite File my_project/src/com/egolife/ssh/po/media/ImageSprite.java ORM my_project/src/com/egolife/ssh/hbm/media/ImageSprite.hbm.xml

Service Naming

Package com.egolife.ssh.service.media Interface ImageSpriteService Method ImageSprite findById(String id); File my_project/src/com/egolife/ssh/service/media/ImageSpriteService.java

Class ImageSpriteServiceImpl Method public ImageSprite findById(Srting id){ ... ... } File my_project/src/com/egolife/ssh/service/media/impl/ImageSpriteServiceImpl.java

Spring

File my_project/resource/spring/applicationContext-media.xml

Action Naming

URL http://../media/findImageSpriteById.action?id=DEADBEEF Package com.egolife.ssh.action.media Class ImageSpriteAction Property private String id; Method public String findImageSpriteById(){ ... ...} File my_project/src/com/egolife/ssh/action/media/ImageSpriteAction.java

Struts File my_project/resource/struts/struts-media.xml

除了 Java 文件,还涉及到 Struts, Hibernate, Spring 一堆 XML 的配置文件,当然,你也可以使用 Annotation 实现 “零配置”。

###Rails

Rails 命名规范举例(直接引用 AWDR4):All these conventions are shown in the following tables.

Model Naming

Table line_items File app/models/line_item.rb Class LintItem

Controller Naming

URL http://../store/list File app/controllers/store_controller.rb Class StoreController Method list Layout apps/views/layouts/store.html.erb

View Naming

URL http://../store/list File app/views/store/list.html.erb (or .builder) Helper module StoreHelper File app/helpers/store_helper.rb

###ORM 命名策略

由于关系数据库与面向对象的不匹配,ORM 应运而生。在 Java 中比较典型的 ORM 框架是 Hibernate,采用 XML 文件描述 Java POJO 和数据库表之间的对应关系, 可以让开发人员以面向对象的方式来完成 Java 与数据库的交互,而不再纠缠于 JDBC,写大量的原生 SQL 和参数的 setter/getter;是的,这时最满意的要数程序员的 手指头。在 Rails 中,ActiveRecord 担任了此角色,但省去了 XML 文件,这时你会更觉满意。

随着 ORM 的出现,Model 和 Table 的命名问题也逐渐浮出水面:

  • Table: line_item, line_items, or tb_line_items ?
  • Id: id, line_item_id, or line_items_id ?
  • Model: LineItem or LineItems ?

在以 SSH 框架为基础的 Java Web 项目开发中,一般有两种选择:

  • ddl2java:先进行数据库设计,然后通过逆向工程生成 Java 代码,包括 Model, XML, DAO, 甚至是 Service。此时 Java 层的命名由数据库层决定。
  • java2ddl: 标准的面向对象设计,手写 Model, XML,或直接使用 Annotation,然后通过正向工程生成数据库 DDL。此时数据库层的命名由 Java 层决定。

在接触过的项目中,以 ddl2java 的选择居多,逆向工程可以帮忙生成很多代码,这是自底向上的设计思路。

无论是 ddl2java,还是 java2ddl,都有一个叫NamingStrategy的工具 在帮你进行一些默认的转换,毕竟 Java 和数据库各有各的命名规范,迁就哪一个都觉得有所不妥。

在 Rails 中同样有 NamingStragety,只不过这是一个很隐匿的家伙,约定俗成以至于不需要它了。

关于 Model 和 Table 的命名问题,最大的要数单数还是复数了。Java Web 开发中暂未确定,随开发人员高兴,但一般还是挺一致的,要么都采用单数,要么都采用复数, 但这样又似乎确凿有些别扭:

  • Singular: User(Class) -> user(Table),表 user 有多条记录,每个记录代表一个 User,也就是多个 User,这样表名用 user 是否有些不妥?
  • Plurals : Users(Class) -> users(Table),表 users 有多条记录,每个记录代表一个 User,似乎比上面好多了。但 1)根据 id 查找用户时,应返回 null 或者 User,此时却是 Users,是多个用户吗,有点奇怪? 2)模糊查找时返回 List,此时却List<Users>,Users 不是已经是复数了吗,这时你不会有一种使用 foreach 嵌套循环的冲动?这样似乎也有些不妥?

终极方案似乎是这样的:

  • Mixing: User(Class) -> users(Table),但此时需要你自定义 Hibernate 的 NamingStragety,谁有时间去干这事儿;再说满足需求就行了,这事儿谁在意呢。

这问题在 AWDR4 中解释得很好,摘抄如下:

David says: Why Plurals for Tables?

Because it sounds good in conversation. Really. “Select a Product from products.” And “Order has_many :line_items.”

The intent is to bridge programming and conversation by creating a domain language that can be shared by both. Having such a language means cutting down on the mental translation that otherwise confuses the discussion of a product description with the client when it’s really implemented as merchandise body. These communica- tions gaps are bound to lead to errors.

Rails sweetens the deal by giving you most of the configuration for free if you follow the standard conventions. Developers are thus rewarded for doing the right thing, so it’s less about giving up “your ways” and more about getting productivity for free.


## 日志处理

先讲一个笑话,第一次见到Log4j,你会怎么读?"Log|Four|J",还是"Log| 四 |J"?饱受中文和阿拉伯汉子熏陶的 Java 程序猿,若是第一次碰到,不出意外,大都 会读错,即读成 "Log| 四 |J",在我不长的 Java 开发生涯里,已经碰到好几例。

即使联想到"J"是"Java"的缩写,也难以想到"4"代表什么;但若知道这世上还有 Log4cxx,Log4php,那大概可以猜到"4"其实代表"For",只是"LogForJava"写起来太长了,"Java"缩写成"J","For"干脆就用"4"代替了;更进一步,可以说 Log4j 所代表的是一种思想、一种设计,只不过刚好是 Java 语言的实现。 这和"B2B"、"B2C"是一个道理,但君不见也有某主持人把"B2B"读成"B 二 B"的。

调试 Java 程序,难免会有打印输出,使用System.out.println(message)System.err.println(error)就可以满足需求;但你一定干过这事儿:1)第一版的代码里为了调试写满 println,调试好后觉得输出的无关信息太多,看着怪怪的,手痒了就非常勤快地把它们删掉;但使用时还是莫名地出错,于是又手贱地再写了一遍println。 2)正式上线前,经理突然说把项目里的调试代码注释掉,以免影响运行的性能;好家伙,这一天没写一行代码,反倒删除了几千行。

这时,Log4j 可以帮你免除手痒手贱之苦。使用 Log4j 可以自定义输出级别,方便控制项目在测试阶段、上线运行时的日志输出;你也可以在日志输出到标准输出的同时,保存一份到文件或数据库中,以便定时查看和统计分析;碰到 Error/Fatal 类的错误时,发送一封日志邮件给开发维护人员也很不错,何乐而不为呢。

Log4j 是很多 Java 程序里默认的日志组件,在 Hibernate 逆向工程生成的 DAO 里即可找到它的身影。看起来很不错,但要在自己的 Java 代码用到,还是得稍微花点功夫。这时你需要引入 Log4j 的配置,熟悉 rootLogger、LogLevel、Appender、Layout 等概念,若有兴趣,似乎也想看下 Log4j 的设计原理和具体实现,趁机 “Pick Up” 一些设计模式, 然后为己所用。不仔细看文档,直接上配置和代码的人可能要折腾一小会儿了,好在打造一份 Log4j.properties 之后,就可以随你 “Copy and Paste”。

Rails 中有类似的日志组件,叫 Logger -- supporting rollover,零配置即可用;当然了,遇到项目上线运行时还是需要定制下的。只是在此不得不感叹下,在 Rails 中使用 Logger 似乎出乎天性、理所当然,但 Log4j 却要一些折腾,一些配置。

Gists:


## 单元测试

在最初的 Java Web 开发里,是没有单元测试的概念的,即使到现在开发人员也依然习惯说:功能我写好了,你看!

jUnit 是什么?为什么要单元测试?即使我看了 jUnit in Action,理解测试的重要性,也不见得会按部就班的进行严格的单元测试。

在 Java Web 项目中,可以借助 IDE 自动生成单元测试用例,虽然功能有限,但也省了不少时间(如果连这个功能都不知道,那可以说你还生活在原始时代)。 出于对 IDE 自动生成的单元测试用例的不满,自己写过两个版本的小工具。一个是 Java 版的,粗野的将文本扫描和正则表达式相结合,渲染 freeMarker 模板,批量生成 TestCase 和 Tests,并自动填充 Parameters 和 Asserts,接下来所要做的工作就是更改 Parameters 和 Asserts,并运行测试即可。第二个是 Python 版的,最初是想用 Java 重写,但还是 脱离不了扫描源文件(想过使用反射来实现,但看 Java 提供的反射 API,运行时源代码中定义的参数名丢失了,实在不忍用 arg1, arg2 来代替 start, pageSize),当时正好在学 Python, 所以改用 Python 重新实现。代码只能捂脸见人,所以就不贴出来了,思路在模板,见jUnit TestCase Gist

对涉及到数据交互的单元测试,jUnit 已经不够用了。当时找到一个叫 DbUnit 的小框架,是 jUnit 的扩展,可以用 XML 事先构建一些测试数据集,在单元测试的时候载入数据库, 测试完成后从数据库中清除,有效的控制了测试数据库的状态。使用 DbUnit 大概有两个好处:1)构建测试数据集,可重复测试,再也不用担心测试数据被修改或丢失;2)测试完成后清除测试数据,保证了测试前后数据库的数据是一致的。

当然,使用 jUnit 已经很折腾,加上 DbUnit,好像又得花几天的时间了。

那么,Rails 中是怎么解决的呢?

Rails 提供了 scaffold 和 generator,可以自动生成测试用例,而且把我想通过编写小工具去实现的功能完成得更加优雅;在构建测试数据时,Rails 一致地选择了 YAML,对了,这应该称作 Fixtures,你可以在 test/fixtures 目录下找到它们。

YAML 是什么呢,YAML is a recursive acronym for "YAML Ain't Markup Languade". Early in its development, YAML was said to mean "Yet Another Markup Language", but it was then reinterpreted(backronyming the original acronym) to distinguish its purpose as data-oriented, rather than document markup. 详情请见Wikipedia: YAML

为什么不使用 XML,因为 YAML 面向数据、自解释,你再也不用写一堆标签和属性。

这还不是最重要的,最重要的是,在这种内在的测试支持的帮助下,你会很乐于做这件事而无需额外折腾,正文 AWDR4 文中所言 “One of the real joys of the Rails framework is that it has support for testing baked right in from the start of every project.”

## 构建工具

Java 中用于自动化构建的工具有 Ant 和 Maven。Ant 起步比较麻烦,需要手写一大堆东西;Maven 无需配置,可直接上手使用。但 Maven 的网络特性更强一些,在隔离互联网的内网开发环境下是难以生存的,所以要用也只用到 Ant。

Ant 的介绍:Apache Ant is a Java library and command-line tool whose mission is to drive processes described in build files as targets and extension points dependent upon each other. The main known usage of Ant is the build of Java applications. Ant supplies a number of built-in tasks allowing to compile, assemble, test and run Java applications. Ant can also be used effectively to build non Java applications, for instance C or C++ applications. More generally, Ant can be used to pilot any type of process which can be described in terms of targets and tasks.

Ant 可以编译、打包、测试和运行 Java 程序,但不限于此,你还可以编写自己的扩展,加入到 Ant Lib 中,实现更多更丰富的任务,比如创建 Java 项目的目录和包结构;一些开源的项目也提供了 Ant Lib,比如 Hibernate,jUnit。

从头开始写一个 Ant 配置有点麻烦,但写好之后基本可以复用,有不一样的地方只需根据项目需求进行调整即可,这样似乎有点一劳永逸了,也似乎有点不够优雅,更别提创建一个新项目的时候你还记得有这事儿吗?踩进与 Ant 有点关系的深坑,要数实习期间的一个 Web 项目,前端使用 Adobe Flex 3, 在给 MyEclipse 装上一大堆插件之后,编译 Flex 代码变得奇慢无比;若是你不小心勾选了自动编译的选项,Flex 代码的任何一点改动都可以让你等上一二十分钟。这时想到了 Ant,查到 Ant 和 Adobe Flex 的官网,确实提供有编译 Flex 的 Lib,也有一些教程,接下来就是测试和移植工作了。那会儿顿时觉得很兴奋, 希望一天内就能完成,实际上零零散散花了一周多的时间还没搞定,记得好像是某些 style 资源始终无法编译到 SWF,最后就不了了之。

Gists:

那么 Rails 表现如何呢?Rails 提供了 Rake,比起 Ant 需从头编写 build.xml 以及使用 Flex Task 时遇到的困难,Rake 更像 Maven,内置了很多任务,无需配置;到目前为止,我还没踩进 Rake 的坑。

Rake 的介绍:Rake is like having a reliable assistant on hand all the time: you tell it to do some task, and that task gets done.

Rake 在你键入"rails new my_apps"时,已经陪伴你左右,随时待命。见Rake Gist

是的,Rake 是一个值得信赖的好助手,随时随地就在身边供你差遣;而 Ant 需要你手工打造,好与坏完全取决于自身的水平。

## 参考

共收到 42 条回复

欢迎楼主,其实国内的 Ruby / Rails 社区很小,建议你上传一个头像,经常泡泡论坛,互相混个脸熟,将来一看到你的头像 ID 就能把你认出来啦。

为啥会这么长。。。

oracle DBA 是多么有钱途的职业 我身边 oracleDBA 不是公鸡精上线就是土豪

为啥会这么长。。。

为啥会这么长。。。

楼主你在干什么?

没有看完的举手,🙋

忘了 java 吧

为啥会这么长。。。 阮一峰和王垠都是两个特别有思想的人。特别是王垠,他的行文犀利刻薄,经常遭人质疑,但是往往却给我很多启发。

要是单纯的看各种 跑分成绩 的话,用 java 来实现的东东都在 top 里面呢。。。

为啥会这么长。。。

太长了 , 看了一半 ...

用合适的工具做合适的事情, No silver bullet

太长了切割下,还有排版需要整理下

感觉可以提取下,总结下,分为几篇发出~~

好长……markdown 为啥没解析……

唉 看到了好多熟悉的东西 又想起来我做 java 外包的时候 36 小时上班的时候了 欢迎小伙伴转投 ruby

又一次看到王银的换工作情况。

真心读不完

读不完的举手, 🆙

#1 楼 @lgn21st 谢谢提醒,已经默默更新了头像。

#2 楼 @wcp1231 #4 楼 @miclle #5 楼 @messiahxu #12 楼 @jjzxcc 确实有点长。跟各位打声招呼,也一起回了,见谅。

#23 楼 @dylanninin 你这个头像不好,选头像跟你做了个 iPhone App 选图标一样,到任何地方,weibo,facebook,twitter,whatever,人家都能一眼认出你来得头像才是好头像,是很重要的事情。

#3 楼 @ZombieCoder 说得极是,但看到身边的顾问 (代表技成可以去 Oracle 原厂的一派),Eygle(云和恩墨创始人,代表技成可以创业的一派),自己 (从小白入门 Oracle DBA,代表混在公司的的一派,管理体系实在不敢恭维,再多的想法也只能搁浅),感觉那不是我想要的生活,所以想回到互联网。

#6 楼 @ruby_sky Java 的学习堆栈很深很广,Rails 刚上手,目录结构、包结构、命名规范、日志处理、原位测试、自动构建等在 Rails 中随手可得,所以有意吐槽下,辛苦你了!

#7 楼 @OhCoder 不吐不快,O(∩_∩) O 哈哈~

#8 楼 @sallon88 最近都计划好好学习下 Ruby 和 Rails,等到非得 Java 上阵再折腾!

#9 楼 @MrPasserby 同感,知道他们还都是大学同学介绍他们的博客和故事,一看到就很喜欢。从他们那里要学习的东西太多

#10 楼 @willmouse 只能表示喜欢了!

#11 楼 @ywjno 好贴,收藏了。

#13 楼 @song940 辛苦您了,耐心看了这么久

#14 楼 @kongkong 谢谢指点,可能这一年多我用的工具有点 overkill!

#15 楼 @mojidong #16 楼 @xiaogui #18 楼 @Kabie 差不多是深夜发帖,又是在 Ruby China 的处女贴,所以还没来得急熟悉这儿 Markdown 的解析情况;我只用 jekyll 看过渲染效果,以后会注意的。 差不多是吐槽,把吐槽再分批次发出,是不是不太好,有点骚扰 Ruby China 的嫌疑。

#17 楼 @bhuztez 没看懂,求解释!

#34 楼 @dylanninin LZ 的风格好特别啊~一个一个回复辛苦了

#19 楼 @zj0713001 这,36 小时的节奏,怎么熬过来的!

#20 楼 @Blues 他很遵从内心的想法,感觉很值得我学习,只是我理论和技术水平低,迫于活命,尚还处在求温饱的阶段,告诫自己先好好努力了,但也勿忘初心。

#21 楼 @2008feixu #22 楼 @shatle 我再看了一遍,果真是读不完。。。

最近在看 functional programing javascript (走着其实刚开始的想法是写一个能浏览器上跑的 scheme,但不知为啥 scheme 那么漂亮,js 那么丑。。。),觉得 functional programing 是把大的问题分解为小的问题,既,由大到小的的思维方式,觉得这样的思维方式更好一些,当然只是觉得,没什么依据。

觉得 ruby 带给我最大的感触是,给精简提供一种可能。我会学着把代码写的干净,学着把代码的结构搞好。

ruby 很灵活,但 rails 有些地方却很资质,比如 routes,远没有 django 的灵活。但带了很多便利。觉得 ruby 的灵活,和 rails 的一些 configuration 是非常有意思的组合。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册