跪拜 Guibai
← All articles
Frontend · AI Programming · Agent

Frontend DDD Stops Small Feature Requests From Wrecking Your Codebase

By 古茗前端团队 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Frontend teams keep hitting the same wall: a small product ask forces a component rewrite because business rules are baked into JSX and event handlers. DDD in the frontend gives those rules a single home that survives UI churn and framework changes, cutting the cost of iteration on complex B2B or e-commerce surfaces.

Summary

A single product requirement—grouping cart items by delivery type—turns a clean React component into a tangle of inline filters, payload assembly, and conditional checks. The root cause isn't the requirement itself; it's that business knowledge lives scattered across components, hooks, and utility functions, with no stable entity to carry it. When the technical model doesn't match the domain model, every business change forces a redesign of the UI code.

Moving to a rich domain model fixes this. A `CartLine` class encapsulates not just data but also computed properties like `amount`, `isDailyDelivery`, and `canSubmit`, plus validation logic. A mapper isolates backend DTO changes from the domain, and domain services handle cross-entity strategies like split-delivery decisions. An interaction model hook orchestrates the use case—fetching data, calling domain logic, submitting—so the view layer becomes a thin shell that only renders state and delegates actions.

The payoff is two-fold: business changes update the domain layer without cascading into views, and the domain code stays reusable across web, mobile, or even framework migrations. The approach isn't a silver bullet—simple CRUD pages don't need it—but for systems where business complexity keeps outpacing the component tree, it stops the redesign-death-loop cold.

Takeaways
Rich domain models bundle data with behavior—a `CartLine` class owns its own `amount`, `isDailyDelivery`, `canSubmit`, and validation, instead of spreading that logic across the component tree.
A mapper function acts as an anti-corruption layer, translating backend DTOs into stable domain objects so API changes don't ripple into views.
Domain services handle logic that spans multiple entities, like deciding whether to split an order by delivery date; they can be pure functions or class factories that extend aggregates.
An interaction model hook orchestrates the full use case—parallel data fetching, strategy calls, parameter assembly—leaving the view component to only render state and wire up events.
Business changes update the domain layer without touching views, and the domain code stays reusable across React, Vue, or even a mobile rewrite.
Simple CRUD pages, static displays, and basic forms don't benefit from DDD; the overhead only pays off when business rules are complex and frequently changing.
Conclusions

Most frontend architecture advice focuses on component composition and state management, but the real source of rot is business logic without a permanent address—DDD gives it one that outlives any particular UI.

The article's distinction between utility functions and domain services is underrated: a price formatter is a util, but a split-delivery strategy is domain knowledge, and treating them the same is how codebases become unreadable.

Frontend DDD doesn't require the full ceremony of backend DDD—no repositories, no aggregates in the Evans sense—just the discipline to ask 'does this logic belong to the business or the UI?' before writing it.

Concepts & terms
Rich (充血) vs. Anemic (贫血) Domain Model
An anemic model is a data bag with getters/setters and no behavior; business logic lives elsewhere. A rich model encapsulates both data and the operations on that data in the same object, so a CartLine knows how to calculate its own amount and validate itself.
Anti-Corruption Layer / Mapper
A translation layer that converts external data shapes (backend DTOs) into internal domain objects. When the API changes field names or structure, only the mapper needs updating—the domain and UI layers stay untouched.
Domain Service
A stateless operation that embodies business rules spanning multiple entities. Unlike a utility function, it expresses domain knowledge—e.g., deciding a split-delivery strategy based on product types and dates—rather than generic technical convenience.
Interaction Model
An object or hook that orchestrates a single user use case end-to-end: fetching data, invoking domain logic, assembling submission payloads. It sits between the view and the domain layer, keeping the component free of workflow knowledge.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗