DDD领域驱动设计批评文集>>
《软件方法》强化自测题集>>
《软件方法》各章合集>>
本文转载自:https://juejin.cn/post/7051749719214653471
本文是基于lucio最近对软件方法的学习,整理了lucio学习后的一些思考,我们不会去了解,像UML等实操的内容,只是分享一些,我以前“不了解”,读到后“大受震撼”的观点。
开发的时候,你在烦恼什么?
在诸如CSDN和掘金的技术论坛上,各种软件开发相关的教程琳琅满目,几乎所有我们编码过程中,可能出现的问题,都能找到对应的答案。
这些对刚刚接触软件开发的我们来说,有很大的帮助,我们个人编程技术的增长,也是随着一篇篇技术文章的阅读,一步步增长的。
但是随着参加工作的时间增加,lucio慢慢发现,让lucio烦恼、占用每天大量工作时间的,不是解决不了的技术难题——技术难题最后总能找到解决方案的,而是难以理解的需求、没完没了的实现细节确认沟通、急促的排期和改不完的bug。
如果一个需求,让lucio半夜三点辗转反侧睡不着,绝对不会是因为不知道某个技术点怎么实现。更常见的原因是:担心排期时间到了,完不成工作;担心产品上线了,突然有发现了bug;发现某个需求迭代,由于旧代码实现留下的坑,你不得不用更复杂的实现,去挖下另一个坑。
编程技术水平,我们学的快或慢,只要肯学一定会有提高。但是这些困扰我们的,编程技术之外问题,应该怎么解决呢?
有的开发人员可能会觉得,这是解决不了的问题,因为问题出现的原因并不在自己身上,产品经理提的需求不清晰,产品经理总是变更业务实现,项目经理安排的排期不合理。
确实,缺乏知识经验产品团队,和不流畅的沟通,很容易带来糟糕的开发体验,但是我们技术人员认真剖析自己想一想,我们自己就没有问题么?
如果还是觉得没有,或者问题不大,那我们来好好思考这几个问题:
- 什么样的需求是“好需求”,什么样的需求是“坏需求”?
- 业务流程“又”变更了,为什么你之前没预料到它会变更?
- 看完需求文档,你真的理解需求了么?为什么会有这个需求,实现了需求,对谁最有好处?
仔细想想,是不是发现好多时候,我们对需求好坏的判断,都是自己主观的想法,或者基于以往经验的判断,并没有真正的标准和依据。“这个看起来不太清晰...”,“以前不是这么做的...”,这样的说法,显然很难说服产品经理。
有时候我们确实改变不了开发上游的工作规范,但是至少在开发环节,我们能把需求分析这一环节做好,做好了需求分析,我们可以更合理的进行软件的设计,可以避免小变更带来大规模的修改,甚至可以反推产品,补充需求中不完善的路径,预先确认好可能发生的变更点。
结论
很多时候,我们的烦恼,都来前期对需求分析的不充分。
需求分析确实会耗费一些时间,但可以肯定,但带来的收益能证明花时间是值得的,这种收益随着项目体量增大,会体现的越来越明显。
如果想了解如何进行需求分析,不妨接着读下去,一步步去理解,什么是软件开发?什么事需求分析。
软件开发是在做什么?
长久以来,我们在编程中做的优化,主要的目的就是两个,节省编码的工作量,让软件提供更好的服务。
但依据《软件方法:业务建模和需求》这本书中的观点,我们开发软件,做需求就是为了销售,提高需求的质量,就是为了提升销售额;编码设计就是成本,我们优化编码,节省编码的工作量,就是降低成本。
经营的公式是:利润 = 收入 - 成本。
软件开发的公式就是:利润 = 需求 - 设计。
结论
我们软件开发的目的,无论是节省工作量也好,提升用户体验也好,最终的目的,都是为了提高利润,这个利润,对我们开发人员来说可能并不直接体现,但也以其他各种红利的形式反馈给我们。
谁在为软件买单?
我们开发了一款软件,这个软件是为谁服务的?
这是一个很容易给出错误答案的问题,我们举几个例子:
问:微信支付,这是几乎每个人都会用的产品,微信支付是为谁服务的呢?
答:用户,使用移动支付购买的用户。
相信这是很多读者的回答,很遗憾,这个回答不正确。
仔细想想,微信支付并没有从使用移动支付的用户那里收取费用,用户也不会为了可以更快捷的支付,给微信支付买单,比如假设每年交100块的会员费,才可以使用微信支付,相信很多人会选择不用。
真实为微信支付买单的,是接入微信支付的商户,是他们给微信支付交手续费。而微信支付给他们带来的,是提高收费的效率、减少出错、让用户不带现金也能走进商户消费。提升移动支付用户的体验,其实最终目的也是为了让更多人去商户使用微信支付,为了商户的利益。
类似的例子,一个武侠风的RPG游戏,服务的不是大多数的零氪玩家,而是那些真实为游戏充值的人,零氪玩家更像是游戏开发者提供给氪金玩家的玩具。
类似的例子,支付宝的过年集五福,服务的不是每天矜矜业业扫码的用户,而是五福卡片背面的商家、品牌,支付宝的产品可不关心最后用户瓜分了多少红包,他们需要关注的,是品牌广告有多少的露出,商家发出的优惠券,给商家带来了多少转换和利润。
理解软件真正的目标人群,真正为谁服务,需求分析时,产品提出的很多交互就更好理解了。比如用户集五福的时候,有个痛点,是每张优惠券都需要从福卡翻面去领取,为什么不领到福卡后,就直接把优惠券收到卡包呢?因为集福卡,可不是为了让用户方便,其真实的目的,是让支付宝的商户和品牌有更多的曝光和核销,这一步“繁琐”的操作,就是为了让用户多看一眼领到了什么优惠券,多思考一秒要不要去用这个优惠券。
结论
需求分析的时候,我们常犯的一个错误,就是忽略去思考需求的目标人群,以及我们能为目标人群提供什么样的服务。多思考一下这个问题,我们也就能进一步理解产品经理提出需求的意图,理解意图后,在程序设计阶段,我们就可以设计更合理的架构,为可能出现的需求变更预留好接口。
其实很多的需求变更,都是可以预见的,是“假的需求变更”。理解需求的意图,能提高我们预见变更的能力。
改bug,实际上改的是什么?
软件出现的bug,一般是什么问题导致的呢?我们经常会在复盘的时候,给bug基于原因做分类,比如前端逻辑错误、后台逻辑错误、需求理解错误等等。
随着开发经验的增加,单纯因为编程设计导致的bug,会越来越少,随着和产品团队的磨合,我们遗漏需求功能点、文档理解错误的情况也会减少。
但是bug依旧存在,而且越来越多的bug,其出现的原因变得“不好解释”,比如下面这个故事。
程序员小张完成了一个抽奖的功能,产品小红体验功能:运气好,抽中了,显示“恭喜获得”;运气不好,没抽中,显示“很遗憾,你运气不好”。貌似一切都没什么问题,于是小张和小红开开心心得把功能上了线。
但是没过多久,线上出问题了,许多用户抽了奖,却什么都没显示。小张连夜排查问题,终于发现了,用户抽中了礼包,但是礼包早被消耗完了,于是用户什么也没有看到,于是小张连夜给抽奖代码加上了判断,告知用户“礼包发完,下次再来吧”。
问题复盘的时候,小张需要选择bug原因,虽然觉得有点懵,但确实是改了几行代码问题才解决的,于是,小张恹恹的选了“程序逻辑错误”作为bug原因。
QAQ摸摸小张的头,问题出现了确实有点问题,但至少不能因此就说小张的编程能力不行,就上面的问题来分析,“程序逻辑错误”并不是最本质的原因,我们透过现象看本质,导致问题最本质的原因,是“需求逻辑的错误”,当然这也不能说小张完全没有问题,小张的问题在于没有进行需求分析,没有及时发现功能点缺少的扩展路径。
结论
实际上,我们改的很多bug,本质上都是需求逻辑错误,出现问题的原因是我们没有对需求进行分析。
一个功能点,有基本路径和扩展路径。
基本路径,是用户与软件交互最顺利,最终能达到目的的路径。
比如用户用银行卡到自助取款机取钱,其基本路径是:用户插卡->输入密码->输入金额->取款机吐出现金。
扩展路径,是基本路径外,其他发生意外的路径。
比如还是用户用银行卡到自助取款机取钱,存在的扩展路径有:
用户插卡->输入密码->密码错误;
用户插卡->输入密码->输入金额->用户余额不足;
用户插卡->输入密码->输入金额->取款机没现金了;
···等等。
产品提需求或者开发人员分析需求的时候,最容易犯的一个错误,就是只关注了基本路径,而忽略了可能存在的扩展路径。
开发需要进行需求分析,而且不只是浏览需求文档,更重要的是,发现可能存在的扩展路径,及时反馈给产品并一起补齐扩展路径,需求分析做好了,bug自然就少了。
学会辨别什么是“好的需求”?
很多时候,我们判断需求写的好不好,都是凭借过往的经验,或者看需求文档里面字多不多、流程图画的多不多,交互图清不清楚。这虽然也有点道理,但是不完全是对的。
你奋笔疾书一个月抄了整本新华字典,不能就直接把曹县的文科状元颁给你吧。
那什么是“好的需求”,具体的判断可以读读《软件方法:业务建模和需求》一书,总结下来,需要有下面这些元素:
- 明确需求服务的目标组织(理解为谁服务,进一步理解需求)
- 明确需求带来了什么样的改进(开发通过这个点理解需求的意义,理解意义是为了更好的程序设计)
- 明确软件的执行者是谁(不一定是目标组织,比如高铁购票app的执行者是买票的用户,但是目标组织是高铁集团)
- 明确的系统用例(从业务序列图识别出来,表示需求中,软件提供给执行者的功能,比如抽奖活动,其系统用例有:用户->抽奖,用户->查看抽到的奖励,等等。这些常常是在需求中写出来详细流程了,但却缺少了提炼出一个功能点的地方)
- 对每个系统用户(功能点),有明确的用例规约,包括以下内容:
- 前置条件和后置条件(在什么情况下触发,最后达到什么目的)
- 涉众(什么人会参与到这个用例)
- 基本路径(最顺利的交互路径)
- 扩展路径(处理意外的路径,是最容易忽略的地方!)
- 补充约束(用户输入信息的验证条件,软件可以运行的平台,质量要求等等)
这些元素具体的组织格式,在需求中用什么形式给到这些信息,还需要进一步细化。
结论
但我觉得,不管是产品编写需求,还是开发人员分析需求,以这些元素作为check list,都能有一些意外收获。
其实需求文档的理解成本高、需求分析效果不好,最主要的原因还是在于缺少规范,如果提需求和分析需求,都有一个严格的流程和规范,禁止天马行空,自由发挥,那需求逻辑错误和沟通成本应该会减少很多。
当然,规范的制定和执行也是需要成本的,这块的推进,只能说道阻且长。
但是作为开发人员,我们可以先尝试一下,在需求分析阶段,用规范的建模来理解需求,从而服务于我们的程序设计。
UML:基于基本共识进行沟通
UML图,开发人员都会用,但是在什么时候用呢?
相信很多人和以前的我一样,只有到了需要向别人展示自己的业务实现方案的时候,才会去画各种UML,比如答辩或者项目成果展示的时候。
但这其实违背了UML图设计的初衷,UML图原本的目的是为了辅助程序设计的,而不是先有代码,再来画图。
这种“先代码,后画图”的工作方式,其实就是抛弃了“需求分析”这一环节,这样的工作方式,很容易导致整体设计的不合理,后续功能难以扩展。
UML图使用的另一种误区是,画了一个序列图,却需要展示者先来“讲一讲”,观众才能理解。
UML图是对业务实现的完整描述,是基于软件开发者的一些基本共识产生的。好的UML图,不需要实现者的讲解,也能准确描述具体的业务实现。
结论
UML图是辅助程序设计,实现需求的时候,不要跳过建模阶段,直接开始编码。
UML图的这些基本共识,是开发人员节省沟通成本的关键,所以,画图的时候,还是要严格遵循规范。
软件在解决什么问题?
软件的目标是业务现状的改进,这种改进,按《软件方法:业务建模和需求》书中的说法,可以分为三种模式。
- 模式一:物流变成信息流
- 模式二:改善信息流转
- 模式三:封装领域逻辑(用软件系统代替人脑)
物流变成信息流,是现在大多数互联网公司在做的事情,比如移动支付,把现金的交易,变成电子货币的交易。
改善信息流转,比如多个系统协作完成的工作,变成只需要一个系统来完成,比如现在很多政务门户app。
封装领域逻辑,比如相机的“笑脸捕捉”功能。
目前大多数软件,都是基于模式一、模式二做的改进。
结论
其实除了互联网产业,其他产业的改进,很多也是遵循着三个模式的。
当我们面对一个流程或者项目,找不到可以优化的点的时候,可以循着这三个模式,寻找可优化的点。
阿布思考法
通过需求分析,掌握了需求的来龙去脉后,在设计阶段,我们怎么更好地去设计需求的实现呢?
代码设计涉及到很多具体的知识和经验,这里是讲不明白的,lucio依旧还是只分析一些从书中学到的,对lucio有帮助的方法。
《软件方法:业务建模和需求》一书,提到了一个叫“阿布思考法”,就是遇到一个问题是,先假设自己拥有充足的资源,我会怎么实现这个需求?然后在回到现实中,用自己有限的资源,去山寨这个理想的方案。
这个思考法,可以帮助我们突破自身环境的限制,找到真正合理的解决方案。
我们应该都有过这样的经历,规划需求实现的时候,要考虑很多的东西:时间够不够、投入的人力值不值得、已有的组件是怎么样的、能做到什么程度……考虑的东西太多,我们就不得不对实现方案作出妥协,拿出一个勉强可以实现需求的方案。
但是这样的方案,往往是不好扩展和维护的,下次思考方案的时候,不如试试“阿布思考法”,抛开限制,思考一个经得起时间考验的方案。
知识的诅咒
知识的诅咒(Curse of knowledge)是一种认知偏差,指人在与他人交流的时候,下意识地假设对方拥有理解所需要的背景知识。
这也是开发人员和产品沟通的时候,经常犯的错误,我们不能假设产品同学或甲方了解我们代码实现的全部细节,就像我们不能直接拿着UML图和非开发人员讨论方案。
我了解的,别人不一定了解,这很正常,正确的沟通方式是,面对不同的人,采用对方可以理解的沟通方式去沟通需求,代码实现上的限制和难点也要尽量转换为更通俗的方式来解释。
参考资料
《软件方法:业务建模和需求》潘加宇
本文的大多数观点,是基于这本书的思考,这本书对分析需求和工作方式有很大的指导作用,但是也存在一些缺点,比如一些专业名词,和大家共识里面的名词不太统一,但是多读几遍,还是不影响理解的。
《UML和模式应用》拉曼
《编程原则:来自代码大师Max Kanat-Alexander的建议》马克斯·卡纳特-亚历山大
更多实际操作和代码实现的知识,推荐阅读这两本书。
[推荐升级]23套UML EA和StarUML的建模示范视频-全程字幕(2022.6.1更新)
6月23-26晚剔除“伪创新”的领域驱动设计-网络公开课
《软件方法》书中自测题-题目全文 分卷自测(1-8章)16套111题
《软件方法》强化自测题集110题
CTO也糊涂的常用术语:功能模块、业务架构、用户需求……[20210217更新]
如何选择UMLChina服务