Author:Anders小明.

0. 业务分包.

在package命名上,摈斥了Appfuse以及SpringSide中出现的model, service以及manager等技术名词,取而代之的是业务名词和动词,使得行为和模型物理上内聚。我们以为对于开发人员来说,通过包名以及类名获取其业务功能远比了解其技术分类更有助于设计和开发。

这里借用springside的package前缀:

org.springside.insurance.product
org.springside.insurance.quotation
org.springside.insurance.quote
org.springside.insurance.contract
org.springside.insurance.newbiz
org.springside.insurance.cs
org.springside.insurance.claim
 

1. 抽象分层

业务是有抽象层次的. 往大的方面,可以见《Domain Model:基于抽象的分层结构》。这里只往小的方面说,比如保险中accident就拥有自己独立的业务概念和行为,并且这些概念和行为是紧耦合的。我们的目标是类似这样的业务抽象层次,我们只要发布相应的类和资源文件就可以在服务器上热部署。包的命名结构如下:

org.springside.insurance.accident.contract
org.springside.insurance.accident.product
org.springside.insurance.accident.quotation
org.springside.insurance.accident.quote
org.springside.insurance.accident.newbiz

当然可能有朋友说:我也可以这样命名,一样可以达到同样的目的。

org.springside.insurance.contract.accident
org.springside.insurance.product.accident
org.springside.insurance.quotation.accident
org.springside.insurance.quote.accident
org.springside.insurance.newbiz.accident

的确如此,对计算机或者jvm来说没有区别,它不管怎么命名。但是程序是写给人阅读的,我们希望在命名上能够尽量提供信息和暗示。我们以为,上一种命名方式更容易阅读,同时能给出紧耦合的暗示。

 

2. 技术职责分层

减少不必要的技术职责层次. 尤其是减少了Web层的VO. Web层直接访问Domain Model.

当然关于这点在技术上有过很多讨论. 我只想说的: 是否建立VO的题关键在于边界的确立, 建立边界的情况有两种:人员分工以及边界双方存在替换可能. 通常意义上Web和Domain都是一个人开发的,没有特别分工(也有可能不是同一个但没有出现并行开发, 美工除外),即便此时强制要求设计VO,也会发现设计出来的VO和model非常的类似,但增加了不必要工作量,包括copy属性操作,以及null处理(是页面没有提交该值,还是user要清空该值); 同时很少存在Web不替换而替换后台Service以及Model的情况. 因此我们可以得出一个结论:页面依赖于模型.

这样系统需要写代码的只有Service和Model两类对象 

还有一个类对象,传统的Dao,这类对象比较麻烦。采用DDD中提出的Aggregate模式,把domain模型区分开来。Domain Model利用主对象作为root,游走访问其关联对象,减少dao爆炸,使OLTP中的dao保持在较少的一个层次;对于Report或者OLAP则利用其它SQL保持性能。(关于这块目前的没有遇到大的问题,不算成功了,还在尝试中)
 

3. 业务职责设计模块

主要工作在模块间的交互接口设计:适应性接口和公共接口分离。 (原则:不要以用户无法使用或不感兴趣的东西扰乱类的公有接口). 在我的另一篇blog《模块的接口设计》中有描述.

 

4. 代码和文档的统一。

文档的维护一直是比较麻烦的问题。尝试通过Annotation等元数据来帮助我们简化工作。

首先Annotation能够提供的信息有三个级别:代码级别(IDE支持, JavaDoc),编译级别(编译器支持,代码生成),运行时级别(框架反射)。尤其是后两种,既是设计又是代码。除此外Spring的XML还包括很多信息,例如事务声明,Web Flow的页面流程信息等。

尝试通过应用更多既是设计又是代码的元数据,在借助一定手段收集这些信息,减少在文档上的工作量。

 

5. 设计上的细节

在Service对象的设计上。按model是骨架, service是肌肉,而rule是神经的职责分类.service对象的设计以行为为主线,利用template模式把rule做一定分离。另一个原因是系统应用了规则引擎,采用这样的设计有利于单元测试。