15.软件架构设计:大型网站技术架构与业务架构融合之道 --- 技术架构与业务架构的融合

Posted enlyhua

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了15.软件架构设计:大型网站技术架构与业务架构融合之道 --- 技术架构与业务架构的融合相关的知识,希望对你有一定的参考价值。

第15章 技术架构与业务架构的融合 
15.1 各式各样的方法论 
	软件开发方法论:
		1.OOA/OOD/OOP 分析模式与设计模式 
			面向对象的分析,设计与开发。
		2.E-R建模
			关系型数据库领域的建模方法论。
		3.UML
			在OOA/OOD基础上的一套成熟的建模方法和工具。
		4.SOLID原则
			在OOA/OOD基础上,敏捷开发提出的面向对象的几大原则。
		5.SOA、微服务
			基于服务的架构。
		6.RUP 4+1
			统一软件过程,架构的5大视图。
		7.4色建模
			在OOA/OOD和UML基础上发展的业务分析方法。
		8.TOGAF
			由国际权威组织 The Open Group 制定,在1995年发表的 The Open Group Architecture Framework(TOGAF)架构框架。
		9.DDD
			领域驱动设计。

15.2 为什么要“领域驱动”
	1.什么是领域
		领域是面对的"业务问题空间",注意是"业务问题",而不是"技术问题"。所谓的业务问题,是指系统如何很好的处理复杂的业务需求,业务流程与业务规则。
	业务需求一直在增加,并且不断的变化,系统如何快速的应对?

		这里关键是"快速"二个字,当系统足够复杂后,每增加一个需求,就可能牵扯到很多系统的改动,不仅开发周期慢,开发人员很累,还容易改出问题。

	2.什么是领域模型
		如果说"领域"是"问题",那么"领域模型"就是为了解决这问题而给出的"答案"。"领域模型"是在"模型"前面加了领域2个字。从字面上看,领域模型是模型的
	一种。

		领域就是现实世界的业务,是复杂多变的。找到了"本质",也就是"变化"背后的"不变性",也就找到了"问题"的"答案"。

		具体到领域驱动设计方法论,引入了一系列概念:实体,值对象,聚合根,领域事件,Specification。

	3.领域模型如何描述
		要把一个领域模型描述清楚,通常包括2方面的内容:
			1.逻辑层面
				通过类图和状态图,表达出关键的实体与实体之间的关联关系,以及每个实体迁移过程。
			2.物理层面
				这些实体最终会落到数据库中,对应数据库的schema,同时可能是分库分表的。

			逻辑层面和物理层面会有映射关系,但两者并不是完全一样的。假如逻辑层面有2个实体之间存在多对多的关系,在物理层面会多出一张关系表;再比如
		逻辑层面有多个实体之间存在继承关系,但数据库的表之间是没有继承关系的。

	4.为什么要领域驱动
		如果系统很简单,用数据库的CRUD就能搞定,不需要领域驱动;如果做的是基础架构,比如开发一个RPC框架,分布式存储系统,也不需要领域驱动。运用
	领域驱动的前提是业务足够复杂且多变,需要系统的灵活支持。

		领域驱动也就是"领域模型"驱动,让系统围绕着领域模型构建,而不是围绕其他东西构建。

		复杂软件开发的几个阶段:
			第一阶段:确定业务目标和业务价值。要解决什么人的什么问题,创建什么样的业务价值?这个阶段通常由公司高层定义。
			第二阶段:目标被拆解成一系列核心的功能点。
			第三阶段:围绕这些功能点定义 业务流程,业务规则,以及整个过程中涉及什么样的业务数据或业务对象。
			第四阶段:领域建模。要实现这样的业务流程,业务规则,需要建立什么样的领域模型。
			第五阶段:基于领域模型做技术架构设计。比如要做读写分离,做微服务拆分,再系统系统之间的交互流程。

		整个过程,有几个关键点需要说明:	
			业务需求会一直增加,业务流程会改变,业务规则也能改,但"领域模型"却不能随便修改,一改就牵一发动全身。也正是因为如此,领域建模的本质是
		找到"变化背后的不变性"。如果找不到"不变性",领域模型会一直改动,就不是领域驱动。

			既然要找到"不变性",就不能只单纯的看当前业务,而要考虑未来可能有哪些变化,哪些扩展。要做到这一点,不能直接把业务概念和系统概念
		一一对应,需要对业务概念进行分解,抽象。

			在领域建模和技术架构设计过程中,可能会发现想要实现的业务流程或者业务规则,系统需要变得很复杂,这时候会衡量投入产出比。可能需要反向
		修正,修改业务流程或规则。可能需要从技术层面解决问题,也可能上升到产品层面(需求层面)解决问题。


15.3 “业务流程”不等于“系统流程” 
	领域建模处在"业务流程"和"系统流程"之间,如果缺失了领域建模,会直接把业务流程实现成系统流程,而这也是开发人员经常会遇到的问题。其中会产生很多
问题:
	1.业务流程是粗粒度的,给非开发人员来看的,而系统流程需要更细化,比如业务流程说某个"数据"从系统A流向系统B,但并没有说这个"数据"有哪些字段?
这种流向是"推模式"还是"拉模式"?用消息中间件实现,还是用rpc或者http调用?
	
	站在业务人员的角度,不关注这些技术问题,但技术人员需要很关注,因为这些问题会影响系统的可维护性,性能,稳定性等。

	2.数据在多个系统之间拷贝,维护困难,各种数据不一致。站在领域建模的角度,或者站在服务化的角度来看,一个数据(比如业务实体或实体之间的关系数据)在
全局应该只存在一份,有的系统因为高并发或者性能问题,也仅仅是一个缓存而已。但如果纯粹的从业务流程角度看,会出现数据在多个系统之间传递的情况。这种传递
造成了同一份数据在多个系统之间的拷贝,然后各系统又可能对数据做了一定逻辑加工,比如加上了一些额外的字段。合理的方式应该是系统之间传递的仅仅是对象的ID,业务对象本身只在一个系统内管理。
	
	3.业务流程刚刚开始简单,可能是瀑布式的,变复杂之后就会变成网状的。如果系统流程完全按照业务流程实现,系统也会变成网状的,没有分层结构,系统之间
全部是双向耦合的,最后难以维护。
	
	也正是因为如此,在业务流程和系统流程之间需要有领域建模,当业务流程变化或者新加分支流程后,领域模型不变,基于此实现新的系统流程也会相对简单。

15.4 为何很难设计一个好的领域模型 
	要在"变化的现实世界中寻找不变性",希望寻找一个稳定的领域模型,让系统流程可以灵活改变,模型不怎么变。但在实际中却很难做到,这是为什么呢?
		1.意识问题
			在用户,产品,运行人员眼中,沟通的语言是"流程"而不是"模型"。开发人员在与他们沟通的过程中,慢慢就形成了以"流程"为主导,而不是以
		"模型"为主导的思维方式。这使得整个开发过程是"流程驱动"的,而不是"领域驱动"。大家在讨论业务与系统解决方案的时候,大部分时间都花在了
		业务流程,业务规则上,而不是深刻的讨论流程背后的不变因素。

		2.现实世界的复杂性
			业务也就是我们现实世界,灰度的,模棱两可的东西,比计算机的世界多得多,变化也多得多。这导致技术人员往往不懂业务,也不知道如何去分析
		业务。前三步做不到,也就很难进入第四步。因为不知道哪些东西是不怎么变的,什么东西是容易变的,而这恰恰是建模的前提条件。

		3.迭代速度
			再稳固的模型,也不可能一成不变,毕竟现实世界一直在变。当现实世界变化到模型不能支撑的时候,要能马上修改模型才行。但实际情况是,因为
		开发效率的原因,工期赶不上,然后就会在旧的模型上进行打补丁,一个接着一个的打,最后整个系统臃肿不堪,开发效率进一步降低,如此恶性循环。

			互联网公司强调小步快跑,快速迭代。对C端产品可以,对B端产品比较复杂就不行了。

		4.火候的掌握
			领域模型是要对现实世界建模,既要去寻找不变性,又要为可能变化的地方留出扩展性。什么地方是不变的,要作为基础;什么地方是易变的,要留出
		扩展性,这其实并没有准则。另外,各个公司的业务规模,速度不一样,团队的实施能力不一样。所以在实践中,要么会"过度设计",要么会"缺乏设计"。
		对火候的掌握,需要有悟性。只有反复思考,反复推翻自己之前的想法,再重建新的想法,才能在实践中不断找到领域模型,业务发展速度,技术团队能力
		之间的"最佳平衡点"。

15.5 领域驱动设计与微服务架构的“合” 
	微服务是一种"技术架构",从领域驱动设计出发,微服务的拆分有两种思维方式:
		方式1:诸侯制
			一上来就把整个领域分成几个子域或把一个大项目拆分成几个部分,大家把边界定出来,也就是把子域之间的接口定出来,然后每个团队各自负责子域
		的领域模型设计和系统实现。如此细化,每个团队内部可以继续拆分,反正对外界来说是屏蔽的。

		方式2:中央集权制
			先对整个业务做全面的分析,做一个全功能的,完整的领域模型,覆盖整个业务。再把这个大而全的领域模型拆分成几块,让不同的团队去实现。

		两种方式各有优劣:
			方式1的难度相对较小,容易落地,各个团队各司其职,但容易失去全局视野;
			方式2对整体的思考更多,考虑到了各个部分的互相交叉影响,模型会更系统化,但考虑的信息量太大,容易失控,导致最终无法完全落地。

		子域是问题空间,限界上下文是答案空间。限界上下文是为了给每个领域模型有一个明确的定义。就像在自然语言中,同一个词在不同的上下文中有不同的
	意思;只有在一个明确的上下文中,一个词的意思才是明确的。

		理想情况下:一个子域对应一个限界上下文;但实际中,可能一个限界上下文对应多个子域,或者反过来,一个子域对应多个限界上下文。

		在微服务大行其道的今天,很多团队都选择的是方式1,拆,拆,拆。反正遇到复杂问题就拆分... 当业务复杂到一定程度的时候,会发现服务很多,然后服务
	之间各种交叉调用,整个系统到最后很难维护。那究竟该如何处理呢?

		如果领域里面子域的限界上下文本来就比较明显,则可以先拆分。比如电商系统,用户和订单这2个子域的界限明显,可以选择先拆分成两个子域,然后分别
	设计。

		但如果界限不是很明显,比如价格或者优惠活动,如果一上来就拆成价格和优惠两个子域,各做各的,请问:最终用户看到的价格,是价格这个子域确定的,
	还是叠加了优惠活动的?叠加的过程又是怎么样的?在这种情况下,最好是把价格和优惠作为一个整体建模,在快建模好之后,再清晰的拆分成两个子域实施。

		同样,比如库存,一上来就拆分 售卖库存和供应链库存,各做各的?还是把2部分作为整体考虑,然后再分别实施。

		最后,分久必合,合久必分。刚刚开始的时候,业务简单,所有东西都放在一起,看做一个领域;做着做着,某部分越来越复杂,拆出来就变成一个新的领域;
	当越拆越多的时候,发现两个领域之间耦合严重,很多东西类型又有差别,再开始合,如此周而复始。

15.6 领域驱动设计与读写分离(CQRS) 
	系统按领域驱动设计拆成了几个子域或者几个子业务之后,各个子业务去实现自己的系统。如果某个子域业务的流量很大,需要应对高并发的问题,要做读写分离,
加缓存等措施,也只是这个子域的内部问题,与其他子域没有关系;对外部来说,应该尽可能屏蔽。从这个角度来说,读写分离纯粹是一个子域内的技术问题。
	
	这是"小范围"的读写分离,如果扩展到公司级别的"读写分离",又会从技术问题上升到业务问题。比如电商网站的搜索,很显然它是一个"只读"的系统,而写的一端
包括了商品的发布,价格的发布,库存的发布和库存的减扣,这里的读写就变成了2个业务,而不是简单的一个业务内部所做的读写分离。

15.7 业务分层架构模式 
	说到技术的分层,好比一个系统被划分为前端(UI层),网关层,服务层,数据存储层,同技术一样,分层思维同样适用于业务。

	以电商为例,一个商品有很多属性。按照商品的完整流程,可以划分为这样几个阶段:生产,销售,运营,运输。

	SPU和SKU:
		一个SPU下面有多个SKU,一个SKU对应一个颜色的一个尺码,而库存,价格是挂在SKU上面的。一个SPU对应一个商品详情页,里面呈现多个颜色的多个尺码。

15.8 管道—过滤器架构模式 
	在技术领域,管道 - 过滤器的架构模式非常常见:	
		在Linux的管道命令;
		Java的Servlet规范;
		大数据流行的Storm流式计算;

	管道 - 过滤器 有一个典型的特征:计算模块本身是无状态的,数据经过一个处理环节,处理的结果或者数据的状态携带在数据身上,被数据带入下一个环节。因为
计算模块本身是无状态的,这意味着它很容易做水平扩展和高可用。
	
	管道 - 过滤器 或 流式计算 的这种思路在业务领域同样非常常见。只要一个复杂的业务流程可以被拆分成几个环节,且这些环节是线性的,就可以采用流式计算
的思路。
	
	比如电商平台的履约系统,用户下单付钱后,订单开始进入履约系统。在履约系统中有很多环节:拆单,库存调整,财务记账,订单下发到仓库,仓库作业,出仓,
物流运输等。这些环节的职责由不同的系统承担,这些系统之间就组成了一个 管道 - 过滤器 的模式。

15.9 状态机架构模式 
	在处理流程方面,管道 - 过滤器 的方式比较直接。如下,
	数据 => 系统1 => 系统2 => 系统3 => 系统4

	系统3和系统4不会感知系统1的存在,系统4不会感知系统2的存在,,每个系统最多之和2个系统交互:自己的上游,自己的下游。整条链路是线性的,单向的。
伴随着业务的发展,因为某些迫不得已的原因,系统之间开始互调了,到了这个阶段,系统已经变成了"蜘蛛网",既没有层次,也不是一个简单的线性关系。
管道 - 过滤器已经无法满足了,需要一个新的,更灵活的方式,就是 状态机模式或者协调者模式。
	
	在设计模式中,有一个典型的模式 "中介者" 模式,就是为了解决多个模块之间的双向耦合问题产生的。把这种思想应用到业务领域,就变成了状态机模式。在这个
模式中,数据首先进入状态机模块或系统中,然后由该模块决定把数据交给哪个系统处理。关于这个模式,有几点要说明:
	1.四个系统之间没有交互,互相独立。这使得各自非常纯粹,专注的做好自己的事情即可。
	2.之所以叫"状态机"模式,是因为状态机模块维护了原始数据流中的每条数据的状态。正是基于这些状态,状态机才知道每条数据当前是刚刚开始处理,还是已经
	处理到了中间某个环节,或者已经处理完了。基于状态,状态机可以把数据准确的分发到对应的处理系统中。
	3.在实现层面,状态机和四个系统之间可以是rpc同步调用,也可以是基于消息的pub-sub模式调用,也就是微服务里面的Event-Sourcing。

	在面向B端复杂的业务中,时常会用到"工作流引擎":比如OA系统。整个流程是需要高度配置化的,还可以随时调整,这时候就需要用到工作流引擎。工作流引擎
就是一个典型的状态机模式,每种不同类型的单据进入工作流引擎:工作流引擎根据单据的类型转发给不同的审批节点,审批节点完成审批之后,把结果反馈给工作流
引擎,工作流引擎再根据结果决定下一步将该单据转发给哪个节点。

15.10 业务切面/业务闭环架构模式 
	在技术领域有面向切面的编程(AOP):当多个类之间没有继承关系,但却需要所有的类,在其某一个方法完成一个共同的操作。比如在某个方法的开始打印一行
日志,方法返回之前再打印一行日志,这时就需要用到AOP。
	
	同样,在业务领域,可以把公共的业务逻辑抽离出来,做出一个公共的系统,这个系统会横切所有的业务系统。下面举几个例子:
		例1:SSO单点登录
			对于大型公司,员工要拿着自己的工号或者密码登录多个内部系统,在这种场景下,可以把"登录"功能抽离出来,做出一个SSO单点登录系统,所以
		内部业务系统不需要自己做登录功能,而是和SSO登录系统做对接。

		例2:权限统一管理
			权限系统也是B端系统面临的一个公共问题,可以把"权限管理"功能抽离出来,做出一个统一的权限系统。每个业务系统在这个权限系统里面分配一个
		"业务的key",然后在业务下面可以定义自己的业务系统的权限,角色,为组织内部不同层级的人定制角色。

			业务系统与通用权限系统的交互可以是纯粹基于配置,完全自动化的,也就是在通用权限系统配置好权限之后,业务系统不需要代码开发;也可以是
		手动的,业务系统与通用权限系统通过API交互,业务系统通过代码做灵活,复杂的权限控制。

		例3:规则引擎
			在业务开发中,业务逻辑往往非常复杂,会看到很多if-else代码。它们可能层层嵌套,可读写和维护性都非常差。如果把这些逻辑代码总结成一条
		条业务规则,就可以利用规则引擎。

			规则引擎的好处是有人性化的操作界面,可以把这些规则集中的整理在一个地方,便于维护。有新的需求来了,要加新的规则,可能在界面上加一条
		即可,而不用修改代码,重新发布系统。当然,使用规则引擎的前提是,需要对业务进行抽象,归纳,梳理出一条条清晰的规则。

	与"业务切面"相对于的是"业务闭环":业务切面是在"横"向上对公共的业务逻辑做抽离,而"业务闭环"是在"纵"向上把一个业务涉及的完整的东西包在一个业务
领域里,让一个团队负责。这点和商业层面的商业模式很像:所有做"平台"的公司,都是"横"向扩展,在做一个"横切面";而做垂直的公司,会"纵"向发展,延伸产业
的上下游,最终形成一条龙服务。
	
	举例:电商平台的客服系统。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

以上是关于15.软件架构设计:大型网站技术架构与业务架构融合之道 --- 技术架构与业务架构的融合的主要内容,如果未能解决你的问题,请参考以下文章

3.软件架构设计:大型网站技术架构与业务架构融合之道 --- 语言

14.软件架构设计:大型网站技术架构与业务架构融合之道 --- 业务架构思维

13.软件架构设计:大型网站技术架构与业务架构融合之道 --- 业务意识

7.软件架构设计:大型网站技术架构与业务架构融合之道 --- 框架软件与中间件

2.软件架构设计:大型网站技术架构与业务架构融合之道 --- 架构的道与术

1.软件架构设计:大型网站技术架构与业务架构融合之道 --- 五花八门的架构师职业