话说大佬真不是一天练成的,戴维·法利(David Farley)早在 1991年任职于通用电气公司开发 C++ 语言的项目时,就使用 Shell 脚本编写了许多自动化处理的程序,实现了一些持续集成的功能。在他看来,这些自发思考的实践,其实就包含了后来敏捷开发思想的一些精髓。
当 2001 年“雪鸟会议”正式发布了“敏捷宣言”(Agile Manifesto),敏捷运动开始在业界兴起。戴维·法利那时正任职于 ThoughtWorks 公司,该公司正是敏捷开发理念的积极倡导者和推动者,这无疑让他有机会在实践中进一步完善自己的理论。
随后戴维·法利总结自己十年间工作的经验得失,并与 Jez Humble 合著了《持续交付》这一神作,该书获得了 2011 年度 Jolt 大奖。戴维·法利也成为敏捷开发理念积极的布道者。
2011 年,戴维·法利加入 LMAX 金融科技公司。他负责开发了 LMAX 低延时、高吞吐量的在线金融交易所,使其成为全球最快速的金融交易系统。这是他在软件开发过程中实践敏捷理念的又一个重大成果,这一次他有了更多的思考。
在 2016 年离开 LMAX 后,戴维·法利成为独立软件开发顾问,帮助其他公司和组织实践敏捷开发并获得成功。他集自己三十余年的功力,思考提炼后写在了《现代软件工程:如何高效构建软件》这本书中。
让我们来探索一下,戴维大佬将告诉我们的现代软件工程应该是什么样的。
传统软件工程的困境在哪里?
戴维·法利借用康威定律来回答:“任何组织设计一个系统(广义上的定义)所产生的设计,其架构都是该组织沟通结构的副本。” 如果一个企业或组织是逐层向上汇报的层级结构,那在实施软件工程时,就会偏好层层推进的瀑布式模型。
瀑布式开发模型在理论上是完备的,它将软件开发的过程划分为需求分析、系统设计、编码实现、测试,以及部署等。这种方式无疑非常便于从上至下命令式的管理,但对于工程实施来说则可能会掉到官僚主义的坑里去。
一旦需求发生变化,或者上一环节中隐藏的错误在下一环节出现,组织则会陷入到推诿、争论之中,无人愿意为此负责。
所以,软件工程要摆脱掉脱离实际的官僚主义做法,就应当有明确的目标和原则。戴维·法利认为,软件工程是对经验主义的、科学方法的应用,目的是为软件中的实际问题找到高效的、经济的解决方案。
那要如何做到高效、经济的解决问题呢?戴维·法利给出了他的办法。
在戴维·法利看来,缺乏良好设计和结构的代码,是造成软件系统过度复杂的主要原因。对这样的代码,戴维有一个形象的称谓——“大泥球”。这类代码的典型特征是结构混乱、过度耦合,并且难以阅读、难以测试、难以维护。
要解决代码的复杂性难题,戴维·法利从他的工具箱中拿出了一件敏捷法宝:测试驱动开发(test-driven development,缩写 TDD)。TDD 为何如此神奇,且听大佬分解。戴维·法利将实施 TDD 的过程称为“红-绿-重构”,他的做法如下:
这就像交通灯的规则一样,红灯停,绿灯行。在实施中要注意每次前进的步伐是“微小”的,原则就是一次只完成一个函数功能,在简单的进步中积累成功。这就是在迭代式的前进中,通过反馈保证代码的质量。
如果说“红-绿”是保证功能不出错,那么“重构”是保证将事情做对。所以在实践 TDD 的时候不要光顾着一路狂奔,一定要停下来认真做好重构。这需要开发者培养起良好的代码“嗅觉”,即能捕捉到代码中的“坏味道” —— 那些会导致代码变得复杂的迹象。
在书中戴维给出了一段 Python 代码的示例,我们识别一下它有哪些“坏味道”。
def add_to_cart1(self, item):
self.cart.add(item)
conn = sqlite3.connect('my_db.sqlite')
cur = conn.cursor()
cur.execute('INSERT INTO cart (name, price) values (item.name, item.price)')
conn.commit()
conn.close()
上面这段代码将数据存储的细节,与商品购物车业务深度耦合在一起,后续无论是业务需求变更,还是更换底层数据库,都暗含风险。并且这段代码依赖了外部环境,导致难以测试。
我们接着看戴维大佬是怎么重构它的:
def add_to_cart3(self, item, listener):
self.cart.add(item)
listener.on_item_added(self, item)
这是最后优化的版本,它只关注业务层面向购物车中添加商品这一件事。简单而直接,至于存储细节,那是另一个层面的事。这是戴维大佬写代码的一条重要原则:关注点分离。即一次只做一件事,实现代码解耦。
戴维大佬就是用这样直观的代码示例,讲透了模块化与内聚力、信息隐藏与抽象等原则。实践出真知,跟着戴维大佬学写代码,程序员们再也不会写出“大泥球”了。
戴维·法利在 LMAX 期间建立的在线金融交易所,是他对软件工程多年思考之后的结晶。戴维大佬为此总结出了若干行为准则,并提出了一项独到见解:软件开发是学习的过程。
在线金融交易所是一套功能复杂的软件,戴维大佬并未在一开始就做面面俱到的设计,而是紧抓最核心功能,使用 TDD 方式迭代开发。在这个过程中,以微小的步伐增量式前进,重视每一步的反馈结果,以此推动系统向着正确的方向发展。
戴维大佬在书中说了一个金融交易所上线失败的事故,那是一次在正式发布上线前做最后检查时,有位同事提出在他的环境中出现了一个与消息传递有关的 Bug。但大家还是忽略了这个问题,直到上线出现大面积故障紧急叫停,才来重视这个问题。
团队都以为这是和消息传递有关的 Bug,但戴维大佬没有轻易下结论,和大家认真讨论后,找到了正确的方向,发现是线程转储的问题。这就是运用了经验主义原则,在做出正确假设的前提下,通过实验去找到解决办法。
所以说软件开发是学习的过程,在探索未知时,通过迭代、反馈、增量主义、经验主义与实验的方法与原则,去提出正确的问题,直至找到答案。
对于软件工程的最终目标,戴维·法利认为是要为用户交付商业价值。也就是说可工作的软件高于详尽的文档,这也是敏捷宣言的主要原则。在戴维大佬三十多年的职业生涯中,他秉持这个原则为业界贡献了一个又一个成功的软件产品。
在《持续交付》中,戴维大佬讲述了如何更快、更可靠、低成本地实现自动化软件交付,那么在《现代软件工程:如何高效构建软件》中,戴维大佬上升到软件开发的整体层面,详述了基于科学的工程化方法,这包括系列行为准则还有 TDD 等敏捷式方法。
《现代软件工程:如何高效构建软件》书中不仅有戴维大佬总结的经验理论,更有他包含代码的实战事例。技术人从中不仅可以学到大佬高屋建瓴的思维,还有把事情做好做对的具体方法和工具。
所以,技术人只要遵循书中的行为准则,成为学习的专家与管理复杂性的专家,那就能建立起现代软件工程意识,打造成功的软件产品。