服务器 频道

一文分析架构思维之建模思维

  软件里的要素不是凭空出现的,都是源于实际的业务。本文从软件设计本源到建模案例系统的介绍了作者对于建模的思维和思考。

  一、诸内必形于诸外

  软件开发工程师与医生、建筑师所做丛事的工作在本质上没有差别,都在解决现实遇到的问题,因此大家做事的方法也具有相通性。《黄帝内经》中讲到“有诸形于内,必形于外”,意思是人的身体内有了毛病,一定会在身体表面显现出来。比如我们常知道的感冒,有风热感冒和风寒感冒之分,如果咳嗽吐痰是白色的是风寒感冒,咳嗽吐痰是黄色的是风热感冒。

  所以,你会看到我们遇到的问题有表象和本质之分,表象是我们直观能看到的,本质往往是不明显的,是需要深入分析和思考才能得出。国医大师熊继柏把治病总结成两个关键点:一是病变部位;另一个是病邪性质。病变部位是具体在人身体哪个部位出现了问题,病邪性质是风、寒、暑、湿、燥、火中的哪一种或几种。因此,治病关键要知道身体里的哪个部位因为什么产出了疾病,如咳嗽是由于肺部受寒引起的,故治疗的方法是温阳散寒,宣肺止咳。而病变部位和病邪性质会表现在人身体的外表上,如鼻子显现出来的问题与脾胃关联性比较大,眼睛显现出来的问题与肾关联性比较大。

  医生治疗的方法有非常多,如八纲辩证、三焦辩证、卫气营血辩证等,国医大师通过病变部位和病邪性质高度抽象出了治病的本原,那么软件设计的本原又是什么呢?

  二、软件设计本原

  2.1 软件是现实世界的“相”

  在财务领域里做了2年时间里,让我深刻认识到一个体会:软件里的要素不是凭空出现的,都是源于实际的业务。比如财务里的收入,一定是某个具体的业务在某个场景下产生的,绝对不会凭空地做一笔财务收入出来,所以软件世界与现实世界是有关联的,软件里的要素一定是来源于现实业务。  

  软件设计的本原是将现实的“相”映射到软件中,将现实的“相”在软件世界中勾画出来(建模的过程)。现实的“相”可以通过在软件中表达,也可以通过人自己去表达,就像财务领域,没有财务软件财务同学照样可以做账,比如财务同学用Excel做账。不管是财务软件,还是财务同学自己,本身都是要去理解现实的“相”,只不过一个是在软件中,另一个是在财务同学的大脑中。

  软件就像照镜子一样,将现实映射到镜子中,因此现实发生了什么,软件中就发生了什么。比如我们买火车票,在12306网站出现之前,我们要到火车票售票窗口买,支付钱后售票员给我们一张火车票,在12306网站出现之后,我们在网站上支付钱后,我们就有一张电子火车票,两个是不是很相似呢,我们在现实中的行为映射到软件中的操作。

  那么现实的“相”又是什么呢?我借用财务领域的一个概念来表达,“相”即是业务事实,业务事实是通过业务事件可观测的,显性的业务事件好比“诸外”,隐性的业务事实好比“诸内”,“诸外”的业务事实和“诸内”的业务事实构成了业务模型。不管你有没有感知到,业务事实是客观发生的,就像你不是研究电磁波领域,但电磁波无时无刻在发生,只不过你没有关注而已。有的业务事实是可直接观测到,比如电商下单购买商品,有的业务事实是无法直接观测到的,比如WIFI,WIFI是看不见、摸不着,但它是客观存在的,因此“相”是有层次结构的。  

  2.2 “相”的层次结构

  “相”是有层次结构的,我将它分为两层:现象层和规律层,规律层决定现象层的表现,这个与诸内必形于诸外是同一个道理。比如交易系统,本质是平台协同卖家履约交易合约,因此在现象层我们会看到有买家下单、卖家发货、物流配送、买家收货、卖家收到钱的业务事实,而在底层驱动交易进行的是交易合约,它定义了平台、买卖家的行为,驱动着交易流程推进,买家支付后,卖家就要发货,买家收到货后,平台就要将钱支付给到卖家。

  感知现象层最简单的方法就是照着流程走一遍,就会知道整个流程中发生了什么事,而洞察到规律层就没这么简单了,要找到决定现象层的本质规律需要在这个领域有非常深的领域经验,领域是有专业壁垒的,正所谓外行看热闹,内行看门道。现象层是可观测的,更多的是在使用归纳法,不断在收敛、归纳业务事实知识;而规律层更多的需要使用演绎法,把业务事实的本质定义出来,往外发散,同时它是可被推导出来的(因为它是客观存在的)。  

  对应到软件设计中,如果我们只看到现象层的业务事实,那么设计出来的系统是面向业务场景和业务流程的功能设计,而业务场景和业务流程是发散的,具有多样性,那么系统的通用性、复用性会比较差,表现出来的现象是业务需求的研发效率提升不上去,平台能力不断在迭代升级,需求侧等平台侧排期。

  我自己是有过做过业务系统和平台系统的经历,在这一点上有比较深的感触,在做平台系统时习惯于做业务流程抽象,而忽视了领域本质业务事实的抽象,像业务场景、业务流程不是平台系统应该关注的事情,职责也应该交由业务系统的开发同学,平台专注于本质业务事实的处理,就像前面提到交易系统一样,需要专注在交易合约上。一个不太严谨的区分现象层和规律层的业务事实方法,如果两个处理的业务事实是同一个,大概率是现象层中的业务事实,就像操作系统中的内核开发和应用层开发,两个关注的东西和层次是不一样的,平台中如果处理的对象是业务系统中的对象,只能说抽象层次不够,还没有抽象出领域的本质业务事实。面向业务流程和业务模式抽象建设平台的方法被证明是失败的平台设计方法。

  2.3 软件设计本原的要素

  前面提到软件设计的本原是将现实的“相”映射到软件中,将现实的“相”在软件世界中勾画出来,那么落地到软件设计中应该关注哪些要素呢,或者说如何具象软件设计本原关注的事项,就像医生治病看病变部位、病邪性质那么简洁。

  业务事实是伴随着业务事件出现的,即一个业务事件出现了,对应着有一个或多个业务事实出现,比如财务收入的确认时点是用户签收的那一刻,那么用户签收就是一个业务事件,财务收入又会细分成多种收入,每一种收入对应一个业务事实。业务事实之间并不是孤立存在的,彼此间有关联关系,因此,软件设计本原要素我总结出来就三个:看业务事件;找业务事实;建事实关联逻辑。  

  看业务事件是观察业务发生了哪些事件,所有软件具备的能力是要以某种方式对外表现出来的,这种方式就是业务事件。业务事件是冰山上层可直接观测的,只要投入精力就可获知到。我比较欣赏的一句话是“没有调查就没有发言权”,都没有了解事情,怎么能做出判断呢,看业务事件是在收集信息的过程中,为找业务事实和建事实关联逻辑打基础,全面了解业务是设计的前提。

  业务事实是要找的,它并不是全部具象地展示在我们面前,比如用户下单,我们可以得到一个订单的业务事实,它包含了买家家、金额、商品、下单时间等信息,订单业务事实底层还有订单合约这个业务事实,越是接近业务本质的抽象,系统设计出来才更通用和灵活,反之是基于现象和流程归纳出来的是不稳定的系统设计,就像交易有很多种模式,如担保交易、及时交易等,好的抽象应该是不关注这些的。以操作系统为例,它会关注具体的应用是视频应用,还是通讯应用,亦或是文档应用吗,对于操作系统来讲,就是一个个的进程,所以在前面提到业务开发和平台开发关注的层次是不一样的,两个处理的业务事实也不一样。建议的做法是先把业务场景和业务流程对应的业务事实找出来,做一个基础的模型设计,然后再将场景类型发散,考虑多种可能性,再看看不变的业务事实是什么,或者到底是什么业务事实在起关键作用,领域本质在解决什么问题,对领域本质理解得越深刻,会越接近业务的本质。同时反问自己这是本质的业务模型吗,逼迫自己往深层次思考,探索本质的业务事实和业务模型。

  在软件世界中勾画出现实的“相”,即是建一个软件模型表达现实的“相”,建事实关联逻辑即是建软件模型的过程,软件模型是一个最终的产物,过程中是要建立事实之间的关联逻辑,比如用户下单后有支付单,订单和支付单之间就有关联关系,用模型去表达现实业务事实运转逻辑,它能极大的简化对复杂问题的认知成本,后续的系统开发中的对象也是基于这些业务事实对象进行开发。

  三、建模案例

  或许你之前听说过不同的建模方法,如用例建模、四色建模、事件风暴建模,其实本质是相通的,都是在软件中勾画出现实的“相”,只是找现实“相”的方法不一样而已,表达方式不一样而已。而且建模并不是只是技术同学的工作,业务、产品、测试同学都可以进行建模,建模不仅能简化复杂问题的认知,而且还能减少沟通成本,我曾遇到一个概念3个月内不同的人反复在问是什么含义,每次都要解释,沟通成本非常高。

  在建模的过程中,你会体会到抽象的乐趣,越是深刻、灵活的模型,往往就越抽象,建模考验的是不是能把客观业务事实概念化地呈现出来,所以先观察业务事实有什么,再用概念把它表达出来,这里有一个观点:关系即结构,结构即模型,我们本质是要建一个能体现现实业务运转的模型,这个模型包含动静两方面,静的方面即是模型结构,动的方面是相互之间的依赖关系。下面列举一些我做过或看到的建模案例,复杂度也是层层递进的。

  3.1 现实映射抽象

  每次讲到建模时,我都会把它当作一个案例讲,因为它不仅简单,而且它体现了设计思维的转变(有别于面向过程设计的思维)。第一个案例相对简单些,是店铺的导航栏,我们可以直观地看到一个店铺有一个导航栏,导航栏里有多个导航Tab,不同的店铺导航Tab个数不一样,比较有的店铺参加了双11大促,就会有一个双11Tab展现出来。  

  这个模型相对比较好理解,包含了两个概念:导航栏和导航Tab,这个与现实业务事实是一一映射的,因此我们可以画出它的模型。  

  虽然这个例子比较简单,但它是体现了最基础的建模的思想:现实有什么,软件中就有什么,回到软件设计本原上,软件设计最核心的工作就是还原业务事实,把业务事实原本的模样抽象出来。所以,你会看到,我压根儿没有考虑过程,面向过程是人为的把自己当作了“导演”,“导演”了整个流程,只是这个流程是你自以为是的流程,流程的工作应该放在业务层中实现,领域层是不会关注的。

  3.2 抽象层次升维

  第二个例子是Martin Fowler在《分析模式》中的第一个例子,例子本身也不复杂,是一个通讯录的建模例子,模型如下:  

  以上这个模型是对现实业务事实一一映射抽象出来的模型,但它不足以体现通讯录的模型,现在只有个人和公司,还有可能是政府、法人组织等,因此这个模型并没有从本质上刻画出通讯录的本质。Martin Fowler对其优化后的模型如下:  

  这里做了两个概念抽象,首先是有一个参与方的概念,另外有一个组织的概念,将之前个人和公司往上做了一层抽象,然后在泛化出具体子类时,并没有使用之前公司的概念,而是使用了组织这个概念。

  尽管这个例子本身并不复杂,但它给我们揭示了模型要体现普通性,并不是你所看到的业务事实,它还可能包含其它的业务事实并没有被观测到,没有观测到并不表示它们不存在。因此,在建模时要想一想,还有没有其它的业务场景,业务的多样性会不会对业务模型带来冲击,所以,全面的调查是设计的基础,要不然是解决了一部分问题(没有调查就没有发言权,实践出真知)。

  3.3 找隐性概念

  第三个例子也是Martin Fowler在《分析模式》中的例子,它是第三章测量模式的例子,稍微有些复杂。先解释下数量这个对象,它是包含数值和单位两个属性,比如10千克,其中10就是数值,千克就是单位。这个案例的背景是在医院中为每个患者收集数十种测量值(身高、体重、血糖水平等),此时可以将数量作为人的属性(相当于要取最大的测量类型),但是如果考虑到整个医学领域,那么一个人可能会有数以千计的可能测量值。为每个测量定义一个属性意味着对一个人可能有成千上万种操作,这将形式一个不切实际的复杂接口(几十种测量还能勉强接受)。

  如何解决这个问题呢,Martin Fowler抽象出测量这个概念,人是包含了测量这一个集合属性,不像之前要包含成千上万种测量属性,将每种可测量的事物(身高、体重、血糖水平等)抽象成现象类型,现象类型相对是可枚举的,测量这个对象包含现象类型和数量两个属性,如下图所示。  

  Martin Fowler提出了两条建模原则:一条是操作层包含那些每天都在发生变化的概念,这些概念知识的配置由知识层进行约束,其变化频率要低得多;另一条是如果一个类型有非常多类似的关联,那么将这些关联对象抽象成一个新类型,再创建一个知识层类型来区分它们。

  往往隐性概念比较难挖掘,当你没注意到时,在实际开发过程会存在大量重复的操作,或者非常复杂的处理逻辑,就像上面提到的,即使写10几个数量属性,也够麻烦的;当你注意到时,你又会觉得很自然,比如现在你看测量这个对象就非常顺眼。另外有一点是变化可枚举的事物可抽象成类型概念,比如有支付宝支付、微信支付,可抽象成支付方式或支付类型。

  四、小结

  有诸形于内,必形于外。

  软件设计的本原是将现实的“相”映射到软件中,将现实的“相”在软件世界中勾画出来。

  “相”即是业务事实,业务事实是通过业务事件可观测的。

  面向业务流程和业务模式抽象建设平台的方法被证明是失败的平台设计方法。

  没有调查就没有发言权。

  软件设计本原要素我总结出来就三个:看业务事件;找业务事实;建事实关联逻辑。

  业务事实是要找的,它并不是全部具象地展示在我们面前。

  建模考验的是不是能把客观业务事实概念化地呈现出来。

  关系即结构,结构即模型。

  现实有什么,软件中就有什么。

  软件设计最核心的工作就是还原业务事实,把业务事实原本的模样抽象出来。

0
相关文章