Laying (2)
When to separate the layers
什么时候进行分层
虽然我们可以为每一个范例鉴别persentation,domain和data source这三个普通的职责层,
但每一个范例都有它们各自关于它们如何分离各层的问题。如果每一个职责层都相当复杂,
这样把它们分拆为独立的模块是有很有意义的。一个具有复杂逻辑的应用程序应该为presentation、
domain、和data source设立不同的包。实际上,它可能有更进一步的中间层。但比较简单
的系统可能并不如此。如果你要做的所有事情是显示和简单的数据输入,那么把所有逻辑都
放到一系列的服务器网页(server pages)中去是非常合理的,特别是如果你手头有工具能
使编写这些服务器网页变得很容易的时候。
需要分离这些职责的复杂度并不是很容易就能确认的。我不能说如果你的domain logic的复
杂度大于7.4的时候,你就应该把它从presentation中分离出来。(除非我把计算复杂度作
为一个练习留给读者,我猜我就能够这样做了。 译注:也许是讽刺一些教科书作者把自己
都无法解决的问题留给读者作为练习吧)我的经验是,几乎在任何时候,都应该把presentation从
domain/data source中分离出来。我会违反这个原则的唯一情况是:如果domain/data source的
复杂度几乎等于0,而且我手头有工具能非常方便地把所有东西放在一起。一个典型的例子
是许多在SQL数据库之上建立的使用界面。它保证了presentation与数据库结构非常匹配,
而且很少涉及任何检验和计算,这样我就会使用把所有东西放在一起的做法。但一旦检验
和计算开始变得复杂,我就会把它分离到不同的对象中去。
我倾向于对不分离domain与data source有更大的容忍力。对许多简单的应用,这两部分可
能看上去非常相似,这样的话我更倾向于把它们放在一起。但一旦我组织业务逻辑的方式开
始看上去显得与data source的定义不同,我会希望把它们放到不同的模块中去。
当描述应用程序的分层结构的时候,我喜欢使用一个UML package diagram来展示packages
和它们之间的依赖。我在这里并没有提供一个作为例子,是因为实际的依赖与你使用的模
式非常相关。一个颇为抽象的规则是:任何东西都不应该依赖于presentation。任何在domain与
data source的模块都不应该调用presentation中的任何东西。当presentation需要根据
domain中的改变进行更新的时候,这种做法可能会导致问题。当这种情况发生时,你应该使
用一个Observer模式来避免对presentation的依赖。
对于其他更复杂的规则,我们必须了解更多关于模式的细节才能草拟出依赖的情况来。
Choosing where to run your layers
选择在哪里运行你的层
在这本书中,我主要谈及逻辑上的层:把一个系统分为各自分离的部分来减少系统不同部分
之间的耦合。即使这些层都运行在一台物理的机器上,分离这些层是非常有用的。但系统
的物理结构在某些方面会造成不同影响。
对大部分IS应用程序来说,选择在于一个处理是否应该在一个客户端,一台台式机上运行;
或者它是否应该在一台服务器上运行。
通常来说最简单的情况是把所有东西都放到服务器上运行。这样做的一个好方法是使用一个
运用网页浏览器的HTML前端。把所有东西都放到服务器的最大优点在于所有东西都易于更新
和维修,因为它们在数量有限的地方里。你不需要担心如何把它们分发到许多台式机中并保
持它们都与服务器保持同步。你不需要担心与其他桌面软件的兼容问题。
对于这种在服务器上运行一切的偏好,最大争议在于响应能力和离线操作。任何在服务器上
运行的逻辑都需要一个服务器传输回路(server round trip)来响应用户做的任何事。如
果用户想乱动一下界面上的东西又希望立即看到反馈,那么这个回路就成为障碍了。另外,
采取这种方案的应用程序需要一个网络连接来运行。网络似乎在任何地方都有,但我能够这
样说的前提是,我并不是在31,000英尺的高空。网络可能很快就能在任何地方都有,但有许
多人希望在现在就开始工作,而不用等到无线通讯覆盖到Deng End Creak(译注:信息闭塞
不通的Creak印第安部落)的时候。离线操作带来了一些特定的问题,但我恐怕在我的这本
书中不会涉及这些东西。
在存在这些普遍的影响因素的情况下,我们就可以逐层地看看我们能够作何种选择。
Data source几乎总是仅仅在服务器上运行。例外的情况是你能功能性地把服务器复制到一
个合适的强大的客户端中。这种情况通常发生在你希望离线操作的时候。在这种情况下,
在离线客户端上对data source进行的修改需要与服务器进行同步,正如我前面所讲,我决
定把这个问题留到另外一天来讨论-或者留给另外一个作者来讨论。
关于在何处运行presentation的决定因素大部分在于你希望使用什么类型的用户界面。使
用一个胖客户端几乎总是意味着你需要在客户端上运行presentation。使用一个网页界面
几乎总是意味着在服务器上运行presentation。但也有例外的情况,客户软件的远端操作
(例如在UNIX世界中的X服务器)在桌面电脑上运行一个网络服务器,但这种例外非常罕见。
如果你正在创建一个B2C(Businass-to-customer)系统-你没有选择余地。任何汤姆,迪克,
和哈里特(译注:即是任何人)都能连接到你的服务器上,而且你不想有任何人由于坚持在
一台TRS-80上进行在线购物而被拒之门外。在这种情况下,你在服务器上进行所有的处理并
为浏览器提供它们能处理的HTML。你选择使用HTML带来的限制是:客户下的任何一个的决定
都需要一个从客户端到服务器的回路来处理,这样会损害响应能力。你可以通过使用浏览器
脚本和可下载的applets来缓解这种情况,但它们同时减低了你的浏览器兼容能力,常常会
带来更多的头痛。你能尽可能使用越纯正的HTML,你的生活将会越轻松。(译注:pure HTML,
即不包含script和applets的HTML)
即使你的台式机上任何东西都是由你的IS部门度身定做的,轻松的生活仍然显得可望而不可
及。你仍然需要保持客户端是最新版本,和避免与其他软件的兼容性冲突。
人们希望使用一个胖客户端presentation的主要原因是一些任务对于用户来说太复杂了,
因而需要一个更有用的应用程序来提供比网页界面更多的东西。但是,越来越多的人开始
习惯如何使网页前端更有用,因而减少了对胖客户端的需求。当我写这篇文章的时候,我
非常喜欢一个原则:如果你能够的话,使用网页表示;如果你别无选择的话,使用胖客户
端。(web presentation if you can, and the rich client if you must)
剩下的就是domain logic了。你可以在三种运行业务逻辑的方式中选择:全部在服务器;
全部在客户端;或拆开它。再一次提醒,所有东西都放在服务器是一个实现简单维护的简
单方法。而把它放到客户端的需求来自响应能力和离线操作。
如果你必须在客户端上运行部分业务逻辑,你可以考虑把它全部都放在那里 - 至少通过
这样做,它被全部放在一个地方。通常这种做法会与胖客户端结合起来-在一台客户端机
器中运行网页服务器并不会明显地提高响应能力,虽然,这可以成为一个处理离线操作的
方法。在这种情况下(指把所有domain logic放在客户端),你仍然可以保持你的
domain logic在与presentation分离的模块中,事实上,你可以使用Transaction Script
模式或Domain Model模式。把所有domain logic放在客户端的问题是你为了升级和维护必须
做更多的东西。
把domain logic拆开到台式机和服务器听起来是两个世界(译注:指全放到客户端和全放到
服务器)中最差的办法,因为这样做的话,对于这些逻辑碎片中的任何一个,你不知道实
际上应该属于哪一边。导致你这样做的主要原因是,当你仅仅有一小部分domain logic必须
放在客户端。一个小诡计(译注:trick,一些不合常规的小技巧)是把这些逻辑碎片的隔
离到一个自包含的模块中,这个模块不依赖于系统中的任何部分。通过这样做,你可以在客
户端和服务器的任何一边运行这个模块。实现这个方法需要相对多的令人厌烦的欺诈技
巧-但它是实现这种分离工作的一个好方法。
一旦你选择好你的处理结点,你就应该尝试把所有代码放到一个结点,一个进程(process)
中。除非你绝对有必要,否则不要尝试把层分离到不同的进程中,因为这样做会导致性能
下降和增加复杂度,因为你必须加入更多的东西,例如Remote Facdes模式和Data Transfer
Objects模式
More Layering schemes
更多的分层方案
我精选出这三个层是因为这三个主题(subject matter)经常出现,而且我想这三层代表
了对企业应用来说有意义的最简单的分层方案。你可以用不同的方式去分层,而且这些不
同的分层方式往往是很有用的。但我发现把这三层放在心上总是有用的,而其他分层办法
虽然常常有用,但不总是有用。
我将会通过看看一些在其他有用的关于IS架构的书中提倡的分层方案,来举例说明这个观
点。首先是我称作Brown Model的分层方案。Brown Model有五层:Presentation,
Controller/Mediator, Domain, Data Mapping, 和Data Source。基本上,这个模型在基
础的三层之间都加入了附加的中间层:在presentation和domain层之间加入了
controller/mediator层,而在domain和data source之间加入了data mapping层。
我发现在某些时候分出这些中间层是有用的,但并不是所有时候。因此,我会把中间层作
为一种模式来讨论。Application Controller是一种在presentation和domain之间的中间
层。而Data Mapper是在data source和domain之间的中间层。在组织本书的时候,我把
Application Controller放在presentation的部分,而Data Mapper放在data source的部
分。
Brown Fowler
Presentation Presentation
Controller/Mediator Application Controller
Domain Domain
Data Mapping Data Mapper
Data Source Data source
因此对我来说,附加的中间层-常常是有用但不总是有用-代表了一种在设计中可以选择
的额外做法。我的做法是:总是考虑三个基础层,看看他们中是否有任何一个过于复杂,
如果有,加入中间层来进行功能分离。
另一个J2EE的分层方案出现在CoreJ2EE模式中。在这里,各层分别是:client,
presentation, business, integration, 和resource. 在business和integration层中存
在着简单的对应关系。他们(译注:CoreJ2EE的设计者)把由integration层连接的外部服
务称作resource层。主要的不同在于他们把presentation层根据运行的地点不同分为了
client(在客户端运行的部分)和presentation(在服务器端运行的部分)。这常常是一
个有用的分离,但再一次提醒,并不是所有时候都需要这种分离。
CoreJ2EE Fowler
Client Presentation that runs on client (eg rich client systems)
Presentation Presentation part that runs on server (eg http handers, server pages
Business Domain
Integration Data source
Resource The external resource that the data source in communication with
微软的DNA架构定义了三个层:presentation, business, 和 data access。它们直接和我
在这里使用的三层对应。最大的不同在于数据在data access层向上传递的方式。在微软的
DNA中,所有层都对记录集(record set)进行操作。这些记录集是一些位于Data Access层
的SQL查询的结果。这样就引入了一个明显的耦合:business和presentation层都需要知道
数据库结构。
我看待这个模型的方法是:在DNA中,记录集扮演了各层间Data Transfer Object的角色。
business层能够在记录集向presentation传递的途中对它进行修改,甚至自己创建一个记
录集(虽然这种情况很罕见)。虽然这种通讯形式在很多方面来看是很笨拙的,但它具有
一个很重要的优点:允许presentation使用数据感知的GUI控件,这些控件甚至对经过
business层修改的数据仍然有效。
Microsoft DNA Fowler
Presentation Presentation
Business Domain
Data Access Data source
在这种情况下,domain层被组织为Table Module的形式,而data source层使用Table
Data Gateways模式
~~~~~~~ End ~~~~~~~~~~~~~~