谈DotNet解决方案下分层和子项目的划分【转】

分层在英文里面有Tier和Layer两方面的含义。Tier主要是只硬件上的分层,如客户端,应用服务器和数据库服务器。而Layer主要是指软件系统结构下的分层。而这里谈的主要还是软件体系结构上的分层。
  
最近经常看到的DotNet多层架构,七层架构等词语。归根到底其核心还是数据资源层,逻辑层和表现层三个层次。其它层次基本上都是基于这三个层次所做的 扩展。在做一个软件系统的时候,具体如何分层跟要采用的系统架构有密切关系,而要采用何种系统架构又和业务需求密切相关。因此,是业务需求在驱动具体解决 方案的分层,分层和独立新的子项目都绝对不是越多越好,而应该有充足的需求来支持。
  
1.高效开发的分层方案(数据库存储过程+DA数据访问层+UI层)
是否应该使用存储过程或者说业务逻辑是否应该放在存储过程中一直是争论的一个焦点问题。但不可否认的是使用存储过程,并将业务逻辑放在存储过程中是一种值 得推荐的高效开发模式。存储过程的可移植性和可维护性一直是一个问题,但只要我们注意了包,函数和子存储过程的划分,存储过程一样是很容易维护的。
  
从2001年开始使用DotNet开始,我们就一直借鉴了IBuySpy的案例采用这种开发模式,开发的仅存储过程代码可能就超过50万行,2003年后台数据库要移植到Oracle数据库是遇到的最大一次挑战,整个项目组花了3个多月的时间完成了迁移。但经过实践证明,这种简洁的开发模式和分层方式是完全值得中小型项目推广和使用,以获得最大化的开发效率。
  
由于业务逻辑放在存储过程中,因此没有专门的业务逻辑层,仅仅保留了数据访问层,而且采用存储过程这种方式的时候整个DA层都完全通过代码生成器或数据访 问组件来实现。对于数据处理和传输也没有使用专门的DTO对象,而直接使用DataSet和DataTable等来实现,因此也没有专门的数据实体层。 UI层除了处理UI操作和数据展现外,还做简单的数据完整性等方面的校验。
  
开发的公用类,公用组件或异常日志的处理仍然需要单独建立一个公用项目来实现。
  
这种分层方案最大的缺点就是可移植性,当出现数据库需要迁移或移植,或需要支持多数据库的时候往往造成极大的麻烦。
  
2.是否独立专门的DataEntity层存放数据实体
在微软的Duwamish或PetShop等范例程序种都有专门的DataEntity层来存放数据实体。这里首先要讨论的是否要使用数据实体,当我们使 用DataSet或DataTable来作为数据传输对象的时候,DataSet其实已经起到了数据实体的作用,但当这个DataSet是非类型化的 DataSet的时候完全没有必要建立单独的DataEntity项目。
  
当使用Typed DataSet或Custom Entity来做数据实体的时候,一般就需要考虑建立单独的DataEntity项目,这个项目基本上完全独立的项目而不会依赖于其它项目,但 DataEntity项目却会被DA层,逻辑层或UI层的多个项目引用。将数据实体独立为项目的时候就解决了项目间由于要访问数据实体而引起的循环项目依 赖问题。
  
我们经常因为性能问题而抛弃了采用Typed DataSet作为DTO的这种高效的模式,而自己建立相关的对象类和类集合来处理这些记录集。到了客户端又要进行相关的转换以满足数据绑定的需要。 DataSet决定可以算得上是ADO.net中的一个值得称道的对象,有了DataSet后可以大大的简化我们对记录集的处理和绑定。如果我们老把 Java或J2EE中的一些架构和分层思路生搬硬套的往DotNet上使用,而不去考虑DotNet和ADO.net自身的很多优质特性,那就很难真正得 到一个高效的分层架构。
   
3.业务逻辑层
如果不在存储过程中存储业务逻辑,则建立独立的业务逻辑层是完全有必要的。在这里谈到的业务逻辑层更多是业务控制类,因为业务实体类已经单独分离为DataEntity项目。这和RUP里面谈到的实体类和控制类个人认为是有点类似的。
   
对业务逻辑层的错误使用主要来自两方面的内容。一方面是将对数据表的装载或保存等数据操作做为业务逻辑,而这个应该是放到数据层的内容;另外是将本身属于 业务逻辑的内容放置到了UI层。所以我们观察很多实际的软件项目的时候会发现业务逻辑层往往形同虚设,里面基本都是一个简单的Wrapp和转发代码,而无 实际的业务逻辑代码。UI层仅仅是将获取的数据显示到界面上,或者将界面数据整理后传递到逻辑层,以及界面流程的跳转,简单的数据完整性校验等,跟这些无 关的都应该放到逻辑层进行处理。
   
试想一下对于将某一类别产品的最近两个月销售量差别>10%的数据显示为红色的业务逻辑是什么呢?
   
4.关于需要同时支持BS和CS两种模式的问题
应用系统往往有需要同时提供Web和CS的两种访问模式。对于BS应用而言一般不存在分布式部署的问题,而对于CS模式则一般要实现为分布式的应用,需要考虑分布式部署的问题。对于分布式的考虑将在后面进一步描述。
   
当同时支持BS和CS两种客户端的时候,我们的期望是仅仅是WinUI和WebUI两个项目存在不同,而其它各层的相关项目都可以实现完全的重用。为了最 大化的实现这种重用,原来放在UI层中做的UI数据完整性校验等内容也需要抽取出来做为单独的Facade层,这样UI层仅仅处理完全跟UI相关的操作, 当一个功能要由CS转BS的时候仅仅编写最小化的WebUI层代码即可。
    
5.对系统支持分布式应用和部署的考虑
为了让系统支持分布式部署,我们一般需要增加服务代理,服务接口,WebService的相关层和子项目。一个系统为了实现对分布式的支持往往多增加了 2,3个子项目而增加了系统的复杂性。在2004年开始的一个应用系统架构设计中,经过充分的考虑决定了采用Remoting+http+Binary来 实现分布式应用,但整个系统的分布式不增加任何的子项目和分层,仅仅是在客户端和服务器端增加相应的配置文件,所有的分布式都是通过分布式部署来自动实现 的。
   
采用配置文件来实现分布式的方法很好了解决了应用要同时支持BS和CS两种模式的问题。因为在整个解决方案中不会存在仅仅CS才会使用的服务代理或服务接 口层的问题。所有的代码除了UI层外BS和CS都是公用的,实现了很好的复用。从实际运行效果和开发效率来看这都不失为一种好方法,至少不会出现为了增加 一个简单的功能都要修改7,8个项目,增加相关的代码才能够实现的问题。
   
6.对系统复用而建立的公用项目和公用组件
这是无论采用哪种分层架构下都必须考虑的问题。对于公用类和组件必须建立单独的项目来进行管理,这样公用项目既可以实现很好的专人管理,也可以方便被其它各层的项目引用。
   
公用项目应该保护常用的字符串,日期和集合的处理,对DataSet的辅助处理,常用的算法,常用的基础数据的获取等相关内容。而对于公用的组件更建议以 黑盒dll的形式来实现复用。对于严格基于组件和构件开发的系统,复用率可以达到70-80%。因此对于一般的软件系统至少应该达到40%以上的软件复 用。
   
7..架构对异常,日志,安全,缓存,异步等方面内容考虑而增加的独立项目
异常,日志和安全等都是一个系统必须要考虑的非功能性需求。但具体的每个系统要实现到哪个程度,控制到哪个级别则完全是跟具体的业务需求相关的。例如对于 异常日志我们可能仅仅需要的是能够捕获内部异常而给用户提供友好的提示信息但又能够记录在相关异常信息方便分析错误,我们的异常日志功能能够有针对性的满 足到此就足够了。
   
当我们实现一个软件系统不加思索的将微软的Enterprise Library的10多个dll一股脑的全部加入到项目中去后并不一定会给项目带来多少好处,为了实现一个小需求而用这些面面俱到的工具只会增加整个系统的复杂度。我们为何一定要去用微软的Updater App Block呢?获取我们需要的仅仅是自己手写的不超过100行的一个简单的Loader程序。
   
我们完全可以仅仅建立一个独立的项目就可以实现关于异常,日志和安全等所有的项目需要的非功能性需求。一个解决方案下的项目过多只会增加系统的复杂性和管理上的困难。做软件系统需要考虑系统的可扩展性,但我们绝不应该要那种项目根本不需要的扩展作为系统的装饰品。

转自【人月神话的博客
本文为人月神话博客原创文章,转载请务必注明出处。
posted @ 2009-07-25 15:33  hap  阅读(483)  评论(0编辑  收藏  举报