- 1.1.疑问
- 1.1.1.UML何用
- 1.1.2.领域建模
- 1.2.模式
- 1.3.原则
- 1.5.过程
- 1.6.框架
- 1.7.项目演示
最近在研究DDD颇有收获,所以整理出来跟大家分享,共同进步!
我们在设计业务系统的时候都会存在一个非常棘手而又无法回避的问题“业务扩展性”、“业务灵活性、”面向对象化“,尽管我们熟练掌握设计思想、设计模式、设计原则等等关于如何设计灵活性的系统设计理论,但是我们似乎都没有将它们运用到真正业务系统设计、开发当中去,为什么?这样的疑问如果对有心想设计好系统的朋友来说肯定是很早就出现过,只是无法解决,因为我们目前使用的设计方法是与面向对象设计背道而驰的。
漫长的数据库驱动开发历史,导致我们根本无法脱离这个环境进行学习和实战。从教科书再到真正的企业项目开发都是先设计数据库然后进行逻辑的编写,大部分的业务逻辑都是存在于UI和数据库【存储过程、自定义函数】中,所谓的三层架构中的BLL层其实是形同虚设,根本没有起到它应有的作用。
当然我们不是大师,我们只是普通的程序员,希望有一种方法论能引导我们进行真确的系统设计。在未接触DDD之前,我也一样有着同样的困扰,我们编写很多的开发框架、组件、插件、服务等等太多太多类似能提高开发效率的功能,梦想着自己的系统能想真正如书上所说的搭积木一样搭建自己的系统,我们扪心问自己真的可以做到吗?我叹息,很难;
我一直感觉复杂的系统设计对我来说真的没有办法应付,只能凭借细心和对业务的熟悉程度,没有正确的理论引导,那些所谓的大师们的设计思想的书真的对我帮助不大,看了不知道如何进行运用。时至今日我终于可以感觉到那种神秘的设计确实可以带领我们穿越复发的系统设计。当然这条路对刚开始接触DDD的朋友来说会存在很多问题,恰巧在下有幸接触DDD有点心得,也通过分析了一个小的系统进行DDD的开发工作,所以在这里把自己最近研究的心得和疑惑跟同行们分享,如有不对的地方请多指点。
1.1】疑问
在任何一项新技术被采纳之前必须要解决几个关键的问题,这也是我们程序员考虑使用一项新技术的必须过程,它的出现能解决哪些问题和将会带来哪些问题。DDD固然很好,但是要想把它运用到自己的项目当中去,是需要很多时间和精力来分析它的实施过程和对项目团队的要求。当然人为的因素和外在的环境问题我们这里不考虑,毕竟那些是我们无法改变的事情,这里只讨论和我们密切相关的问题。
1.1.1】UML何用
做程序开发的我们都知道UML是干什么的,简单的讲它属于一种标准的系统建模语言,便于我们对系统进行分析和团队之间的合作。既然是语言它的主要作用是沟通,技术人员和分析人间的桥梁。但是到目前为止我没有发现它真正帮助过我进行系统分析和设计,上面已经提过其实是两种开发方法论恰恰相反,所以导致根本无法集成,就拿UML中的类图来讲,我们都是先设计数据库然后进行开发何来的对象?直接是表驱动,通过一些快速的代码生成器进行界面和一些通用的单表的CDUS代码的生成,程序中根本没有对象的概念,业务逻辑遍布UI层[图1.1]。UML画的类图无法在程序中表现出来,所以它无法在绝大部分的企业中普及。
1.1图
上图假设是一个简单的模拟B2C的基本功能,通过它我们能简单的了解到我们的系统开发的问题所在。
以上图中的系统结构,我们很难知道系统的具体业务逻辑,更别说对系统的扩展性能有保障。这样的结构在开发初期没有什么问题,但是在后期的维护工作中将是费事费力的,最后的项目代码无法进行的很好的阅读,也就无法很好的进行稳定性维护。特别是业务系统,它的需求会变的很多甚至很变态,如果按照这种方式进行维护,那么界面上的代码会越来越多,而BLL、DAL中的重复性的功能方法也会急剧变多或者是服务层的相同功能不同方法参数的代码会越来越多。其实到最后也就谈不上什么艺术了,更别说项目进行产品化后上市。
那么UML真的起不到作用吗?或者说我们真的与UML无缘?当然不是,而是我们没有使用相关的软件设计、开发方法论而已。按照DDD的思想,我们是业务驱动开发,先进行领域模型的创建,然后才是数据库的设计。其实只有按照DDD的开发理论来才能最大的保证系统的扩展性和业务整洁性,才能保证项目的良性循环。
1.1.2】领域建模
“领域建模”很抽象也很艺术的一个词,它是软件设计艺术中的一个境界。
我们常常接触面向对象编程、面向对象设计的书籍或者话题,大家都对它有独特的见解,但是我们始终没有将它用作真正的系统性开发中去。但是在编写框架的时候我们都能得心应手的进行面向对象设计,为了保证框架的灵活性乃至最大的扩展性就要进行最细粒度的分解、抽象、提取,这些在非数据库系统开发中都没有问题。然而最大的问题出在对象需要与数据库结合,对象的生命周期持久化在数据库中,生也数据库死也数据库。所以这里的问题就是如何在面向对象设计与关系型数据库设计之间平滑的过度持久化。这是领域驱动开发的最大的问题,也是很多面向DDD框架的开发重点。
在上图中我们目睹了以数据库驱动后系统的大致结构,假设我们需要保证功能模块的最大的扩展性我们在编写数据库驱动代码的时候,很难抽象出复杂的变化点,因为都是贫血型的业务模型或者说根本不知道变化点在什么地方。而且并不是普通的开发人员能发掘到的,当然数据库驱动开发也一样可以进行灵活设计、开发,但是这样毕竟对开发人员要求很高,他需要具备很强的面向对象设计能力,在不污染现有的代码的情况下进行扩展性重构。至少我的经验告诉我很难,而且在需求阶段并没有一个完整的大局观,很容易造成头重脚轻。对后期的系统开发进度也很难控制,因为无法确定每个功能模块到底存在哪些接口。
所以我们还是朝着光明的道路前进,掌握DDD进行系统设计开发。
我们下面试着用建模的方式对上图中的功能点进行大致面向对象设计,尽量提取变化点。
【简单用例】
根据上图的基本功能我们确定两组用例,第一组是【客户Custom】发起的所有动作,第二组是【后台管理人员Admin】,比如配货部门、订单审核部门等等。这里纯粹是为了演示建模的功能不是特地的项目实践,所以功能简单明了。
1.2图
客户首次进去平台之后肯定是需要进行账户的【注册】,有注册就会有【注销】,这里的注销不是退出系统的意思,而是注销在当前平台的使用,就跟销户是一个意思。
(当然有人会觉得注销不妥,电子商务平台是不应该有注销的,这只是主观的设计而已,每个人的想法不同所以可以取长补短 ,我觉得有一个正面的注销功能很好,可以让用户进行使用,到底如何使用我们这里就不分析了。)
成为正式用户之后就可以挑选自己喜欢的商品进行【下订单】,下订单后就会进入平台运行管理的流程的,客户会随时收到平台发过来的流程信息反馈。所以这里有一个【短信管理】用例,该用例当然会包含 【删除信息】、【读取信息】、【回复信息】包含的子用例。
(当然可能我分析的不够细致或者有问题的地方,由于我也是最近接触UML建模所以可能有点不熟悉,对UML有兴趣的朋友可以参考相关专业书籍。)
1.3图
后台管理人员需要对客户下的订单进行【配送】处理,配送环节将牵扯到【客户信息】、【更新订单状态】、【打印配送信息】用例,对【打印配送信息】
功能需要【发送收货信息】给用户,告知用户货物已经发出。这里还包括一个泛化的用例【物品清单、配送地址】,在【打印配送信息】功能里面需要具体的打印出跟配货信息相关的信息。
(这里提一下UML用例图其实是通过纵横向的方式来寻找系统的所有功能点,纵向是系统的所有功能,横向是系统的外部调用者。)
【领域模型】
根据上述用例我们基本能捕获到大致的系统功能,下面我们通过创建UML类图来描述领域模型。
模型的创建要根据上一步的用例图来进行分析,只要创建的模型能满足用例的所有功能点就已经完成了一个大致轮廓。有些隐藏的模型是需要不断的重构才能逐渐的浮现出来。
1.4图
大致的模型已经创建出来,这只能算是一个基本的草图形式的建模,还有几个过程没有走完,比如:反复的重构、与领域专家讨论模型的准确性、与DBA进行沟通等等,这些都是DDD的整个范畴。
有了领域模型之后我们基本算是有了一个大致的业务方向,剩下的就是精益求精的过程,不断的去分析深层业务关系。
【场景序列】
得出了领域模型之后我们需要对它进行一个基本的验证,也就是看看模型是否能满足所有的功能需求。最常用的就是通过序列图来走查场景,对我们创建的领域模型进行逐步验证。
由于时间关系我这里就不给出所有的序列图了,只给出有代表性的序列【配送】。
1.5图
由于怕截图片太大所以给出关键的序列流程,能表达其意思就行了。
这是经典DDD调用序列,对上面具体的对象不是很清楚的不要紧后面有专门的示例进行全面分析。
1.2】模式
模式相比大家都知道是什么意思,一些通用的思考问题的思路、解决方法、分析方法。当然在DDD领域也有很多模式供我们学习和使用,在需求阶段讲解的是行为模式在分析阶段有分析模式,在设计阶段有设计模式,在实现阶段有实现模式,还有宏观的架构模式。
那么在进行领域建模的时候有些前人总结出来的分析模式可以供我们参考。
1.2.1】四色原型模式
四色原型模式是我接触的第一个分析模式,当然目前也是发现它确实很好用,所以给同志们分享一下。
四色原型模式是能帮助我们找出业务当中的核心模型,也就是说核型模式应该具备几个比较重要的特征的。
基本上想要根据UML用例图找出领域模型需要使用名\动词法找出大概的模型,然后顺着领域模型一点一点完善、发掘,从而找出相关的实体模型。但是有些实体模型是一眼就能看出来的,就比如上例中的【用户】、【订单】、【消息】都可以定义为实体类型,也就是当前小示例中的核心领域模型。
看一下四色原型模式的结构图:
1.6图
对照四色原型模式我们很容易发现模型中的核型实体模型,很明显对照上面的领域模型我们确实都是核心模型。
1.7图
对照该模式我们会发现这里的商品其实也是核心实体才对,但是我们能很快发现我们忽视它了,商品也存在状态和一些值类型才对,比如商品的使用状态是不是没货、商品的详细属性是不是也存在独立的值对象。当然这些要看当前项目需求而定。太范式的设计会带来一些问题,有性能问题、有开发成本问题,这些都要进行详细的讨论才能最终确定,所以反范式设计就出现了。