层次架构(三明治)
All problems in computer science can be solved by another level of indirection, except of course for the problem of too many indirections.
—— David Wheeler
上文提到,业务系统对外的呈现是对某种资源的管理,而且,现实世界里的业务系统往往要对多种资源进行管理。这些资源还会互相引用,互相交织。比如一个看板系统中的泳道、价值流、卡片等;LinkedIn中的公司,学校,个人,研究机构,项目,项目成员等,它们往往会有嵌套、依赖等关系。
为了管理庞大的资源种类和繁复的引用关系,人们自然而然的将做同样事情的代码放在了统一的地方。将不同职责的事物分类是人类在处理复杂问题时自然使用的一种方式,将复杂的、庞大的问题分解、降级成可以解决的问题,然后分而治之。
(图片来自:http://t.cn/RSNienv)
比如在实践中,展现部分的代码只负责将数据渲染出来,应用部分的代码只负责序列化/反序列化、组织并协调对业务服务的调用,数据访问层则负责屏蔽底层关系型数据库的差异,为上层提供数据。这就是层级架构的由来:上层的代码直接依赖于临近的下层,一般不对间接的下层产生依赖,层次之间通过精心设计的API来通信(依赖通常也是单向的)。
以现代的眼光来看,层次架构的出现似乎理所应当、自然而然,其实它也是经过了很多次的演进而来的。以JavaEE世界为例,早期人们会把应用程序中负责请求处理、文件IO、业务逻辑、结果生成都放在servlet中;后来发明了可以被Web容器翻译成servlet的JSP,这样数据和展现可以得到比较好的分离(当然中间还有一些迂回,比如JSTL、taglib的滥用又导致很多逻辑被泄露到了展现层);数据存储则从JDBC演化到了各种ORM框架,最后再到JPA的大一统。
如果现在把一个Spring-Boot写的RESTful后端,和SSH(Spring-Struts-Hibernate)流行的年代的后端来做对比,除了代码量上会少很多以外,层次结构上基本上并无太大区别。不过当年在SSH中复杂的配置,比如大量的XML变成了代码中的注解,容器被内置到应用中,一些配置演变成了惯例,大致来看,应用的层次基本还是保留了:
• 展现层
• 应用层
• 数据访问层
在有些场景下,应用层内还可能划分出一个服务层。