[译文]开发者见解系列,第2部分:谈谈编码(下)

原文:The Developer Insight Series, Part 2: Code Talk

作者:Janice J. Heiss

出处:http://java.sun.com/developer/technicalArticles/Interviews/devinsight_2/

 

Victoria Livschitz:编程语言不仅仅是面向对象那么简单



关于Victoria Livschitz

Victoria LivschitzGrid Dynamics的创始人和CEO,在过去超过15年的时间中,她曾是一位多个企业的创建者、革新者以及Java技术和网格计算方面的行业权威专家。

2006年创建Grid Dynamics之前,她在Sun Microsystems作为主要的技术专家工作了10年,担任了多个高级职位,其中包括一些大客户的首席架构师。在Sun任职期间,她还进行了下一代计算机语言的原创性研究,并设计了一种新的编程语言Metaphors1994年作为一个高性能计算工程师她在Ford开始了自己的职业生涯。

Livschitz是几个有名的工程优秀奖的获得者,其中包括FordChairman AwardSun的系统工程师年度奖,她在网格技术方面拥有多项专利。

她拥有Case Western Reserve University大学的计算机科学学士学位,她还曾就读于Vilnius University大学、Kharkov State University大学、 Purdue University大学和Stanford niversity大学,主修应用数学、电子工程和计算科学等。

 

Jaron Lanier辩称,我们不可能编写有大量代码的大程序却不会创建出许多的bug,他的结论是这表明有些事情从根本上就是错误的。

 

我完全同意Jaron的论点,软件的规模和它的质量之间的相关性是压倒性的并且非常具有启发性,我认为他的看法提出了几个问题:为什么大的程序会如此多bug?且不仅是bug多,且多到了超出可挽救的程度。是否存在一种内在的复杂因素使得bug在数目、严重性以及如何难于被诊断方面成倍地增长?如果是这样的话,我们如何来界定复杂性并进行处理?

Jaron强调,用模式识别来代替在目前的编程中占统治地位的刚性且容易出错的二进制“匹配/不匹配”构造,这引起了我的兴趣,特别是因为我一直认为,模糊逻辑原则应该被更广泛地应用在软件工程中,不过,我对Jaron的问题的答案的寻求看起来似乎是产生了与他自己的回答正交的想法。

我可以确定两种合理的创建复杂程序但又不会带来太多bug的方式,如同在医学方面,既有预防也有治愈,涉及预防和治愈的目标和手段这两者是如此不同,因此应该对他们进行各自的考虑。

预防措施努力确保bug不可能会出现在首个地方,在过去的20年中,这方面已经取得了很多进展;诸如允许编译时指定安全检查的强类型化、自动管理内存的垃圾收集器,以及在可追溯和可恢复事件中捕捉和传播错误的异常机制等这些编程实践确实是使得编程更加的安全。

Java语言当然是有着一流系统安全性品质的现代通用编程语言的代表,相对于它的前任C++来说这是一个巨大的进步,关于可视开发工具方面也有许多值得一提,他们简化并自动化了编程的比较单调和比较容易出错的方面。

尽管如此,这些技术上的进步仍不足以处理许多类型的bug,你看,一个“bug”通常就是程序不符合要求的行为举止的识别标志,这种“不合需求性”可能确实是由机械性问题引起的,在这种机械性问题中,代码做了有别于它原打算要做的事情,但更多的时候,代码当时做的正是程序员期望的事,结果(最后)却被证明实际上是糟糕的主意。

前者是一种编程方面的bug,而后者则是设计上的bug,或者在某些特别致命的情况下,是架构方面的bug。与Microsoft产品相关的那些不断出现的安全相关的问题是要归因于其产品的基础平台架构。Java技术则相反,其在病毒方面有着特殊的免疫力,这是因为它的沙箱架构的缘故。

我不认为在软件工程方面的未来进步会防止开发者犯下导致设计上的bug的错误,随着时间的推移,任何成功的软件都要进化以解决新的问题,一段在早期版本中正确运行的代码突然证实是有缺陷的——或者是有bug的,这很正常!编程领域的实际情况已经发生改变,因此程序也必须要改变,bug只不过是新发现的偏差的表现而已,它必须是预期会发生的,千真万确!从这一有利点来说,并不是bug的预防,而是修复——优雅地消灭他们的能力——才是最重要的。

至于修复,我不认为近期会有技术上的突破。多态性和继承帮助开发者编写新的类而无需影响到程序的其他部分,然而,大部分bug的修正都要求某种程度的重构,而这总是危险且难以预料的。

 

作为软件bug的主要起因的复杂性的概念是怎样的?你有一些关于如何降低复杂性的具体想法吗?

 

嗯,我认为有两种主要的手段。其一是来自开发者观点的直观的编程经验,另一种是把整体分解成较小的单元的能力,以及把独个的单元聚合成一个整体的能力,让我先从编程经验说起。

当我们能够在远低于全神贯注、全力以赴、艰苦思考的意识水平之下,凭直觉运作时,事情看起来是很简单的,因此,复杂的对立面——以及对付它的最好手段——是直觉。软件工程应该源于直观的编程经验,能够轻松地应付复杂的程序的编程者并不认为程序有多复杂,这要感谢我们的感觉和认知能力工作的方式,森林是一个复杂的生态系统,但对于一般的徒步旅行者来说,树林看上去并不复杂。

 

你认为现代的编程语言,特别是Java语言能在多大程度上帮助开发者隐藏掉复杂性?

 

不幸的是,我认为现代计算机科学和软件工程未能在这方面取得重大进展,所有主流的编程语言的语法都相当深奥,能够轻松应付纯粹抽象的语法的数学家需花费多年紧张学习以掌握某些特定的技能,但编程者不像数学家,编程者被教导成非按照绝对的证据而是按照工作的隐喻来进行思考。为了理解系统如何工作,编程者不是创建出一个数学方程系统,而是找出她或者她作为一个人所“感受到”的现实生活所象征的正确的东西。编程者是一些“普通”的家伙——他们不得不是这样,因为编程是有上百万人从事的职业,其中的许多人没有大学学位。深奥难解的软件的规模难以扩展到百万的级别,在编程人员方面不行,在代码的行数方面也不行。

现在回到你的问题上来,长期以来,编程者一直在熟练地使用着子例程、函数、数据结构、循环以及其他的一些完全抽象的构造,这些构造忽略了——不,是失去了这一感觉——人的直觉。后来面向对象(OO)编程开始启用了,开发者第一次能够创建效仿现实世界的元素的编程结构——在名称、特征及与其他对象的关系方面。即使是一个非编程者也能够在基本层面上理解“银行账户”对象这一概念,直观的理解事物之间的意义及关系的能力是人所共识的杀手锏,如果在这场反对复杂性的战争中有制胜的法宝的话。

面向对象编程允许开发者创建的行业软件远比过程化编程允许创建的复杂得多,不过,我们看起来好像已经到达了OO的失效点,没有人能够毫无费劲地与有着成千上万的类的系统打交道,因此,很不幸地,面向对象编程有着一个基本缺陷,具有讽刺意味的是,这却是与它的主要优势相关的。

在面向对象的系统中,“对象”是唯一的基本抽象,某个领域总是被简化成一组预定义对象类的集合,其中的一些是另外一些的结构性超集。这种模式的简单性即既是祝福也是诅咒,爱因斯坦曾指出,解释应该尽可能地简单,但不能过于简单,这是非常微妙的一个观点,却常被忽视,通过对象集合来解释世界正是太简单了!这个世界比我们能够用面向对象语法来表达的丰富得多了。

考虑一下人们普遍用来理解和描述所有系统的几个常见的概念——这些概念并没有与对象这一模具相吻合。“之前/之后”范式,同样的还有“前因/后果”范式,以及“系统状态”的概念等都是这其中最明显的例子。事实上,“煮咖啡”、“组装车”或者“漫游者登陆火星”等过程并不能被分解成简单的对象,是的,他们是通过OO语言来这样做了,但这是人为的且是违反直觉的。例程本身的先后顺序——什么在其之前,其处于哪种条件下,该条件基于什么样的因果关系——在OO中只不过是没有意义的表示,因为OO没有先后顺序、状态或是前因的概念。

在现实世界和编程中过程都是非常普遍的,多年来一些复杂精致的机制已被设计出来处理事务、工作流、流程编排、线程、协议以及其他固有其“过程式”的概念。这些机制当他们企图弥补OO编程中固有的不随时间改变的缺陷时就会引发复杂性,相反,通过允许过程特有的构造,比如“之前/之后”、“前因/后果”,以及也许还有“系统状态”等作为语言的核心部分,这个问题应该就能得到解决。

我设想的编程语言是比OO更为丰富的一个级别,其应该基于不多的几条基础概念,对于任何成年人来说都是直观明显的,并且是绑定到众所周知的一些象征性的东西上的,比如对象、条件以及过程等。我希望保留面向对象系统的许多使得系统很安全且便利的功能,诸如抽象类型化、多态、封装等等。到目前为止,这项工作的前景不错。

 

可参阅对Victoria Livschitz所作的访谈:编程的下一步行动构想一种新的语言

 

Brian Harry:在修正错误时,查明平台的较早版本



关于Brian Harry

来自Iowa的开发者Brian Harry,在java.net上也被称作是“leouser”,因其在Java SE 6的错误修正方面所作的贡献而为人所知,其修正的bug数目很可观,总计达到了几百个,这为他赢取了2006年度的Duke’s Choice优秀平台贡献奖。他的方法很简单,就是扫描Sun公开可用的bug数据库来获取那些令人好奇的bug,主要是Swing用户界面(UI)代码中的那些,把他们打印出来,并把这些bug报告放在他的计算机旁边的架子上,然后逐个地修正他们,通过标准JDK社区的捐献流程来提交他们。他的工作是Sun认证的Java开发者(Sun Certified Java DeveloperSCJD)以及独立的顾问。

 

修复Bug是了解代码如何工作的一种很棒的方式,阅读代码是好事,但使用它来工作更好,纵然没有找出解决方案,但通过代码学习你会成为一个更加有实力的开发者。

试想一下你面对着那些具有某种意义的API的时刻,但是你难以让它运作起来,如果你越过Javadoc的范围而进入源代码之中的话,则成功的机会就增加了。比如,我曾帮助java.net上的某人找到了一个关于“JInternalFrame不能与Heavyweight放在一起使用”这一问题的适合的解决方法。Sun的文章和教程通常会说你不能这样做,但因为我对代码很熟悉,所以我能够帮助到开发者,当然,我不是百分之百地满意该解决方案——当改变大小时frame会闪烁——但有东西可以用总比什么都没有要好。

 

有什么贴士是可以和我们共享的吗?

 

首先,始终要拿到错误报告所附带测试,bug数据库的状态是各种事态的混合,有时可见到有测试,有时却没有,如果你失去了耐心,因为测试不可见而决定基于报告来进行修复的话,那么你有可能是在浪费时间来尝试重现问题。在某些情况下,在我重新审查了测试之后,就可以明显看出报告对问题做了错误的描述。

接下来,问问自己这是否是个真的bug,在某些情况下,报告者从Java论坛寻求帮助的话会做得更好一些;此外,有时测试用例是容易出错的。一旦你确定了这是一个bug的话,你就可深入研究它,获取成效的最好方法是熟悉源代码。

还有,当找到有助于澄清问题的方法时写下我的想法,并文档化修改历史以备我需要时重视过程。把你的理解过程记录放在补丁包中有助于与任何评估该补丁包的人沟通。

并可考虑写下多种解决方案,你的方法可能是行得通的,但有可能不是最优的。基于类似的理由,准备再三重复你的方案,这可能看上去是一个好的方案,但意想不到的问题可能会让你犯错误。

至于编写单元测试,考虑补丁代码与之交互的部分,这可能需要浏览大量的代码,但对于测试补丁的各个不同路径来说是必要的。

 

是什么造就了一个好的bug修复者?

 

做一个研究者,并在事情最初犯错时没有放弃。这儿有一个例子,我曾被这一串字节码搞得狼狈不堪:

 

1 goto 8

2 set i to 100

3 set i to 100 --> start protected block

4 do stuff with i

5 return --> end protected block

6 use i to print out error message --> start exception handler

7 return

8 jump to 2 or 3

 

这段代码似乎很简单,设置某个局部变量的值为整数100,但校验器的检查失败了,因为i变量有可能没有被初始化,这种情形怎么会可能发生呢?有可能是在异常处理程序中有一个内存不足的错误被抛出,从而导致了该问题。查看一下VMvirtual machine)规范,数据流分析器一节中说到,其必须“确保指定的局部变量包含有正确类型的值。”我就想:“嗯,这似乎和这儿正在发生的事情对应上了。”

在我开始研究字节码之前,我从没有真正地理解过校验器为Java开发者做了多少事情,如果你是新接触它的话,那么你很快就知道它是一个多么严格的监工,有那么一段时间我都有可能被它逼疯了,不过我还是能够忍受住这一VM规范,并找出了问题合理化的一面以及后来的有效的重构方法。

同样,如果你正在进行Java代码的修复的话,不要只是检查平台的当前版本,我通常都会在4.05.0以及6上测试bug的测试用例,这样就可以查出问题何时开始而在何时终止,看看你是否能够找出为什么问题会开始发生。我的“未初始化”问题的根源在于校验器规范,JDK的一些bug会源于某些过去的版本,纵观全局则有可能会获得提供某些与导致了错误的设计因素相关的线索。

 

可参阅对Brian Harry作的完整访谈。

 

其他参考

 

开发者见解系列,第1部分:编写傻瓜式代码——来自四位首席开发者的建议

Joshua Bloch更有效的JavaJava解惑两个访谈

Masood Mortazavi:访谈1部分2部分,以及博客On the Margins

Jaron Lanier:访谈1部分2部分主页以及关于Phenotropic计算的思考

Vicotria Livschitz编程的下一步行动构想一种新的语言两个访谈

Brian Harry访谈

 

评论

 

你有关于如何编写更好的代码的建议吗?我们欢迎所有的意见,且特别鼓励不同意本文观点的开发者发表你的不同见解。欢迎你加入到我们的社区中来,请保证评论的礼貌性和相关性,你可以选择提供电子邮件地址以获得对你的答复的通知——你的个人信息不会做其他用途。在提交评论时,你要同意这些使用条款

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值