阿里技术专家详解 DDD 系列- Domain Primitive

导读:对于一个架构师来说,在软件开发中如何降低系统复杂度是一个永恒的挑战,无论是 94 年 GoF 的 Design Patterns , 99 年的 Martin Fowler 的 Refactoring , 02 年的 P of EAA ,还是 03 年的 Enterprise Integration Patterns ,都是通过一系列的设计模式或范例来降低一些常见的复杂度。但是问题在于,这些书的理念是通过技术手段解决技术问题,但并没有从根本上解决业务的问题。所以 03 年 Eric Evans 的 Domain Driven Design 一书,以及后续 Vaughn Vernon 的 Implementing DDD , Uncle Bob 的 Clean Architecture 等书,真正的从业务的角度出发,为全世界绝大部分做纯业务的开发提供了一整套的架构思路。

前言

由于 DDD 不是一套框架,而是一种架构思想,所以在代码层面缺乏了足够的约束,导致 DDD 在实际应用中上手门槛很高,甚至可以说绝大部分人都对 DDD 的理解有所偏差。举个例子, Martin Fowler 在他个人博客里描述的一个 Anti-pattern,Anemic Domain Model (贫血域模型)在实际应用当中层出不穷,而一些仍然火热的 ORM 工具比如 Hibernate,Entity Framework 实际上助长了贫血模型的扩散。同样的,传统的基于数据库技术以及 MVC 的四层应用架构(UI、Business、Data Access、Database),在一定程度上和 DDD 的一些概念混淆,导致绝大部分人在实际应用当中仅仅用到了 DDD 的建模的思想,而其对于整个架构体系的思想无法落地。

我第一次接触 DDD 应该是 2012 年,当时除了大型互联网公司,基本上商业应用都还处于单机的时代,服务化的架构还局限于单机 +LB 用 MVC 提供 Rest 接口供外部调用,或者用 SOAP 或 WebServices 做 RPC 调用,但其实更多局限于对外部依赖的协议。让我关注到 DDD 思想的是一个叫 Anti-Corruption Layer(防腐层)的概念,特别是其在解决外部依赖频繁变更的情况下,如何将核心业务逻辑和外部依赖隔离的机制。到了 2014 年, SOA 开始大行其道,微服务的概念开始冒头,而如何将一个 Monolith 应用合理的拆分为多个微服务成为了各大论坛的热门话题,而 DDD 里面的 Bounded Context(限界上下文)的思想为微服务拆分提供了一套合理的框架。而在今天,在一个所有的东西都能被称之为“服务”的时代(XAAS), DDD 的思想让我们能冷静下来,去思考到底哪些东西可以被服务化拆分,哪些逻辑需要聚合,才能带来最小的维护成本,而不是简单的去追求开发效率。

所以今天,我开始这个关于 DDD 的一系列文章,希望能继续在总结前人的基础上发扬光大 DDD 的思想,但是通过一套我认为合理的代码结构、框架和约束,来降低 DDD 的实践门槛,提升代码质量、可测试性、安全性、健壮性。

未来会覆盖的内容包括:

  • 最佳架构实践:六边形应用架构 / Clean 架构的核心思想和落地方案
  • 持续发现和交付:Event Storming > Context Map > Design Heuristics > Modelling
  • 降低架构腐败速度:通过 Anti-Corruption Layer 集成第三方库的模块化方案
  • 标准组件的规范和边界:Entity, Aggregate, Repository, Domain Service, Application Service, Event, DTO Assembler 等
  • 基于 Use Case 重定义应用服务的边界
  • 基于 DDD 的微服务化改造及颗粒度控制
  • CQRS 架构的改造和挑战
  • 基于事件驱动的架构的挑战
  • 等等

今天先给大家带来一篇最基础,但极其有价值的Domain Primitive的概念。

Domain Primitive

就好像在学任何语言时首先需要了解的是基础数据类型一样,在全面了解 DDD 之前,首先给大家介绍一个最基础的概念: Domain Primitive(DP)。

Primitive 的定义是:

不从任何其他事物发展而来 
初级的形成或生长的早期阶段

就好像 Integer、String 是所有编程语言的Primitive一样,在 DDD 里, DP 可以说是一切模型、方法、架构的基础,而就像 Integer、String 一样, DP 又是无所不在的。所以,第一讲会对 DP 做一个全面的介绍和分析,但我们先不去讲概念,而是从案例入手,看看为什么 DP 是一个强大的概念。

1、案例分析

我们先看一个简单的例子,这个 case 的业务逻辑如下:

一个新应用在全国通过 地推业务员 做推广,需要做一个用户注册系统,同时希望在用户注册后能够通过用户电话(先假设仅限座机)的地域(区号)对业务员发奖金。

先不要去纠结这个根据用户电话去发奖金的业务逻辑是否合理,也先不要去管用户是否应该在注册时和业务员做绑定,这里我们看的主要还是如何更加合理的去实现这个逻辑。一个简单的用户和用户注册的代码实现如下:

public class User {
    Long userId;
    String name;
    String phone;
    String address;
    Long repId;
}

public class RegistrationServiceImpl implements RegistrationService {

    private SalesRepRepository salesRepRepo;
    private UserRepository userRepo;

    public User register(String name, String phone, String address) 
      throws ValidationException {
        // 校验逻辑
        if (name == null || name.length() == 0) {
            throw new ValidationException("name");
        }
        if (phone == null || !isValidPhoneNumber(phone)) {
            throw new ValidationException("phone");
        }
        // 此处省略address的校验逻辑

        // 取电话号里的区号,然后通过区号找到区域内的SalesRep
        String areaCode = null;
        String[] areas = new String[]{"0571", "021", "010"};
        for (int i = 0; i < phone.length(); i++) {
            String prefix = phone.substring(0, i);
            if (Arrays.asList(areas).contains(prefix)) {
                areaCode = prefix;
                break;
            }
        }
        SalesRep rep = salesRepRepo.findRep(areaCode);

        // 最后创建用户,落盘,然后返回
        User user = new User();
        user.name = name;
        user.phone = phone;
        user.address = address;
        if (rep != null) {
            user.repId = rep.repId;
        }

        return userRepo.save(user);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值