How to Refactor Monolithic Checkout Code into Clean DDD Modules

This article explains how to identify and refactor typical “流水账” (spaghetti) code in a checkout API by applying Domain‑Driven Design layers—splitting responsibilities into Interface, Application, and Domain layers, using CQE objects, DTO assemblers, and anti‑corruption facades to achieve clear, maintainable modules.

Alibaba Cloud Developer
Alibaba Cloud Developer
Alibaba Cloud Developer
How to Refactor Monolithic Checkout Code into Clean DDD Modules

Case Introduction

We take a common checkout flow where a @RestController mixes validation, business logic, persistence, and external calls, violating the Single Responsibility Principle.

@RestController
@RequestMapping("/")
public class CheckoutController {
    @Resource private ItemService itemService;
    @Resource private InventoryService inventoryService;
    @Resource private OrderRepository orderRepository;
    @PostMapping("checkout")
    public Result<OrderDO> checkout(Long itemId, Integer quantity) {
        // 1) Session management
        Long userId = SessionUtils.getLoggedInUserId();
        if (userId <= 0) return Result.fail("Not Logged In");
        // 2) Parameter validation
        if (itemId <= 0 || quantity <= 0 || quantity >= 1000) return Result.fail("Invalid Args");
        // 3) Data enrichment
        ItemDO item = itemService.getItem(itemId);
        if (item == null) return Result.fail("Item Not Found");
        // 4) External service call
        boolean withholdSuccess = inventoryService.withhold(itemId, quantity);
        if (!withholdSuccess) return Result.fail("Inventory not enough");
        // 5) Domain calculation
        Long cost = item.getPriceInCents() * quantity;
        // 6) Domain object creation
        OrderDO order = new OrderDO();
        order.setItemId(itemId);
        order.setBuyerId(userId);
        order.setSellerId(item.getSellerId());
        order.setCount(quantity);
        order.setTotalCost(cost);
        // 7) Persistence
        orderRepository.createOrder(order);
        // 8) Return
        return Result.success(order);
    }
}

Why This Is Problematic

The method mixes concerns, making future changes risky and violating SRP. Any change in validation, calculation, or external integration forces modifications across the whole method.

DDD Refactoring Steps

Interface Layer : Extract a thin controller that only handles protocol conversion, authentication, session, rate‑limiting, caching, and exception mapping.

Application Layer : Define use‑case services that accept a single Command , Query or Event object, orchestrate the flow, and delegate business logic to the domain.

Domain Layer : Keep pure business rules, calculations, and invariants inside entities or domain services.

Interface Layer Details

Typical responsibilities include:

Network protocol conversion (handled by framework annotations).

Unified authentication (e.g., AppKey+Secret checks).

Session management (extracting logged‑in user ID).

Rate limiting.

Pre‑caching for read‑only data.

Exception handling that returns a Result object instead of leaking stack traces.

Example of a clean controller method:

@PostMapping("checkout")
@ResultHandler
public Result<OrderDTO> checkout(Long itemId, Integer quantity) {
    CheckoutCommand cmd = new CheckoutCommand();
    // populate cmd fields
    OrderDTO orderDTO = checkoutService.checkout(cmd);
    return Result.success(orderDTO);
}

Command, Query, Event (CQE) Objects

These are value objects that give semantic meaning to each use case. They replace long parameter lists and make the API self‑describing.

public class CheckoutCommand {
    @NotNull(message = "User not logged in") private Long userId;
    @NotNull @Positive(message = "Valid itemId") private Long itemId;
    @NotNull @Min(1) @Max(1000) private Integer quantity;
}

Application Service Guidelines

Avoid branching logic; keep cyclomatic complexity close to 1.

Do not perform calculations; move them to domain entities.

Use DTO assemblers (e.g., MapStruct) to convert entities to DTOs.

Return DTOs, never entities.

Let validation happen via Bean Validation annotations; let exceptions propagate.

DTO Assembler

MapStruct example:

@Mapper
public interface OrderDtoAssembler {
    OrderDtoAssembler INSTANCE = Mappers.getMapper(OrderDtoAssembler.class);
    OrderDTO orderToDTO(Order order);
}

Anti‑Corruption Layer (ACL)

Wrap external services with facades that translate external DOs into internal DTOs, isolating the application core from upstream changes.

public interface ItemFacade {
    ItemDTO getItem(Long itemId);
}

@Service
public class ItemFacadeImpl implements ItemFacade {
    @Resource private ExternalItemService externalItemService;
    public ItemDTO getItem(Long itemId) {
        ItemDO itemDO = externalItemService.getItem(itemId);
        if (itemDO == null) return null;
        ItemDTO dto = new ItemDTO();
        dto.setItemId(itemDO.getItemId());
        dto.setTitle(itemDO.getTitle());
        dto.setPriceInCents(itemDO.getPriceInCents());
        dto.setSellerId(itemDO.getSellerId());
        return dto;
    }
}

Orchestration vs. Choreography

Orchestration uses a central coordinator (command‑driven), while choreography relies on events (event‑driven). Choose based on dependency direction and who owns the business responsibility.

Summary

By applying DDD layered architecture—clean Interface layer, semantic CQE objects in the Application layer, domain‑centric entities, DTO assemblers, and ACL facades—spaghetti checkout code becomes modular, testable, and resilient to change.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavamicroservicesAnti‑Corruption LayerDDDCQEapplication serviceInterface Layer
Alibaba Cloud Developer
Written by

Alibaba Cloud Developer

Alibaba's official tech channel, featuring all of its technology innovations.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.