细数Ruby语言优缺点
解释以上这些究竟在做什么显得有些罗嗦了。但是我希望传递的是,使用ruby这个语言时候的体会。尽管你不能自己亲自尝试,但是你可以通过屏幕看到这一系列的过程。现在我想展示另外一个例子。我希望你们可以所看到的内容中,得到一些体会。如果你之前还没有尝试过任何一种脚本语言,那么我鼓励你去学习ruby. 我认为ruby是非常值得学习的。因为它是很容易学习和使用的,只需要花几分钟去学习。脚本语言的另一个特点是,你可以写一些代码,然后直接去看它的运行结果。Ruby是一个非常优秀的脚本语言。但是,我想ruby的意义不仅在于它是一个好的脚本语言。接下来的几分钟,我将讨论这个问题。
首先,我希望通过ruby的特性来讨论这个话题。这一点你可能已经从刚在的例子里面有所体会了。Ruby又很简洁的语法,这样你不需要写很多的代码,就能够获得很强大的功能。从刚才的例子里面就可以看到,在写参数的时候,你不需要写括号,当然,你也可以根本没有参数。这个特点可以使你快速的编写代码,但是更重要的是,你可以快速的阅读代码。我们可以对比java, c系列的语言,当你试图去阅读代码的时候,你的视线总是会被分散,并不容易弄明白代码究竟在做什么。松散的类型检查可以帮助我们更快,更好的理解代码。严格的类型检查可以导致更差的可读性。Ruby 在这之间做了很好的一个平衡。代码的可读性无论是对ruby而言,还是对使用ruby的开发人员来说,都有非常重要的价值。我认为用ruby写的代码是可读性很好的。这并不意味着ruby是一个很小的语言,就像smalltalk那样。Ruby是一门很复杂的语言。它具有很多复杂的语法特性,比如在同一行代码中实现多个任务这些小的语法点。如果你使用过其他的脚本语言的的话,(会发现)perl和python的特性都被带到了ruby中。这些给ruby的学习增加了难度。这又是一种新的平衡。在简单的语言里面表达事情是复杂的比如smalltalk, 然而,在ruby里,是很方便的,特别是在控制collection方面。在ruby里,List的语法是很方便的。我并没有展示hashtable在ruby中的使用,但是它们的用法一样是简单的。
有一点很受到关注,不像java,c#这些主流的静态类型的语言,你不需要在ruby中定义变量类型。它是具有严格的类型的。记得我们在刚才的实验里面举的例子,字符串类型进行减运算,是会被提示错误的。但是你只有在运行的时候才会被告知有错误存在,而不是在编译的时候。所以ruby有严格的类型。但是它的类型是动态的。所以你只有在运行时才能发现错误。这就造成了下面这一个结果,很多人担心在编写ruby的代码的时候是很难发现类型错误的,这不像我们通常在java和c#里面期待的那样。但是,我发现在大多数使用ruby的开发人中并不存在这样的问题,他们通过测试解决这个问题,尤其是单元测试。我本人是测试的拥护者,我会非常多的使用到测试,不是在当前这个小的演示程序里面,而是在以前的稍微大一些的项目里。如果你使用单元测试,你发现那些类型错误的速度将会像在编译中发现错误一样快捷。我非常喜欢这种特性,尤其是在一开始使用smalltalk建立大型系统的时候。只有在很少的情况下,测试是不能发现类型错误的。但是在这样的语言里面有一个缺点,在阅读代码的时候,你不容易理解程序究竟完成了什么,因为在操控这个变量的时候你不能知道他究竟是哪一种类型的。这意味着,ruby还不能像smalltalk那样有一些强大的调试工具,这样可以在调试环境里面步进的运行程序,看到变量的类型。总体来说,我喜欢动态语言带来的这种灵活性。对象可以被替代,在很多地方都可以作为各种类型被使用。但是在另一方面,它又提高了代码的可读性。当你试图去阅读代码的时候,它是比较容易被理解。这就需要看个人的喜好了,有的人喜欢使用静态的语言,有的人喜欢使用动态的语言。所以,你需要挑选一种更喜欢的语言。很多人认为种类是很重要的,我认为这并不是决定性的。
我认为,ruby的另外一个特性是它具有很强的面向对象的特性。Perl并不是一门面向对象的语言,尽管后来加入了一些面向对象的机制。Python也并不是完全面向对象的。但是ruby在一开始就是面向对象的。在这里我可以展示另外一段代码。(写了一段代码)。所以,在ruby里即使是Nil也有一个类,nothing也是一个对象。这就像smalltalk。一个对象和一个基本的构造类型(primitive build type) 的区别在于:在ruby中,对象就是全部。尽管你看我之前的一些代码是,你并没有看到初始化的代码。Ruby 就是这样被建立起来的。这里有另一个很不错的例子。(写了一段代码)。我们看到,在这里我们得到了一些很大的整数。你能在java里面用这么简单的语句实现么?不能,因为你需要考虑,当你的值增大到一定程度的时候,你应该如何处理。需要考虑类似于增大位数这样的事情。有趣的是ruby在后台这样做了,但是我们看不到。现在来输出它的类型,看看将会发生什么。(写代码)这样做可以使你的输出居中。这里我们看到,这些数字的类型一开始是”fixnum”,是比较小的整数类。当他增长到足够大的时候,它需要像在java里一样,变成比较大的类型bignum. 所以,这里能够显示具体的实现类。这就是动态语言的优势了,用smalltalk甚至可以做得更好,它可以根据你的需要,把数字类型转换分数,浮点类型等等。所以,ruby具有非常好的面向对象的背景。在这样的脚本环境中,可以使你的程序具有更好的结构。你可以有一个比较好的速度,好的机制,更好的结构,使你写出更好的结构性程序。这是不断结合的结果。
然而,不是ruby里面所有的东西都是好的,它有它的缺点。比较重要的一个问题是,它还没有一个非常好的开发工具,特别是在你熟练的使用它的编辑器之后,它不能够像java那样的开发环境,比如eclipse. 和我最喜欢的Intelligent J,提供智能的提示,能够引导程序员编写代码。这些在ruby的社区中还不存在。我当前推荐使用的是emacs。这对于人们来说绝对是一个缺点。这些取决于人们究竟投入多少资源。由此而引发的另外一个问题是,我们不能像在java和c#里面那样进行重构。在动态类型的语言里,进行重构是比较困难的。这也不是绝对的,第一个开发出重构功能的是smalltalk. 但是也并不完善。
Ruby的另外一个问题是,ruby在block上的时间并不快。在脚本语言的标准中中,它是一个门较慢的语言。但是这并不是一个很严重的问题。在我们开发的程序中,ruby被用来调用数据库。跟数据库的连接和硬件的一些功能相比,ruby还是具有比较好的性能的。但是在其他的一些方面ruby还不是最好的。人们把ruby的API内置到c的library中,是很常见的一种情况,像Perl和Python也是这样做的。
Ruby的另外一个不足之处在于处理Unicode. Ruby 处理Unicode是很糟糕的。我刚在演示的程序实际上是使用ACSII类型的字符串。你不能像很多人那样使用Unicode进行代码。它并不像采用起来那么容易。这个问题将会在下一个版本中得到解决,可是,至少目前看来,ruby不能像java和python那样,那么好的支持Unicode。
工具和DSL缔造Ruby魅力
最有趣的和最值得关注的地方在于它的库(library)以及框架(framework),一个web 开发的框架。在我们参与的一些项目里面,ruby on rails是一个可以带来高生产率的web开发框架。在开发企业应用时一个重要的问题是,数据库的代码和其他的代码被糅合在了一起。你必须控制这些代码,使数据库的请求是有效的。当数据库由另外公司不同的部门进行管理时候,这成了非常重要的问题。如果你对数据库有一定的控制,那么你可以你的环境就会变得混乱。Rails是专门针对某些种类的应用程序而设计的,而不是为了解决所有的问题。例如对于互联网应用,它有着特别的优势。
Ruby中的另一个吸引人的库,这也是我个人认为非常有用的是,它能够管理每一个build版本。在Unix环境中有一个非常著名的,就是可以构建C语言的程序。RAILS这个可以帮助我们描述一个build.我将要在一个小窗口里面展示这个特点, 这会非常有趣。这里是网站上的构建脚本。这里我定义个了任务和依赖。Default 任务依赖于all. all任务依赖于这些所有的任务。这里是任务的逻辑代码,它会去执行这一段代码。我们往下看,这里有help的函数,这里还有clean任务。熟悉ruby代码的人会熟悉这些都是在做什么。这里的task就是方法的定义。在default这里,你可以看到一个箭头指向all,你可以在一个hashtable里面找到对应。这里用到了closure(注:就是前面讲到的匿名方法)。所以特殊的build 语言,是有着特殊的用处的。Build文件有自己特别的属性。你希望列出所有task的分支结构,和依赖关系。任何人都想获取任务间的依赖关系,所以tag标记那一个任务是必须被执行的。我在ruby的代码里面定义这些任务。在内存中构建这些task, 然后必要任务会被执行。构建我的网站意味着构造700个文件。但是我可以知道哪一个文件是被修改过的,哪一个需要重新构建,然后做最小化的构建,得到我想要的结果。我们发现这个是非常有意思的,它可以记录很少的历史信息。这一类的比较早的语言是make语言,通常在Unix系统下使用。Make 是一种特殊的文件格式,用来描述怎样构建代码,它是一种特殊的domain语言,可以用来构建应用程序。它有它自己的格式和语法,描述怎么样构建C语言程序。Make存在一个问题,这就是它学习起来并不容易。你也很难去理解那些自动生成的makefile。但是很多程序都有自动生成make文件的能力,因为如果是你自己去写的话,是不容易掌握的。Java一开始是没有构建工具的。所以James Duncan Davidson写了ant用于java的构建。Ant的作者不想让构建涉及到语法的问题,他们使用xml作为构建的脚本。我并不是在抱怨这个问题,在那个时候xml是不错的选择。使用xml语法会有两个问题。因为语法是十分严格的,你需要花很多精力用于关注语法,所以读懂它执行的操作就变得困难了。另外的一个问题是,当系统越来越大的时候,build文件会包含很多逻辑,就给建立ant文件造成了困难。所以当系统变得很大,建立一个ant的文件来构建系统就会十分困难了。我们需要找到一种方式,从xml中释放出来,用来构建这些类。
Ruby 就是这样一个强大的语言,在有一定语法限制的情况下,去验证ruby的语法。Ruby并没有引入太多新的语法。这看起来还不错,因为你需要一门新的语言,来实现这个功能。但是你还是有一个局限,就是你不能在ruby以外使用它。但是另一个好处在于,当你需要做非常复杂的事情的时候,你可以使用ruby. 所以,你有更强大的能力来完成这件事情。这个外部的语言让你可以使用它的语法,使你逐渐变得更有能力应对。因为在越来越复杂的时候,它可以帮助你编译。这种能力是很容易获得的。它的语法是很直接的,你可以容易的学习。把这样的语言作为宿主(host)语言是一个很传统的想法了。但是这是很有用处的。
有的时候,使ruby能够吸引使用者并不是一件容易的事情。我成为ruby的爱好者已经有几年了。我致力于把它推广用于我们的工作中。我告诉别人我喜欢ruby,并且鼓励别人去使用它。但是在一个产品中使用或者不用并不是非常重要的。我并不推荐所有的工程都使用。但是在最近半年的许多项目里面,我们都使用了ruby. 我们发现,在一些工程里面ruby可能并不适合,但是在另一些工程里面使用ruby是非常适合的。这个核心在于,那些成功的案例证明,那样项目,才是ruby真正适合的。尽管Rails提供了一个大的框架,但是如果不用ruby的话,几乎不可能成功。这也是项目成功的原因之一。
我的同事正在做的一个项目是需要大量操作数据库的。把数据从数据库中取出来,在内存中进行计算,再把数据放回数据库是没有必要的。你希望用spl进行这些操作。而使用sql是有一定限制的。它很强大,但是不容易使用。Sql的一个最主要的问题在于,它完全基于domain. 它可以对表格式的数据进行很好的操作,但是没有把表抽象出来的能力。所以如果你想要对表进行操作,这个是非常好的。但是如果你想进行其他操作,就非常麻烦了。典型的例子是:具有层级结构的数据库是比较复杂的,用sql来操作它也变得复杂和困难。在这个项目里面,使用了ruby语言,允许输入domain specific language的ruby, 可以生成sql代码对数据库进行操作。这样的特殊的语言是非常好用的。领域的专家可以脱离出来,去阅读和理解这些代码,不用去考虑语法和究竟如何产生这些。可以把精力放在其他的地方。ruby这样的domain specific language的特点使它非常具有吸引力。
Ruby社区令人激动
现在来看几张照片来总结这个演讲。Ruby是一个有趣的系统。我不能说它适合用于任何地方,但是它的确适合用在很多地方。DSL是它的核心。一些特定类型的网站,特别是那些需要用到数据库的,还有使用RAILS框架的。几乎所有的administrating work 和 scripting work都适合使用ruby. 你可以开始使用ruby,因为他是一个非常强大的工具。Ruby是我见过的最好的脚本语言,你也会有同样的体会。在构建方面,Rake(注:ruby的构建工具)是非常好的构建工具。大约在六个月以前,我把我的网站全部换成使用它进行构建和维护这些构建的文件。我想你一定不会后悔的,因为构建和维护这些构建文件都是非常容易的。
在我完成这次演讲之前,我还有最后一件事情。当我谈论软件开发的时候,我一直在强调,无论你使用什么样的工具,什么样的实践,比如结对编程,测试驱动,关于软件开发项目成功与否的最重要的因素是工作在项目中的人以及这些人如何一起工作。在敏捷软件宣言中,首要的价值观就是个体与互交比过程和工具更重要,更有价值。Ruby值得关注的原因不在于它的特性也不是它的框架,也不是它带来的在RAILS中的生产率的提高,而是ruby社区成员的工作。Dave Thomas (注:<< pragmatic programmers >>一书的作者)多次提到了这一点,这是正式它吸引我的地方。我在最近的二三年内一直很感兴趣。Ruby社区吸引着越来越多高手的加入,从而使它本身不断进步。另一个优点在于,Ruby的开源作品都可以通过网络直接安装, 如果你想要使用,那么可以非常容易的通过RubyGem安装——这是一个package management system. (注:就好像debain的Unix package management system) 。Ruby的社群正在飞速成长,因为不断有优秀的成员加入到这个团队,在这个环境中工作,这使得这个团队非常值得关注。这也是我一直关注ruby的最主要的原因,因为很多值得关注的人都在这个社区里面工作。