zoukankan      html  css  js  c++  java
  • 【DDD】Thoughtworks笔记(目录划分、异常设计)

    参考:https://insights.thoughtworks.cn/backend-development-iteration0/  后端开发实践——开发者的第0个迭代

    代码样例:https://github.com/e-commerce-sample/order-backend

    目录设计:

    1、首先基于业务分包(基于聚合根)

      早年的Java分包方式通常是基于技术的,比如与domain包平级的有controller包、service包和infrastructure包等。这种方式当前并不被行业所推崇,而是应该首先基于业务分包。比如,在订单示例项目中,有两个重要的领域对象OrderProduct(在DDD中称为聚合  根),所有的业务都围绕它们展开,因此分别创建order包和product包,再分别在包下创建与之相关的各个子包。此时的order包如下:

    ├── order
    │   ├── OrderApplicationService.java
    │   ├── OrderController.java
    │   ├── OrderNotFoundException.java
    │   ├── OrderRepository.java
    │   ├── OrderService.java
    │   └── model
    │       ├── Order.java
    │       ├── OrderFactory.java
    │       ├── OrderId.java
    │       ├── OrderItem.java
    │       └── OrderStatus.java

    更复杂场景:如果代码结构足够的简单,那么没有必要再次进行子包的划分,

    ├── order
    │   ├── OrderApplicationService.java
    │   ├── OrderController.java
    │   ├── OrderPaymentProxy.java
    │   ├── OrderPaymentService.java
    │   ├── OrderRepository.java
    │   ├── command
    │   │   ├── ChangeAddressDetailCommand.java
    │   │   ├── CreateOrderCommand.java
    │   │   ├── OrderItemCommand.java
    │   │   ├── PayOrderCommand.java
    │   │   └── UpdateProductCountCommand.java
    │   ├── exception
    │   │   ├── OrderCannotBeModifiedException.java
    │   │   ├── OrderNotFoundException.java
    │   │   ├── PaidPriceNotSameWithOrderPriceException.java
    │   │   └── ProductNotInOrderException.java
    │   ├── model
    │   │   ├── Order.java
    │   │   ├── OrderFactory.java
    │   │   ├── OrderId.java
    │   │   ├── OrderIdGenerator.java
    │   │   ├── OrderItem.java
    │   │   └── OrderStatus.java
    │   └── representation
    │       ├── OrderItemRepresentation.java
    │       ├── OrderRepresentation.java
    │       └── OrderRepresentationService.java

    2、对于一些不隶属于任何业务的代码可以单独分包,比如一些util类、公共配置等。比如我们依然可以创建一个common包,下面放置了Spring公共配置、异常处理框架和日志等子包:

    └── common
        ├── configuration
        ├── exception
        ├── loggin
        └── utils

    3、异常处理

      在设计异常处理的框架时,需要考虑以下几点:向客户端提供格式统一的异常返回;异常信息中应该包含足够多的上下文信息,最好是结构化的数据以便于客户端解析;不同类型的异常应该包含唯一标识,以便客户端精确识别

       异常两种设计形式:

        1、层级异常:每种具体的异常都对应了一个异常类,这些类最终继承自某个父异常;

        2、全局一个异常:再以一个字段来区分不同的异常场景

      层级异常设计

    
    
    // ErrorCode枚举中包含了异常的唯一标识、HTTP状态码以及错误信息;而data字段表示各个异常的上下文信息。
    public abstract class AppException extends RuntimeException {
        private final ErrorCode code;     
        private final Map<String, Object> data = newHashMap();
    }
    
    /// 具体异常
    public class OrderNotFoundException extends AppException {
        public OrderNotFoundException(OrderId orderId) {
            super(ErrorCode.ORDER_NOT_FOUND, ImmutableMap.of("orderId", orderId.toString()));
        }
    }

    在返回异常给客户端时,通过一个ErrorDetail类来统一异常格式:

    public final class ErrorDetail {
        private final ErrorCode code;
        private final int status;
        private final String message;
        private final String path;
        private final Instant timestamp;
        private final Map<String, Object> data = newHashMap();
    }

    样例

    {
      requestId: "d008ef46bb4f4cf19c9081ad50df33bd",
      error: {
        code: "ORDER_NOT_FOUND",
        status: 404,
        message: "没有找到订单",
        path: "/order",
        timestamp: 1555031270087,
        data: {
          orderId: "123456789"
        }
      }
    }

     4、多环境构建

      在软件的开发流程中,我们需要将软件部署到多个环境,经过多轮验证后才能最终上线。在不同的阶段中,软件的运行态可能是不一样的,比如本地开发时可能将所依赖的第三方系统stub掉;持续集成构建时可能使用的是测试用的内存数据库等等。为此,本文的示例项目推荐采用以下环境:

      local:用于开发者本地开发
      ci:用于持续集成
      dev:用于前端开发联调
      qa:用于测试人员
      uat:类生产环境,用于功能验收(有时也称为staging环境)
      prod:正式的生产环境

  • 相关阅读:
    给我30000出租车,还你一个不堵车的北京
    使用vim代替IDE
    (转)声明,函数与函数指针
    想恶作剧的请看过来
    bash命令提示符的更改
    (转)微软面试
    140个Google面试问题
    UTF8 GBK UTF8 GB2312 之间的区别和关系(转)
    MyBooksReadingStatic
    让SlickEdit 自动编译Keil C51工程
  • 原文地址:https://www.cnblogs.com/clarino/p/15506039.html
Copyright © 2011-2022 走看看