Google首席架构师谈Java的命运

发表于:2011-3-14 09:33

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:chenqiuge    来源:51Testing软件测试网采编

  我编写了自己的锁管理器,所以我怀疑是它出了问题。但是锁管理器轻松地通过了测试。最后,我觉得问题不在锁管理器,而是它依赖的互斥体的实现!那时候操作系统还不支持多线程,我们需要写自己的多线程包。原来负责互斥体代码的工程师,不小心把我们的Solaris的线程实现中的lock和try-lock的汇编代码的标签弄混了。所以,每次你以为你在调用lock的时候,其实调用的是try-lock,反之亦然。也就是说当真的有争用发生的时候——在当年其实是很罕见的——第二个线程直接就进入了第一个线程的临界区,因为第一个线程也没有锁住。搞笑的是,这也就是说,整个公司几个星期都在运行没有互斥体的程序,而且谁都不知道。

  Knuth有句关于测试的名言,Bentley和Mcllroy的精彩论文“Engineering a Sort Function”中曾经引用过,大概意思是说,做测试时,要不惮以最大的恶意来推测所要测试的代码的错误。做这些测试的时候,我就是这么做的。但是这样会把所有东西纠结在一起,更难找到Bug。首先,并发的时候很难这么做,往往完全无法复现场景。其次,到最后可能会发现你的核心假设是错的。喜欢喊“耶,这语言出错了”或者“系统出问题了”是新手干的事儿。但是在这里,我依靠的基石——互斥体,确实出问题了。

  Seibel:也就是说Bug不在你的代码中,但是同时你只能对你的代码进行彻底的单元测试,因为你没有别的办法,只能去检查自己的代码。你觉得这些测试是不是可以,或者说应该让互斥体代码的作者来写,这样你就不用浪费一个星期,节省了一半的测试量,而且也可以找到这个Bug。

  Bloch:给互斥体代码加一个好的自动化单元测试肯定可以避免让我遭受那些痛苦,不过注意那可是90年代初。我想都没想过要抱怨那个工程师没写个好的单元测试。即使是今天,为并发工具写单元测试还是一种艺术形式。

  Java的命运

  当你改进一个成熟语言的时候,你必须更加仔细地考虑能力和复杂度之间的平衡。

  Seibel:既然你说到这里,Java是否逃脱了灭亡的命运了?它变复杂的速度是不是比变好的速度更快呢?

  Bloch:这个问题不好回答。具体说来,Java5加入了比我们设想的更多的复杂度。将泛型特别是通配符加到语言中到底有多复杂我也说不好。我得为有功劳的人说句话,GrahamHamilton真是了不起,那时候他就想明白了一切,而我不明白。

  有趣的是,他抗争多年,希望阻止泛型进入Java语言中。但是在泛型被成功地阻挡在Java外的这些年里变体的概念,也就是通配符的隐含意义流行了起来。如果它们来得更早,没有变体,也许我们现在可以有一个更简单的、更容易跟踪的语言。

  引入通配符有实际的好处。子类化和泛型之间根本就是阻抗不匹配的,通配符尽力在弥合这种不匹配。但是这么做又显著地增加了复杂度。有些人认为在声明空间,而不是用户空间,变体是更好的解决方案,但我不太相信这一点。

  这仍旧悬而未决,因为它们都还没经过在真实世界里海量的程序员们的测试呢。一些语言经常只在小范围内获得成功,人们会说:“噢,这些语言很不错,只是可惜没有成为世界范围成功的语言。”但是这往往是有原因的。希望使用Scala或者C#4.0,这样的声明空间变体的语言可以彻底解决这一疑问。

  Seibel:那么是什么推动Java引入泛型呢?

  Bloch:没看起来那么精彩啦,我们的新闻报道是可信的。我的思维模式是,“嗨,集合多半都应该是同质的——一组字符串,一个从字符串到数字的映射,等等。而现在默认情况下集合是异质的:它们都是对象的集合,取出时都需要类型转换,这简直是胡闹。”如果我可以告诉系统,这是一个从字符串到数字的映射,它会帮我做类型转换,而且会在编译期间帮我盯着,防止我做错什么,那不是挺好的吗?它可以抓到更多的错误——它可以包含高层的类型信息,看起来是件好事儿。

  我认为泛型和其他加入到Java5的语言特性一样,我们只是让语言去做以前我们要手工去做的事情而已。某些情况下我坚信:foreach就是好。它所做的就是对你隐藏遍历器和索引变量带来的复杂性。代码更短,概念也不复杂。从某种意义上说,它的概念更简单,因为我们为数组和其他的集合创建了这种伪多态机制,你可以遍历一个ArrayList或者一个数组,而无需关心你遍历的是什么类型。

  这种思想不能适用于泛型的主要原因是,它是对已经很复杂的类型系统的大扩展。类型系统是很微妙的,修改它们可能对语言带来深远的、难以预期的影响。

  我认为得到的教训是,当你改进一个成熟语言的时候,你必须更加仔细地考虑能力和复杂度之间的平衡。而且,实际上,复杂度跟语言的功能数量间至少是平方级关系。为一门老语言加上了一个新的功能,通常就意味着为它加入了一大堆复杂度。当一种语言已经达到或接近程序员理解能力的极限时,那么你加入任何复杂性进来都会加剧理解的难度。

  语言更复杂后就会消失吗?不会。我认为C++早已超越了它的复杂度极限,但还是有很多人用它编程。可这实际上是逼人们只使用其中一个子集。所以我认识的每个用C++的公司都说:“对,我们用C++,但是用的是多继承,不用操作符重载。”有很多功能你完全不用,因为使用它们会造成代码太复杂。即使不得不用那些功能,我认为也实在没什么好处。那样的话,程序员就读不懂别人的代码,也就不存在“程序员的可移植性”了。

42/4<1234>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号