我在大学里面学的专业是自动控制。反馈是任何自动化控制系统中必不可少的。比如,在控制锅炉炉温的控制系统中,想要把炉温控制在600℃,那么传感器必须周期性采集锅炉的温度,控制系统再根据炉温来调整火力。温度不够的话,烧火的还得再给点力;温度差不多了可以一边歇着了。
反馈的概念相当简单,它在很多地方都发挥着重要的作用。本文抛砖引玉,初探软件开发流程和实践中的反馈以及利用反馈来改进流程的一些想法,并利用反馈的原理来分析现有的开发流程和佳实践。
软件开发中的反馈
大型软件的开发是分布在世界各地的开发人员的数个月的体力和脑力劳动。各大公司都有一套开发流程来保证产品能够按期交付。如果仔细分析这些流程以及流行的佳开发实践(Best Practice),它们无不是利用了反馈的基本原理。
在软件开发中,我们应特别关注反馈的以下两个因素:
反馈的成本(Cost):成本主要是指要花多少开发或者测试人员的时间来获得反馈。
反馈的价值(Value):如果没有这些反馈信息,会产生什么影响,以及在以后需要多大的成本来修复,这也是反馈的价值。
仔细分析流程中反馈的这两个因素,可以找到流程改进的方向:
关注流程中成本过高和反馈时间太长的反馈,想办法使得某些反馈能够自动化。尽量减少人工的参与,因为人的成本是很高的。
去掉或者优化流程中那些成本大于价值的反馈。反馈的引入是为了及早发现问题,因为通常问题早发现的修复成本更低。但是如果问题不严重,而且修复的成本也很低,为什么要在前期花更多的时间来避免这样的问题呢?
开发流程的反馈
1、原型测试
在项目正式开发之前,产品经理通常会和交互设计师一起设计系统的原型,然后邀请一些用户来做测试。
原型测试将用户对产品的想法,比如用户是否对产品有需求,用户是否愿意掏钱买等信息反馈给了产品经理,使得产品经理能做出相应的决策,比如如何去调整产品的方向,是否继续在这个产品上投入。在这个反馈中,反馈的成本远小于反馈的价值。如果方向错了,后期开发和测试的时间都是白费了,所以原型测试被广泛地采用。没效率的事情是在错误方向上努力做事。
我所在的公司,开发人员在开发与界面相关的功能时,也是首先用mockup工具或者画图板把界面先画出来,找到相关的专家审核,通过审核后再开始写代码。虽然看起来正式写代码的时间比较晚,但是能避免后期返工,所以总的时间比一上来写代码花的时间要少。
2、开发过程中的反馈
2.1 集成开发环境(IDE)中的反馈
用过Eclipse的程序员都知道,假如写错了一个关键字或者方法的名字,Eclipse会立刻高亮显示错误的关键字,这样程序员可以立刻修改错误。IDE将语法和编译错误及时地反馈给了开发人员。在这个反馈中,反馈几乎是实时而且几乎没有成本的,极大提高了生产效率,所以在实际的开发中没有不用IDE的。
2.2 单元测试
单元测试是对一个类或者方法进行的测试,它保证你写的类或者方法是按照你的想法工作的。
单元测试将一个类或方法中的错误反馈给了开发人员,使得开发人员能及时修复错误。单元测试中发现的问题通常很快能修复因为测试的范围于一个类或者方法。在这个反馈中,写个测试案例可能只要几分钟,但是如果不进行单元测试而是直接把整个系统跑起来测试,很有可能你的一个拼写错误(比如把!=写成了==)要花上1个小时才能发现,或者你没有考虑的边界情况在客户现场导致很诡异的问题,要花上几天才能找到原因并且给客户不好的印象。仅仅从这个角度来讲,单元测试也是很有必要的。想要做好单元测试,需要良好的环境支持,参见这里。
2.3 代码审查
医生通常不会一个做手术,那么同样程序员也不能一个人写好代码提交了。因为是人会犯错误,代码审查是让其他同事帮助发现代码的问题。
代码审查者将代码中如下问题反馈给开发人员,比如代码风格是否统一,新写的代码是否符合系统的设计思路,是否重新发明轮子等等。
真要做好代码审查,成本还是蛮高的。首先,为了让别人能看理解你的代码,特别是代码比较多的时候,要组织大家来介绍一下背景,然后被邀请的同事再去阅读代码并提出修改意见。其次,争议比较大的时候,还要组织会议来讨论这些修改意见。可以看到,代码审查不是占有一个人的时间,而是几个人的时间。所以,从提交代码审查到拿到审查意见的反馈周期还是有点长,一般需要1-2天的时间。
为了使得代码审查的反馈更加及时,我所在的团队采用的方法是,在做大的改动之前,先把修改思路和设计方案与审查者沟通一下(解决方案的审核),及时发现与当前系统设计不一致的问题,然后才开始编码,从而避免代码已经写好了,审查者对系统设计提出大量的意见。
如果没有代码审查的话,
可能会隐藏某些潜在的问题(比如,某人改动了一个基础的方法,没有考虑到该方法在其他地方也用到。其他同事在审查代码的时候也许能帮助发现问题);
新写的代码与系统初的设计思路不吻合;
重新发明轮子,同样的工具方法,每个人都实现了一遍,到后谁也不知道该用哪个。
这些问题在后期是很难修复的,特别是涉及到系统设计的问题,开发人员会说,“已经通过QA的测试了,再修改的话,他们还得测试呢”,后也只好那样了。新加入的开发人员由于不知道一些历史原因,修改代码的时候参考现有代码,经过几个版本后,代码的设计和初的思路完全不一样,然后大家会抱怨系统设计得太烂了,之前的代码写得太烂了。
虽然代码审查的反馈成本高,但是没有代码审查的影响也很大。因此,在各大软件公司和开源项目中一直都是必须的,
3、产品运营数据分析
产品好不容易上线后,用户有没有使用新加入的功能,用得爽不爽,花了多少时间完成一个典型的任务。这些问题是产品经理们非常关心的,它们关系着产品是否达成预定目标以及未来产品改进的方向。不只是产品经理,开发人员也常抱怨自己不知道自己做的功能用户的反馈怎么样,如果能够得到用户正面的反馈对开发人员是极大的鼓舞。
收集产品运营的数据能够给产品经理提供这些方面的反馈。在这个反馈中,收集用户使用产品的数据的成本是非常高,需要在软件里面加入相应的功能模块,并且想办法把数据从客户那里传回来(这里针对的是客户端软件),后还得有程序来分析数据。但假如没有来自用户使用行为的反馈,做产品是盲人骑瞎马,加了一堆用户根本不用的功能,而对用户的痛点却一概不知。因此,现在很多软件里面都会收集用户使用行为,有的会告诉你搜集了哪些信息,有的流氓一点悄悄地搜集了。
这个反馈的时间很长,必须要等到产品做出来之后,并且用户使用一段时间后才能得到反馈,这需要利用原型测试来得到用户早期的反馈。
反馈与软件开发实践
1、持续集成
持续集成的基本思想是每当有人签入代码的时候,都会触发一次系统的构建(Build),并且运行所有的单元测试。如果有问题,立刻通知后一次签入代码的开发人员。在没有持续集成的时候,系统的构建通常是在夜深人静的时候启动,每天构建一次。
每天构建一次的问题是什么?如果有很多人提交代码,并且当天的构建失败了,或者有单元测试失败了,大家只有在第二天来的时候才知道,这将影响到等待需要用当天构建做测试的同事。同时,因为有很多人签入了代码,谁都有可能是导致构建失败的人。如果有持续集成,构建一旦失败,肯定是后签入代码的那个人的代码造成的,问题的原因很快能找到。
持续集成将新签入代码对系统的影响的反馈时间从下降到一次系统构建的时间。持续集成的成本很低,一旦配置起来,无需开发人员的参与,一切都是机器自动完成的。因此,现在持续集成是个非常热门的话题的。
2、敏捷开发
传统的瀑布开发流程是全部开发好了再交给客户。而敏捷开发的思想之一是在每个迭代结束都向客户交付可以运行的软件并听取客户的意见。显而易见,客户反馈的时间明显减少,客户的需求也能在下一个迭代中得到解决。
3、结对编程
结对编程可以解决代码审查反馈时间过长的问题。当你在写代码的时候,你的伙伴扮演了代码审查者的角色,并持续地给你反馈。但是其成本较高,没有被大规模地采用。
总结
软件开发流程和实践非常多,在决定是否增加一个步骤到流程中或者是否采用某种开发实践的时候,看看它是否在流程中增加了反馈,并利用反馈的基本原来来分析一下,它带来了什么,成本是什么,没有它又会怎么样,有没有替代的办法来平衡反馈时间和成本,这样才能调整出适合自己团队的流程。