每个开发人员必须理解的两件事:

  1. 框架设计是必要的。
  2. 花哨的架构图并不能真正的描述应用程序的架构。

真正的架构是从开发人员编写的代码中找到的;如果在开始时我们不设计应用程序的架构,我们最终会得到一个具有多个架构的应用程序。

这是否意味着开发人员应该听从架构师呢?

没有。框架设计是太重要了,不能仅仅是架构师的事,这就要求开发人员也必须擅长进行架构设计。

良好架构的两个原则

软件架构是软件系统的高层次结构,创建这种高层次结构的原则,以及这种结构的文档。

尽管历史经验能帮助我们创建更好的架构,但是架构设计的基本原则实际上相当简单。我们要做的是遵循这两个原则:

1. Separation of Concerns (SoC)

关注点分离(SoC)的原理分离规定如下:

关注点分离(SOC)是一种设计原则,将计算机程序划分成不同的部分,这样每一部分都有一个单独的关注点.。

这意味着我们应该

  1. 确定我们需要照顾的”关注点“。
  2. 该如何去解决这些关注点。

换句话说,这个原则将帮助我们设计所需的层级及每层的责任。

说白了还是“高内聚,低耦合”。

2. Keep It Simple, Stupid (KISS)

KISS原则规定:

大多数系统工作最好,如果他们保持简单,而不是复杂;因此简单性应该是设计的关键目标,并且应避免不必要的复杂性。

这个原则是理性的声音。它提醒我们,每一层都有代价,如果我们创建一个复杂的架构,有太多的层,代价会太高。

换句话说,我们不应该设计一个这样的结构:

资料来源:Geek And Poke:Footprints  -  CC 3.0许可

我认为约翰·朱迪,马克和大卫是有罪的精神自慰。他们遵循分离关注原则,但他们忘记了最小化其架构的复杂性。可悲的是,这是一个常见的错误,它的代价比较高:

  1. 添加新功能,需要花费更多的时间;因为我们必须通过每一层传输信息。
  2. 维护这样的应用程序几乎是不可能的,因为没有人能真正理解这样的架构。

这产生了一个明显的问题:

什么样的架构可以为我们服务?

三层架构设计应该足够为每个人

如果考虑一个Web应用程序的职责,我们注意到一个Web应用程序有以下“关注”:

  • 它需要处理用户的输入并将正确的响应返回给用户。
  • 它需要一个异常处理机制,向用户提供合理的错误消息。
  • 它需要一个事务管理策略。
  • 它需要处理认证和授权。
  • 它需要实现应用程序的业务逻辑。
  • 它需要与使用的数据存储和其他外部资源进行通信。

我们可以只使用三层来满足所有这些关注。这些层是:

  • Web层是一个Web应用程序的最上层。它负责处理用户的输入并将正确的响应返回给用户。处理其他层抛出的异常并向用户反映错误的发生;对用户进行认证,拒绝未认证的用户访问。
  • Service层Web 应用的中间层。它应该组织业务逻辑,为 Web 层提供服务;使得所有服务都是事务性的;负责用户的授权。
  • Repository层Web 应用的最底层。它负责操纵数据库,以实现对数据库的增删改查。

属于特定层的组件可以使用属于同一层或其下面的层的组件。

经典Spring Web应用程序的架构如下所示:

我们要做的下一件事就是设计每一层的接口,而这正是我们碰到类似的术语:数据传输对象(DTO)和领域模型(Domain Model)。这些术语描述如下:

  • 数据传输对象是一个对象,它仅仅是一个简单的数据容器,它用来传输用户可见的数据,屏蔽了 Web 应用的内部实现。
  • 领域模型由三个不同的对象:
    • 域名服务是一个无状态类,它提供了相关的一个领域概念,但不是一个实体或值对象的“自然”的一部分业务。
    • 实体是由它的身份通过其整个生命周期保持不变定义的对象。
    • 值对象描述的属性或一件事,而这些对象没有自己的身份或生命周期。值对象的生命周期绑定到实体的生命周期。

现在我们知道这些术语是什么意思,我们可以继续并设计每个层的接口。

  • Web层应该只处理DTO。
  • Service层将DTO作为方法参数。它可以处理领域模型对象,但它只能将DTO返回到Web层。
  • Repository层将实体作为方法参数,并返回实体。

这提出了一个非常重要的问题:

我们真的需要数据传输对象吗?为什么我们不能将领域模型直接返回给Web层?

主要是因为下面两个原因:

  1. 领域模型指定了我们的应用程序的内部模型。如果我们将这个模型暴露给外部世界,客户端将必须知道如何使用它。换句话说,我们的应用程序的客户端将不得不处理不属于他们的东西。如果我们使用DTO,我们可以从我们的应用程序的客户端隐藏这个模型,并提供一个更容易和更清洁的API。
  2. 如果我们将我们的领域模型暴露给外部世界,我们不能改变它,而不打破依赖于它的其他东西。如果我们使用DTO,我们可以改变我们的域模型,只要我们不对DTO做任何更改。

经典Spring Web应用程序的“最终”体系结构如下所示:

有许多未解答的问题

本文描述了Spring Web应用程序的经典架构,但它不提供任何有关真正问题的答案,例如:

  • 为什么X层负责关注Y?
  • 我们的应用程序分层能否超过三层,或者少于三层?
  • 我们应该如何设计每个层的内部结构?
  • 我们真的需要图层吗?

其实原因很简单:

在搞清楚原理之前,我们就可以运行