关于业务规则放在哪一层上的问题?(200分)

  • 主题发起人 主题发起人 阿朱
  • 开始时间 开始时间

阿朱

Unregistered / Unconfirmed
GUEST, unregistred user!
关于业务规则放在哪一层上的问题?
放在数据层,做成视图,存储过程,触发器,好处是:安全性高,速度快(不用编译优化SQL语句
),数据完整性好,业务规则统一管理,修改业务规则不用修改程序。缺点是:绑定在了特定的DBMS
上,不利于跨数据库,第二是不利于扩展(现在的主流数据库产品都还不是分布式数据库)。
如果放在中间层,数据库就成了一个数据存放地,强大的数据库功能被放弃了,而且一个存储过
程就能做了的事用程序实现却需要写不少代码,并且与数据库大量交换数据,还要负责与客户端交换
数据,这就引起性能瓶颈,只好扩展中间层服务器,这也正好是中间层的初衷。但似乎总觉得牺牲的
太多,而得到的太少。
 
你的意思是不是说在数据库服务器上只有表,没有了存储过程,不会吧?
 
我个人的观点是:
把每一层的最优点最大化的发挥。
适合写成存储过程触发器的就尽量写在数据库端,更复杂的业务流程用数据库端的一些
存储过程组合调用来实现,实在实现不了的在中间层做,中间层尽量做到复用性好,安全
性好,与数据库、客户端连接尽量少,不要使大数据在网络上来回传输。而客户端就尽量
做到瘦,数据提交前检查一下数据完整性(其实这也是业务规则),不要让错误数据流到
网上,又被中间层重复代码检查一次打回去,既增加了网络流量,又增加了中间层的负担。
代码又重复编写。我终于想通了,业务规则处处都可分布,不要听书上教条,我们要负载
平衡,数据与业务规则分布应用,这才是我们的要求与三层的核心思想。我的思路是:
最基本的数据操作规则(这应该叫数据层的业务规则,专门针对与开发人员使用的)写在
数据库端,与商业具体业务流程有关的规则放在中间层,至于增删改数据,调用数据层端
的数据操作规则就行,客户端只是对中间层下来的数据做应用,并在业务逻辑和数据逻辑
上保证它的正确性,不让错误数据到上一层,至于某些人说的客户端只是一个图形界面,
我不敢苟同。还有人把所有的规则都写在了中间层,业务操作与数据操作混杂在一起,
这些都是不对的。至于可移植性,如果你要求移植性好,只有全写在中间层,但牺牲了
性能与各层的优点,如果想使性能最优,只好放弃可移植性,这就如JAVA一样。
 
我觉得还是应该放在中间层。
数据库服务器本身就应该是一个单纯存放数据的地方!所谓“强大的数据库功能”到底有多少实用价值呢?
那些数据库产品自以为聪明,标榜自己的东西可以实现什么数据完整性、一致性的可靠保证,
提高了数据操作的速度性能,提供了众多的功能函数……可是实际上一个复杂的项目当中存在那么多的
数据逻辑关系并不是数据库里简单的几个关联可以维护得了的;还有大量的自定义的数据结构也不是
数据库产品本身能够包容并处理的;有时候为了“迎合”数据库本身的限制还不得不破坏程序的逻辑
做一些补丁……
事实上,我们都是被这些数据库厂家给误导了——本来关系数据库的初衷是好的,初期效果也不错,
可是发展来发展去,被这些厂家给“扩充”的越来越臃肿了!诚然,对一些小的或简单的项目,这些
扩充的功能已经够用了,可以节省不少开发时间和难度。但问题是这些厂家忘记了一点——
之所以出现并存在“数据库”这个东西就是为了大量数据存储、查找的方便这个目的;
数据库里的数据只是实际程序中数据的一部分;数据库只是程序中用到的众多数据结构中的一种;
数据库里的数据是要和程序中其它数据和数据结构配合使用的——你们只是把数据库本身的操作封装地很好,
可是没有考虑到这样的封装使得在和其它数据打交道的时候还会有很多不一致的问题,
这些问题反过来又会影响到数据库本身的可靠性!你们既然不能给出一个完整的数据解决方案,
为什么不把精力放在提高查询、删除这些基本操作的执行性能这些最关键的方面,而非要提供一些
本来就应该属于应用程序职责范围内的旁支末节呢?——这样做唯一的好处是:使用户对他们的数据库产品
产生倚赖,不得不依附于他们而生——这纯粹是一种“钓鱼”行为!

话说回来,从我们的应用程序角度来看:我们为什么一定要受数据库产品的制约呢?恐怕是因为大家脑子里
有这样一个误区:“既然那么多大的数据库厂家都在努力实现这些东西,那肯定是大势所趋,肯定是好东西!”。
但是实际上国外理论界已经对所谓的xNF范式这些东西提出了怀疑——不要说实际操作中很难做到了,
就算做到了对系统性能的提高又有多少好处呢?无非徒劳无谓地给系统加了很多限制罢了。
而这些东西在应用程序中实现的话并不是特别困难的事,而且可以加入很大的灵活性和实用性。
一句话,“不识庐山真面目,只缘身在此山中”,是我们自己把自己限制在了这个框架里面而不能自拔!

再从实际应用中碰到的问题来看:对一个大型系统来说,最大的瓶颈在于响应的速度即系统的性能。
你的完整性做得再好,触发器写得再漂亮,数据量一上去什么都是白费!用户看的是最终的实际的效果,
他们并不关心我们到底用了多少“先进”的数据库技术,只要好使,怎么着都行!
所以我觉得我们应该把我们的终极目标定位在系统性能的提高上面,至于功能,那就看各自的发挥了,
反正应该相信一点:数据库里能做到的(用户的实用性要求),程序里也一定可以!
并且如果抛开数据库产品提供的额外功能不用,只是对基本数据进行操作,加上适当的缓存和优化,
我觉得在程序里实现的时候不见得比数据库本身实现慢很多;因为它为了维护自身的一致性要做很多
额外的、并不是每个程序都需要的、可能相当费时的操作。

至于阿朱担心的“牺牲的太多,而得到的太少。”我觉得不会的,三层结构的最大好处是系统维护和
升级的简便易行——而对于大系统来说,这两点是最让人头疼的问题!
当然在设计和实现中间层的过程中也会很头疼(我现在正为这个发愁呢:),但是一旦做出来了,
对以后的工作会有莫大的甚至是喜出望外的帮助的!
 
我看了DQ兄的留言,我最初做三层的初衷也是觉得好维护,但我实施了两个工程以后,还是
觉得这个特点不太明显,从主机模式,到胖客户端模式,大家都是不能做到平衡负载,总是
使其中一层工作太重,而另一层又太轻,三层产生的初衷便是使计算与数据分布,即分布式
计算环境,让中间层成为两层的负载缓冲,充当一个负载平衡点,且使这个负载点能具有扩充
性,能应付未来的业务需要,如果我们在数据层上什么都不做,客户端也作成瘦客户,那么
负载最重的当然是中间层,又回到了以某一层为中心的失重状态,我们似乎违背了三层最初
的思想。我们追本求源只是为了实现三层最初的核心思想,至于非要让某一层充当核心,我觉得
不可取。我这的应用要求是:如果改变了企业业务流程,就改变中间层,如果只是改变某
些字段的时候必须要把另一些表的字段进行更新做相应的操作计算,我们就放在数据层交给
存储过程触发器,如果数据库结构也要改变,那么我们就要在每一层做相应的改变。过去我们
在做工程时,如果遇见写某一字段时要求必须对其他字段做操作计算时,只能带着源码去,
改变中间层源码,对一个商业软件的源码保护和版本维护,我觉得都不好,我们试着做了些
调整,现在维护量小多了。而且从做工程来看,中间层的规划以面向对象封装成可复用组件是
很重要的核心。这是我做工程的一些体会,希望对其他朋友有所启发,或许这种思路也不是
最好的解决方案,希望大家集思广益共同探讨。
 
我是倾向于把尽可能多的任务交给中间层去做,但我理解的中间层不只是单纯的一个层次乃至一个大的模块。
也就是说中间层还要再分成若干个不同的层次,至少要有一层是面向客户端服务的,有一层是面向数据端服务的。
比如“如果改变了企业业务流程”,那就修改中间层中的客户服务层;如果出现“改变某些字段的时候”,
那就在中间层中的数据服务层做相应修改;并且两方面的修改应该做到对另一方毫无影响,也就是说这两层是相对独立的。
所以我认为在这两层中间还要有一个逻辑数据层——这一层不涉及任何物理的字段名、表结构;也不关心具体的数据表示
工作,而只是在逻辑上对一个自定义的数据环境中的各个数据项的关系进行操作;为了做到使源程序既和数据源无关又能
有效地表示业务关系,我的想法是构建一个逻辑数据库的结构,用自定义的文件系统保存,并为之做一个驱动和管理程序。
这样做的好处是一旦物理结构有所变动(数据结构的修改或者数据库产品的更换)完全不必触动中间层的核心;
我们要做的只是修改中间层中最底层的数据库驱动模块和利用逻辑数据库管理工具修改对应的字段信息等,
而主程序代码根本无须做任何调整——也就是说,为每一个数据库产品独立地实现自己的基本驱动(注意,是最基本的功能,
只是针对各个数据库产品对SQL的不同限制(比如函数名的不同)而写的东西,而不是复杂的查询等);至于其它复杂的数据库
操作则由逻辑层解释过之后转化为基本的伪SQL语言为接口的函数调用等形式再交给底层驱动来处理;从底层驱动得到基本数据
之后再由逻辑层按客户端传过来的要求进一步进行处理后返回客户端。

下面是我以前写过的一段对三层结构设计的理解,摘录于此,希望能和大家共同商榷——

客户端完全独立于数据库结构,开发、维护的工作量尽量的小;
中间层要求通用,一旦主流程开发完毕之后,基本上不必再根据需求变动对程序本身作任何修改(需要改动的只是自定义数据结构的配置文件)。

客户端完全面向事物、面向对象,而非面向“一个简单的"表" ”;
  中间层最主要的工作不是处理实际数据库中表的关联等复杂关系(当然要有这些功能),
而是实现客户端面向对象方式下直观的数据请求描述到实际数据库数据操作命令(SQL或伪SQL语言)的转换或者说“翻译”。

我认为其中最重要的工作是中间层的设计,初步想法是将中间层再分三层(以从客户端到数据库为序):

第一层是各种实体对象和事物对象。负责将实际数据以一种用户可以直观理解的形态展示给客户端,
客户端利用这些对象可以非常方便地描述他们的需求和各种操作,客户端程序员只要熟悉整个系统的业务流程就完全掌握了客户端程序的流程,
最终用户只要根据其业务操作经验就可以顺利地在客户端程序界面中找到他所需的东西。同时这些对象负责同第二层的通讯
(可以考虑使用共同的具有通讯能力的基类对象或某一通用的通讯对象来实现)。这一层根本不必体现二维形态的表关系。

第二层是通用的翻译、解释模块。负责第一层和第三层之间的对话,它完全不了解系统的业务流程和规则,也不必了解数据库结构
(这一层是通用性要求最高的,因此抽象度比较高,难度也大,目前对其具体实现还相当茫然)。

第三层是数据层。负责响应第二层的数据操作请求,而这一层面对的数据不仅是数据库中的数据,也包括系统自定义的一些数据及文件等。
在这一层需要作相当多的优化、关联工作,并尽可能将接口一致起来,不然这一层的工作量是相当大的。

实现原则是:第一层——方便;第二层——通用;第三层——高效;总体——简单。

数据库设计的原则是——
在应用程序可以控制的范围内,越简单、越高效越好。换句话说,我们应该把心思放在提高数据库查询等操作的性能上,
而把字段、表之间关系的维护交给应用程序(在我的设计中,此即第三层的任务)。
再换个说法,数据库应该设计成只用最简单、最基本的查询语言(比如SQL-92标准语言,而无须各个数据库产品提供的各种复杂的、
“先进”的扩展SQL语言)就能获得我们需要的数据。
 
长了不少见识
 
好东西呀!
 
当然应放在中问层的应用服务器上了,
这样维护扩充比较方便,
不然要中问层干什么?
时髦吗?
两层时,如数据库是大型的,
自然放数据库上比较好,只是,嘿嘿!
维护起来……
 
多人接受答案了。
 
后退
顶部