一早看怪怪同学评论《ThoughtWorks文集》公开的样章,一谈多语言开发(第5章),二谈测试(第13章)。怪怪同学的看法是贬前者而捧后者,并提出“同样一个包装下、同一个公司不同的作者,差异如此之大,那么在我们的学习过程中,就要注意去芜存菁了”。说实话,我没有理解他对第5章的评价,如在“抽象方式”方面的说法我没有太深的理解。如果怪怪看到我这篇文章能够再详细说说抽象方法的看法就再好不过了——目前我只能说我同意他的论点(讨论软件思想学习这方面),但是没有理解他的论据,呵呵。

我对第5章有自己的看法,讲的是多语言开发。我是非常提倡多语言开发的,原因可能一是因为我是语言爱好者,二是因为.NET平台是多语言共存的一个良好环境,我以前也经常提出过用IronPython作动态逻辑的“宿主”,用F#作并行开发等等。因此,我是拥护“混合开发”的一个人。但是,很巧,对于这第5章,我还是同意它的论点(或描述),而不同意它的论据(即示例)。

例如,书中举的第一个例子是使用Groovy的方式读取文打印文件每一行,并在每行之前加上行号:

def number = 0
new File(args[0]).eachLine { line ->number++println "$number: $line"
}

与书中举出的二十多行Java代码(样章的代码是图片,我不想敲一遍了)相比,Groovy的确是简单了很多。但是在我看来,这个例子是很不妥当的。如果您看一下书中的Java代码就会发现,复杂的Java版本是在于使用了类似C#中StreamReader的做法,以及一个古怪而复杂的LineNumberReader,需要打开文件,再一行一行地读,并且加上异常处理。为什么不使用一个number变量,而且Groovy代码的异常处理在哪里呢?也就是说,Groovy版本并没有完成Java版本所处理的所有问题。

当然,有人可能会说,我们目标是完成工作,本就不需要关心异常,而Java中的异常处理代码是因为语言特性,迫使我们必须这么做。但问题就在于,这其实涉及的是“类库”方面的内容。例如,您看这段C#代码:

int number = 0;
foreach (string line in File.ReadAllLines(@"C:\test.txt"))
{number++;Console.WriteLine(number + " " + line);
}

这和那段Groovy代码有本质区别吗?但是,在这里代码里有没有使用Java所无法实现特性呢?没有。也就是说,Java代码麻烦是麻烦在“缺少类库”,而不是“语言特性”。因此在我看来,用这个例子证明Java是种生产力低下的语言是不恰当的——远不如我之前谈委托时的示例有说服力。

样章中还举了其他一些例子,如判断是个字符串是否为空所使用的isBlank方法,Java需要写在一个额外的StringUtils类中,而Ruby直接打开String类型并添加新方法就可以了:

class Stringdef blank?empty? || strip.empty?end
end

这个示例与Jaskell(JVM上的Haskell语言)中SafeArray的示例相对就有说服力多了——但是它后面又举了一例:Haskell的函数惰性求职特性可以轻易生成无限长的列表:

makeList = 1 : makeList

这点在Java语言中就不可以了吗(您可以用C#语言想一下可以怎么编写一个辅助方法来实现这个功能——但不要使用yield)?我在读这些文字的时候会有一种感觉,作者是一个动态语言的爱好者,但是在举这些示例的时候并没有想过这些示例的说服力如何,是否真的可以体现出与Java的差距,这差距究竟是语言上的还是类库上的。

而在下一个使用Ruby进行单元测试的示例中,我脑子里差点就冒出“骗子”两个字。为什么这么说呢?首先,您可以去看看样章里Java和Ruby两个语言的测试代码。如果您熟悉单元测试,如果你可以区分Mock和Stub两个概念的区别,您应该也可以看出其中的问题来。

简单的说,Java代码的单元测试使用的是Mock,使用了非常接近于Record/Playback的方式,而Ruby代码使用的是Stub,是单元测试的AAA(Arrange,Act,Assert)模式。Record/Playback是早些年较为流行的测试方式,它首先通过Mock对象“录制”待测试对象的行为,然后交给待测试对象进行测试,最后验证它和“录制”的结果是否相同。这种做法本身就较为复杂,因此目前在很多情况下已经被AAA给替代了。从名字上便可看出,AAA的做法是先安排,再行动,最后验证。它关心的只是被模拟对象“在某些调用时的反应”,而并不在意被模拟对象的整体行为。打个比方,在样章中举的Java示例,其中有这样的代码:

warehouseMock.expects(once()).method("remove").with(eq(TALISKER, eq(50)).after("hasInverntory");

看到这个after语句了吗?这个after表明remove方法的执行需要在hasInverntory方法调用之后执行。这就是Record/Playback的特征之一:“录制”的行为是可以要求严格按照顺序的。而AAA模式只关心待模拟的对象在某些调用时的反应状况(所以叫做Stub),因此它在“顺序严格”的情况下反而会麻烦一些。例如,如果您要确保一个ITransaction对象的Commit方法必须在Begin之后调用,使用AAA的方式,可能就要自己准备一个order变量,在Begin和Commit方法中引发回调,并检查order的当前数值了。

在来看看Ruby的代码,它使用的便是Stub,并且——它并没有去确认remove方法和hasInverntory方法的调用顺序。如果要确认的话,使用的代码便会复杂一些了。也就是说,Ruby版本使用的本身就是简单的AAA模式,且功能实现的并不如Java版本的完整。以此说明Ruby用于测试更加方便,是不是有点“忽悠”的嫌疑呢?

顺便一提,大名鼎鼎的Oren Eini正打算Rhion Mocks 4.0的开发,计划之一便是移除Record/Playback模式的支持,仅保留AAA方式。而后起之秀Moq框架从一开始就只支持AAA方式。

上周我读了样章的作者Neal Ford的另一本书《卓有成效的程序员》(一本200多页的小册子),其中“元编程”一章中他也提到了使用Groovy进行单元测试比Java方便很多,在我看来这同样也是类库的问题。因为Groovy可以使用普通方法调用的方式去访问一个对象的private成员,而Java中使用反射会麻烦很多(和C#差不多,因此您可以想象一下)。但是,这完全也可以通过补充一些辅助方法来完成工作。此外,Java代码中最麻烦的还是checked exception特性,Neal使用的Java代码中大部分还是在try...catch。

《卓》是好书,但是Neal在两本书中对多语言编程的论述的确不能让我感到满意。可能混合编程是个大话题,不是一句两句话能说清的吧。

最后,样章提出ThoughtWorks的第一个商业产品Mingle使用了JRuby进行开发,但我认为这不是混合编程的优秀示例。因为——它还是只用了Ruby,即使是运行在JVM上,Ruby语言还是Ruby语言。因此Mingle的成功可以证明JVM上运行Ruby的可靠性,可以证明Ruby的生产力比Java高,但我认为它不能作为混合编程的典型案例。

我想讲的东西讲完了,其实挺矛盾的。一则是我在为自己一直鄙视的Java说好话,二是我“反对”了别人对混合编程的论证,而混合编程也是我一直提倡的东西。不过,毕竟要达成目的也必须通过正确的方式。对就是对,错就是错,虽然我坚持技术人员的信仰,但我也认为个人情感不应该左右判断。如果我看到鄙视Java的说法就叫好,那和某些人无端对微软技术搞FUD又有什么区别。

转载于:https://my.oschina.net/abcijkxyz/blog/721374

谈谈我对《ThoughtWorks文集》中多语言开发部分的看法相关推荐

  1. linux中c语言开发实验报告,Linux下C语言编程实验报告.doc

    第五章: Linux下的C语言编程 姓名: 学号:520913080429 专业:信息安全09-04 实验内容: 1.c语言编程 2.vi编辑器 3.gcc编辑器 4.gdb编辑器 5. gdb中运行 ...

  2. GPS服务端解析程序编写日记之--vs2010中多种语言开发及调试的若干注意事项

    最近在写一个gps协议的解析程序,因为先前的库文件大部分都是用C#写的,而考虑到系统运行的速度,及窗口界面的操作的方便性.有关界面的部分,我准备用cli/c++写,毕竟c++与api打交道还是方便的. ...

  3. 软件开发沉思录--ThoughtWorks文集

    软件开发沉思录--ThoughtWorks文集 市场价 :¥39.00 会员价 : ¥29.25(75折) [原出版社] Pragmatic Bookshelf  [作 者]ThoughtWorks公 ...

  4. 《软件开发与创新:ThoughtWorks文集:续集》

    <软件开发与创新:ThoughtWorks文集:续集> 基本信息 原书名:The thoughtWorks anthology, volume 2:More essays on softw ...

  5. python中的语言特性_python自测——语言特性

    语言特性 1.谈谈对 Python 和其他语言的区别 答:Python 是一门语法简洁优美,功能强大无比,应用领域非常广泛,具有强大完备的第三方库,他是一门强类型的可移植.可扩展,可嵌入的解释型编程语 ...

  6. 谈谈对CNN在NLP中可行性的理解

    谈谈对CNN在NLP中可行性的理解 谈到CNN,人们的直观感受还是其在图像处理领域取得的巨大成就,虽然近几年越来越多的论文使用到CNN与RNN的模型来探索卷积网络在自然语言处理中的应用,但始终还是无法 ...

  7. 计算机多媒体对语文教学的提高,谈谈多媒体在语文教学中的运用(教师中心稿)...

    二十一世纪的今天,信息技术与语文学科的有机整合,给语文教学带来了新的生机与活力.如何科学.艺术使用现代技术,以及让这些技术更完善地与课程整合在一起,是我们每个语文教师都需努力的方向.进入信息时代的今天 ...

  8. Silverlight 2中多语言支持实现(上)

    引言 最近项目要在Silverlight 2应用程序中实现本地化,原以为这个过程非常简单,却没想到实现的时候一波三折,好在结果还算不错.需求是这样的,用户第一次访问的时候,默认为英文,当用户选择一种显 ...

  9. 在Visual Studio 2012中使用VMSDK开发领域特定语言(一)

    前言 本专题主要介绍在Visual Studio 2012中使用Visualization & Modeling SDK进行领域特定语言(DSL)的开发,包括两个部分的内容.在第一部分中,将对 ...

  10. 频率计c语言程序,数字频率计中C语言编程的研究

    在单片机应用系统中利用C语言编程具有一定优点.介绍了用C语言实现数字频率计的软件设计.介绍了C语言使用中几个关键问题.并对数字频率计的主程序.显示程序中小数点处理程序进行了论述.全部软件编程不是采用常 ...

最新文章

  1. debian10 简单的bash脚本监控apache运行状态
  2. [C# 网络编程系列]专题十一:实现一个基于FTP协议的程序——文件上传下载器...
  3. 为什么你应该深入Github
  4. linux环境下python的部署
  5. Android开发之第三方推送JPush极光推送知识点详解 学会集成第三方SDK推送
  6. excel二极管伏安特性曲线_晶体二极管的识别与检测方法图解
  7. 撒花!吴恩达《Machine Learning Yearning》英文版完结!
  8. php ascii hex编码
  9. linux禁止其他主机ping自己
  10. oracle中的sga和pga
  11. alpine_glibc 构建sun jdk 8的docker镜像
  12. 用几张图片教你,财务分析的平台、架构、指标体系、模型
  13. 容器化时代到来!跳转机分配问题终于“有救”了
  14. Kylin设置JDBC配置greenplum数据源
  15. 拆解任務與目標、按時完成,不再被deadline追著跑
  16. HDU 1240 Asteroids!(DFS简单搜索)
  17. 操作系统笔记(王道考研) 第一章:计算机系统概述
  18. Eclipse配置反编译
  19. 实现echarts中国地图迁徙图
  20. 计算机丢失bass,dll,bassasio.dll(缺失bassasio.dll文件修复工具)V1.0 正式版

热门文章

  1. Linux网络基础知识
  2. 使用netmeeting进行网络培训
  3. Go语言躲坑经验总结
  4. 浅谈程序猿简历的写法,你会如何写你的简历呢。
  5. 使用sql语句对数据库脱敏
  6. python结巴分词_“结巴”分词:做最好的Python分词组件
  7. 易康eCognition9.0安装教程-附软件安装包
  8. 深度学习——PReLU激活
  9. android 自定义圆形进度条,Android自定义控件实现圆形进度条
  10. 神州计算机u盘启动,神舟台式电脑怎么bios设置u盘启动教程