在哥本哈根 GOTO 大会上,Daniel Terhorst-North 在演讲“当下最佳简易系统”中指出,在积累技术债务与错过交付期限之间做选择,其实是一种伪二分法。程序员往往热衷于泛化处理,而非解决眼前的具体问题,这会导致未来修改难度增加。相反,我们需要培养保持系统简洁的技能和直觉。
许多程序员认为自己不得不不断地做权衡:为了赶上截止日期而不断积累技术债务,或者推迟管理层或业务人员设定的截止日期,以便有时间“把事情做好”:
只要做出恰当的权衡和设计决策,你就能始终拥有一款可交付的产品,并且能够将质量标准保持在一个足够高的水平上。
Terhorst-North 解释说,“当下最佳简易系统(BSSN)”具备以下三个特点:
没有多余或推测性的代码,只有当前所需的代码(“Simple”)。这种设计具有“面向未来”的特性,因为它非常简单,便于修改,而不是因为我们在认为可能发生变化的地方到处设置扩展点。
满足所有当前需求(“for Now”),同时谨慎地忽略或推迟了任何未来的需求。
所有代码均遵循适当的标准(“Best”)。对于生产环境代码,这意味着需要包含遥测数据、自动化测试、API 文档、自动化部署流程等。对于用于探索想法的“草图”类代码,标准可以适当放宽。但在任何情况下,对于那些有“良好习惯”就可以避免的缺陷——如命名不当、不必要的复杂性(源文件过大、方法或函数臃肿、文件结构混乱等)——都绝无借口可言。
Terhorst-North 引用了 Terry Pratchett 在《碟形世界 4:实习女巫和冬神》中对女巫所需技能的描述:
“第一眼与再三思量”,这就是女巫所必须依赖的技能:靠“第一眼”看清事物的本质,靠“再三思量”审视“第一眼”的判断,保证自己的想法正确无误。
Terhorst-North 表示,如今的设计首先要靠“第一眼”:看清事物的本来面貌:
我们真的需要一个规则引擎吗?还是说这不过是几个裹着大衣的 if 语句罢了?对于只有 10 名用户的内部 Web 应用,Azure 托管的 Kubernetes 是否是合适的部署平台?
程序员喜欢进行泛化,这会引入一系列的复杂性,而我们已经学会了忽略这些复杂性。Terhorst-North 认为,我们已经失去了最初的洞察力。这可能会增加未来变更的难度,尤其是当这些变更朝着我们未曾预料的方向发展时。
关于保持简单性,Terhorst-North 的建议是:不妨直接尝试,并做好一再犯错的心理准备。培养保持事物极度简单的技能和直觉,但在这个过程中,你难免会在某些方面过度思考、过度编码或过度索引。
Terhorst-North 解释道,大多数情况下,正是坏习惯和后天习得的行为阻碍了人们设计出聚焦本质的简单系统:
作为一名拥有数十年经验的程序员,我自视甚高,坚信自己对编程了如指掌,因此,每当我试图预测某个产品或代码库的未来发展方向时,我总是很难承认,自己往往是“差之毫厘,谬以千里”。
尽管在编写代码时总是尽量遵循 BSSN 规范,但他发现,自己还是会因为“以防万一”而过度思考或过度设计解决方案,Terhorst-North 说道:
我发现克服这一难关的唯一方法就是练习、练习、再练习!就我个人而言,我发现,结对编程时,我会更加坦诚;我的搭档会阻止我过度优化,或者质疑我对下一步方向的假设,从而让我不偏离轨道。
Terhorst-North 总结道,等他回过神来,自己早已深陷于又一项根本用不上的优化之中,或是正在添加另一个永远不会被调用的接口或弹性点。
InfoQ 就“当下最佳简易系统”这一话题采访了Daniel Terhorst-North。
InfoQ:您曾建议不要以任何方式预测未来。为什么?
Daniel Terhorst-North:这就是当下设计的核心所在。一款产品随时可能因为各种原因发生各种变化。我将这些称为“变化的维度”。
以下是一些例子:
- 虽然还有许多其他类型的报告工具,但我们选择了一款领域专用的,尽管它有极高的领域灵活性,却无法连接到其他所有这些数据源
- 同一份报告有许多变体,但添加新变体既昂贵又耗时,因为我们“出于性能考虑”将其锁定了
- 报告复杂度增加,因为法规遵从性需要数据溯源,但这将极大地拖慢报告生成速度,因为我们是针对规模而非细节做优化
- 我们其实想要的是一个仪表盘,因此“报告”将动态生成
这些并非假设;我全都亲身经历过!无论我们在设计中预测或预先防范了哪一种可能的未来,我们都得与其他选项进行对比权衡,并完全基于推测引入了复杂性。
我的观点是,真正的“灵活性”和“可扩展性”,关键在于尽可能保持事物的简单性,这样无论接下来发生什么变化,你都能迅速调整方向。
InfoQ:如何才能使我们的系统既简单又最佳呢?
Terhorst-North:我提倡“假装直到成功”,或者更确切地说,“通过行动来培养新的思维方式”。你无法说服别人,系统可以始终保持简单;也无法说服他们,代码库越简单,未来的变更就越容易;他们必须亲身体验,而且要多次体验。讽刺的是,工程师经验越丰富,就越难以相信自己不应该预先设想下一轮变更。毕竟,这不正是所有经验的意义所在吗?
我不再纠结于自己的设计是否“正确”。我对自己的工作习惯——TDD、版本控制、重构、代码“草图”——充满信心,因此我知道,自己能够迅速纠正任何错误的决策,并转向新的方向。我也学会了,当内心有个声音说知道接下来会发生什么时,不要轻信。