1.1 实现了期望的功能
软件理应实现期望的功能,这无须多言。如果开发的软件不能给业务相关人带来价值,那对它所做的一切开发活动自然都是浪费。
不过,碍于软件所解决问题的复杂性和人类沟通的复杂性,实现期望的功能并不那么容易。在实际工作中,我们经常会遇到下面这些情况。
用户心目中的目标和用户能描述出的内容并不一致。
产品经理所理解的用户表述,和用户描述的内容存在偏差。
产品经理编写了需求文档,但未能进行精确的需求表述。
即使需求文档表述准确,开发者也有可能产生误解。
即使开发者的理解是正确的,也可能存在用户没有描述出来的隐含需求。
……
历史悠久的秋千漫画
相信有不少读者见过图1.1的这组漫画。不过,很少有人考证过它的历史。如果知道这幅漫画的历史有多长,或许你会大吃一惊:原来在软件领域,过了这么多年,这组漫画描绘的问题一直都在,并没有随着技术发展产生根本的改变。
图1.1 历史悠久的秋千漫画
据考证[1],这幅漫画的最早版本至少在1968年就出现在公开出版物上了,迄今已有50多年的历史。它形象地反映了我们刚刚描述的情况:用户真正需要的和用户描述的往往并不一致,经过层层加工,信息更是进一步失真,最终不仅成本大量超出预算,所开发的东西也不能真正满足用户的需要。
1.1.1 为什么需求问题如此普遍
没有谁愿意把宝贵的人生耗费在毫无价值的错误需求上。不过仅仅“不愿意”是不够的,只有在理解了为什么会有这样的问题之后,才能找到恰当的解决方案。
软件解决的是现实世界的复杂问题
需求问题如此普遍的最根本原因是软件解决的是现实世界的问题。现实世界有多复杂,软件就有可能多复杂。从图1.1中的第一幅画和最后一幅画就可以看出:即使是用户自己,其表达出来的需求也和自身真正的期望相去甚远。
开发软件的过程是一个持续建立认知的过程。我们不能寄希望于业务人员一开始就对问题有直达本质的认知,随着开发过程的展开,渐渐地弄明白问题是很正常的。同样,我们也不能寄希望于开发人员一开始就能有直达本质的解决方案,随着开发过程的展开,渐渐地弄明白方案也是正常的。
要真正产出有价值的软件,需要关注以下两个重要的方面。
加快认知的过程。
增加设计的弹性,在出现问题时能较快调整。
高质量沟通是困难的,也是容易被忽略的
秋千漫画还反映了导致需求问题产生的另一个重要维度:沟通。在现实世界中,每一次信息传递都意味着一次信息损耗。在综艺节目中有一个常见的“拷贝不走样”游戏。这个游戏之所以有趣,是因为信息在前后传递的过程中,很可能会产生偏差。
在软件开发中,情况也非常类似,即使一开始的认知是正确的,可由于信息传递过程中不可避免的偏差,也常常导致最终的产出和预期相去甚远。如何降低信息在传递过程中的失真,也是软件开发人员不得不面对的一个问题。
实现高质量的沟通非常困难,身在其中的人往往并不自知。一个经常发生的现象是:业务人员觉得自己已经交代得很清楚了,开发人员也觉得自己理解得很清楚了——结果是表面上一致,事实上却谬之千里。
此外,“实现正确的需求”并不仅仅局限在系统层次。系统的某个局部可能是由多个开发者协作完成的,这个局部也存在需求问题,并且越是局部问题,细节就越多,这些问题也就更加值得重视。
1.1.2 解决问题的方向
优秀的开发者会关注自己开发的软件的真正价值,而不只是盲目地接收到手的需求。实践表明,开发者的积极投入是高效理解需求、提升设计质量的关键。没有来自开发者的积极沟通,需求设计的质量就很难提升,开发工作的结果自然也不可能太好。
结构化的探索
软件开发从本质上讲是“从无到有”的过程,在这整个过程中,一个客户或业务方脑海中的想法,逐步变为真实运行的软件系统。
“从无到有”意味着探索,而探索是需要结构化的方法的。如果没有清晰的探索方法,探索效率就不可能高。一件事情的确定性越弱,所需要的结构化思维能力就越强。例如,面对需求的不确定性问题,本书第3章介绍的需求分析金字塔就是有效探索需求的方法。此外,第4章介绍的领域模型,则是增强认知、加强沟通的重要工具。
注重沟通
优秀的软件工程师往往也是沟通的高手。不得不承认,许多人可能对此有偏见。如果认为编程就只是和机器打交道,那就忽略了软件其实是解决现实问题的工具这一本质。软件工程师不一定都开朗活泼、妙语连珠,但是在尊重他人、认真理解对方意图、准确达成一致方面,优秀软件工程师的表现至少和其他行业的沟通高手相差无几,甚至远远超出后者。
强调设计契约
契约不是让客户“签字画押”。在认知不足的时候“签字画押”只能是一种双输行为。契约的本质是信息明确、以终为始。只有尽可能地强调明确,才可以发现需求的模糊性,提升在早期发现问题的概率。
本书中有大量围绕设计契约展开的内容。例如,第6章会讲解如何把接口表述为清晰的设计契约,第7章会讨论如何通过测试前置的方式,促成需求或者设计契约的明确化,并对理解一致性展开早期验证。
做到演进式设计
如果软件设计得足够好,那么完全可以在用户需求发生变化时随机应变。与此相对的是惧怕变化。设计有“刚性”和“柔性”之分。刚性的设计无论考虑得如何周全,也仅能适应预先认知的场景。柔性的设计恰恰相反,它可以灵活地适应环境的变化。好的设计应该是柔性的。
做到演进式设计极其重要但是并不容易,它需要坚实的设计基础和卓越的设计实践。这就是第11章将要探讨的核心内容。