三层架构的进一步理解
三层架构也有十年的历史了,虽然刚毕业的时候做的就是三层架构的应用,但是今天回想起来当时并没有真正理解三层架构需要解决的问题,只是盲从,生搬硬套而已。
现在是人都知道什么是三层架构,无非用户界面(UI)、业务逻辑(Business Logic)和数据层(Data)。UI和Data这两层都好说,数据一般不就数据库(当然还可能是文件系统或者其他数据服务,当然利用DBMS一定是最多的)么,UI也好理解,总要给用户界面才能用,现在基本都是图形界面,无非是窗口、页面或者报表之类的东西。关键是业务逻辑该放点什么东西,这往往是争议最大的地方。看到很多人抱怨三层结构平添了接口的复杂度,中间添加了一层转换,可能会带来性能问题,所以我们往往会困惑,三层架构优点在哪儿?
大多数人对于业务逻辑层的理解就是有这么在一组对象,他们封装了所有数据库的操作;用户界面层只是通过调用业务逻辑层的对象进行工作,创建对象、调用对象的方法,总比写SQL看起来简单很多,另外一方面,只能通过业务逻辑层访问数据库,在业务逻辑层能够完成安全性的检查,数据完整性的保证。听起来不错,另外还有人说,三层架构便于分工,让擅长数据库的老兄去开发业务逻辑层对象,而擅长UI的老兄开发界面,或者可以快速的为用户定制功能等等。好像很完美呀,那么我们就用这个架构上吧。
可以做着做着,问题就来了,有几种情况最常见:
i) 查询结果如何处理。
查询结果通常都是返回很大一组数据,比如1000行的结果集。业务逻辑层查询数据库得到一个1000行记录的结果集,这应该没有疑义,但是如果返回给用户界面呢?是包装成对象,生成1000个对象,再把这1000个对象的集合返回;还是直接把查询到的结果集返回?
如果重新包装返回对象集合,稍微有点良知的人都会有些惶恐,那可是要创建1000对象,然后1000对象属性的赋值,很显然会带来大量的开销,而且这种查询是很频繁发生的,普通的“树-列表”的应用模式下,每一次树节点的选择,都会执行一次查询,那么频繁的对象创建和销毁,势必会产生很多内存碎片,又是一个影响性能的地方。
如果直接把结果集返回,岂不是用户界面这一层需要关心数据库的结构,甚至字段名,本来想对数据库进行隔离的目的不就达不到了么?这时候多个中间层,好处何在?
ii) 需求变化时修改的地方反而多了。
如果到今天还有人幻想着,需求能在开发之前固定(不要说软件外包,那是编码,不是开发),那么他不适合做开发,可以转行了。需求的变更是永恒的,不变仅存于人们美好的愿景中。
一旦需求变化了,例如业务对象增加了一个特性,大家会发现,我数据库需要增加一个字段,业务对象需要增加一个属性,用户界面可能需要增加一个输入框。慢着,我们不是说三层架构是松耦合的么,怎么还是要改一起改呀。也许高明一点的设计师可以通过数据库扩展字段和对象扩展数据的方法,使业务逻辑层和数据库层适用这种变更。但是当增加一种业务对象,或者业务对象的关系发生变化时怎么办?要知道用户永远比你想象中无知,也永远不可能让用户去服从你的架构,尽管你自以为架构很完美。
天哪,现在当发生变化时我需要修改三个地方,还不如两层结构只需要修改两个地方呢。这不是给自己添麻烦么。
相信仅这两点就可以让很多人信心动摇,不行我们要回忆一下业务逻辑层的好处:
a) 装数据库操作,使业务逻辑与用户操作相分离。但是一般DBMS都有存储过程(Stored Procedure,SP),我可以把业务逻辑放到SP中呀,不也是和用户操作相分离么。
b) 以对象的形式提供业务方法,简化界面的调用。这个优点似乎还在,不过仅仅是为了包装成对象,方便调用,那么其实把业务对象和UI部署在一个物理节点上也可以达到这样的效果,哪我搞台App Server出来干吗?
c) 使开发组内的成员各取所长,专注于自己所擅长的领域。算了吧,没几十个人的团队根本不可能分工如此细致。以笔者招聘的经验,就算是划分三层架构,还不是按模块分配工作,一位老兄从头干到底。
既然好处缺缺,我们是不是可以说三层架构“中看不中用”呢?笔者也曾经困惑过这个问题。
不过软件行业毕竟不是娱乐圈,炒作有之,务实的人更多。何况这几十年来软件这个领域集中了全世界那么多聪明的人,计算机科学本身又是和实际应用联系非常紧密的一门学科,大家都是工程师,鼓捣十年,还在继续鼓捣,显然是有实际价值的,要知道这些年来有多少技术已经被抛弃。既然不是三层架构的问题,就应该是我们理解的问题;我们之所以不能理解三层架构本质的优势,是因为我们所构建的应用的规模太小,没有达到那个Level。当我们要选择三层架构时,请先问一下自己:我们系统的并发访问量是否已经高到我们不得不用负载平衡(Load Balance)才能够解决的地方?是否存在多个数据节点,一定要应用分布式事务才能够保证数据访问的有效性;或者数据量巨大到我们不得不划分多个数据节点才能够存储?
分层的目的是为了隔离,隔离的目的是为了当一方的下游发生变化时,它的上游无需随之变化。这种变化不仅仅是功能上的变化,而是性能或者应用模式上的变化,例如:从局域网迁移到Internet上,原先满足1000个用户,现在需要满足100,000个用户。这其实就是系统可伸缩性(Scalability)的问题,三层架构就是为了解决可伸缩性问题的,至于对业务逻辑提供对象形式的包装都是顺带的,老是以这个作为三层架构优点反复鼓噪的人,简直是误人子弟,至少当年笔者就被误了。
为什么我们需要中间层,因为数据层可能会发生变化。系统开始可能使用Access,随着业务量的增大需要升级到SQL Server;原先一张表可以记录一类数据(比如交易数据),现在需要分割成多张表(按年或者月水平分割,或者主从表垂直分割);原先一个数据节点能够存储所有的数据,现在需要部署到多个节点。这时候只需要修改中间层对象以满足数据层的变更,而用户界面层无需任何变化,系统在成长,但是用户的体验是一致的。
在这样的架构中,数据层需要能够能够分割,甚至支持多节点(DBMS通常不支持负载平衡),或者自己实现的负载平衡的数据服务;业务逻辑层(中间层)需要支持负载平衡,以及分布式事务等一些高级的应用;用户界面层,也就是前端服务也需要支持负载平衡,以适应将来可能上万甚至几十万用户的并发访问。只有做到这一点,系统才是可伸缩的。至于业务逻辑层是不是面向对象的,自己看着办吧,这只是设计方法和架构关系不大。
总之一句话,只有在高可伸缩性的环境下,三层架构才能体现出自身的价值;如果一台应用服务器和一台数据库服务器就能够覆盖我们全部应用的话,那么除了三层架构,随便玩,分多层不能给我们带来太多好处,反而增加了系统复杂度。