Overview

3 Building the domain core

In building the domain core, the central goal is to make the business model independent, trustworthy, and easy to test. The domain should contain only concepts that express real business rules and invariants, while technical concerns such as persistence, controllers, messaging, and security remain outside. The chapter frames the inner hexagon as a pure Java model made up of entities, value objects, aggregates, and domain services, all designed so that correctness is enforced by the model itself rather than by scattered checks elsewhere in the system.

A major theme is the Always-Valid Domain Model: invalid objects should never be allowed to exist. Entities use private constructors and factory methods that validate all rules before creation, returning errors instead of incomplete objects. This avoids the weaknesses of validating after construction or placing domain rules in application handlers. Value objects complement this approach by turning implicit primitive data into explicit, self-validating types, and domain services handle business logic that spans multiple entities without introducing orchestration or infrastructure concerns.

The chapter also separates two kinds of validation. Input validation belongs at the boundaries, where commands and adapters check syntax and data shape, while business invariant validation belongs inside the domain, where semantic rules are enforced at construction time or during state transitions. For creation, the chapter recommends explicit factory methods, sometimes supported by standalone factories when external services are needed. It closes by emphasizing that this design makes the domain core highly testable, because objects are valid by construction, error handling is explicit, and unit tests can run without frameworks or infrastructure.

The contrast between domain and infrastructure concerns.
The domain layer inside the hexagon. Shows entities, value objects, aggregates, and domain services inside the innermost ring. Ports sit at the ring boundary. Adapters and frameworks are outside. Arrows emphasize that nothing from outside points inward into the domain.
Persistence and serialization frameworks may require construction paths that do not express domain rules clearly. The domain model keeps creation explicit: callers enter through validateThenCreate, and the private constructor is reached only after invariants pass
Primitive obsession vs value objects. Left: method signature with String, String, Long parameters—no type safety, validation scattered. Right: same method with Title, Content, AuthorId parameters—each type self-validating, compiler enforces correctness.
Validation checkpoints across layers. Shows the flow from HTTP request through adapter → command → handler → domain entity → repository. Green checkmarks at adapter (transport validation), command (input validation), and domain entity (business invariants). Gray pass-through at the handler and repository—they trust upstream validation.

Summary

  • The domain layer is the innermost ring of the hexagon. It contains entities, value objects, aggregates, and domain services—all pure code with no framework dependencies.
  • Three functional principles—purity, encapsulation, and completeness—guide domain design. Maximize them where they matter most: in entities and value objects.
  • The Always-Valid Domain Model is the single most important design decision in the domain layer. The constructor is private; the only way to create a domain object is through a factory method that validates all invariants first. If validation fails, the factory returns an error, not an invalid object.
  • The recommended pattern is validateThenCreate using Vavr's Validation type, which can run several checks and return all validation errors together instead of stopping at the first one. The CanBeCreated pattern is a defensible alternative when CQS adherence is a priority.
  • Value objects replace simple language types with domain concepts. A Title type that enforces its own constraints is safer and more expressive than a raw String.
  • Domain services handle business logic that spans multiple entities. They live in the domain layer, carry no framework annotations, and are pure functions of their inputs.
  • Factories encapsulate object construction. For simple entities, the factory method lives on the entity class. For complex construction involving identity generation or external lookups, use a standalone factory class.
  • Input validation (syntactic) guards the hexagon's boundaries. Business invariant validation (semantic) guards the domain itself. They use different mechanisms and live in different layers.

FAQ

What belongs inside the domain layer in Hexagonal Architecture?The domain layer contains business concepts that enforce rules and invariants, such as entities, value objects, aggregates, and domain services. It should not contain framework code, persistence concerns, REST controllers, or messaging infrastructure.
Why should invalid domain objects never be created?Because the domain should follow the Always-Valid Domain Model: if an object exists, it must already satisfy all business invariants. This prevents invalid states from spreading through the system and reduces bugs.
Why use a private constructor with a factory method for domain entities?A private constructor prevents direct instantiation. A factory method like validateThenCreate becomes the only creation path, ensuring all invariants are checked before the object can exist.
What is the difference between validation after construction and validation in a factory method?Validation after construction allows an invalid object to exist briefly, which is unsafe and harder to reason about. Factory validation checks rules before the object is created, so only valid instances are ever produced.
What is a value object and why is it useful?A value object represents a domain concept defined by its attributes rather than identity. It makes implicit concepts explicit, enforces constraints at construction time, and helps eliminate primitive obsession.
How do value objects differ from entities?Entities have a persistent identity that remains the same across state changes. Value objects have no identity and are equal based solely on their values.
When should a domain service be used?Use a domain service when business logic spans multiple entities or aggregates, or when the rule does not naturally belong to a single entity. A domain service contains business rules, not orchestration.
What is the recommended approach for validating and creating an Article?The book recommends a validateThenCreate factory method that returns a Validation result. It validates all required fields, collects all errors if needed, and only constructs the Article when everything is valid.
Why is the Validation type preferred over Either for object construction?Validation can accumulate multiple errors at once, which is useful when several fields must be checked together. Either stops at the first failure, so it is better for sequential operations rather than multi-field validation.
What is the difference between input validation and business invariant validation?Input validation checks the shape and format of data at the boundary, such as blank fields or malformed UUIDs. Business invariant validation checks domain rules, such as whether content is required or whether an article’s data is valid according to business logic.

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Clean Applications with Hexagonal Architecture ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Clean Applications with Hexagonal Architecture ebook for free