草庐IT

【软件工程底层逻辑系列】建模的底层逻辑

轻风博客 2023-03-28 原文

 

 

建模对于大家来讲并不陌生,而且建模的方法也有很多,如用例建模、四色建模、事件风暴等,但在日常工作中,大家又觉得建模挺虚的:怎么把建模落到实际开发工作中。个人认为建模是分两部分:第一部分是业务概念建模,对现实业务抽取核心概念构建出模型(知识层);第二部分是系统建模,系统建模是源于业务概念模型,遵循某些原则最终形成开发可落地的模型(操作层)。在本文中,给出建模的底层逻辑:用图形逻辑地表达现实业务的抽象,通过一些大家通识的技术案例讲述建模的过程。

 

一、建模的底层逻辑

建模的作用不言而喻,它可以极大简化大家对复杂事物的认识,让人能在短时间内有全局视野看清楚业务,而且建模是用面向对象的思维分析事物,也容易转化成类图。用一个公式表达建模的底层逻辑:建模 = 图形 + 逻辑 + 现实的抽象,用一句概括即是用图形逻辑地表达现实业务的抽象,接下面主要讲述图形、逻辑、现实的抽象这三部分的内容。

1.1 图形

图形即为UML图形,下面是6种对象间的关联图形,在建模中尽量遵循UML标准画图,方便大家理解。

  • 继承:子类继承父类的特性,有的语言仅支持单继承。

  • 实现:子类实现父类定义的接口。

  • 组合:一个类包含另外的类,但它强调的是一种强关联关系。

  • 聚合:也是表达一个类包含另外的类,但它的关联关系比组合要弱。

  • 关联:通过一个类可以关联到另外一个类,可分为单向关联和双向关联,一般以类的成员变量体现。

  • 依赖:比较弱的一类关联关系,一般是以接口参数的形式体现。

 

1.2 现实的抽象

我们的现实业务有的是非常复杂的,如果涉及到专业领域概念,新手想入门是挺难的,当我们不清楚业务链路和逻辑时,直接看代码实现时很难有全局的视野,不能够串起全局业务间的内在联系。当我们切入到一个新领域中,并非短时间内就要成为该领域的专家,急需一种方法用20%的时间能够掌握该领域80%的业务知识,一个可行的方法就是建模,通过对现实业务进行抽象,构建出全局业务概念模型,有了全局的认识,再去了解业务细节就会快得多。模型好比地图,先做到心中有谱,再"按图索骥",我们比较迷茫时,往往是看不到全局的"地图",因此也就做不到心中有谱。我们要建模的对象即是问题域,我们并不需要覆盖所有的点,而是基于核心的内容进行建模,Eric Evans 在建模书中提到一个观点:建模是出于某种目的而概括地反映现实,这里的概括就是抓住核心的意思。现实的抽象有三层意思:一类是直接映射,比如现实有一个杯子,那么我们的模型中就有一个杯子;另一类是往上抽象一层映射,比如我们的组织中有一级结构、二级结构、三级结构等,那我们可以抽象成组合结构,形成父子节点的结构,这种抽象就更灵活了;最后一类是隐性抽象,前面两类抽象比较容易做到,最难的是隐性概念抽象,它很大可能是之前不存在的,需要新造出一个概念,就像软件设计中,通过新增加一层来实现解耦一样,通过新造的概念串联元素间的内在关联关系,如下面示例的中的"债权"概念。举一个金融理财的案例,需要将投资的钱给到借款人那里,然后借款人还款时将还款给到投资人,当投资人的钱给到借款人时,就产生了债权关系,因此有一个债权的概念,这记录了投资人与借款人间的债务关系,债权就是一个桥梁。当借款还款时,对应的债权就会减少,当投资周期到了,债权就会进行债权转让,转到下一个投资人身上,当前的债权关系就结束了,下图虽然比较简单,但对理解系统至关重要。

1.3 逻辑

逻辑即为因果,也即元素之间存在某种关系,如果两个完全没有关系的元素放在一些,就会显得前因不达后果、风马牛不相及,让人不好理解。那么对应到建模上,我们的模型应该是非常具有逻辑性的,从模型上能看出业务核心要素,要素与要素之间的关系是怎样的。逻辑主要体现在时空两个维度上:时间维度,一件事情节点完成之后,会影响后续的事情节点;空间维度,更多的体现在结构上,我们常说的空间结构就是这个意思。以时间维度为例,在电商结算中,当订单支付成功后,结算收单,收单后接受到放款的执行指令,在放款之前需要计算出放款明细信息,如卖家应收到多少钱、公司应收到多少佣金等,最后是打款转账,这个过程就是按照时间节点不断往后驱动,可抽象出如下图的模型。

空间维度即是结构关系,比如下图中的组织结构,像这样的结构类型,我们还可以找到更多的实际案例,比如交易订单有主子订单结构,执行单包含多个执行明细信息,模型最终呈现出来的就是一个结构,从结构维度也可以将其分解出更小的粒度。

不管哪种建模的方法,最根本的还是体现出了建模的逻辑性,用例建模的逻辑性体现在能够清晰地定义出用例场景,把所需要做的事讲清楚;四色建模通过人、事、物、时间、地点维度描述清楚一件事;事件风暴通过时间轴勾画出核心关键的事件。当我们构建不出模型时,并不是我们缺少建模的方法,而是建模的逻辑性上有问题,建模缺的不是方法而是经验和实践。我们不能神化建模,建模是很纯粹的,就是为了简化对复杂事物的认识,并且模型能够映射到实际开发的模型中。

 

二、建模的方法

建模的方法有很多种,方法多并不意味着建模的难度会很低,相反建模的门槛很高,对抽象思维要求非常高,而且建模并没有标准的答案,因此很多人觉得没啥意思。其实这里面有两部分:一部分是源于业务概念的抽象,它需要对业务的理解和抽象,往往大家在这一部分觉得没啥意思;另一部分是在业务概念模型的基础上,结合设计原则,最终设计出合理的系统模型,这部分是考验大家的设计功底。下面列举2种实践中常用的方法,这些方法并非是新的方法,是在日常工作中不断总结、实践出来的,具有更便捷实用性。

2.1 定义法

定义法建模的核心思想是通过简洁的一句话描述事物,然后根据定义进行建模,虽然方法听起来很简单,但真正用熟还需要大量的实践。

2.1.1 命令设计模式建模

命令模型在23种模式中,相对还有点复杂的模式,有一句话描述命令设计模型:A下达了命令,B接受到命令后按要求执行。将A抽象成命令发起者,B抽象成命令接受者,因此很容易找出有三个对象:命令发起者、命令接收者、命令。接下来就分析这三个对象间的关系:

  • 命令发起者与命令的关联:命令是命令发起者发起的,因此命令发起者是要感知到命令的,具体地表现就是命令发起者是要包含命令的。
  • 命令接收者与命令的关系:命令接收者是具体执行命令的对象,到底是命令接收者关系命令,还是命令关联命令接收者呢?这个可以看谁变化的可能性比较大,应该用稳定的对象包含易变的对象,根据现实经验,命令相对稳定,而命令接收者是易变的,比如做菜,今天是张三做,明天可能就换成了李四了。
  • 命令发起者与命令接收者的关系:它们之间是不会产生直接有关联的,是通过命令进行解耦的,命令发起者定义做什么,命令接收者完成具体的工作。

最终命令设计模式的概念模型如下图所示。

2.1.2 导航栏建模

店铺导航栏平时大家在浏览店铺时常遇见,可以点击不同的导航Tab看到不同的商品,比如新品、爆品等。用一句话描述导航栏:导航栏是由若干个导航Tab组成,点击导航Tab渲染出对应的页面。很容易分析出有两个对象:导航栏、导航栏Tab,但在导航栏Tab中还隐含了另外一个对象:导航栏Tab规格信息,这个规格信息描述了Tab的颜色、排序、跳转链路等信息,因此我们可以很容易画出导航栏的概念模型图。

 

很可能有些人觉得这个例子太简单了,如果你按照这种思路分析业务对象,是有别于传统面向过程分析的,比如导航Tab该不该展示是由它自己负责的,并不是在一个大的方法里控制的。

 

2.2 因果法

因果法的本质同事件风暴建模一样的,在用熟的基础上按照自己的习惯进行运用,不管什么方法,只有内化成自己的方法才有用。它的核心是基于一个对象不断往前和往后找因果关联对象,最终构建出完整的业务概念模型。

2.2.1 Spring容器建模

Spring IOC容器对大家并不陌生,以这个案例描述因果建模的方法。首先Spring IOC是一个工厂,因此有一个BeanFactory对象,同时它会包含业务Bean对象,因此最简单的一个Spring IOC 概念模型如下图所示。

 

接下来就需要不断追溯了,Bean是怎么到Bean工厂中的呢?应该有一个Bean注册器,在上图的基础上,再完善下。

再想这个Bean是怎么来的呢?即哪些业务对象会标识成要放到Bean工厂中的,会有一个扫描器扫描业务对象,发现有标识@Componet、@Service等注解的类需要放到Bean工厂中,因此这里面就会有三个对象:BeanDefinitionReader、BeanDefinition、BeanDefinitionRegistry,迭代后的Spring IOC概念模型如下图所示。

虽然这是一个简陋的Spring IOC概念模型图,但它还是把Spring IOC核心包含的对象展示出来了,结合现实需求,我们还可以加一些对象进来,比如考虑扩展性,会有BeanFactoryPostProcessor等。这里仅仅是一个业务概念模型,具体到系统模型需要结合设计原则来设计,如Bean工厂在实际中会拆分成多级Bean工厂继承的关系。

 

三、建模案例

根据第二节中讲的方法,下面通过三个技术案例描述在实际学习中的运用,通过模型可以快速让我们理解技术涉及的原理,当我们有了基础理解后,再去看技术框架源码时也会快得多。

3.1 异步事件建模

异步事件对于开发来讲并不陌生,将事件定义与事件执行进行解耦,用一句话描述异步事件:事件发布者发布一件事件后,经由事件分发器分发后,找到对应的事件监听器处理。这里面就包含了四个对象:事件发布者、事件分发器、事件监听器、事件。事件发布者是将事件发布到事件分发器上,因此事件发布者是需要关联事件和事件分发器;事件分发器通过事件类型匹配,匹配上事件后调用对应的事件监听器进行处理,因此事件分发器包含了多个事件监听器。异步事件的概念模型图如下图所示。

在Spring事件广播器中,有添加事件监听器,以及通过事件查找到对应的事件监听器进行处理。

 

3.2 切面建模

切面编程在实际工作中应用得也比较多,比如在服务上增加横切功能,如日志打印、方法耗时统计等,接下来用因果建模法对切面进行建模。最开始有一个目标对象,即为我们要增加横切功能的对象,那么怎么表达这个横切功能呢?至少要包含三种信息:谁需要被增强?;增强的逻辑是什么?;什么时候增强?,描述谁需要被增强的对象抽象成切点。增强的时间节点抽象成通知。因此可得出初步的模型。

目标对象与切面是怎么关联上来的,相当于在目标对象的方法前后要额外增加一段逻辑,可以通过代理来实现,因此有一个代理对象,它会链接目标对象和切面,最终切面业务概念模型如下图所示。

当熟悉了切面业务概念模型后,再去看Spring AOP的源码会容易些,模型就是简化认识,提炼出核心关键的事物要素。

3.3 ORM框架建模

ORM是将传统SQL映射到对象上,更符合面向对象的习惯。同样我们使用因果建模的方法,ORM框架在底层最终还是要执行具体的SQL,因此将SQL语句抽象成Mapper,数据库配置信息抽象成配置信息,有了这两个配置信息,自然有对应的解析配置的类,初步的模型如下。

将执行SQL的过程抽象成会话,会话会执行SQL,将执行SQL的对象抽象成SQL执行器,在SQL执行过程中,需要做两件事:一件是参数解析;另一件是结果解析。最终的ORM框架概念模型如下图所示。

在执行器中,我们可以看到有配置信息、参数信息。

 

四、建模经验总结

4.1 能清晰地描述事物建模就成功了一半

建模是将混沌的事物抽象成有序关联事物的过程,混沌到有序,因此我们需要梳理清楚事物间的关联关系,如果我们都不能够清晰地描述事物,是很难建模的。不能够描述清楚事物,说明我们自己都还没有理清内在的关联关系,也就做不到抽象出有序的模型。在日常工作中,可以尝试用几句描述一件事,看大家能不能理解到。在学校老师经常让我们概括文章的中心思想,就是锻炼这种建模能力,通过几句话把文章的核心内容勾画出来。我们在软件建模也是一样的,通过几句话把业务的涉众、业务结构、业务目标、核心关注点表达出来,然后通过业务概念模型呈现出来。

4.2 通过描述事物的结构是建模常用的方法

模型最终呈现出来的是一个图,这个图往往是有清晰的结构,比如房屋模型,它就有自己的结构:坐北朝南,有大厅、睡房、厨房、洗手间等,软件模型也是一样的,在2.1.2节中举了一个店铺导航栏的例子,如下图所示,当我们看到店铺导航栏时,可以想像下它是怎样的结构。

在实际的业务中,有两类模型:一类是偏结构型的模型;另一类偏行为型的模型,从个人接触到的业务看,结构型的模型偏多,比如订单有主子订单模型。我们也可以尝试从结构的角度去定义事物。

 

4.3 建模要区分知识层和操作层

模型一般有两层:一层是知识层;另一层是操作层,知识层中包含的概念是通识的概念,往往是面向使用者,比如我们在使用AOP切面编程时,可以用@Aspect、@PonitCut、@Before等注解时,它们就是属于知识层,知识层的内容抽象层次比较高,大家比较容易理解,我们所做的业务运营工作台也是做的知识层的内容,比如配置页面模板、站点配置等,这些可枚举的维度都是知识层。另一层是操作层,操作层是支撑知识层的,还是AOP为例,底层有对注解的解析、动态代理的生成等;再比如Spring IOC中,有各类Bean的注解,在操作层中,有BeanDefinition的加载、识别、解析、Bean实例化、Bean初始化等,操作层中的实现也并非面向过程的设计思维,它也包含了抽象设计和遵循某些设计原则,这一点在下一节中会专门讲到,同样的设计,张三和李四可能不一样,正所谓"文无第一,武无第二",大家的设计理念、角度不一样,技术设计本应如此,就像一百个厨师做同样的菜,做出来的菜也有一百个样。如果知识层偏表达,那么操作层就是偏实现支撑,这两类的视角也是不一样的,知识层更抽象,而往往我们开发人员更关心的是操作层中的具体实现类,缺乏抽象意识,这也是我们自己心中非常清楚,但别人很难理解,需要转换视角,思考通识的知识层有什么。

 

五、小结

在文章中主要讲述了建模的一些方法,方法虽然简单,但用熟还是需要大量的实践经验,建模分为两个阶段:第一个阶段是业务概念建模,它无关于技术,是通识的建模(知识层);第二个阶段是系统建模,基于业务概念建模的基础上,考虑具体的技术实现(操作层),遵循某些设计原则构建可落地的模型。建模的确会简化对复杂事物的认识,以学习技术框架为例,如果一头扎进源码中,很难有全局观,相反如果我们从全局对技术框架有一定的理解,再去看源码也会快很多。

 

作者:高福来(不拔)

有关【软件工程底层逻辑系列】建模的底层逻辑的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby-on-rails - 建模收藏夹 - 2

    我希望将Favorite模型添加到我的User和Link模型。业务逻辑用户可以有多个链接(即可以添加多个链接)用户可以收藏多个链接(他们自己的或其他用户的)一个链接可以被多个用户收藏,但只有一个所有者我对如何为这种关联建模以及在模型就位后如何创建用户收藏夹感到困惑?classUser 最佳答案 下面的数据模型怎么样:classUser:destroyhas_many:favorite_links,:through=>:favorites,:source=>:linkendclassLink:destroyhas_many:favor

  3. ruby-on-rails - 使用一系列等级计算字母等级 - 2

    这里是Ruby新手。完成一些练习后碰壁了。练习:计算一系列成绩的字母等级创建一个方法get_grade来接受测试分数数组。数组中的每个分数应介于0和100之间,其中100是最大分数。计算平均分并将字母等级作为字符串返回,即“A”、“B”、“C”、“D”、“E”或“F”。我一直返回错误:avg.rb:1:syntaxerror,unexpectedtLBRACK,expecting')'defget_grade([100,90,80])^avg.rb:1:syntaxerror,unexpected')',expecting$end这是我目前所拥有的。我想坚持使用下面的方法或.join,

  4. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  5. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  6. 软件测试基础 - 2

    Ⅰ软件测试基础一、软件测试基础理论1、软件测试的必要性所有的产品或者服务上线都需要测试2、测试的发展过程3、什么是软件测试找bug,发现缺陷4、测试的定义使用人工或自动的手段来运行或者测试某个系统的过程。目的在于检测它是否满足规定的需求。弄清预期结果和实际结果的差别。5、测试的目的以最小的人力、物力和时间找出软件中潜在的错误和缺陷6、测试的原则28原则:20%的主要功能要重点测(eg:支付宝的支付功能,其他功能都是次要的)80%的错误存在于20%的代码中7、测试标准8、测试的基本要求功能测试性能测试安全性测试兼容性测试易用性测试外观界面测试可靠性测试二、质量模型衡量一个优秀软件的维度①功能性功

  7. 阿里云RDS——产品系列概述 - 2

    基础版云数据库RDS的产品系列包括基础版、高可用版、集群版、三节点企业版,本文介绍基础版实例的相关信息。RDS基础版实例也称为单机版实例,只有单个数据库节点,计算与存储分离,性价比超高。说明RDS基础版实例只有一个数据库节点,没有备节点作为热备份,因此当该节点意外宕机或者执行重启实例、变更配置、版本升级等任务时,会出现较长时间的不可用。如果业务对数据库的可用性要求较高,不建议使用基础版实例,可选择其他系列(如高可用版),部分基础版实例也支持升级为高可用版。基础版与高可用版的对比拓扑图如下所示。优势 性能由于不提供备节点,主节点不会因为实时的数据库复制而产生额外的性能开销,因此基础版的性能相对于

  8. ruby - 从结束值创建一系列字符串 - 2

    我使用irb。下面是我写的代码。“斧头”..“bc”我期待"ax""ay""az""ba"bb""bc"但结果只是“斧头”..“bc”我该如何纠正?谢谢。 最佳答案 >puts("ax".."bc").to_aaxayazbabbbc 关于ruby-从结束值创建一系列字符串,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7617092/

  9. 建模分析 | 平面2R机器人(二连杆)运动学与动力学建模(附Matlab仿真) - 2

    目录0专栏介绍1平面2R机器人概述2运动学建模2.1正运动学模型2.2逆运动学模型2.3机器人运动学仿真3动力学建模3.1计算动能3.2势能计算与动力学方程3.3动力学仿真0专栏介绍?附C++/Python/Matlab全套代码?课程设计、毕业设计、创新竞赛必备!详细介绍全局规划(图搜索、采样法、智能算法等);局部规划(DWA、APF等);曲线优化(贝塞尔曲线、B样条曲线等)。?详情:图解自动驾驶中的运动规划(MotionPlanning),附几十种规划算法1平面2R机器人概述如图1所示为本文的研究本体——平面2R机器人。对参数进行如下定义:机器人广义坐标

  10. 网站日志分析软件--让网站日志分析工作变得更简单 - 2

    网站的日志分析,是seo优化不可忽视的一门功课,但网站越大,每天产生的日志就越大,大站一天都可以产生几个G的网站日志,如果光靠肉眼去分析,那可能看到猴年马月都看不完,因此借助网站日志分析工具去分析网站日志,那将会使网站日志分析工作变得更简单。下面推荐两款网站日志分析软件。第一款:逆火网站日志分析器逆火网站日志分析器是一款功能全面的网站服务器日志分析软件。通过分析网站的日志文件,不仅能够精准的知道网站的访问量、网站的访问来源,网站的广告点击,访客的地区统计,搜索引擎关键字查询等,还能够一次性分析多个网站的日志文件,让你轻松管理网站。逆火网站日志分析器下载地址:https://pan.baidu.

随机推荐