Martin Thompson是Java Champion称号获得者,同时也是一名高性能计算科学家。他说,为了写出更好的代码,程序员需要运用基本设计原则,阅读已有代码。在QCon London 2016大会上,他做了题为“挖掘你的工程师属性(Engineering You)”的演讲。InfoQ在会后采访了他,内容涉及软件行业面临的挑战及程序员如何应对那些挑战成为更好的软件工程师。
InfoQ:您在演讲中引用了1968年第一届NATO大会上有关软件工程的一些内容,它们仍然成立。软件行业为什么还是在苦苦挣扎?
Martin Thompson:1968年的NATO大会有好几个主题。他们认识到,软件行业存在交付危机。他们也看到了一些成功的项目,并且希望弄清楚如何吸取好的经验,进行更广泛地应用。在我看来,其中有几点比较突出,就是认识到软件开发是一个迭代过程,注重试验/学习,需要专门人才领导,并且最好是在小型团队内完成。他们在几十年之前就从许多方面描述了TDD和敏捷这些在当时并不常见的做法。
作为一个行业,我们已经取得了很大的进步,但是我们仍然有很长的路要走。软件开发是一个非常年轻的学科,我们仍然有很多东西要学。我喜欢Dijkstra对它的描述,“焕然一新(radical novelty)”,而使用一些很不恰当的隐喻和类比,会注定我们的失败。软件构建是在之前活动基础上的跃变。这些活动和约束与之前的活动截然不同。有些人有这方面的天赋,有些人需要学着做,而大多数人很挣扎。在土木工程学方面,我们耗费了几个世纪才具备了现在的能力,因此也就不奇怪软件行业当前的挣扎。
InfoQ:您为什么认为理解基本设计原则,如耦合和内聚,很重要?
Thompson:软件开发面临的其中一个最大的挑战就是处理应用程序规模增长带来的复杂性。对象、组件、模块或系统之间的耦合程度越高,我们需要承担的后果就越多。这些后果包括但不限于修改困难、故障蔓延、由于争用而无法扩展、由于关联操作而导致的性能问题。时间、空间和实现上的松耦合对于扩展性和弹性而言至关重要。“共生性(Connascence)”可以很好地描述耦合,一个模块/组件的变化会导致另一个模块/组件的变化。
我发现,內聚比耦合更微妙。我喜欢将内聚理解为统一性。当我们考虑在不同的方面使用同一个组件时,就失去了统一性,这会导致不必要的行为和特征。软件设计中的低内聚常常是一个很好的需求或团队状况指标。通常,内聚设计很容易跟踪,由于相关的函数和特性都进行了分组,相互关联,所以可发现性很高。
如果我们希望成为更好的软件工程师,那么提高我们运用基本设计原则的技能应该成为我们日常活动的核心。在训练和实践中不断重复是让技能成为第二天性的最好方法。
InfoQ:您能举几个例子说明下,如何运用分解和抽象帮助开发人员写出更好的软件吗?
Thompson:我认为,抽象是软件开发领域被人误解得最深的话题之一。Dijkstra将抽象描述为一种创建“新的语义层次”的方式,“在这个语义层次中,一个人可以做到绝对精确”。大多数开发人员都完全是乱用这个术语,创建他们所谓的抽象来掩饰他们不懂的东西。Joel Spolsky甚至发明了“抽象泄露(leaky abstractions)”原则,拙劣地想为这种误解正名。我们有些很棒的抽象示例,如Linux内核或设备驱动中的块设备,但遗憾的是,大多数软件抽象通常是源于某种形式的精神自慰,导致弗兰肯斯坦怪兽的诞生,让代码更难以处理,而不是更严密更容易理解。糟糕的抽象比重复的成本更高。
我们需要更擅长将业务目标分解成可衡量的具体成果,然后以高质量、低耦合的可组合组件为基础构建软件。商业公司希望我们在他们的框架内完成构建,那样他们可以锁住客户。这些框架是错误的示范。它们是商业压力催生的产物。商业压力与交付高质量的可维护软件往往是矛盾的。
如果看一下其他工程学科,我们就会看到,工具的使用是为了支持交付流程,而不是强加一个流程。我们似乎展现了这个时代的一个特征,商业广告聚焦于人天价格、per-CPU许可及锁定维护合同。现在,类似Amazon这样的公司提供了实用计算,让我们可以根据需要使用。非常有趣的是,云计算很好地支持了持续集成和交付模型。这改变了市场格局,推动了更好的行为。我们也可以从工具方面看待这个问题,类似Jetbrains这样的公司将你锁定在他们的产品合同上;他们是通过提供可以提高生产力的优秀产品把你锁定的。
InfoQ:您提到,把重读代码作为发现缺陷或改进代码的方式。您能详细地阐述下吗?
Thompson:任何创造性的尝试都可以从不断地审视和完善中受益。你曾经回过头来阅读已经写好的邮件、论文、博客或报告等等,然后觉得某些部分可以做得更好呢?这是一件很自然的事情。当我们回过头来看时,情况不同了,我们会有新的认识。从最简单的层面来说,我们的写作初衷已经从我们的短期记忆中消失了,我们必须真正的重读和思考。换句话说,我们有了更多的信息,世界发展了,我们的知识也丰富了。
我喜欢将代码视为一个可以捕获当前看法的地方。我们都会犯一些回过头来看时可以纠正的错误,除了纠正这些错误外,我们还可以记录我们更深入的理解。一般而言,应用程序是业务流程的软件模拟。如果软件没有捕获当前了解的业务流程,那么开发人员就必须做一个心理映射。在任何项目中,心里映射都是一个很大的负担。这是我认为领域驱动设计是一个重要的软件开发工具的原因之一。
定期阅读所有的代码,而且不只是你自己的代码。阅读他人的代码是一种很棒的学习方式。正如作家Stephen King所言,“读其他人的书是让你成为一个更好的作家的最好方式。”这同样适用于代码,开源是我们这个行业采取的最好的措施之一。通过公开开发软件,我们可以分享理解,获取反馈,向其他人学习。参与开源是让你成为一名更好的工程师的最佳方式之一。