我研究领域驱动设计已经近4年时间了,在这4年里,我从了解领域驱动设计的基本思想开始,系统地学习了与领域驱动设计相关的概念、开发模式以及应用系统架构风格,并将其运用在了实际的项目架构与开发中。在此之前,我一直被一些应用程序架构设计上的问题所困扰,比如:在数据持久层,如何让数据持久化机制能够支持不同的数据库类型,甚至是非关系型数据库;如何能够让开发人员将关注点放在领域模型上,而在更改领域模型的同时,不用去关心数据持久化的细节内容;如何将应用程序的视图模型部署在服务器端,而客户端可以通过不同的用户界面代理产生不同的视图展示机制,等等。为了实现设计思想,我于2008年开发了一套基于类似XUP协议的应用框架原型,在客户端通过WCF技术与服务器进行通信,以支持服务端事件的响应与处理,而数据访问部分则采用NHibernate的Schema Tools,在服务每次启动的时候比对领域模型与数据库的差异从而动态调整数据库结构。整个系统的运行机制有点类似ASP.NET,但它可以支持诸如Windows Forms、WPF等多种用户界面机制(如图一)。在完成了第一阶段的原型开发后,我在《计算机工程与应用》期刊上发表了一篇题为《基于XML的松耦合UI架构的设计与实现》的论文,阐述了这个应用框架的设计与开发的要点与细节。
  遗憾的是,我并没有真正地完成这个框架的开发。首先,在基础结构层,使用NHibernate的Schema Tools来完成数据库的同步过程,会产生很多限制,比如:自动化的数据库结构变更会出现很多冗余信息,数据库必须采用关系型数据库,框架本身需要依赖于一套特定的机制才能实现其功能,ORM具有一定程度的性能损耗,于是应用程序会产生性能调优的瓶颈;其次,没有对领域模型的设计与开发做出很好的支持,整个框架更多地是在技术层面为应用程序的开发提供便捷,忽视了领域模型的重要性,这使得整个框架没有一个清晰的思路去解决数据映射与传输方面的问题;再次,虽然框架已经实现了基于XML的界面描述、事件绑定、事件桩与事件路由等基本特性,但与成熟的框架相比,还是有很大的差距,而弥补这样的差距还需要花费很大的努力,比如:资源管理系统、基于角色的权限管理系统、商业许可证的授权方式与支持系统、报表管理系统、基于LUA或Javascript的客户端事件处理系统等等,而这所有的内容都不是光靠我一个人所能完成的。总之,从技术架构上看,除了能够支持多种用户界面机制外,整个框架跟ASP.NET很相似。
  然而在设计与实现这个框架原型的过程中,我思考了很多,也学到很多。随着领域驱动设计思想的引入,我慢慢地在思考:领域模型能否以DTO的形态出现在应用层?仓储是领域概念,但如果真正将其实现在领域层则明显不合适,因为它需要与外部技术架构打交道,但如果设计在基础结构层,由于仓储是直接对领域对象进行操作的,那么从.NET的开发上来看,基础结构层的程序集必须引用领域模型的程序集,于是,领域模型无法去引用基础结构层的程序集,因为会产生循环引用,因此也无法去使用基础结构层的服务了,像这样的问题又如何解决?在领域模型中,领域对象能直接操作仓储来完成业务逻辑吗?应用层的作用是任务协调,而任务又包含哪些内容?协调又是怎样的一个过程?应用层与用户界面层通信是通过数据传输对象(Data Transfer Object,DTO)实现的,那么是否需要为每一个领域对象设计一个DTO,如果是的话,那岂不是开发过程会变得非常繁杂,而且会降低应用程序的可维护性,比如今后如果领域模型发生了更改,那么也需要相应地更改DTO。更进一步,是否在领域层与基础结构层的数据访问组件之间也需要引入类似DTO的概念,以便解耦领域模型与数据模型?但如果的确如此的话,那系统中岂不是充斥着各种各样的数据对象?这是基于领域驱动设计的软件架构的佳实践吗?
  只有真正地实践,才能很好地回答这些问题。于是,我开始结合ADO.NET Entity Framework来实践领域驱动的软件架构,并结合自己的收获总结了《Entity Framework之领域驱动设计实践》系列文章,发表在了博客园上。该系列文章获得了博客园社区读者的广泛关注,很多朋友纷纷参与讨论,并提出了不少针对性很强的问题,我也尽我自己的大努力,尽量做到有问必答,于是通过反反复复的讨论与相关知识的慢慢积累,一种面向领域驱动的软件架构设计方式已经在我脑海里成型了,并且在实践过程中,自己总结了一些“哪些方式是可行的、哪些方法是不合理的”基于领域驱动的软件架构设计佳实践。
  之后,我开始着手把我所总结的这些内容实现在一个应用程序开发框架上,使得软件人员能够非常方便快捷地开发出基于领域驱动的软件架构的应用程序。我将这个框架取名为Apworks(Application Development Framework and Tools的缩写,取名其实也是来源于我之前提到的那个未完成的框架名称)。在2009年底到2010年初,我在微软的开源网站codeplex上签入了Apworks的第一份代码,而在2010年底,成功完成了Apworks的Alpha版本,与此同时,Apworks Alpha版的第一个演示案例TinyLibrary CQRS(tlibcqrs)也在codeplex上发布,社区不少朋友对Apworks以及tlibcqrs都非常关注,有朋友甚至希望能够将Apworks整合到他们的项目中,在此,我对这些朋友们的支持表示衷心感谢。
  基于.NET的框架的设计与开发更不是一件容易的事情,这与“领域驱动设计”相比,它又属于另一个领域:我们需要考虑的不是通用语言,不是4+1视图,不是用例,不是角色,不是DCI,不是领域建模;我们需要考虑的是如何搭建一个高效的、稳定的、安全的、可扩展的、基于.NET的应用程序开发框架。而这些,是本文所要重点讨论的内容。
  本文将分为两大部分,第一部分重点讨论基于.NET的框架架构设计的设计指南与佳实践,这部分内容都是我在设计与实现Apworks框架的过程中,结合一些理论知识总结出来的,比如如何使用分离接口模式以减小框架本身与第三方组件之间的依赖,如何提高框架的可测试性等;这部分内容还将给出几个常用的设计模式、体系结构模式和语言惯用法的.NET(C#)实现,以便读者们在构建自己的应用程序开发框架时,可以在需要的时候直接引用本文给出的模式实现方式,提高开发效率。当然,这些内容都是我的经验总结,或许会因为我能力有限而出现疏漏或不合理的现象,这需要读者朋友们给出意见给予指正了,我也会跟进这些反馈信息而不定期地修订原文。第二部分将以Apworks为例,详细讲解Apworks框架中某些组件的设计构想,例如,在设计外部事件存储(Event Store)的时候,我是如何考虑并实现存储机制的技术无关性的,又比如,“快照提供者(Snapshot Provider)”是如何支持可扩展的基于不同策略的快照功能实现机制,这些内容将在这部分进行讨论。
  总之,本文将主要讨论基于.NET的应用程序框架架构设计实践,在此过程中会引用Apworks框架作为案例进行讲解,选用Apworks作为案例,首先是因为本文所讨论的所有内容都来源于该框架的设计与开发过程中,其次,Apworks已经是一个现成的框架了,读者朋友在学习的过程中可以有个成品作参考,以便更好地理解本文所讨论的内容。希望读者朋友不会误认为本文是Apworks的广告而对之产生反感,我真心希望本文能够给爱好企业级应用系统架构的朋友带来一定的参考价值。