朋友们好,学习进度慢了些,此次继续学习《软件质量管理和保证》的第11章‘高质量的软件需求分析’和第12章‘提高软件设计质量’。
先看书里的摘录,这两段分别从软件项目失败原因比例和费用角度分别说明,软件需求分析的重要性再怎么强调都不为过。
StandishGroup调查了自1995年开始的8000个软件项目,结果显示:三分之一的项目没能完成,而在完成的项目中,又有二分之一的项目没有成功实施。与需求过程相关的原因占了45%(其中缺乏最终用户的参与占13%;不完整的需求占12%)。ESI在对17个国家3800公司的调查(1996年)中发现超过50%的问题存在于需求规格说明和需求管理中。
Boehm的调查(1981年)显示,在项目的最后阶段修正需求错误比在需求阶段修正它要多花费200倍的代价。
最近传的沸沸扬扬的一篇7.5万字雄文‘置身钉内’,没看的可以搜着来看看,失败的故事其价值往往会胜过成功的故事,其中不乏对需求的很多理解。
项目视图描述了产品最终所具有的功能特征集,范围描述了产品应该实现的部分和不应该实现的部分;当然,它还确定了项目的局限性。
书中介绍了一个项目视图法来呈现功能特征集,外行没接触就不聊了,但对其说的描述范围很有感触,一般就理解可能是要把要做的放进去就行了,但实则不应该实现的部分也同等甚而更加重要,所谓项目的局限性就是项目都是有边界的。
能想象这个场景,如果在软件要做的和不要做的东西之间反复变更跳转,这个是非常痛苦的,所以如果能一开始就想清楚,定义明白,肯定会节省很多心力。
这个我有过切身的体会,当然我那个时候是作为内部客户,就是我们一开始需要什么,是有一个框架的,但是在做的过程中,你会发现希望软件有更多的功能,这个时候你忍不住就想把新的需求加进去。怎么办?项目明确拒绝,最后是妥协了,加了一个第二阶段来实现这些新需求。
需求很重要的另一面是需求的获取非常困难,也最容易出错。
我先说一个小例子做一个前味菜,之前在洗衣机工厂上班的时候,去跟终端客户交流,记住啊我们这个可是选的实打实的外部终端用户。洗衣机核心功能单一,就是把衣服洗干净。
那什么叫把衣服洗干净?有些是比较直观的,就是洗完以后衣服上还有可见的污渍,那还有些是洗衣液有残留等。那这些问题还是好解决的。但你知道现在城市里的衣服很难有那种特别脏的,但是依然会有客户反馈说你们的洗衣机洗不干净衣服。
有一天我们在跟客户聊的时候,说出来令人啼笑皆非,她判断衣服能否洗干净是说你这个洗衣液放进去以后不起沫,就是不起沫代表不干净。这个回头立马改正,让洗衣机在前期多进点水沫就肉眼可见了。但这个点你在前期哪怕跟客户聊,能得到这样的信息吗?要打问号吧。
在看《置身钉内》的时候,里面看到有个共创的概念,这个概念也容易理解,就是找一些所谓的目标客户参与到软件开发的整个生命周期中来,其实是非常好的,想达到的目的是让这部分人代表客户提意见,早改善。
但是里面揭示了一个现象还是蛮触目惊心的,即参与共创的人因为自己从头到尾参与,一者不断有人会去解释,很多功能为什么要加?哪怕他提出来好像没有价值;这个按钮为什么要这么放?哪怕他提出来这个按钮有误碰的风险;二者随着自己的参与,也有了主人翁的代入感,自己已经不是客户了而是软件开发者中的一员。
这个现象其实很可怕的,因为等这个在内部一片叫好的软件面对真正的外部客户时,这些外部客户是没有这些开发过程和解释背书的,可想而知,只能是一片唏嘘了。这个值得警惕。
补充下,有个叫‘The Mom Test’的需求沟通方法,需要可以去详细学习了解下,这个列举核心三点。
谈论他们的生活,而不是你的想法:访谈应聚焦于了解客户当前的工作流程、痛点和已尝试的解决方案,而不是推销自己的产品概念。
询问过去的具体情况,而不是泛泛而谈或对未来发表意见:问题应指向客户过往的真实行为和经历,避免关于未来意图或假设性场景的提问。
少说,多听:访谈者的角色是引导和倾听,让客户提供具体细节。
我接触的更多是硬件,硬件有原型制作,早期的时候更多是东拼西凑,现在3D打印已经很成熟了,细节满满价格也能接受,所在公司自己有3D打印机了,很酷啊。
软件的理念比较多的都是来源于硬件,这里的原型制作也是如此,拿到需求后,不要急着做一个所谓的完美品出来,先东挪西凑地搞一个能跑的原型出来,让大家有一个实际的感受,去印证一下需求,这个时候需求调整成本是很低的。
用例分析技术的历史源头可以追溯到1967年,当时Ivar Jacobson在瑞典爱立信公司负责AXE电话交换机项目时,为了解决大型复杂系统的需求捕获与沟通问题,开始探索并实践一种基于“使用场景”的描述方法。这种方法后来在1987年被他正式总结并命名为“用例”,并最终成为统一建模语言(UML)和统一软件开发过程(RUP)的核心要素。
做个记录,use case 现在常常挂在嘴边,起源在这里。
这一起源意味着用例技术从一开始就强调 “从外部用户视角定义系统功能” ,将系统视为一个黑箱,聚焦于系统能为用户提供什么可观测、有价值的服务,而不是系统内部如何实现。这种思想从根本上区别于传统的、从内部结构出发的功能分解方法。
我倾向于认可这个观点,尤其是AI技术的当下,AI之争已经从模型本身的能力转为实际场景的应用。模型再牛,跑分再高解决不了用户实际的痛点,那也是白搭。
书里讲到结构化分析建模这个环节,没懂不展开学习,但是对数据字典和词汇表有感触,摘录下。
创建数据字典和词汇表,可以大大减少由于项目的参与者对一些关键信息的理解不一致带来时间浪费。如果能够保持词汇表和数据字典的正确性,那么在系统的整个维护期以及后续产品的开发中,它们都将是非常有价值的工具。
数据字典和词汇表,就是建立共同语言了。写个啥缩写,大家能立马心领神会,那就很棒了。反之,如果不理解,说半天还是鸡同鸭讲,那就很糟糕了。
联想到一般外企就喜欢搞缩写,如果你从一家外企跳到另一家外企的时候,可能会经历一段头疼的日子,缩写词汇很可能打架,哈哈。
审查要素如下。
正确性/完备性/易理解性/一致性/健壮性/易修改性/易测试性和可验证性/易追溯性/兼容性
健壮性,你们能理解哦?我学了也老是忘记,好像硬件需求很少提健壮性。做一个单独的记录,健壮性是分为容错能力和恢复能力。我很健壮,容错能力体现在别人打我一拳我啥事没有,那我容错能力很强;恢复能力体现在,别人打我一拳我确实是受到影响了,但我需要多久就恢复了,或者恢复了几成能力。
另外,需求评审也是非常重要的一个节点,用之前学习的点就是基线。你看,很多后面的东西都要在这里体现,后面遇到的麻烦就往前倒腾,绝大多数都会倒腾到这里。这里多花点时间是值得的,当然不是说仅仅是需求评审这个狭小的节骨眼哦,往前走到需求收集本身上。
参与评审的人
各自所处的立场不同,对同一个问题的看法也不相同。
对系统有足够了解的人员参与进来、领域专家不一定就是评审专家
参与评审的人很重要,有很多误区先要排除掉,人不是越多越好,这个好理解些。领域专家不一定是评审专家,第一看到有点反直觉,对吧?我们往往有专家和权威光环,但是如果这个专家对本身参与评审的项目一点不知,发表的意见会是什么样子呢?隔靴搔痒,说不到点上。
我记得第一家上班的公司的时候评审是有个专门的评审专家的,后来经历的,更多是各个部门的经理,一般也都是技术或质量背景。
分层次评审
目标性需求/功能性需求/操作性需求
分阶段评审
分阶段评审好理解些,因为天生产品是有很多阶段的。分层次评审有个拆解,我觉得这个理念很好,这样你每次评审的时候可以邀请少数的人,高效有效地进行评审。
它的目标是最大限度地减少需求变更带来的误解和错误,提高生产效率。
变更控制就像双刃剑,过于繁杂的变更控制会削弱团队创造力,新颖的设计思会被扼杀;而无控制的变更就像脱笼的猛虎,难以控制,会迅速导致混乱。
关于变更,要建立一些基本概念,譬如变更不可避免,敏捷开发之拥抱变化对吧,这个之前有文章聊过敏捷开发。还有变更要有价值,到底为了什么而变,而不是为了变而变,为了变而变说的是变化的东西实际对客户并没有什么价值,而是可能为了宣传,噱头,甚而是为了满足一些上层的趣味,这些有时候已经超过了项目的能力范畴。
回到本节,还要注意需求变更需要控制,控制也需要掌握一个度,要平衡。
软件需求分析交付以后,接下来最重要的就是软件设计了。硬件里叫概要设计,我看软件这样叫好像也能懂。学习下软件设计的目标。
可靠性/性能和安全性/可扩展性/可定制性或可移植性/可维护性/可重用性/可测试性和可追溯性
这里,我说下我学这本书得到的比较重要的一个点吧,就是建立度量的意识。这里建立了目标,那立马就得关联到如何去度量。
举个例子,譬如可追溯性,设计阶段要往前能追溯到需求里面皆有定义,这个反过来理解,设计不能设计出需求没有定义到的内容。
只有两条:
设计过程始终以质量为目标而展开。
设计越简单越好。
思想原则10条
用户需求远比技术重要
需求其实很少改变,改变的是我们对需求的理解。
接受变化。建模期间考虑这些假设的情况,就有可能开发出足够强壮且容易维护的软件。
不要低估软件规模的需求。
软件设计没有捷径。避免走捷径,只设计一次但要设计对(do it once by doing it right)
不要对某一种设计模式、体系结构崇拜。越成熟的或越被广泛应用的模式或体系结构,应优先得到考虑。
沟通对设计质量的提高同样重要。
工具只是手段,不能代替一切。
理解完整的软件开发过程,设计者要考虑全局,对需求、编程、测试、维护过程和方法也要非常清楚。
常做验证,早做验证。
原则性的东西,值得反复念。
迪米特则(Law of Demeter,LoD)或称最少知识原则(Least Knowledg Principle,LKP),一个对象应当对其他对象有尽可能少的了解。如果两个类无须直接通信那么这两个类就不应发生直接的相互作用;如果其中的一个类需要调用另一个类的某情法,可以通过第三者转发这个调用。
降低类之间的耦合度是其核心目标,外行理解下,就是各管各事,各过各日子那是最好,实在要联系,找个中间人搞一下。但任何事都讲究平衡的魅力,显然如果中间人太多了也不好。
在学习到这里时,其实是被独立性三个字所吸引,衍生学习搜到一句话也送给朋友们。它出自美国作家、诗人克里斯托弗·莫利(Christopher Morley,1890-1957)。
“There is only one success, to be able to spend your life in your own way, and not to give others absurd maddening claims upon it.” (成功只有一种:按照自己的方式度过人生,而不让别人那些荒唐而令人发狂的要求支配你的生命。)
将设计模式引人软件设计和开发过程的目的在于充分利用已有的软件开发经验,这是因为设计模式通常是对于某一类软件设计问题的可重用的解决方案。
这句话是一句福音吧,如果有一个东西直接批量复制就解决了问题,太棒了,直接复用那是更好。想到了现在agent了又,现在经常刷到介绍‘一人公司’啊,旗下安排几个agent,agent下面搞几个skill,拥有24小时打工机器人,想想还挺美的。
这就是技术啊,开发一种能力,打包下,批量应用。有没有要注意的呢?那显然也有,是借助设计模式,显然不是量身定做的,所以具体问题还要具体分析,不能一股脑硬用,出现一些过设计就得不尝失了。
书里面给讲了一些模式,譬如MVC设计模式( Model-View-controller, MVC)模式。还是上面独立性的逻辑,各干各事的好处就是相互间影响小,一个要动就动了,不用太考虑对其他两个的影响。反过来,看缺点也是一样,要搞很多中间人来把独立的模块给串联起来,那势必也会带来架构的复杂了。
还是回到那句话,没有绝对意义的好与差,只有适不适合。
规格说明完成后,需要对系统的各个模块及模块之间的关系仔细地分析,从而确定哪些部分使用硬件完成,哪些部分使用软件实现。
之前说,早期硬件出现在前,软件发展在后,软件的很多概念是借鉴的硬件成熟逻辑。现在渐渐发展到两者相互促进,继而是两者可以互相替代,我看到这个就有一个问题就是依据什么来选择靠硬件还是软件呢?
大家感兴趣可以搜,实践的时候依然是没有一刀切的标准,看你的需求,看你实际的预算,看你软硬资源的协同性等等,这里就不展开了。
延伸学习的时候,搜到一个概念叫FPGA, Field Programmable Gate Array,理解为可编程的硬件,这就让软硬件的边界没有那么明显了,硬件也可以编程了。时代在发展,一起期待更多厉害的事物。
数据是一个软件系统的核心,数据层则是介于系统与数据库之间,为两者交互提供服务。因为业务的不确定性或业务发展,导致系统的变更几乎无法避免。同时一个开发好的系统也可能需要使用不同的数据库。引入数据访问模型使得变更在数据层不用更改代码,可以使用同一个数据层组件来适应不同的系统。
理念比具体的方法更为重要。拥抱变化不是一句口号,而是从具体机制上得到落实。之前知道软件天然比硬件有更多变化的地方,那对应之法不能像硬件那般,只要有变化就要全部推倒重来,靠纯粹的项目响应速度来支持,显然不现实。而是要把经常可能变化的地方隔离开来设计,让其他模块无感变化那是最完美。
开发者不需要被迫使用某项目开始时采用的过时技术,不受遗留系统技术的约束。
我看到这个还有点感动的,为什么?现在项目开发,有时候为了提高复用性,缩短开发时间,降低开发成本,直接依赖老的产品,甚而是过时的技术以及没有解决的历史遗留问题。带来的是,同样的问题变成跟基因一样代代继承。
微服务架构好啊,不受历史的约束。
但这里也就是说一说,依然回到核心远点,没有绝对的好只有适不适合,简单延伸学习就看到微服务架构也有很多劣势,如网络延时,调用链路长等就不一一罗列了。大家感兴趣再拓展学习。
好了,这两章学习结束。我们下期再见。

夜雨聆风