简单设计落地三板斧
如果你认同 简单设计的价值观,我相信 解析简单设计原则 对你来说很容易理解并接受,它不像面向对象设计原则(比如:SOLID)那么晦涩难懂,它给你指明了一条明朗可通行的道路。即便如此,前进的道路依然不是一帆风顺,尤其对于新手来说,怎么将这些已经很接地气的原则更高效地落地,从而创造更大的价值,本文我将分享帮助我们落地简单设计的三板斧:TDD、重构和整洁代码。
价值体系
假如让你去建造一幅巨大的广告牌,你会怎么做?从大框架来看,首先要打牢地基,再使用结实支柱做支撑,最后在顶部挂上广告牌。地基和支柱是帮助完成目标的必备条件。那么,如何实现简单设计的核心价值?我们可以以简单设计价值观、简单设计原则做为地基,并通过打造TDD、重构 和 整洁代码 三大支柱来支撑起简单设计的 “广告牌”:
三大支柱
TDD
作为极限编程的一项实践,测试驱动开发经过被大量的开发者证明是一项具有实用价值的实践。从广义上讲,TDD不限于开发人员在编码的过程中先写测试用例,然后驱动出代码实现,就连我们拿起一个待实现的用户故事[1],在脑海中开始构思如何去验收这个功能,也是一个TDD的过程,只不过这个T存在于你的大脑中,没有被可视化出来且不能复用。
本文我所要表达的TDD聚焦在编码层面中的单元测试。它包含了三层含义:
- Test Driven Development
- Test Driven Design
- Task Driven Development
Test Driven Development
测试驱动开发,它是TDD在操作层面的落地方式,也是最普适的含义。它遵循一个基本流程:写测试 -> 执行测试(红) -> 写实现 —> 执行测试(绿)。在TDD中融入重构步骤之后,它的一个具体详细的完整流程如图所示:
Test Driven Design
编码如艺术,优秀的程序员即是一名设计师,也是一位艺术家
作为一名用代码改变世界的程序员,我们应该试图将自己的设计思想融入到代码中,让代码充满生气和灵性,从而远离机械式的僵尸代码。在解析简单设计原则 一文中我谈到设计不足和设计过度时所催生三类问题:
- 难以修改
- 难以测试
- 难以阅读
TDD能让我们在编写测试的时候就开始思考即将实现的功能代码的可测试性。试想如果我们在编写测试阶段就举步维艰,此时不得不逼着自己去思考如何让API能够利于测试。这个过程主要面临了两方面的挑战:
- 视角切换。从用户视角出发,将脑海中的隐性验收测试落地到代码层面。
- API设计。如何让API更加职责清晰、内聚,从而更加有利于测试。
这些挑战对开发人员的设计思维提出了较高的要求,所以也能理解不少新手在起步阶段颇为痛苦,以至于他们会觉得TDD降低了开发速度,对它的价值产生了怀疑。
从我个人经验以及身边一些大牛身上总结出一个结论:掌握TDD最好的捷径是刻意练习。所以如果你刚起步,不要气馁,找一些Kata勤加练习[2]
Task Driven Development
任务驱动开发,强调的是将大任务拆解成小任务。人的大脑在处理足够简单的问题的时候(比如1+2-3+4-5 = ?
),能够快速给出方案。然而,面对较为复杂的问题的时候(比如2-1*5*3/2+2-3/2-2/1*5+4-5 = ?
),大脑难免捉会襟见肘,此时就有必要借助一些辅助工具来做到事半功倍。
任务驱动的方式会用到一个思维工具 – Tasking[3]。在练习TDD时,建议你将待完成的任务进行分解,然后将分解后的子任务可视化出来。可视化的好处之一是它可以作为沟通的工具,去收集反馈,进而完善自己的思路。任务拆解之后的好处是,待实现的功能更加小而单一,有利于编写测试。
Tasking同样需要刻意练习,它对分析性思维提出了一定的挑战,练习分析性思维的四步法:
- 定义问题 - 清楚定义问题
- 分解问题 - 将问题进行分解
- 关联问题 - 通过输入和输出寻找子问题的关联关系
- 限界问题 - 识别出子问题的边界,明确假设和结果
关于TDD的示例,欢迎观看我录制的视频[4]。
重构
重构,它是极限编程中的一项实践,Martin Flower在 《重构:改善既有代码设计》[5] 一书中对重构进行了全面的定义。它提倡我们对代码最佳实践充满敬畏之心,在不改变软件行为的前提下去修改代码,不断改善代码的设计,提升软件的响应力。
作为程序员,我们经常在修改代码,在修改之前,建议你先问自己四个问题:
- 软件已经工作,还需要修改这段代码? - 软件可工作,可能有坏味道
- 如何识别这段代码浮现出的坏味道? - 换味道是什么
- 针对坏味道,我们应该怎么修改? - 怎么去坏味道
- 修改完之后,如何确保功能没有发生变化? - 软件可工作,坏味道变少
四个问题环环相扣的,始于目标,终于目标。你若能给出答案,并形成闭环,便实现了重构的核心价值。通常最难回答的是最后一个问题,以至于迟迟不敢下手,导致软件逐渐恶化。所以重构提倡重构要在测试的保护下进行,人工测试亦或自动化测试,只要能给出正确的答案。
重构是一门手艺活,在日常编码中,你应该始终保持警惕,积极思考上述四个问题,另外辅以大量的刻意练习[5],同时我强烈推荐你以《重构:改善既有代码设计》[6] 这本书作为起点。
结合TDD,重构大有用武之地,测试先行保驾护航,重构演奏,方能唱出悠久的歌声。然而重构到什么程度?让整洁代码来回答这个问题。
整洁代码
整洁代码,从其字面来看是要编写整洁的代码,但这个问题仁者见仁、智者见智,很难有一个标准答案。回到我们文章的初衷 – 落地简单设计,所以整洁的代码至少是:
- 尽量不重复
- 尽量揭示意图
- 尽量简单的
小到变量命名,大到类交互设计,我们应该在意识中不断强化对以上三点的认知,在实践中养成良好的编码习惯。
Robert C在《代码整洁之道》[6] 一书中提供了很多案例,另外《编写可读代码的艺术》[6] 也是一个很好的开始。理论结合实践,在日常开发中,建议你在团队中组织Code Review[7],它是一个难得的学习提升机会。
价值着陆
TDD、重构和整洁代码并不能直接让我们设计出来的代码就天生符合简单设计。TDD带我们开了一个头,一旦开始了,在过程中不断地审视自己的代码,并通过重构来让代码变得整洁:
欢迎你以文中提到的案例和网站作为开始,进行大量的刻意练习从而让简单设计的核心价值能够着陆你所开发的软件,提升软件的响应力。
注释
用户故事是极限编程中的一个实践,请参阅 我在ThoughtWorks中的敏捷实践
关于编码Kata,欢迎访问 http://www.cyber-dojo.org/
有关Tasking更多解读,欢迎阅读ThoughtWorks仝键老师的 像机器一样思考系列文章
我已经将 TDD实现斐波那契数 的视频发表于B站
关于重构的练习,欢迎以 GlidedRose 案例作为开始
关于编程方面的书籍,欢迎从我的GitHub programming-books 库中获取
Code Review是项非常有价值的编码实践,它不仅能够促进团队互相学习,还能防止代码库恶化,更多内容请参阅 我在ThoughtWorks中的敏捷实践
版权声明:自由转载•非商用•非衍生•保持署名 | Creative Commons BY-NC-ND 4.0