一.背景
在我们的工作中,时常伴随的架构一词,如:MVC架构、微信架构、淘宝架构…,虽然常见,但具体的指的是什么呢?
架构和框架是什么关系?有什么区别?
Linux 有架构,MySQL 有架构,JVM 也有架构,使用 Java 开发、MySQL 存储、跑在 Linux 上的业务系统也有架构,应该关注哪个架构呢?
微信有架构,微信的登录系统也有架构,微信的支付系统也有架构,当我们谈微信架构时,到底是在谈什么架构?
要想准确地回答这些问题,关键在于一些似是而非的概念,如:系统与子系统、模块与组件、框架与架构。
1.系统与子系统
维基百科对系统的定义为:
系统泛指由一群有关联的个体组成,根据某种规则运作,能完成个别元件不能单独完成的工作的群体。它的意思是“总体”“整体”或“联盟”。
在这段描述中可知,系统的主要关键点可以提炼为关联(个体之间是有一定的关联关系的),规则(个体之间需要按照某种骨规则运行),能力(系统能力和个体能力会有本质的区别,不是简单的 1+1 的关系)。
维基百科对子系统的定义为:
子系统也是由一群有关联的个体所组成的系统,多半会是更大系统中的一部分。
其实子系统和系统的定义没有什么差别,只是观察的角度不一样,一个系统可能会是另一个更大系统的子系统。以微信系统做分析:
微信本身是一个系统,包含聊天、登录、支付、朋友圈等子系统。
朋友圈这个系统又包括动态、评论、点赞等子系统。
评论这个系统可能又包括防刷子系统、审核子系统、发布子系统、存储子系统。
评论审核子系统不再包含业务意义上的子系统,而是包括各个模块或者组件,这些模块或者组件本身也是另外一个维度上的系统。例如,MySQL、Redis 等是存储系统,但不是业务子系统。
2.模块与组件
模块和组件是很容易让人混淆的两个名词,如:Mysql 模块只要负责数据的存储;XX项目有安全加密组件、审核组件,某某 App 的下载模块使用了第三方的组件等描述。模块和组件的定义如下:
维基百科对模块的定义为:
软件模块(Module)是一套一致而互相有紧密关连的软件组织。它分别包含了程序和数据结构两部分。现代软件开发往往利用模块作为合成的单位。模块的接口表达了由该模块提供的功能和调用它时所需的元素。模块是可能分开被编写的单位。这使它们可再用和允许人员同时协作、编写及研究不同的模块。
维基百科对组件的定义为:
软件组件定义为自包含的、可编程的、可重用的、与语言无关的软件单元,软件组件可以很容易被用于组装应用程序中。
从两者的定义来看,其实没有太大的差异,主要原因是:因为模块和组件都是一个系统的组成部分,只不过是从不同的角度进行拆分。
如果我们从逻辑的角度对系统进行拆分,得到的就是“模块”;如果我们从物理的角度对系统进行拆分,得到的就是“组件”。而划分模块的主要目的是职责分离;划分组件的主要目的是单元复用。其实组件的定义,更类似于我们生活中的“零件”一词。
3.框架与架构
框架和架构也是一个比较相似的概念,并且这两者在工作上有较强的关联关系,其定义如下:
维基百科对框架的定义为:
软件框架(Software framework)通常指的是为了实现某个业界标准或完成特定基本任务的软件组件规范,也指为了实现某个软件组件规范时,提供规范所要求之基础功能的软件产品。
从定义中可看出,对于框架一词,主要的描述为框架是组件规范(如 MVC 开发规范)、框架是提供基础功能的产品(如 Spring MVC框架、Spring 框架等,提供了一下基础功能,简易了开发)。
维基百科对架构的定义为:
软件架构指软件系统的“基础结构”,创造这些基础结构的准则,以及对这些结构的描述。
从两者定义的角度看,框架和架构的关注点是不一样的,框架关注的是规范;而架构关注的是结构,但是对于这个基础结构,并没有明确的说明是从哪个角度进行分解的,所以也就有了 IBM 的 RUP 将软件架构视图分为著*名的“4+1 视图”。
4.4 + 1 视图:学生管理系统分析
在实际工作中我们却经常碰到一些似是而非的说法。例如,“我们的系统是 MVC 架构”“我们需要将 android app 重构为 MVP 架构”“我们的系统基于 SSH 框架开发”“我们是 SSH 的架构”“XX 系统是基于 Spring MVC 框架开发,标准的 MVC 架构”……
究竟什么说法是对的,什么说法是错的呢?
其实这些说法都是对的,造成这种现象的根本原因隐藏于架构的定义中,关键就是“基础结构”这个概念并没有明确说是从什么角度来分解的。
假设我们要做一个学生信息管理系统,这个系统从逻辑的角度来拆分,可以分为“登录注册模块”“个人信息模块”“个人成绩模块”;从物理的角度来拆分,可以拆分为 Nginx、Web 服务器、MySQL。
从业务逻辑的角度分解,“学生管理系统”的架构是:
从物理部署的角度分解,“学生管理系统”的架构是:
从开发规范的角度分解,“学生管理系统”可以采用标准的 MVC 框架来开发,因此架构又变成了 MVC 架构:
“4+1”视图模型
“4+1”视图模型是从5个不同的视角去描述软件的体系结构,这些视图包括:逻辑视图、进程视图、物理视图、开发视图和场景视图。
每一个视图只关心系统的一个侧面,5个视图结合在一起才能反映系统的软件体系结构的全部内容(架构)。
5.重新定义架构
参考维基百科的定义,可以将架构重新定义为:软件架构指软件系统的顶层结构。
这个定义看似比较简单,但包含的信息却很丰富,基本上把系统、子系统、模块、组件、架构等概念都串起来了。
首先,“系统是一群关联个体组成”,这些“个体”可以是“子系统”“模块”“组件”等;架构需要明确系统包含哪些“个体”。
其次,系统中的个体需要“根据某种规则”运作,架构需要明确个体运作和协作的规则。
后,维基百科定义的架构用到了“基础结构”这个说法,这里改为“顶层结构”,可以更好地区分系统和子系统,避免将系统架构和子系统架构混淆在一起导致架构层次混乱。
6.架构的发展史
要想深入理解一个事物的本质,好的方式就是去追寻这个事物出现的历史背景和推动因素。
(1)机器语言(1940 年之前)
使用二进制的形式,其主要的问题是:太难写、太难读、太难改!
(2)汇编语言(20 世纪 40 年代)
汇编语言又叫“符号语言”,用助记符代替机器指令的操作码,用地址符号(Symbol)或标号(Label)代替指令或操作数的地址。
解决了机器语言读写复杂的问题,但是本质上还是面向机器的,因此,需要去了解计算机很多底层知识(CPU、寄存器等);同时,不同 CPU 的汇编指令和结构还不一样。
(3)高*级语言(20 世纪 50 年代)
称为高*级语言是因为不需要程序员去关注计算机底层的知识,只需要关注自己的业务即可;同时,通过编译器的处理,能将其编译成适合不同 CPU 指令的机器语言。
(4)次软件危机与结构化程序设计(20 世纪 60 年代~20 世纪 70 年代)
“1963 年美国(http://en.wikipedia.org/wiki/Mariner_1)的水手一号火箭发射失败事故”,“IBM 的 System/360 的操作系统开发事故”等事故,创造了“软件危机”一词,为了解决软件危机问题,分别提出了解决方案:
1968、1969 提出“软件工程”方案
1968 年“结构化程序设计”方案
结构化程序设计的主要特点是抛弃 goto 语句,采取“自顶向下、逐步细化、模块化”的指导思想。结构化程序设计本质上还是一种面向过程的设计思想,但通过“自顶向下、逐步细化、模块化”的方法,将软件的复杂度控制在一定范围内,从而从整体上降低了软件开发的复杂度。结构化程序方法成为了 20 世纪 70 年代软件开发的潮流。
(5)第二次软件危机与面向对象(20 世纪 80 年代)
第二次软件危机的根本原因还是在于软件生产力远远跟不上硬件和业务的发展。次软件危机的根源在于软件的“逻辑”变得非常复杂,而第二次软件危机主要体现在软件的“扩展”变得非常复杂。结构化程序设计虽然能够解决(也许用“缓解”更合适)软件逻辑的复杂性,但是对于业务变化带来的软件扩展却无能为力,软件领域迫切希望找到新的银弹来解决软件危机,在这种背景下,面向对象的思想开始流行起来。
虽然面向对象开始也被当作解决软件危机的银弹,但事实证明,和软件工程一样,面向对象也不是银弹,而只是一种新的软件方法而已。
(6)软件架构
软件架构的出现,并不是整个行业面临了类似的问题,也不是为了解决新的软件危机。而是当时某些企业发展到一定程度后,为了解决面临的软件问题,而被提出。如: Rational 或者 Microsoft 这样的大公司。
软件架构的出现有其历史必然性。20 世纪 60 年代次软件危机引出了“结构化编程”,创造了“模块”概念;20 世纪 80 年代第二次软件危机引出了“面向对象编程”,创造了“对象”概念;到了 20 世纪 90 年代“软件架构”开始流行,创造了“组件”概念。我们可以看到,“模块”“对象”“组件”本质上都是对达到一定规模的软件进行拆分,差别只是在于随着软件的复杂度不断增加,拆分的粒度越来越粗,拆分的层次越来越高。