铜剑技校

仝键的个人技术博客

0%

编程的精进之法

【旧文搬家】
(作者注:阅读本文需要一定的编程经验和对一些敏捷实践,如TDD,有一定的了解)

编程,众所周知被定义为知识工作,所有的知识工作,从业者和门外汉都喜欢把它神秘化,将整个过程以不可知论的风格来解释。理由往往只是简单粗暴的讲诉一些体力工作时代形成的方法照搬到知识工作中来失败的故事,也毫无理论依据。偶有几个人写理论理由,写出来的理由跟癔症者的呓语也无甚差别。我个人是反对将知识工作神秘化的,我是科学管理原理的忠实粉丝,我觉得尽管科学管理原理的具体案例都过时了,但泰勒的研究方法依然是工作的,只是研究者和被研究者发生了一些微妙的变化。

彼得德鲁克在《21世纪的管理挑战》中提到,知识工作者需要自我管理,那么很明显不是体力工作时代形成的方法不能用在知识工作中,而是不能指望个体之外的人对个体进行简单的粗暴的分析和命令就可以形成很高的生产效率了。这个分析和下命令的人必须是知识工作者自己,我们需要自己纪录自己的行为,然后分析、优化,才能得到生产力的提升,任何向外诉求都会很快的撞上一个“天花板”而无法提升。如果非要寻求外部控制,那么我们只能说,对于新时代的管理者的定位,比起老板,更像老师,以引导和帮助训练为主,每个人真正的效率提升主要还是要靠自己。

那么如文章标题所述,追求知识工作的一种——编程的效率,是本文关注的重点。但我们首先要声明,本文不是给一个可以直接产生高生产效率的方法,而是给一个可以可视化自己生产效率以找到瓶颈的方法。至少在不改变质量的前提下,可以极大的提升你的效率,如果使用得当,可能会质量和效率双提升。

本文引入的方法也并不新鲜,简单说来,就是任务列表法+PDCA的一套组合使用而已。大道至简,坚持者寡,而坚持下来的人往往都可以获得数倍的效率提升。

任务列表法

我们做任何事情都应该划出任务列表,按照任务列表一项项去完成,这不是什么特别少见的工作方式。然而,很多人的问题在于,列出的问题列表不能达到完全穷尽,各自独立。

完全穷尽是什么意思呢?
当我开始做事情的时候,我不能把所有的事情穷尽,我列出的列表跟我做的事情是不完全等价的,这说明我们的工作行为是非常混沌不可视的,哪怕是对自己。
有时事情看起来在大面上是穷尽了,但是做的时候,发现又出现了新的任务。那说明每一项任务的输入和输出没有想清楚,所以当发现输入输出有欠缺的时候(主要是输入,输出欠缺的结果也是要补输入),就需要新的任务来准备输入,于是任务列表就增加了,这也是一种没有穷尽。

各自独立是什么意思呢?

意味着,每一项任务都可以单独做完,而不需要先做完其中一项任务,才能做完另一项。
假如我有三项任务

1
2
3
# 任务1
# 任务2
# 任务3

我做的时候,必须把任务2做完,任务1才能做完。任务3做完,任务2才能做完。结果我就从任务1开始一路做到任务3,最后再逐步回到任务1,整个过程非常混乱,那就不是各自独立的。

在现实生活中想做到各项任务都独立挑战还是比较大,但是在编程的世界里,挑战没有那么大,程序世界做到这一点真的太轻松了。优秀的设计都是要求解耦的,如果做不到,基本等于活儿比较烂。

当我们做到任务的完全穷尽与各自独立之后,我们任务列表法才算达标,这之后才能高效的工作,然而达到这一点并不是一蹴而就的,没有谁可以一上来就做到任务划分可以完全穷尽、各自独立,需要不停的刻意练习。所以我们称之为编程的精进之法。

PDCA

PDCA是Plan-Do-Check-Action四个词的组合。这是著名的戴明环。讲究从计划开始,经过实践,再反思,产生的改进行动再纳入下一轮计划的持续改进过程。

当我们把这一套从工业领域搬过来的时候,我们对计划的理解还是工业领域那一套。如果用在个人提升方面,我们应该把PDCA微观化,这之后就有两个问题需要被解答,一个是Plan是什么?一个是Check什么?

第一个问题的答案是很显然的,我们前面讲的任务列表法就是在形成这个Plan。

第二个问题本身是一个母问题,每当我们对这个问题的回答,都要回答一个衍生出来的子问题:我们要做点什么才能在需要Check的时候能够Check。常用的套路有两个:

  1. Plan的时候估计一个时间,然后开始做,做的时候计时,做完就要Check这个时间是否达标,无论快了还是慢了(通常是比较明显的差距才反思,比如20%以上的差距),Check都要反思并产生Action,纳入到未来的Plan中去。
  2. 估计的任务列表和实际做的任务列表是否是一样多的?往往是会多出来,这时就要反思,自己在哪里有不足导致了这个差别。

这些反思往往是发现自己的问题,比如自己不熟悉的知识点,不熟悉的方法,甚至不熟悉的业务知识,最后的Action也往往都是进行刻意练习来提升生产效率,比如反复练类似题目。有时也会是通过一些效率工具的使用来提升效率,比如抽取live template,使用快捷键,只是效率工具的使用往往也需要刻意练习就是了。有时也可以通过复用技术(其实live template已经是复用技术了)来提升生产效率,然而可复用模式的识别与抽取本身也是需要练习的,否则在那里纠结浪费的时间更长。

有些同学会感觉到,记录了时间却不知道哪里有问题,这个时候可以跟TDD相结合,把时间划分为写测试的时间,写实现的时间和测试通过的时间。其实除去这几种时间,还有其他时间消耗,比如调研的时间。不管怎么划分,将时间消耗结构化掉,一部分一部分的追求最高效率是一种可行的办法。

举例

我们做一个简单的修改用户信息功能的API。那么我们在某一个Java技术栈上可能的任务列表是长这样的:

1
2
1. 写UserController (10分钟)
2. 写UserDAO (15分钟)

当你真正开始做的时候,会碰到两种主要的意外:

  1. 任务列表扩张
  2. 时间估计不准

我们下面就这个例子,讲一讲遇到这两种意外,我们应该怎么反思和处理。

任务列表扩张

任务列表扩张,顾名思义,就是指我们一开始估计的任务的数量随着我们开始工作变的比预想的多,可能有两种主要原因:

  1. 技术原因
  2. 业务原因

技术原因,比如在这个案例里面,第二项任务:写UserDAO,就是一个没想清楚的事情。我们还需要建数据库表,我们在一个有migration脚本支持的技术栈设计上工作,我们还需要写初始化脚本和回滚脚本,也许这是我的第一个表,所以我还得配置数据库,搞不好还要把ORM的基础代码都写完,所以这些导致了我可能任务估少了。再比如,我们的项目规范要求我们Controller不能直接调DAO,要在中间加一个Service,尽管我个人觉得这是一件很二的规范,然而规范就是规范,我对项目技术规范不熟悉结果导致我画出来的任务缺少了一些必要的任务。再比如,我们的项目采用的是Jersey,根本没有Controller这么一个东西,那么不了解技术框架导致我的任务根本就划错了。

这种情况属于我对技术了解不足,通过对任务列表扩张原因的Check,我会得出一些Action:去了解技术规范,去深入了解项目的技术架构,现有的代码,以防止以后的任务画错。

业务原因,也比如在这个例子里,我们的系统需要在更新用户信息的API里不能更新密码,所以我们还需要一个专门的修改密码的API。再比如,这是一个遗留系统,用户信息的修改会触发数据库里的一系列触发器,从而修改系统的其他数据,然而有些修改是有前提的,那么我就需要更多的任务去处理这些前提条件;或者当数据变化时,要求我去修改系统里的其他数据,那么我就需要更多的任务去完成这些工作。

这种情况属于我对整个系统的业务了解不足,通过对任务列表扩张原因的Check,我会得出一些Action:通读数据库表,通读代码,更全面的阅读需求,或者跟需求方更多的沟通,以了解业务。

时间估计不准

时间估计不准就简单了很多,在这个例子里,就是这两个任务我估计的时间与我做的时间不相匹配。可能的主要原因也有三个:

  1. 任务列表扩张了,但是我没意识到,比如UserDAO写起来没有我想的那么简单,所以多花了时间;
  2. 单纯的技术不熟练;
  3. 花了太多时间在纠结上;

对于隐藏的任务列表扩张,时间估计不准给了我们一个很好的线索去发现。一旦发现了,可以前文所述去处理,也就不再赘述

对于单纯的技术不熟练,就如前文所述,要去设计刻意练习。比如我就曾设计过对数据库的增删改查的一组训练以提升自己的速度,使得我即便使用TDD依然保持一个极高的速度。我们自己没有意识到,基础能力的不熟练对于我们的高级能力的限制有多严重,这种体验也只有基础能力已经熟练的人去教基础能力不熟练的人一些高级技能的时候才会发现。这种视而不见的收益,使得大多数人都会轻视基本功的练习。哪怕已经获得收益的人,也容易鼓吹要更多的启发而忽略了基本功的价值。

对于花了太多时间在纠结上,这其实也是一种不熟练,是对设计知识和能力的不熟练。之前看的设计知识只能有一个大概的感觉,对于每个知识的边界、使用之后的发展、如何从一种设计过渡为另一种设计了解不清,从而害怕在那一刻犯错。实际上真正值得纠结的部分没有那么多,大多是自己吓自己,或者引入了过度设计。当然也有一种情况是暴露出了架构级的问题,比如我们对于应该提出的原则性规范没有提出,所以导致我们每个地方都要现想,大家可以想象没有RESTful之前设计Web API,我们可能真的是每一个API都现想的,有了它之后,我们的纠结时间就变少了。这种情况下,通过本方法,架构师也算是有了相应的数据支持,那么架构师也就有了发现问题的一种工具。

结论

总的来说,任务列表法+PDCA式工作法形成的组合方法,是一个通过逐渐提升个人能力以达到高效工作的方法。这两种方法单独拿出来用,都会由于各自的局限而有各自的天花板,只有有机的结合才能真正突破这个天花板。刚开始使用起来,对于很多人来说会有一些痛苦,这一点上我只能说,提升就是痛苦的,而新的习惯一旦养成,痛苦也就不翼而飞,所以美国心理学之父威廉詹姆士说,“我们需要在尽可能早的时候,让尽可能多的有用的动作变成自动的和习惯的……一段痛苦的艰难时期之后就是自由的时光”。当我们基础能力达到一个极高的效率之后,我们会发现我们争取自由的筹码会变得更多。

广告时间

有人可能会觉得列出符合上文所述标准的任务列表比较难,欢迎阅读拙作《像机器一样思考》系列文章:

像机器一样思考(一)—— 宏观的基础
像机器一样思考(二)—— 数据的细节
像机器一样思考(三)—— 穷尽就是力量
像机器一样思考(四)—— 一图抵千言
像机器一样思考(五)—— 第一个应用
像机器一样思考(六) —— 脑中的重构
像机器一样思考(七) —— 跨应用思考