Traditional CRUD vs Wow: From Shipping Endpoints to Shipping a Domain Model

An order feature can start with a controller, service, and repository, or with commands, aggregate invariants, and domain events. Both paths can ship software. They differ in where business decisions live and which costs the team accepts.
This article's argument is: when domain rules, state history, and cross-aggregate collaboration dominate complexity, a domain model is usually a clearer delivery unit than an endpoint. This is not a quality judgment about every “traditional architecture,” nor a Wow guarantee about delivery speed or defect rates.
Define the Comparison First
“Conventional CRUD” here means a common workflow: a request passes through a controller and service, which reads and updates current state inside a transaction. Mature systems can also have strong domain models, events, and excellent tests; non-Wow does not mean anemic.
“Wow” means the command dispatch, event sourcing, snapshots, projections, sagas, wait stages, metadata, and testing capabilities in the current repository. Architecture Overview owns exact component responsibilities; Introduction owns the fit and adoption-cost boundary.
Two Ways to Organize Delivery
| Decision | Common CRUD layering | Current Wow approach |
|---|---|---|
| Modeling start | resource, endpoint, and current data | business command, aggregate boundary, and invariant |
| State change | update current records in a transaction | aggregate produces events; sourcing functions apply them |
| History | design a separate audit/history mechanism | EventStore retains versioned domain-event history |
| Reads | reuse the write model or build custom queries | sourced aggregate state and projected views are distinct paths |
| Cross-aggregate work | organize service calls, messages, or workflows | saga consumes an event and sends another command |
| Domain verification | team selects unit/integration layers | AggregateSpec / SagaSpec express Given → When → Expect |
This table is an architecture view, not a complete contract. Core Concepts owns the canonical command, event, state, projection, and saga vocabulary.
What Wow Connects to the Domain Model
The current Wow runtime connects the same domain artifacts to:
- command messages and aggregate processing;
- event append and state reconstruction;
- snapshots, projections, and query paths;
- event handlers and sagas;
- WebFlux/OpenAPI metadata;
- aggregate and saga specifications.
That is the engineering meaning of “domain model as a service”: reusable runtime capabilities are assembled around the model. It does not mean one aggregate class automatically supplies a correct API, security, capacity, or recovery plan.
What the Current Repository Example Proves
The cart example separates responsibilities:
Cart.kthandlesAddCartItemand produces eitherCartItemAddedorCartQuantityChangedfrom current state;CartState.ktapplies those events through sourcing functions;CartSaga.ktsends a remove-items command after an order created from a cart;CartSpecandCartSagaSpeccover accepted, rejected, and no-follow-up-command branches.
Kotlin Order and Cart is the canonical walkthrough, and ./gradlew :example-domain:check is the focused gate for this example.
This evidence proves the example behavior and test layer. It does not prove that every application writes a fixed percentage less code, gains a fixed productivity improvement, or reaches production capacity automatically. This rewrite removes those unsupported quantitative inferences.
Cost Moves; It Does Not Disappear
Wow can reduce the need for each business service to re-own command routing, event-store abstraction, state replay, wait coordination, and domain-test setup. The team still owns:
- correct aggregate boundaries and event contracts;
- authorization, tenancy, owner/space rules, and external-side-effect idempotency;
- persisted-event evolution and replay compatibility;
- selection and verification of storage, messaging, and query adapters;
- environment evidence for capacity, backup, recovery, alerting, and rollback.
The value therefore depends on whether the problem needs these capabilities. If current state and one database transaction fully express the business, event history, asynchronous projections, and message recovery may be unnecessary cost.
When Wow Is Worth Evaluating
Ask four questions:
- Are there business invariants and illegal state transitions that need one explicit guardian?
- Does the reason state changed, historical versions, or replay have business value?
- Must writes and multiple read models evolve independently?
- Do cross-aggregate flows need explicit progress, idempotency, and recovery boundaries?
If most answers are no, clear CRUD is usually simpler. If most are yes, validate Wow with one real business slice before attempting a system-wide migration.
Minimal Adoption Path
- Write the command, invariant, event, and state for one core scenario.
- Prove accepted and rejected paths with the Domain Test Suite.
- Follow Getting Started to expose one real command and read sourced state.
- Add a projection only for a real query requirement, and a saga only for a real cross-aggregate flow.
- Use Application Testing for real adapters, restart, redelivery, and security boundaries.
- Complete Production Best Practices and Backup, Restore, and Replay gates before production.
Conclusion
“From endpoints to a domain model” does not mean replacing controllers with more architecture vocabulary. It means placing decisions, facts, and verification behind stable boundaries while the framework owns reusable runtime mechanics.
Keep simple problems simple. A complex domain may justify event sourcing, eventual consistency, and operational cost; labels such as “traditional” and “modern” do not.