本文要点:
唯一不变的就是变化。这一点在软件工程中表现得尤为明显,在软件工程中,开发人员的日常工作就是修修补补、调调改改,甚至是重新构建他们所负责的系统。
随着应用程序的增长和团队规模的扩大,仍能保持对该软件清晰的理解变得更具挑战性。复杂性会影响工程师理解软件并根据需要做有效的变更。
可理解性这一概念,即系统所呈现的内容应该使工程师能够很容易理解它。一个系统越容易被人理解,工程师就越容易以可预测和安全的方式改变它。
如果某一系统符合完整、简洁、清晰、有条理这些标准,那么它就是可理解的。
可理解性和可观察性是互补的,但后者更侧重于两件事:在系统行为不正常时发出警报的能力,并帮助识别原因,以便恢复正常服务;以及,帮助识别性能瓶颈的能力,以便分配额外的资源或通知相关团队。
2500 年前,赫拉克利特说过:“唯一不变的就是变化。”这一点在软件工程中表现得尤为明显,在软件工程中,开发人员的日常工作就是修修补补、调调改改,甚至是重新构建他们负责的系统。还有一个方面使软件工程在人类学科中显得特别独特,那就是计算机科学定义了一些人为边界,在此边界内我们有着高度的自由来决定我们的工作。
我们能够有效地运用这么强大的力量,却常常在一个非常令人意想不到的地方做不到位,那就是我们认识自己所创造的东西的能力。随着应用程序的发展和团队规模的扩大,对软件本身保持清晰的理解变得更加困难,导致项目像圣经中的巴别塔一样崩溃。
举个恰当的例子
大多数商业软件工程任务都不是从头开始的。现在已有一款应用程序,它是使用某种计算机语言编写的,依赖于一组框架和类库,并运行在某些操作系统之上。
我们自己(或我们的团队)负责变更现有的这款应用程序,以满足某些需求,比如开发一个新特性,修复一处已有的 bug,等等。同时,我们需要继续满足所有现有的文档化或非文档化的需求,并尽可能维持现有的表现。
每一个初级软件工程师在这项任务上第一天开展工作就会发现,编写一段代码解决一个简单的计算机科学问题(或者从 StackOverflow 复制人家的答案)的复杂程度远不及在一个庞大而复杂的系统上解决同样的问题。
可理解性是什么?
借用金融行业的说法,让我们来定义可理解性:“即系统所呈现的内容应该使工程师能够很容易地理解它。”一个系统越容易被人理解,工程师就越容易以可预测和安全的方式改变它。
进一步推导,我们可以说,如果一个系统符合以下标准,它是可理解的:
完整。系统必须使用一组预定义的来源(源代码、文档等)来呈现,以涵盖所有的关键信息。任何重要的信息都不能丢给工程师去想象。
简洁。系统源代码不应该将用户淹没于过多的细节中。关注点分离和抽象应该能就这一点发挥很好的作用,它们使工程师能够专注于手头的任务。
明确。使用便于读者浏览的展示方法。一致性、编码约定、源代码格式、代码注释和语法高亮显示能够使这一点产生天壤之别。
有条理。工程师应该能够很容易在系统中找到相互引用的信息。模块化、软件文档、源代码导航控件和源代码管理工具使工程师们能够做到这一点。
运行时的可理解性
随着软件即服务(SaaS)和其他新的软件交付范式的兴起,许多组织正在实践整体对软件负责,授权工程师在整个生命周期中对应用程序负责。
在这样的组织中,可理解性以一种更为强力的形式表现出来,它决定了工程师对软件如何运行以及应用程序的客户如何利用软件有多么深入的理解。
因此,决定这么做的团队可以获取诸如使用模式、真实的输入和输出以及实际性能和可用性统计数据等非常有价值的信息。
可观察性不是可理解性
阅读本文时,你可能会想,重点应该是可观察性和监视工具吧。很遗憾,事实并非如此。这些工具是为了支持更传统的 IT 问题,主要关注于:
当系统出现不正常行为时发出警报,并帮助识别根源,以便恢复正常服务。
识别性能瓶颈,以便分配额外的资源或通知相关团队。
为运维、安全性和支持目的保留详细的事件日志。
这些都是很好的用例,IT 从很早以前就已经开始在处理这些用例了,而且由于它们有着非常清晰明确的投资回报率,所以许多供应商都提供了很好的工具来解决这些问题。然而,这些不是软件工程团队所要负责的用例,这些工具从来就没有对他们起到什么帮助作用。
所有这些 IT 用例的共同点是,这些具备系统方面常识的人需要确切地知道系统在特定实例中的行为,以便他们能够适当地做出响应。这意味着我们就一组预定义事件收集相关数据,这些数据往往是关于系统如何与周围的世界交互的。
而反之,软件工程团队对系统的内部工作方式有深入的了解,并希望更多地了解它是如何工作的。基于他们对系统所做的特定变更,每天(甚至是每小时)收集所需了解的数据。
战胜复杂性
软件随着不断地发展变化,变得越来越复杂。很大一部分复杂性是内在的,原因很简单,因为事实上业务需求的数量就是在不断地增长。除此之外的复杂性是不必要的,随着时间的推移,应用程序被改变了用途,再加上糟糕的设计选择,造成了这些复杂性,通常它们被称为技术债务。
不管复杂性来自哪里,它都会影响工程师理解软件并根据需要有效更改软件。人员流动会造成一定的知识损失,这往往进一步加剧了这一问题。
当然,在软件行业中大家都很清楚,必须尽量减少软件的复杂性。软件越复杂,开发新功能的成本就越高,系统的整体质量就会越低。关于如何构建软件能将复杂性降到最低,并使系统和团队更好地扩展,已经有人写过很多文章。
新软件的可理解性
当你正在开发新的软件时,可能会忽视可理解性,而偏爱它的另一面:复杂性。如果专注于避免和减少复杂性,你将自然而然地使软件拥有可理解性。幸运的是,无数软件开发工具和技术都特别关注软件的复杂性。
首先,要有一支高素质的员工队伍。富有才华的工程师们利用他们的经验在软件源代码和架构中以简单优雅的方式表达复杂的业务问题,创造出更容易理解的软件。
其次,尝试使系统尽可能小,因为从本质上讲越小的系统就越没有那么复杂,也更容易理解。将真正重要的业务需求作为关注焦点,而忽略(至少是暂时忽略)那些非强制性的需求,可以从“顶层”缩减系统规模。通过使用更高层次的抽象,比如新的编程语言、高级框架和现代数据库,通常也可以在“底层”对系统进行简化。
最后一点同样重要,确保有恰当的脚手架,以便在复杂性出现时予以处理。以单元测试和系统测试的形式编写自动化测试,以确保你的工程团队能够安全地重构复杂性。使用高质量的观测工具来帮助你从高层次上理解系统。自动化集成和部署流水线,使你能够快速改进和迭代。
现有软件的可理解性
另一方面,当涉及到现有的软件时,我们往往接受工程团队无法理解代码,因为这可谓是神藉灾难。直接改变复杂性不再是提高可理解性的可行方法。
通常,你面对的遗留系统都是使用较低级别的工具编写的,而不是现行的工具,原作者可能很久之前就已经离职了,而且没有留下任何脚手架。面对这些必须处理的技术债务和你的工程师无法理解的“不可读的代码”,抱怨不会带来任何帮助。也不要做什么长远的重构和迁移之梦,因为很少有美梦成真的时候。
这就是生产调试平台的亮点之所在。通过让你的工程师深入了解他们正在与之缠斗的代码,使他们可以开始切入去理解它。并且他们可以通过跨环境和用例来跟踪碎片逐步解开复杂性。
结语
现在我们对软件开发中可理解性的重要性有了更全面的看法。一方面,我们一直都清楚,保持代码易于阅读和易于维护是很重要的,而软件工程主要就是致力于实现这一目标。而现在,我们更深刻地认识到,软件随着时间的推移而带来的发展变化对它有着多么大的影响。
另一方面,我们也挑战了这样一个假设,认为总是可以通过处理复杂性、设计和编写更好、更简单的软件来提高可理解性。很多时候,我们发现自己是在中途登上的火车,几乎无法控制火车是如何到达目的地的。因此,我们必须开始跟踪和管理可理解性,将其作为自己的关键度量,尽最大可能提高工程速度和质量,甚至未处于最佳条件下。
作者简介:
Liran Haimovitch 是Rookout的联合创始人和首席技术官。他是敏捷、精益和 Devops 等现代软件方法论的倡导者。Liran 的热衷于去理解软件是如何工作的。当他不去想代码的时候,通常会去潜水或者徒步旅行。
译者简介:
冬雨,小小技术宅一枚,从事研发过程改进及质量改进方面的工作,关注编程、软件工程、敏捷、DevOps、云计算等领域,非常乐意将国外新鲜的 IT 资讯和深度技术文章翻译分享给大家。
原文链接:
Article: Understandability: The Most Important Metric You’re Not Tracking
评论