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

Posted enlyhua

tags:

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

第14章 业务架构思维 
14.1 “伪”分层 
	典型的互联网分层架构:
		客户端 => 接入层 => 聚合层 => 业务层 => 基础服务层 => 数据层

	伪分层架构可能具有的一些特征:
		1.底层调用上层
			比如某个基础服务调用上层业务服务,怎么解决呢?
			
			办法1:要思考业务逻辑是否放错了地方?或者业务逻辑是否要一分为二,一部分放在业务服务,一部分放在基础服务。也就避免了底层调用上层。

			办法2:OOD 中的典型办法,DIP(依赖反转)。底层定义接口,上层实现,而不是底层直接调用上层。

		2.同层之间,服务之间各种双向调用
			比如业务服务1,业务服务2,业务服务3 之间都是双向调用。

			这时候就要思考,业务服务1,业务服务2,业务服务3 之间的职责分配是否有问题,出现了服务之间的紧耦合。

			是否应该有一个公共的服务,让公共服务和业务服务1,业务服务2,业务服务3 交互,而三个业务服务之间互相独立。

		3.层之间没有隔离,参数层层传递,一直穿透到最底层,导致底层系统经常变动
			例如,APP一直发版,为了实现兼容,服务器有类似下面的代码:
				if (version = 1.0)
					xxx
				else if (version = 2.0)
					xxx
				else 
					xxx

			这个例子比较明显,一看就知道是客户端的东西,所以通常在服务的业务入口做了拦截,不应该透传到了最底层服务。但很多业务层面也会遇到类似的
		问题,但不容易看出来,需要很好的抽象能力才能发现。

			比如客户端要支撑各种各样的业务,肯定有类似 businessType 这样的字段用于区分不同的业务,或者说区分同一业务的不同业务场景。
		businessType 字段一直穿透到最底层的基础服务,在基础服务里面能看到 if businessType = xxx 这样的代码,这就是典型的上层的业务多样性
		透传到了底层。

			虽然是严格分了层,层层调用,但"底层服务"已经不是底层服务,因为每一次业务变动都会导致从上到下跟着一起改。

		4.聚合层特别多,为了满足客户端需求,各种拼装
			遇到这种情况,往往意味着业务服务层太薄,纯粹从技术角度拆分了业务。而不是从业务角度然让服务成为一个完整的闭环,或者说一个领域。

	一个优秀的分层架构应该具有的典型特征如下:
		1.越底层的系统 越单一,越简单,越固化;越上层的系统花样越多,越容易变化。要做到这一点,需要层与层之间有很好的隔离和抽象。
		2.做到了上面一点,也就容易做到层与层之间严格的遵守上层调用下层的准则。

14.2 边界思维 
	所有的架构思维模式中,如果说最终只能留下一种思维模式,那就是边界思维。"优雅的接口,龌龊的实现"。在技术领域,"封装","面向接口的编程"等技术,
也都是边界思维的体现。只要一个系统对外的接口是简洁,优雅的,即使系统内部混乱,也不会影响外部系统。相当于把混乱的逻辑约束在一个小范围内,而不会扩散
到所有系统。
	
	边界思维是一种通用的思维方式,下面从小到大来看边界思维在不同层面的体现:
		1.对象层面(SOLID原则)
			在面向对象的五大原则中,第一个原则 S 就是单一职责原则(The Simgle Responsibility Principle)。通俗地讲,就是一个函数,一个类,
		一个模块只做一件事情。不要把不同的职责杂糅在一起,这就是边界思维的体现。

			当然,这里说的"一件事情"是从同一个抽象层次来说的。对一个类来说,里面所有的函数都处在同一个抽象层次中,不要让一个函数做两个函数的事情;
		对于一个模块来说,里面所有的类处于同一个抽象层次中。

		2.接口层面
			对于开发人员来说,做一个系统往往先看如何实现。而利用边界思维,首先想到的不是如何实现,而是把系统当做一个黑黑盒,看系统对外提供的接口是
		什么。接口也就是系统的边界。接口定义了系统可以支持什么,不支持什么。所以,接口的设计往往比接口的实现更重要。站在使用者的角度来看,并不在意
		接口如何实现,而更在意接口的定义是否清晰,使用是否方便。具体来说,就是:接口的输入,输出参数分别是什么?哪些参数是可选的,哪些是必选的?如果
		输入参数很多,为什么不是分成多个接口?设计策略是什么?接口是否幂等?各种异常场景,接口的返回结果是什么。

		3.产品层面
			对于产品,常说的一句话是:内部实现很复杂,用户界面很简单。

		4.组织架构层面
			组织的各个部门之间如果没有非常清晰的边界,就会导致该自己做的事情,互相推诿;不该做的事情,抢着做。

		回到系统,不管用哪种分析方法和设计方法,最终必须保证每个系统有清晰的边界,各种分工清晰。无论谁要了解系统,他不用看这个系统的实现,只要看
	系统的接口,就知道系统支持什么,不支持什么。

		边界思维的重点在于"约束",是一个"负方法"的思维模式。什么意思呢?比如要看一个开源的软件,要看的不是它能做什么,而是它不能做什么。不能做什么
	决定了系统的边界,或者说它的"极限"。

		做架构尤其如此,架构强调的不是系统能支持什么,而是系统的"约束"是什么,不管是业务约束,还是技术约束。没有约束,就没有架构。一个设计或系统,
	如果"无所不能",则意味着"一无所能"。

14.3 系统化思维 
	与边界思维相对应的是系统化思维。不能头痛医头,脚痛医脚。

	系统化的思维,把不同的东西串在一起,而不是割裂后分开来看。另外一个体现是,遇到问题要刨根到底,直至事物的本质。这点在物理学中叫做"第一性原理"。


14.4 利益相关者分析 
	做一个系统与做一个产品一样,首先要了解用户是谁,在架构里面称为利益相关者。

	以"黑盒"的方式思考:在考虑利益相关者时,考虑的系统范围可大,可小。在大的方面,把公司所有系统都放在一起看,当做一个黑盒子,看外部系统有哪些利益
相关者;小的方面,可以只看一个系统里面的一个子系统,一个模块,看其外部都有系统。
	
	为什么谈业务架构,要先谈"利益相关者"呢?
		1.利益相关者其实是从"外部"来看系统。把系统当做一个黑盒子,看为哪几类人服务。这其实也就定义了整个系统的边界,定义了整个系统做什么和不做什么。
		2.前面说到一个词"业务",业务具有"闭环"的特点。而利益相关者就是一个最好看待业务的视角。
		3.每个利益相关者代表了一个视角。站在C端用户的视角和B端商家的视角,对系统有不同的看法。系统很复杂,无法从一个角度全面看问题,每个视角都是
		盲人摸象,只能看到系统的一部分。
		4.利益相关者往往也对应了一种业务划分,系统划分。根据不同的利益相关者,可以划分出不同的系统和业务。

14.5 非功能性需求分析(以终为始) 
	软件有功能需求和非功能需求,FURPS需求模型。

	非功能需求有:
		1.并发性
			衡量指标有 tps 和 qps,平均响应时间/最大响应时间,并发数。

		2.可用性
			从服务角度,一个服务不可用有2层意思:
				1.机器宕机,不能对外提供服务,直接抛错;
				2.机器虽然没有宕机,但是超时。这涉及"性能"问题。

		3.一致性
			比如数据库的参照完整性,事务,缓存与数据库数据同步,多备份数据一致性问题。

		4.稳定性和可靠性
			"稳定性"指系统没有任何未定义的行为,体现在如下几方面:
				1.所有的 if-else 语句里面,没有不处理的分支;
				2.所有的api调用,每种异常返回值都有处理;
				3.考虑内存,磁盘的上限;
				4.系统不会时不时冒出一个问题;
				5.出了问题,有很好的日志监控,能快速修复问题;
				6.系统的qps不会有抖动(除非业务有变化,如大促),是一条平滑的曲线;
				7.发布新版本,有回滚方案;
				8.新系统上线,灰度平滑切换;
				9.Monkey Test?压力测试;
				...

		5.可维护性
			1.系统架构设计简单,接口简洁,表数据关系清晰;
			2.老人离职,新人接手,无需很长时间就能厘清代码逻辑;
			3.系统功能不耦合,改动一个地方不会牵动全身;
			4.系统某些模块即使时间久远,也有人能厘清内部逻辑;
			...

		6.可扩展性
			1.来了一个新需求,伴随着一些新功能,可以在现有的系统上灵活扩展;
			2.没有地方写死,可以灵活配置;
			3.容易变化的逻辑没有散落在各个系统里面,不需要多个地方跟着一起改。

		7.可重用性
			开发新的需求,旧的功能模块可以直接拿过来用。

		通常来讲,对于C端应用,会关注高并发和高可用,然后有的业务(比如支付)对一致性要求非常高;对于B端业务,会更关注系统的可维护性,可扩展性,
	可重用性,有了这些特性,系统才不能拖业务后腿,可以快速的支撑各种各样的复杂业务需求的开发。

		上面是想说明做架构的一种"以始为终"的思维方式。先明确落脚点,或者说最终要达到的目的,即非功能性需求,再去想要达到这些目的可以用哪些技术
	手段。只要能达到目的,可以用各种办法。

14.6 视角(横看成岭侧成峰) 
	架构的4+1视图:
		其中的1是指 "功能视图",其他4个视图都是围绕该视图展开的,分别是逻辑视图,物理视图(部署视图),开发视图,运行视图(进程视图)。

		功能视图:
			对于B端的复杂业务系统,往往会画用例图,但对于C端产品,往往直接看 交互设计稿或最终的UI原型图。

		逻辑视图:	
			系统的逻辑模块划分,数据结构,面向对象的设计方法论里面的 类图,状态图等。

		物理视图:
			整个系统所在的机房,各类机器数目,机器配置和网络带宽等。

		开发视图:
			代码所在的工程结构,目录结构,Jar包,动态链接库,静态链接库等。

		运行视图:
			系统的多进程,多线程之间的同步。

		除了4+1视图,还有一个常见的视图"数据视图",称为5+1视图。逻辑视图和数据视图有什么区别?

			逻辑视图是一个比数据视图更加宽泛的概念,在传统的以数据库为中心的开发中,数据视图也就是 E-R 模型,同时也是逻辑视图,所谓的"贫血模型";
		在领域驱动设计中(DDD),提倡"充血模型",逻辑视图往往指的是类图,在其他的非数据库的系统中,逻辑模型也可能是指内存中的数据结构。

			另外还有一个问题,微服务的拆分是架构的逻辑视图,还是物理视图,还是开发视图?微服务既反映了一种逻辑上的拆分,同时也对应了一种部署,同时
		也是一种开发方式。可以把多个微服务部署在一台机器上,也可以把一个微服务部署到多台机器上。

			讨论这些不同的架构视图,是想说明一个关键的问题:视图本身只是一个框,一个形式,引导开发者把系统的架构描述清楚,而重点是系统面对的问题
		描述清楚,而不是拘泥于形式本身,并且不同类型的系统的侧重点也不同,也未必每个视图都需要很清楚的描述。否则,架构就是一个"空架子",虽然视图
		很多,但没有阐释关键问题。


14.7 抽象 
	1.什么是抽象
		1.语言中的抽象
			语言的抽象阶梯。语言只是对现实中我们所注意到的事务特征的一种抽象,每一次命名,都是一个抽象化的过程,这种过程忽略了现实中事物的许多
		特征。

			从阿花,牛,家畜,农庄资产,资产,财务,就组成了一个抽象阶梯,抽象程度越来越高,而其中的组成部分的细节特征显示的也越来越少,到后来
		真实的特性也就完全不提了。

			所以,抽象是一个化繁为简的过程,也是一个"可能性,多样性越来越小"的过程;抽象的过程也是一个总结,分门别类的过程。

		2.计算机中的抽象
			1.存储的抽象:关系型数据库,表格。
			2.计算的抽象是顺序,选择,循环。再复杂的算法,逻辑计算到了计算机里面,最终都会变成顺序,选择,循环三种语句。
			3.面向对象的方法学:父类与子类,继承。
			4.面向接口的方法学

			把面向对象的方法再往前推进一步,就是所谓的"面向接口的方法学"。接口是双方交互的一种协议,也是对交互细节的一种抽象。

	2.怎么做抽象
		1.分解:找出差异和共性。
			要做抽象,首先要做的是分解。只有分解,才知道两个事务之间的差异和共性。

		2.归纳:造次。
			找到了共性和差异,把共性的部分总结成一个新的东西,造出一个新词来表达"共性",就是归纳,也是抽象。所以抽象的过程往往也是一个"造次"
		的过程。

	3.抽象带来的问题
		抽象的好处是找出共性,简化事物,但抽象也会造成问题。
			1.抽象造成意义模糊
			2.抽象错误:地基不稳
			3.抽象造成关键特性丢失
			4.抽象过程

14.8 建模 
	软件领域的建模:面向对象建模,业务建模,领域建模,UML建模,ER实体建模,四色建模法,DCI ...

	建模的本质到底是什么:
		1.建模的本质:重要的东西"显性化"
			很多时候会遇到重要的情况:一个函数写了几百行代码,里面的if-else 写了很多,计算各种业务规则。另外一个人接手后,分析了好几天,才把
		业务逻辑彻底理解清楚。

			这个问题从表面上来看是代码写的不规范,要重构,把一个有几百行代码的函数拆成一个个小的函数。从根本上来说,就是"重要逻辑"隐藏在代码里面,
		没有"显性"的表达出来。

			这只是一个函数,推广到类,模块,系统,是同样的道理,比如:
				1.业务流程隐藏在多个对象的复杂调用关系里面;
				2.某个业务的核心概念没有提取出来,其职责分摊到了其他几个实体里面;
				3.系统耦合,职责边界不清...

			所以,建模的本质是:把重要的东西进行显性化,进而把这些显性化的构造块互相串联起来,组成一个体系。

		2.重要的东西:构造块
			哪些东西是"重要"的呢?比如领域实体,某个业务流程(对应领域驱动设计里面的"领域服务"),比如某条重要的业务规则(对应领域驱动设计里面的
		Specification模式),比如复杂对象的创建过程(对应领域驱动设计里面的工厂模式)...

			说白了,就是把系统里面"重要的"东西挑出来,让它在"设计图纸"上可见,而不是分析完代码才能看出来。

		3.显性化
			重要的东西找到了,如何显性化呢?其实就是"命名"。"名不正言不顺",名字反应了职责,名字也让领域专家,架构师,程序员对"同一个东西"进行
		讨论,而不是"牛头不对马嘴"。

		4.形成体系
			找到了"重要的东西"并"命名成构造块",接下来就是通过某种结构把这些"构造块"组装起来,成为一个整体,这就成了某种"方法论"。

		5.建模的层次
			不仅做业务分析才有建模,即使没有任何的业务建模,直接写一个超级大的函数,里面包含所有代码,这何尝不是一种建模呢?只不过这种"建模"的
		构造块太小:加减乘除,if-else,for,while ... 这些就是这种建模方法的构造块,并且这种方法对于程序员尤为擅长。

			把建模范式应用到不同的粒度,不同的层次的建模方法:
				1.自然语言建模
					构造块:常用的几千个汉字
					语法规则:主谓宾定状补

				2.计算机语言建模
					构造块:加减乘除,if-eles,for,while...
					语法规则:程序员很熟悉。

				3.过程建模
					构造块:函数
					语法规则:整个系统描述成一个个过程,每个过程通过函数的层层调用组成。

				4.对象建模
					构造块:对象
					语法规则:整个系统描述成对象与对象之间的关系。

				5.领域驱动设计建模
					构造块:实体,值对象,领域服务,领域事件,聚合根,工厂,仓库,限定上下文
					语法规则:"构造块"之间的联系(不是很明显,需要深入研究,也正是领域驱动设计难掌握的地方)。

14.9 正交分解 
	比"分解"更为严谨,更为系统的是"正交分解"。

	在物理学中的傅立叶变换,任意一种形状的波形都可以由一系列标准的正弦波叠加而成,这也是正交分解。分解的过程要保证2个原则:
		1.分清。同一层次的多个部分之间要互相独立,无重叠。
		2.分净。完全穷尽,无遗漏。

		每种分法之间互不重叠,同时又完全穷尽所有的人。

	案例1:电商的供应链来说,一个很重要的就是仓库。极大核心业务:
		1.采购
		2.退供
		3.调拨
		4.售卖
		5.客退

		这些业务的业务流程和逻辑都很像,站在仓库的角度,如何支撑这些业务呢?其中一个思维就是正交分解:虽然业务种类繁多,但站在仓库的角度,只有2种
	操作:"入库"和"出库"。

	案例2:电信公司的套餐种类繁多,但拆解来看,主要有电话,短信,宽带3种。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

《软件架构设计:大型网站技术架构与业务架构融合之道》思维导图

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

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

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

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

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