John Carmack谈论软件工程中艺术和科学的一面

虽然我不是一个游戏超级玩家,但我是因喜欢视频游戏而开始学习编程的(特别是图像渲染的算法)。所以当我看到John Carmack在2012 Quake­Con上的发言时,我想我应该听一听,学习学习游戏设计以及游戏开发相关的知识。

不过我所听到的是一个黑客在谈论他的最近感悟 - 软件工程事实上是一门社会科学。其中的大约10分钟,他涉及到了人性的各个方面,比如开发人员犯的错误,编程语言设计,静态分析,代码评审,开发人员培训,成本/收益分析。文中强调的部分是我加的(本文是我转录的,如有错误,还请海涵)。

在尝试让游戏跑得更快(我们的主要发展方向)的过程中,我们犯了不少Doom 4中已有的错误。其中的一些显然是无法改变的,但就是迫于提速游戏的愿景,不得不做。
因为这些行不通,你懂的,两个游戏相隔了6年。

在软件开发方面,你们或许知道一件有趣的事情,那是一个对我的访谈。那个访谈中我提到我是如何学习到那么多知识的,不过与一年前相比,现在我是一个更好的开发者,当时主持人对此很是惊讶。你知道经过了20年,经历了所有的一切,最终一切都浮出水面。关于软件开发我确实学习到很多,既包括个人的技能方面,也包括更多的关注团队积极性的一面。
而后者是过去多年来我所忽视的,因为把自己标榜为一个软件工程的科学家,处理一些抽象、证明、正确相关的事情,真的很酷。

事实上在计算机科学中,真正属于科学的唯一事情就是你在谈论算法,优化属于工程范畴。但是那些没有一直开发算法的人,大部分的时间都花在编程上。我们中确实有少数的程序员在做一些优化以及挑选算法的一些事情,但是90%以上的程序员在做的是编写程序,只是为了实现一些功能。当我开始审视这一切的时候,发现这些工作中的绝大部分没有科学、工程、正确的一面。或许,其中的一个程序员会说,他做了很多的巧妙编程工作,实现了一些功能。我们喜欢把自己想象成聪明的工程师,用正确的方式去开发好的软件。随着我观察的越来越多,发现这根本不是事实。

除了那些能够评估的东西以外,我们用来评估和重现的工具才是科学的精华所在,有了它们才能评估一些东西,重现它,做出预测并测试验证。我们会在做优化和算法的时候涉及到那些,但是我们做的所有其它事情,跟科学都没有关系。是关于程序员之间的交流,甚至于与不同时期的自己交流。我们谈论函数式编程,lambda演算,monads,这些想想就很美,但是这对你在软件工程方面做的事情没有任何影响,这些仅仅是最佳实践而已,一些过去总结的好的做法,但真的只是在阻止人们犯某些类型的错误的时候有意义。纯函数式的,用最严苛的科学的视角写出来的代码,最后还是会转化为汇编语言,事实上你也可以用诸如BASIC或者其它任何语言来实现它。

另一件对我有启发意义的事情是,我的大儿子开始学习编程。我确实摇摆过是否应该让一个7岁的孩子学习Haskell,最终决定不要,我不认为自己是一个足够出色Haskell程序员以至于愿意去指导别人。当我思考人们到底是如何开始从零开始学习编程时,豁然开朗,意识到我们从软件工程社区获取了如此之多的东西,事实上是一些构建在一个核心基础之上的由多层组件组成的东西。当你回退到结构化编程,不论是while循环,还是for循环,在底层,你如何解释编程,计算机做些什么,最终都会归于流程图(flow chart)。这种条件执行这个,否则执行那个。甚至尝试解释在一个地方到底是应该用for循环还是while循环时,这仅仅关乎惯例,一个解决人们经常犯的错误的惯例。但是它们不是计算机在做些什么的核心。这些只是人们根据以往经验总结的让你少犯错误的经验。

另外一件严峻的事情是,程序员一直在不断的犯错。我去年谈论了很多关于静态分析开展的工作,并尝试静态分析覆盖我们所有的代码,希望所有的都能够顺利通过,可惜扫出了数以千计的错误。扫出问题,很确定是个问题,并指出来,同伴说好的,确实是个BUG,下次不会再犯了,这感觉不错。如果一些错误没有从语法上阻止它,那么它就可能发生。那正是我投入那么多精力到静态分析上的原因之一。我希望能够开启更多严格的语言限制,因为我们一直在犯错

最近我开始做的一件事情是code review,查看每日提交的代码,找出一些典型的错误案例出来,给team成员讲讲。标注出一小段代码,说这是个静态分析工具扫出的bug,推荐这样的写法,更简单清晰,也不容易犯错,刚开始时有些成员对这种公开文化有些反感,不过我觉得大家现在都接受这样的做法了。但是有个问题,我看看大家都做了什么就会花费很多的时间,更别说逐个code review了。能够指出组内其他成员犯的错,并告诉大家当心类似的问题,那才是真正的价值所在。只要组员都接受这件事情,我想那是有积极意义的。

当你在争论譬如是否应该在函数的参数之前加上const关键字时,想象一下会发生什么。这些很难客观的给出结论,大多数这种情况,我们称之为缓存失效,要耗费很大的精力来说服。如果一个结论很客观,你可以评估它,那不会有争论。但是其它的很多事情涉及的只是代码风格问题,你或许会说,根据多年的经验,这样会导致种种的错误,但是很多人会回答说,我从来没有看到那种错误,对于我来说那不是问题,我从来没有犯过那种错误。这个时候能够演示错误很重要,看,就是这个问题导致的错误。

随着这些事情我做的越来越多,并思考相关的问题,我觉得这些不是科学,是解决人类的弱点的过程,我希望能够有更好的办法来处理它们。我们都希望成为更好的程序员,这会让我们开发出更好的产品,把工作做得更好,但是事实归结为去训练数十个人按一致的风格做事情。组内成员有进有出,不断更迭,新人进来,看着代码库,不了解惯例规则。有更好,也有更坏的方式做事情,不过这真的很难衡量。

这些是我正在花更多的时间关注的事情。我阅读了NASA的软件工程报告,在大量的资料中并没有找到任何有价值的东西。真正有价值的是关于自动化相关的事情,无需人工参与,它会自动评估。我觉得那才是越来越大的项目的最终归宿。现在我们开发的一些项目代码量是非常惊人的。你回头看看NASA的报告,他们认为3,4百万行代码的项目是大项目。现在我们的游戏引擎的代码量远远超过那个数字。这样来评估游戏引擎很有意思,它比送人类到月球上并返回,控制宇宙飞船,操作太空舱,维护空间站还要更复杂,所有这些巨型项目都没有市面上的任何主要游戏引擎复杂。

我的答案并不是到此为止。使用NASA风格的开发流程,他们能够交付bug率非常低的产品,但那是建立在非常低的生产力的基础上的。你能够做的其中一件事情是,分析成本/收益,你会说我们会开发出很棒的产品,但那时才推出实在是太晚了。或者我们可以做得很快,领先市场,不过可能做的不是很精细,不过我们让一些很酷的功能尽快推出。这是一个典型的例子,合适的工具,处理合适的任务。现实中发生的是你会很快推出很酷的产品,但是你会在多年内忍受它的折磨(译者注,猜测是指维护产品)。而在这方面我觉得我们做的不是很好。

我们知道我们的代码将会维护十年,我们是这样认为的。我告诉队员这是个好机会,你写的代码,并没有与特定的游戏强相关,或许会活跃10年的时间,会有数以百计的程序员看你写的代码,使用它,调用它,那是一个不小的责任。在软件的API设计层有很多的问题,找出这里的问题,这是艺术,需要技艺精湛的工匠。我希望以后能够有更多关于软件工程艺术的内容分享出来,我正在花很多时间在这上面。

英文原文地址

你可能感兴趣的:(项目管理,软件工程,代码审查,代码静态分析)