《企业应用架构模式》是Martin Fowler的经典著作,也是软件架构领域的必读书之一。我第一次读这本书是在刚工作不久,当时很多内容看不懂。工作了几年之后再读,才真正理解了书中的思想。这本书彻底改变了我对软件架构的理解,也影响了我后来所有的架构设计。本文是我的读书笔记,包括书中最核心的架构模式、我最受启发的观点、以及这些思想如何在实际项目中应用。如果你也在做企业应用开发,强烈推荐这本书。

一、关于这本书和作者

先简单介绍一下这本书和作者吧。

Martin Fowler是世界级的软件开发大师,敏捷开发的创始人之一,也是很多经典软件书籍的作者。他的书以深入浅出、实用性强著称,对整个软件行业产生了深远的影响。

《企业应用架构模式》(Patterns of Enterprise Application Architecture,简称PEAA)出版于2002年,虽然已经过去了将近20年,但是书中的思想至今仍然非常有价值。现在流行的很多框架和架构模式,都能在这本书中找到源头。

这本书的核心内容是总结了企业应用开发中常见的架构模式,包括分层架构、对象关系映射、Web表现层、并发处理、会话状态管理、分布策略等。每个模式都有详细的介绍、适用场景、优缺点和实现思路。

我第一次读这本书是在刚工作的时候,那时候我主要做CRUD开发,对架构没有什么概念,读这本书的时候觉得很多内容都很抽象,看不懂。工作了几年之后,参与了几个比较大的项目,遇到了各种架构问题,这时候再读这本书,才发现书中说的都是真知灼见,很多问题书中早就给出了解决方案。

可以说,这本书是我架构设计的启蒙书,它让我从一个只会写业务代码的程序员,开始思考架构层面的问题。

下面分享一下书中最核心的内容和我的理解。

二、分层架构:企业应用的基础

分层架构是企业应用最基础的架构模式,也是全书的基础。

Martin Fowler把企业应用分成了三个主要层次:

  • 表现层(Presentation):负责处理用户交互,展示数据,接收用户输入
  • 领域层(Domain):负责处理业务逻辑,是系统的核心
  • 数据源层(Data Source):负责和数据库、消息队列等外部系统交互

这个分层架构看起来简单,但是真正理解并做好并不容易。

为什么要分层

分层的核心目的是关注点分离。每个层次只负责自己的事情,层次之间通过明确的接口通信。这样做的好处是:

  • 可以独立开发和维护每个层次
  • 可以替换某个层次的实现而不影响其他层次
  • 可以更容易地测试每个层次
  • 代码结构更清晰,更容易理解

分层的原则

分层有一个重要的原则:上层可以依赖下层,下层不能依赖上层。也就是说,表现层可以调用领域层,领域层可以调用数据源层,但是反过来不行。

还有一个原则是,领域层不应该依赖表现层和数据源层的具体实现。领域层应该是纯粹的业务逻辑,不关心数据是存在数据库还是文件里,也不关心数据是展示在网页上还是手机APP上。

这个原则说起来简单,但是实际开发中经常被违反。很多项目的业务逻辑写在Controller里,或者写在SQL里,导致领域层名存实亡。

我的教训

我刚工作的时候,参与过一个项目,就是典型的分层不清。Controller里写了大量的业务逻辑,Service层只是简单地调用DAO,DAO层又有很多业务逻辑。结果就是代码很难维护,改一个业务逻辑要改好几个地方,测试也很难写。

后来读了这本书之后,我们重构了这个项目,把业务逻辑都抽到了领域层,Controller只负责参数校验和调用Service,Service负责业务逻辑编排,DAO只负责数据存取。重构之后,代码结构清晰了很多,维护起来也容易了。

从那以后,我做任何项目都会首先考虑分层,确保每个层次的职责清晰。这是做好架构的第一步。

三、领域层模式:处理业务逻辑的三种方式

领域层是企业应用的核心,也是最复杂的部分。Martin Fowler总结了三种组织领域逻辑的模式:事务脚本、领域模型、表模块。

1. 事务脚本(Transaction Script)

事务脚本是最简单的模式,就是把每个业务操作写成一个过程,从数据库读取数据,处理业务逻辑,然后写回数据库。

这种模式的优点是简单直观,容易理解,适合业务逻辑比较简单的系统。很多小型项目或者快速原型都用这种模式。

缺点是当业务逻辑复杂之后,代码会变得很臃肿,大量的重复代码,很难维护。而且业务逻辑和数据访问逻辑混在一起,很难测试。

2. 领域模型(Domain Model)

领域模型是把业务逻辑封装成面向对象的模型,每个领域对象都有自己的状态和行为。业务逻辑分布在各个领域对象中,通过对象之间的协作来完成业务操作。

这种模式的优点是能够很好地应对复杂的业务逻辑,代码结构清晰,可维护性好,容易测试。面向对象的设计也更符合人类的思维方式。

缺点是学习曲线比较陡,需要掌握面向对象设计和领域建模的技巧。而且对于简单的业务逻辑来说,用领域模型可能会过度设计。

3. 表模块(Table Module)

表模块是介于事务脚本和领域模型之间的一种模式。它不是以单个对象为单位,而是以表为单位,一个表对应一个类,这个类包含了操作这张表的所有业务逻辑。

这种模式在.NET平台比较常见,因为.NET的DataSet和DataTable天然支持这种模式。它的优点是比事务脚本更有组织性,比领域模型更简单。缺点是不如领域模型灵活,处理复杂的对象关系比较困难。

我的理解

这三种模式没有绝对的好坏,关键是根据业务复杂度来选择。

业务逻辑简单的系统,用事务脚本就够了,不要为了用领域模型而用领域模型。业务逻辑复杂、变化频繁的系统,就应该用领域模型,把业务逻辑封装好,否则后期维护会很痛苦。

我见过很多项目,业务逻辑很简单,但是非要用DDD(领域驱动设计),搞了一堆聚合根、值对象、领域事件,结果代码比业务逻辑还复杂,开发效率很低。这就是典型的过度设计。

也见过很多项目,业务逻辑已经很复杂了,还在用事务脚本,一个方法几百行代码,改一个需求要看好久,bug不断。这就是设计不足。

所以,选择合适的模式很重要。没有最好的架构,只有最合适的架构。

四、数据源层模式:对象关系映射的智慧

数据源层主要解决的是对象和关系数据库之间的映射问题,也就是所谓的ORM(Object-Relational Mapping)。

Martin Fowler在书中详细介绍了几种数据源架构模式:表数据入口、行数据入口、活动记录、数据映射器。

1. 表数据入口(Table Data Gateway)

表数据入口就是一个表对应一个类,这个类封装了对这张表的所有数据库操作,比如查询、插入、更新、删除。业务逻辑层调用这个类来操作数据库。

这种模式很简单,很多早期的项目都用这种模式。优点是简单,容易理解。缺点是业务对象和数据库表结构耦合紧密,表结构变了,业务代码也要跟着变。

2. 行数据入口(Row Data Gateway)

行数据入口和表数据入口类似,但是它是以行为单位的,一个对象对应数据库中的一行记录。每个对象都有自己的增删改查方法。

这种模式比表数据入口更面向对象一些,但是还是和数据库结构耦合紧密。

3. 活动记录(Active Record)

活动记录模式是把数据访问逻辑封装在领域对象中。一个领域对象既包含业务逻辑,又包含数据访问逻辑。对象自己知道如何保存自己、加载自己、删除自己。

这种模式很流行,很多ORM框架比如Ruby on Rails的ActiveRecord、Django的ORM都是这种模式。优点是简单,开发效率高,一个对象就能完成所有操作。缺点是业务逻辑和数据访问逻辑耦合在一起,不符合单一职责原则,对于复杂的系统可能不太合适。

4. 数据映射器(Data Mapper)

数据映射器模式是把数据访问逻辑完全分离出来,领域对象完全不知道数据库的存在。有一个独立的映射器层,负责在领域对象和数据库之间转换。

这种模式是最干净的,领域对象是纯粹的,只包含业务逻辑,不关心数据如何存储。这样领域层可以独立测试,也可以很容易地替换存储方式。

缺点是比较复杂,需要写很多映射代码。不过现在有了Hibernate、MyBatis等ORM框架,数据映射器的实现已经简单很多了。

我的理解

这几种模式也是各有适用场景。简单的系统,用活动记录就很好,开发效率高。复杂的系统,对领域层的纯净度要求高,就用数据映射器。

我个人比较喜欢数据映射器模式,因为它让领域层保持纯粹,业务逻辑和数据访问分离,维护起来更舒服。但是对于一些小项目,我也会用活动记录,因为简单快速。

关键还是那句话,根据实际情况选择,不要一刀切。

五、表现层模式:MVC和它的朋友们

表现层负责处理用户交互,Martin Fowler在书中介绍了几种表现层模式,其中最著名的就是MVC(Model-View-Controller)。

MVC模式

MVC把表现层分成了三个部分:

  • Model(模型):负责数据和业务逻辑
  • View(视图):负责展示数据
  • Controller(控制器):负责接收用户输入,调用模型,选择视图

MVC的核心思想是分离关注点,让数据、展示、控制逻辑分开,各自独立变化。

MVC模式现在已经成为Web开发的标准模式,几乎所有的Web框架都是基于MVC的。Spring MVC、ASP.NET MVC、Django、Rails等都是MVC的实现。

MVC的变体

除了经典的MVC,还有一些变体,比如MVP(Model-View-Presenter)、MVVM(Model-View-ViewModel)等。这些变体主要是为了更好地测试和更复杂的界面交互。

MVP中,Presenter负责View和Model之间的交互,View是被动的,不直接和Model交互。这种模式更容易测试View的逻辑。

MVVM中,ViewModel负责把Model的数据转换成View可以直接使用的形式,View和ViewModel之间通过数据绑定通信。这种模式在前端框架中很流行,比如Vue、Angular、React等。

前端控制器模式

Martin Fowler还介绍了前端控制器(Front Controller)模式,就是用一个统一的入口来处理所有的请求,然后根据请求的类型分发给对应的处理器。

现在几乎所有的Web框架都用了前端控制器模式,比如Spring的DispatcherServlet、Struts的ActionServlet等。这种模式的好处是可以统一处理一些公共逻辑,比如权限校验、日志记录、异常处理等。

六、并发和会话:企业应用的难点

企业应用中,并发和会话管理是两个比较难的问题。Martin Fowler在书中也有专门的章节讨论。

并发管理

并发管理主要解决的是多个用户同时修改同一份数据时的冲突问题。主要有两种策略:乐观锁和悲观锁。

乐观锁是假设冲突很少发生,修改的时候不加锁,提交的时候检查数据是否被其他人修改过。如果被修改过,就回滚重试。乐观锁适合冲突少的场景,性能好。

悲观锁是假设冲突经常发生,修改的时候先加锁,其他人必须等锁释放才能修改。悲观锁适合冲突多的场景,但是性能差一些,而且可能导致死锁。

这两种策略没有绝对的好坏,要根据业务场景选择。大部分Web应用都用乐观锁,因为Web应用的冲突通常不多,而且用户体验要求高。

会话状态管理

会话状态管理是指如何保存用户在多个请求之间的状态。主要有几种方式:

  • 无状态:每次请求都携带所有需要的信息,服务器不保存状态
  • 服务器端会话:状态保存在服务器端,通过Session ID关联
  • 客户端会话:状态保存在客户端,比如Cookie、LocalStorage
  • 数据库会话:状态保存在数据库中

每种方式都有优缺点。无状态的方式最容易扩展,但是实现复杂。服务器端会话简单,但是不利于扩展。客户端会话不占用服务器资源,但是安全性和大小有限制。

现在的趋势是尽量做无状态设计,把状态保存在客户端或者分布式缓存中,这样服务器可以方便地水平扩展。

七、这本书如何改变了我的架构

读了《企业应用架构模式》之后,我的架构设计理念发生了很大的变化。

1. 从"能跑就行"到"关注结构"

刚工作的时候,我写代码只关心能不能跑起来,不关心代码结构。读了这本书之后,我开始关注代码的组织结构,关注分层,关注职责分离。我意识到,好的架构不是为了好看,而是为了可维护性、可测试性和可扩展性。

2. 从"什么都自己写"到"善用模式"

以前遇到问题,总是自己想解决方案。读了这本书之后,我发现很多问题都是经典问题,已经有成熟的解决方案了。遇到问题的时候,先想想有没有对应的模式,然后根据实际情况调整,这样效率高很多,方案也更可靠。

3. 从"追求新技术"到"关注本质"

以前总是追求新技术、新框架,觉得用了最新的技术就是好架构。读了这本书之后,我意识到技术和框架只是实现手段,架构的本质是关注点分离、职责划分、接口设计。这些本质的东西是不会随着技术变化而变化的。掌握了本质,就能快速掌握新的技术和框架。

4. 从"一刀切"到"因地制宜"

以前觉得某种架构模式好,就什么项目都用。读了这本书之后,我明白了没有最好的架构,只有最合适的架构。要根据项目的规模、业务复杂度、团队情况来选择合适的架构。简单的项目用简单的架构,复杂的项目用复杂的架构,不要过度设计,也不要设计不足。

八、一些阅读建议

如果你打算读这本书,这里有一些建议。

第一,不要期望一次就读懂。这本书内容很丰富,很多模式需要有实际经验才能理解。第一次读可以先了解大概,有了一些项目经验之后再回来读,会有更深的理解。

第二,边读边实践。读到一个模式的时候,想想自己做过的项目中有没有用到这个模式,或者有没有可以用这个模式改进的地方。结合实际经验来读,收获会大很多。

第三,不要死记硬背模式。模式是解决问题的方案,不是教条。理解每个模式的核心思想、适用场景和优缺点,然后根据实际情况灵活运用,而不是生搬硬套。

第四,可以结合其他书一起读。比如《设计模式》、《领域驱动设计》、《代码整洁之道》等,这些书和《企业应用架构模式》是互补的,一起读会有更全面的理解。

九、写在最后

《企业应用架构模式》是一本经典的软件架构书籍,虽然出版已经将近20年了,但是书中的思想至今仍然非常有价值。现在流行的很多框架和架构模式,都能在这本书中找到源头。

这本书改变了我对软件架构的理解,让我从一个只会写业务代码的程序员,成长为一个能够思考架构、设计架构的开发者。它让我明白了,好的架构不是什么高深莫测的东西,而是对常见问题的合理组织和抽象。

如果你是一个做企业应用开发的程序员,如果你想提升自己的架构设计能力,我强烈推荐你读一读这本书。它可能不会让你立刻变成架构师,但是它会给你一个思考架构的框架,让你在面对复杂问题的时候,有章可循。

最后用Martin Fowler的一句话结束本文:"任何足够复杂的系统,都需要架构来管理其复杂性。"愿每一个开发者都能掌握架构的智慧,构建出优雅、可维护、可扩展的系统。