领域驱动设计主要参与者为领域专家和研发人员。领域专家是精通某个业务领域,熟练掌握该领域各种专业术语;而开发人员偏重于程序架构设计,mvc框架,mysql数据持久化等等。这样,开发人员不懂专业术语,而业务专家也不明白各种开发技能,这就导致了他们之间沟通困难。
如何解决这种困难呢,这就需要引入DDD之通用语言。
什么是通用语言呢,它有什么特点?从字面意识上来讲,它就是大家都能够使用明白的一种语言。它具备简单易学,使用频率高,使用范围广等特点。在软件开发过程中,正是由于 简单 通用 使用率高 ,项目需求沟通讨论中,各方参与人员能够对需求理解达成一致,进而愉快的开发测试上线。
通用语言最大的价值就是解决了交流沟通障碍问题。使各方能够协同合作,确保交付正确的产品。另外,基于通用语言,开发人员能开发出可读性更好的代码,能够准确的将业务需求转化为代码设计,达到代码即设计的目标,领域专家也能够看懂。
最后来个例子进行通用语言说明:
比如我们的采销系统,需要新增加 可销控制 这个功能。什么是可销控制呢,研发一脸懵逼。这明显是个专业术语,只有领域专家才懂,它不是通用语言。那可销控制是什么意识呢?在ERP中,在做单时对销售员负责的客户进行范围控制。比如,A客户是销售员小李发展过来的,小李希望仅能自己负责对A客户的业务。原来可销控制就是销售员-客户销售范围控制,需要程序建立数据映射配置。
怎么将领域设计转化为代码设计,并让领域专家也明白呢;在《实现领域驱动设计》书中有一个简单的例子(P238),我们一起来看一下:
“系统必须对User进行认证,并且只有当Tenant(租户)处于激活状态时才能对User进行认证”
上面这个用例就是基于通用语言的用例,简单清楚的说明了业务规则。
我们先看第一种代码实现:
bool anthentic = false; User user = _userRepository().FindUserByTenantIdAndUserName(tenantId, userName); if(user!=null) { authentic = user.IsAuthentic(password); } return authentic;
这段代码完全不能反应通用语言,主要存在以下问题:
1.这段代码先查找user,再对user进行密码匹配来完成认证。其中user.IsAuthentic(password);
表示的是“用户是否被认证”的意思,而没有表达出“认证”这个过程,即“对用户进行认证”。
2.未体现“检查Tenant是否处于激活状态”这个前提条件
知道问题后,我们可以讲代码略做改动:
bool anthentic = false; Tenant tenant = _tenantRepository.FindTenantById(tenantId); //检查租户是否激活 if(tenant!=null&&tenant.IsActive){ User user = _userRepository.FindUserByTenantIdAndUserName(tenantId, userName); if(user!=null) { authentic = tenant.Authenticate(user, password);//租户对用户进行认证 } } return authentic;
以上代码虽然也不是最终结果,但至少对通用语言进行了体现。通读代码,就能明白业务用例,体现代码即设计这一思想。
备注:在不同的限界上下文中,同一个概念可能代表着不同的含义,所以通用语言的应用范围应该限制在它们所属的限界上下文中。