领域驱动设计笔记

http://tommwq.tech/blog/2020/12/13/275

这篇文章是阅读Thought Works中国知乎专栏 DDD-领域驱动设计 时记录的笔记。

架构设计是以组件化为手段,实现关注点分离,从而降低局部性复杂度的一项软件设计工作。设计首先是要解决问题的复杂度,其次是要建立团队协作沟通的共识。达成这两点,根本目的在于让系统能够更快地响应外界业务的变化,并且使得系统能够持续演进。

类似工业总线(ESB)这样的组件化其实是面向技术的,希望通过技术平台的灵活性来解决业务变化的多样性。虽然短时间能够收到一定的成效,长期看必然把自身做成瓶颈,因为所有业务的变化最后都堆积到了这个技术组件来解决。这也回答了为什么实施了传统SOA架构的企业最后都发现响应速度其实并没有提升起来。

面向业务变化而架构就要求首先理解业务的核心问题,即有针对性地进行关注点分离来找到相对内聚的业务活动形成子问题域。子问题域内部是相对稳定的,即未来的变化频率不会很高,而子问题边界是很容易变化的,比如在一个物流系统中:计算货物从A地到B地的路径是相对固定的,计算包裹的体积及归类也是相对固定的,但根据包裹的体积优化路径却经常会根据业务条件而变化。

业务对象可以采用实体(entity)或值对象(value object)表达。二者的区别在于,实体是有状态的,拥有唯一标识和生命周期。

账户管理领域的“转账”业务行为,可以使用领域服务(domain service)封装。转账涉及两个账户,因此不适合作为账户的行为。同时转账也不适合作为实体。

应用服务(application service)是领域模型的门面(参考GoF facade模式)。协议适配层(如controller)将使用某种协议封装的请求转换为对应用服务的请求,委托应用服务传递给领域模型。

聚合根(aggregate root)的意义在于维护业务规则一致性。比如下面的代码

order.changeProductCount(productId, count);
order.updateTotalPrice();
price = order.getTotalPrice();

订单种品项(order item)和总价是密切相关的,品项的变化导致总价发生变化。在这段代码里,维护二者的一致性的职责由客户端代码承担。如果客户端代码发生错误,业务约束一致性将遭到破坏。因此应当将职责分配给聚合根Order。

public class Order {
    public void changeProductCount(int productId, int count) {
        if (isPaid()) {
            throw new PaidOrderCannotBeModifiedException(id);
        }

        OrderItem item = retrieveItem(productId);
        item.updateCount(item);

        updateTotalPrice();
    }
}

聚合根一定是实体,但反之实体未必是聚合根。Listing 1: DDD处理业务流程的典型例子

public class OrderApplicationService {
    public void updateProductCount(UpdateProductCountCommand command) {
        String orderId = command.getOrderId();
        String productId = command.getProductId();
        int count = command.getCount();

        Order order = orderRepository.byId(orderId);
        order.updateProductCount(productId, count);
        orderRepository.save(order);
    }
}

领域事件通常随着聚合根状态的变化而产生。领域事件本身是不变的,并且只应当包含事件相关的上下文信息,不应包含聚合根的全部状态。

事件驱动架构有两种风格:事件通知、事件携带状态转移(Event-Carried State Transfer)。在事件通知风格中,事件包含的信息较少,通常只有聚合根ID。接收方需要通过额外的API获得事件上下文。这种方式实现起来较为简单,但增加了接收方和发送方的耦合度。事件携带状态转移风格则要求事件携带全部的必要信息,接受方通过事件就可以知道发生了什么。

猜你喜欢

转载自blog.csdn.net/tq1086/article/details/111143519