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

本文由阿里技术专家讲解,深入探讨DDD中的Domain Primitive(DP)概念,旨在降低DDD实践门槛,提升代码质量。文章通过案例分析,揭示DP在数据验证、接口清晰度、业务逻辑和可测试性方面的重要性,并提出DP的三个使用原则:隐性概念显性化、隐性上下文显性化和封装多对象行为。此外,文章还对比了DP与DDD中的Value Object、DTO的区别,提供老应用重构的实战流程。
摘要由CSDN通过智能技术生成

前言

 

由于 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 的思想让我们能冷静下来,去思考到底哪些东西可以被服务化拆分,哪些逻辑需要聚合,才能带来最小的维护成本,而不是简单的去追求开发效率。

求关注 


欢迎大家关注我的 B站账号
B站账号
如果内容有帮到你,欢迎大家点赞、收藏 + 关注

学习交流群
交流群

所以今天,我开始这个关于 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);
    }

    private boolean isValidPhoneNumber(String phone) {
        String pattern = "^0[1-9]{2,3}-?\\d{8}$";
        return phone.matches(pattern);
    }
}

 

我们日常绝大部分代码和模型其实都跟这个是类似的,乍一看貌似没啥问题,但我们再深入一步,从以下四个维度去分析一下:接口的清晰度(可阅读性)、数据验证和错误处理、业务逻辑代码的清晰度、和可测试性。

▍问题1 - 接口的清晰度

 

在Java代码中,对于一个方法来说所有的参数名在编译时丢失,留下的仅仅是一个参数类型的列表,所以我们重新看一下以上的接口定义,其实在运行时仅仅是:

User register(String, String, String);

 

所以以下的代码是一段编译器完全不会报错的,很难通过看代码就能发现的 bug :

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值