Ruby on Rails简介

Ruby on Rails 简介

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

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

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

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

#!/usr/bin/perl

open(FILE, "count.txt");
$num = <FILE>; $num++;
close (FILE);

open(WRITETO, ">count.txt");
print WRITETO "$num";
close (WRITETO);

print <<PRINTAREA;
content-type:text/html\n\n
<style>
<!--
body {background-color: black; line-height:1;
margin-top: 0cm;
margin-left: 0cm;
margin-right: 0cm}
-->
</style>
<body><center>
<b><font size=1 color=white>
$num</font></b>
PRINTAREA

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

<?php
  $db = mysql_connect("localhost", "root", "password");
  mysql_query("SET NAMES 'utf8'");
  mysql_select_db($SERVER['db']);
?>
<html>
  <?php
    $sql="select * from news where Class='1' or Class='3' order by CTDate desc limit 0,5";
    $result= mysql_query($sql);
    while ( $arr=mysql_fetch_array($result) ) {
      echo <<<NEWSEND
        <div class="box">
          <span class="box-title-1"> <b>【$arr[Title]】</b> $arr[CTDate] </span>
          <div class="box-content">
            $arr[Text]
          </div>
        </div>
      NEWSEND;
    }
  ?>
</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 开发框架。

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

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

ORM

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

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

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

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 会用到的函式库,例如 Template 、 Email 、 Session 、快取、 JavaScript/Ajax 、测试等等。这也是为什么使用 Web 框架可以大大加速网站专案的开发时程,因为开发 Web 应用程式会用到的功能大部分都内建了,我们不需要重复开发轮子。

什么是Ruby on Rails?

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

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

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

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

为何选择Rails?

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

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

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

Rails 不是什么

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

什么是Ruby?

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

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

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

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

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

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

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

动态语言的好处

为什么开发服务器端应用程式,使用动态语言(Ruby 、 Python 、 PHP 、 Perl 等)比起静态语言(Java 、 C++ 等)有更好的优势呢?

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

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

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

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

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

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

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

为何选择Ruby?

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

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