Ruby on Rails 简介

“Life’s too short to build something nobody wants” - Ash Maurya, Running Lean 作者

Ruby on Rails是一套非常有生产力、维护性高、容易布署的Web开发框架。从一开始不知名的玩具,到现在它已经成为全世界Web应用程式开发的首选框架之一。进入学习的旅程之前,我们先了解为什么它如此特别?

什么是网站开发框架(Web framework)?

1990Tim Berners-Lee发明全球资讯网之后,就开始有了动态网页的需求,早期最风行的方法是使用Perl CGI,会在Perl程式中,输出HTML内容,例如以下是一个简单的计数器:

  1. #!/usr/bin/perl
  2. open(FILE, "count.txt");
  3. $num = <FILE>; $num++;
  4. close (FILE);
  5. open(WRITETO, ">count.txt");
  6. print WRITETO "$num";
  7. close (WRITETO);
  8. print <<PRINTAREA;
  9. content-type:text/html\n\n
  10. <style>
  11. <!--
  12. body {background-color: black; line-height:1;
  13. margin-top: 0cm;
  14. margin-left: 0cm;
  15. margin-right: 0cm}
  16. -->
  17. </style>
  18. <body><center>
  19. <b><font size=1 color=white>
  20. $num</font></b>
  21. PRINTAREA

读者可以发现,这样的方式在HTML内容佔多数的情况,显着十分不容易维护及阅读。大约在2000年左右,PHPASP等以样板(Template)为主的程式语言出现了,同时期搭配着关联式数据库如MySQL一起流行起来。这种写法与上述的Perl CGI恰巧相反,是在HTML样板中内嵌入程式和SQL指令,例如以下是一个PHP&MySQL程式,其中用<?php … ?>括起来的部份,就是PHP程式:

  1. <?php
  2. $db = mysql_connect("localhost", "root", "password");
  3. mysql_query("SET NAMES 'utf8'");
  4. mysql_select_db($SERVER['db']);
  5. ?>
  6. <html>
  7. <?php
  8. $sql="select * from news where Class='1' or Class='3' order by CTDate desc limit 0,5";
  9. $result= mysql_query($sql);
  10. while ( $arr=mysql_fetch_array($result) ) {
  11. echo <<<NEWSEND
  12. <div class="box">
  13. <span class="box-title-1"> <b>$arr[Title]】</b> $arr[CTDate] </span>
  14. <div class="box-content">
  15. $arr[Text]
  16. </div>
  17. </div>
  18. NEWSEND;
  19. }
  20. ?>
  21. </html>

这种用法非常容易使用。特别像是讨论区、部落格(Blog)、内容管理系统(CMS)Wiki这类系统,重点主要在资料的保存和显示,牵扯的复杂商业逻辑不多,特别适合这样的开发方式。程式只是数据库系统的糖衣接口,不需要MVC架构、不需要页面与程式逻辑分开、不需要物件导向技术,也可以开发的很好。

但是近年来随着Web 2.0和云端风潮带来越来越多的Web应用程式开发需求,网站软件的规模开始增加,需要加入更多的商业逻辑和功能,这样的开发方式,导致了整个专案的结构变得十分混杂,不利于团队合作开发。要接手维护这样的网站,常常会不知道如何阅读及修改起,因为所有的商务逻辑与HTML混杂在一起,不同人开发就有不同的程式架构,缺乏程式文件是常有的事情,也不容易进行测试。

于是我们有了Web开发框架的需求,引入完整的物件导向观念和技术。而所谓的框架就是制定好了一套规范和惯例,让开发者在该架构下来进行开发。

维基百科是这样定义的:「软件框架(Software framework)」是为了实现某个业界标准或完成特定基本任务的软件组件规范,也指为了实现某个软件组件规范时,提供规范所要求之基础功能的软件产品。框架的功能类似于基础设施,与具体的软件应用无关,但是提供并实现最为基础的软件架构和体系。软件开发者通常依据特定的框架实现更为复杂的商业运用和业务逻辑。这样的软件应用可以在支持同一种框架的软件系统中运行。

非常多的Web框架都实践一个叫做MVC的软件架构设计模式,将软件分成三个部分:

  • Model物件包装了资料与商业逻辑,例如操作数据库
  • View表示使用者接口,显示及编辑表单,可内嵌Ruby程式的HTML
  • Controller负责将资料送进送出Model,处理从外界(也就是浏览器)来的HTTP Request请求,与Model互动后输出View(也就是HTML)

MVC diagram

这张图示中的执行步骤是:

  • 浏览器发出HTTP request请求
  • 负责处理的Controller操作Model资料
  • Model存取数据库
  • Controller将得到的资料餵给View样板
  • 回传最后的HTML成品给浏览器透过MVC模式,我们可以有系统的组织程式码,并且分离商业逻辑和使用者接口,让前端与后端开发者可以独立作业,也让程式码有着一致性的结构,档案位置清楚,这些惯例Web框架都帮你想好了。有了程式规范,也就比较容易维护开发了。

也有不实践MVC的小型Web框架,通常称做Micro-framework,例如Sinatra,我们会在Ruby锦囊妙计一章中简单介绍这个不同思维的Web开发框架。

桌面软件的MVCWeb MVC有一些差异,主要是因为Web MVC中的View没有办法透过Observer模式来进行更新。有兴趣的朋友可以参考Model View Controller: History, theory and usage这篇文章。

Web框架通常包括以下功能,

ORM

ORM(Object-relational mapping)可以用物件导向语法来操作关联式数据库,容易使用、撰码十分有效率,不需要撰写繁琐的SQL语法,也增加了程式码维护性。例如:

  1. SELECT * FROM orders, users WHERE orders.user_id = users.id AND orders.status = "Paid" LIMIT 5 ORDER BY orders.created_at;

这一段SQL叙述,在Rails中的语法是:

  1. Order.where(:status => "paid").includes(:user).limit(5).order("created_at")

URL路由

不同于PHP直接使用档案目录结构来对应网址,例如网址是/foo/bar,就得有个档案在/foo/bar.php下。这种一对一的方式虽然直觉,但是却大大限制了程式架构和开发,网址也常常不漂亮,不利于SEO(Search engine optimization)

使用Web框架则没有这种问题,你拥有最大的弹性,您可以指定任意URL对应到任一个Controller的动作,跟档案位置是无关的。

此外,Web框架也附带了非常多开发Web会用到的函式库,例如TemplateEmailSession、快取、JavaScript/Ajax、测试等等。这也是为什么使用Web框架可以大大加速网站专案的开发时程,因为开发Web应用程式会用到的功能大部分都内建了,我们不需要重复开发轮子。

什么是Ruby on Rails?

Ruby on Rails(官方简称为RailsRoR非官方简称)是使用Ruby这套开放原始码(采用MIT授权)、物件导向程式语言所开发的Web开发框架,主要用于开发数据库网站应用程式。Rails是一套专业的开发框架,采用了MVC(Model-View-Control)模式、内建支援单元测试和整合测试、支援AjaxRESTful接口、ORM机制,以及支援各种最新的业界标准像是HTML5JQuery等等功能。它的发明人是David Heinemeier Hanson(DHH)DHH2004年将Rails37signals商业产品中独立出来成为开源专案。

它的设计目标是只要开发者熟悉它的惯例,它就可以让网站开发变的非常容易。而相对于其他程式语言和框架,Rails可以让你用更少的程式码达成更多的功能,它甚至让网站开发变得更有趣。

Rails的哲学包括以下指导原则:

  • 不要重复自己(DRY: Don’t Repeat Yourself) – 撰写出重复的程式码是件坏事
  • 惯例胜于设定(Convention Over Configuration) – Rails会默认各种好的设定跟惯例,而不是要求你设定每一个细节到设定档中。
  • REST是网站应用程式的最佳模式 – 使用Resources和标准的HTTP verbs(动词)来组织你的应用程式是最快的方式(我们会在路径一章详细介绍这个强大的设计)

为何选择Rails?

这是一个开发框架的时代,熟悉开发框架的人,可以很快的完成任务以及熟悉网站程式的架构。而各种程式语言要入门上手,其实都不会太困难。我认为重点会在于你不能够熟悉做事情的框架。

所以,撇开程式语言的偏好,Ruby on Rails是目前网站开发框架中做前端(提供动态HTML给浏览器)应用服务器最为成功和技术先进的。它的概念也深深影响了非常多其他程式语言的后进网站开发框架,例如ASP.NET MVCCakePHPGrailsTurboGearsPylonsweb2pycatalyst等等(模仿是最大的恭维)。我们可以用非常有效率的程式码开发出网站应用程式。另外,可能会让你感到意外的是,它也是目前动态语言中,生态圈最为丰富的网站开发框架,相关的书籍、研讨会、顾问公司、第三方服务、外挂套件等等十分丰富。因为使用Rails的人数众多,所以在开发上各个方向都有人提供了最佳实务,像是如何写出好的程式码、网站安全性、网站性能、扩充性、全文搜寻、异步处理等等,这是一个非常活跃的社群。

当然,最重要的一个理由,就是采用Rails后生产力暴增:写新的应用程式、增加新功能变成容易地多。让你可以用更少程式码做更多的事情,而且程式也更容易维护。当然,学习新工具总是需要时间投资的,一开始可能没办法立刻见效。但是如果你有长期的开发工作,而且网站有一定的复杂性,那么一个短期学习Ruby on Rails的投资,长期来说将会是非常值得的。

Rails 不是什么

  • 如上所述,Rails是一个打造网站应用程式的开发框架,如果你只需要静态的HTML,那是绝不需要用到Rails的。
  • Rails不是CMS(Content Management System)内容管理系统。CMS是一套写好的架站系统,可以让你不需要写程式就可以架站。市面上流行成熟的CMS系统多为PHP写成,例如DrupalWordPress等。当然也有用Ruby写的,例如Radiant。如果这些架站系统刚好符合你的需求,那就不一定需要Rails
  • Rails是一套网站开发框架帮助你建立网站应用程式,它不是程式语言。

什么是Ruby?

Rails是一套使用Ruby开发的网站框架。如果您对Ruby一无所知就一头栽进Rails,恐怕不是个好主意。

Ruby是一套开放原码、物件导向的动态直译式(interpreted)程式语言,它有着简单哲学、高生产力、精巧、自然的语法。他的创造者是来自日本的松本行弘(又名Matz),设计的灵感来自于LispPerlSmalltalk,设计的目的是要让程式设计师能够快乐地写程式。

让我们看一个非常简单的范例:

  1. str = "May Ruby be with you!"
  2. 5.times { puts str }

这的范例就简单告诉我们有关Ruby的三件事情了:

  • 动态分型(typing),不需要宣告型态
  • 每样东西都是物件,包括数字
  • 使用Code Block形式的匿名函式(anonymous function)随处可见

我们会在Ruby一章介绍基本的语法,让各位读者可以很快的入门。

动态语言的好处

为什么开发服务器端应用程式,使用动态语言(RubyPythonPHPPerl等)比起静态语言(JavaC++等)有更好的优势呢?

静态语言和动态语言的差别在于,前者的变量型别需要事前宣告,后者则是执行期才动态决定。实务上,就看程式需不需要事前编译这个动作了。

着名的”人月神话”一书作者Fred Brooks曾说:「一个程式设计师一天能产生的程式码行数是差不多的,无论什么程式语言」。因此一个具有表达能力的高阶程式语言,就会比低阶的程式语言能完成更多功能。相较于静态程式语言,使用更高阶的动态脚本语言可以帮助我们:

  • 用更少程式码做更多事情,大大增加生产力
  • 更快因应客户开发需求,敏捷开发不过,动态语言也不是没有缺点:

  • 执行效能是绝对比不上静态语言的

  • 没有编译期可以检查型别错误但是,我们知道现在的电脑越来越快、越来越便宜、上网越来越容易、内存越来越多、硬盘越来越大。另外,行动装置也越来越多,需要搭配的网络服务需求也增加了。这些趋势告诉我们有更多的软件的需求,另一方面由于硬件效能的增强,人力开发成本比起软件的执行期的效能,也越来越重要。同样一个程式,用动态语言执行的效能已经可以达到实用(例如每秒可以处理50~500个的HTTP请求,也可以透过增加服务器来扩展架构),也许用静态语言后的执行速度可以再快一倍,但是却需要十倍以上的时间来开发,这件事情是不是值得呢?

在硬件资源有限的行动装置及嵌入式系统上,仍是静态语言的天下,这一点需要更多时间才有动态语言的生存空间。

没有编译期可以检查型别错误的问题,也随着单元测试和TDD(Test-driven development)测试驱动开发等敏捷最佳实务而逐渐降低重要性。而大部分的Bug会出自于商业逻辑错误,而不是型别错误上。

为何选择Ruby?

Ruby 是一套非常重视使用性(Usability)的物件导向程式语言,非常看重程式码的可读性及维护性。Matz在设计Ruby时,就特别考量一般人容不容易了解(他说我们都是凡人,像Lisp是给神人用的)。这也是为什么你常常会听到Ruby的程式码自然简洁又漂亮。您可以看看这份 Ruby创造者MatzWhy Ruby?投影片或是Matz的演讲:RubyConf 2008RubyConf 2009Mountain West Ruby Conference 2010,相信您会更了解及喜爱Ruby的哲学。

Ruby也是目前做Domain-specific language(DSL),特别是Internal DSL最为成功的程式语言。透过DSL,程式不但可以拥有非常好的可读性,也可以大幅增加生产力。成功的DSL函式库例如有:Rake建构工具、RSpec测试工具、Chef服务器设定工具、Cucumber验收测试等。这些函式库正积极地影响我们对软件开发的想法。我们相信,还会有更多更有趣的DSL函式库出现。