要设计良好的架构,必须做到关注点分离,这样可以产生高内聚、低耦合的系统,这是美丽架构的终极原则。
文 / 王海鹏
什么是架构? 每个人可能都有自己对架构的定义。我比较喜欢的定义是:“架构是系统的组成部件及其之间的相互关系。”根据观察者的视角不同,架构又可以分为业务架构和技术架构。一般来说, 功能性需求会对业务架构产生影响, 而非功能性需求会对技术架构产生影响。
例如:“注册用户可以向自己的相册上传图片,并与好友分享”。这是一项功能性需求。它告诉了我们在系统的业务架构中,会出现“注册用户”“相册”、“图片”、“好友”等组成部件,它们之间存在着相互关系。而“系统可以支持10万并发用户,并在需要时可以方便地伸缩,扩展到支持100万到1000万的并发用户”,则是一项非功能性需求。它告诉了我们系统在性能、负载、吞吐量、可伸缩性方面的特性,目标系统的架构必须对这些特性提供支持。
架构体现的是对复杂系统的分解设计。而如何进行分解,则是软件设计领域永恒的话题。实际上,架构体现的是关注点分离的原则和方法。经典的三层架构,由展现层、业务逻辑层和持久层构成;其中体现了我们对用户界面、业务逻辑和数据持久的关注点分离。这种架构从命令行时代的软件就开始有了,直到最新的AJAX 加RESTful的Web 应用架构中仍然可以看到它,因为这种关注点的分离在这些应用中是必要的。
我们可以在Web 应用中不采用三层架构,也就是不进行这种分离。我们可以在JSP/ASP/PHP中混合用户界面、业务逻辑和数据持久层。但是这样的代码是难以维护的,难以适应大规模项目开发,难以适应将来的变化。关注点不分离的代码为阅读和理解制造了更多的障碍。用户界面、业务逻辑和数据持久三者的分离,让它们能够相对独立地进行变化,比如实现新的用户界面方式、改变业务逻辑和采用新的数据持久机制。
依赖注入的架构方式因Spring、Guice 等框架而被广大Java 程序员所熟悉,进而扩展到.NET等其他语言和平台,它也体现了关注点的分离。
首先,依赖注入体现了“做什么”和“怎么做”的关注点分离。学过C语言的程序员都知道,这种关注点的分离有着悠久的历史,它表现为.h文件和.c文件,一个规定函数原型,一个规定函数实现。这种关注点分离后来还在面向对象的设计中表现为“针对接口设计”,于是我们在依赖注入的架构方式中,看到了许多的接口,以及接口的不同实现。组件的使用者关注组件做什么,组件的实现者关注组件怎么做。其次,依赖注入体现了对实例生命周期(特别是实例创建)和组件装配的关注点分离。我们可以集中指定对象创建的方式,方便灵活地改变系统的装配方式。通过这样的关注点分离,依赖注入的架构让系统变得更灵活,让组件的实例化和组装方式集中在系统的一个局部来确定,而不是分散在系统各处。
《彩色UML建模》一书中提出了4种领域无关的架构型,体现了业务流程、业务事件、参与者角色、具体参与者、分类分组的关注点分离。它研究的是业务架构,告诉我们如何设计一些组件来体现业务逻辑。
以ATM机取款为例,它包含一个业务流程,由身份认证、取款、打印凭据等事件组成。单独来看取款这个事件,彩色UML方法会在模型中体现出“取款(时刻/ 时段)”、“账户(物品)”、“信用卡(物品)”、“ATM机/ 取款柜台(地点)”等组件。这样的关注点分离,使得这一组取款组件可以从业务流程中独立出来,所以它也可以参与其他业务流程,如柜台取款。
REST是一种Web应用架构风格,它的主要特点包括:
- 资源是由URI来指定。
- 对资源的操作包括获取、创建、修改和删除资源,这些操作正好对应HTTP协议提供的GET、POST、PUT和DELETE方法。
- 通过操作资源的表形来操作资源。
- 可以通过内容协商机制来取得同一资源的不同物理表现形式,可以是XML、HTML、JSON或其他格式,这取决于请求者是机器还是人,是消费Web服务的客户软件还是Web浏览器。
在REST架构风格中,体现了对资源命名、请求处理和资源物理表现形式的关注点分离。
由于实现了这些关注点分离,REST有下面这些好处:
- 可以利用缓存Cache来提高响应速度。
- 通讯本身的无状态性可以让不同服务器处理一系列请求中的不同请求,提高服务器的扩展性。
- 浏览器即可作为客户端,简化软件需求。
- 相对与其他叠加在HTTP协议之上的机制,REST的软件依赖性更小。
- 不需要额外的资源发现机制。
- 在软件技术演进中的长期的兼容性更好。
AOP(面向方面编程)也是关注点分离思想的一种体现。记日志是说明AOP 思想的一个常用例子。当我们在业务代码中嵌入很多日志代码时,业务代码的可读性就下降了,因为业务逻辑和日志是两个不同的关注点。通过AOP技术来分离这两个关注点,就提高了代码的可读性和可维护性。
Ivar Jacobson在他的《Aspect-Oriented Software Developmentwith Use Case》一书中, 提出了AOP思想与用例技术结合的方法。例如,在“用户利用电话系统通话”和“对用户的通话计费”这两个用例中,我们的关注点是不同的。但是如果不采用AOP的方法,实现代码中必然将这两个关注点的代码编织在一起。如果对一个业务过程有许多不同的关注点,代码就变得复杂而难读了。于是Ivar提出,分离两个关注点, 再利用AOP的技术将它们最终编织在一起。这样,我们就能单独面对一个方面的关注点。
AOP技术用一种特别的方式实现了关注点分离,它的好处是明显的,但也有一些不足。比如对于编织后的系统除错,会因为执行流的跳转而变得比较复杂。这时候,我们需要通过一些其他技术来弥补,例如回归测试。我们在实现了“用户利用电话系统通话”后,写一个回归测试将工作成果确定下来。在我们实现之后的业务关注点时,经常跑这个回归测试,确保不会因为新的编织而在系统中引入缺陷。
EJB技术虽然在早期受到了一些诟病,但是它的架构设计总体上仍然是非常漂亮的。EJB体现了分布式计算、持久、实例化、缓冲、事务、安全性等关注点的分离。
Google提出的MapReduce技术是一种新的集群计算思想, 它体现了分布式并行计算的关注点分离。Apache 的Hadoop项目就是这种技术的一个实现。通过这种技术,实现了对大规模分布式系统的性能、可伸缩性、可靠性的关注点分离。程序员可以在不了解太多分布式计算细节的情况下,开发出大规模分布计算程序。
关注点分离带来的是高内聚、低耦合的系统,这是美丽架构的终极原则。在实践中,这种关注点分离可以是一开始就设计好的,也可以是逐渐形成的。如果是逐渐形成的,那就是所谓的演进式架构。例如,我们可以先不实现持久机制,在项目进行到一定阶段再来实现。或者在以后方便地更换持久机制。
我们在系统分析时确定系统都有哪些关注点,然后设计一个架构来支持这些关注点的分离,最终将得到在相同的关注点上高内聚,在不同的关注点上低耦合的设计。
作者简介:
王海鹏,1994年毕业于华东师范大学物理系。拥有理学士和文学士学位。独立的软件开发者、培训师和咨询师,也是十余本软件开发书籍的译者。从事软件开发十余年,目前主要的研究领域是软件架构和方法学,致力于提高软件开发的品质和效率。
原文链接: http://history.programmer.com.cn/675/