Skip to content
Back to skills

Java Ddd Aggregates

ASecurity

Design and implement Java DDD aggregates when deciding which entities must change atomically, moving invariants out of setters, separating creation from rehydration, or preventing concurrent writes from bypassing the root. Covers domain identity, child ownership, valid transitions and aggregate version checks. Use for aggregate boundaries and lifecycle behavior; bounded-context discovery and ORM mapping have separate owners.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 1, 2026
developmentjavaspringtestinggitdatabase

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned October 1, 2026

npx -y skills add robsonkades/agent-skills --skill java-ddd-aggregates --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Java Ddd Aggregates?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Java Ddd Aggregates
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/robsonkades-java-ddd-aggregates/badge)](https://www.skillsdirectory.com/skills/robsonkades-java-ddd-aggregates)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: java-ddd-aggregates
description: >-
  Design and implement Java DDD aggregates when deciding which entities must change
  atomically, moving invariants out of setters, separating creation from rehydration,
  or preventing concurrent writes from bypassing the root. Covers domain identity,
  child ownership, valid transitions and aggregate version checks. Use for aggregate
  boundaries and lifecycle behavior; bounded-context discovery and ORM mapping have
  separate owners.
---

# Java DDD Aggregates

## Purpose and scope

Make a business consistency boundary explicit in Java: one root controls the state
and behavior required to preserve its invariants. An aggregate is neither every
object reachable from an ORM entity nor a collection of tables with the same prefix.
This skill owns tactical boundary, identity and lifecycle decisions. Optional
handoffs are `bounded-context-design` for context boundaries,
`java-ddd-value-objects` for value semantics, `java-ddd-repositories` for persistence
implementation, and `java-ddd-testing` for broader test design.

## Workflow

1. **Inspect the actual model.** Read build/toolchain settings, the context's package
   tree, aggregate/identifier/validator foundations, commands, persistence mappings,
   transaction owner and relevant tests. Identify all write paths, including bulk
   updates and maintenance jobs. Keep the project's Java version and dependencies;
   the illustrative Java fragment uses a Java 17 baseline without frameworks. A
   reference project or an existing class name is evidence, not proof of a rule.
2. **Write the invariant before drawing the boundary.** For each relevant command,
   state what must hold when it succeeds, what state it reads, and whether another
   writer can invalidate that decision. Separate rules about one object, a root and
   its children, and independently owned aggregates. Name when the business permits
   intermediate states; never infer eventual consistency merely to obtain smaller
   aggregates. When choosing or changing a boundary, read
   [boundaries and concurrency](references/boundaries-and-concurrency.md).
3. **Choose identity and ownership.** Distinguish continuity of an entity from the
   attributes of a value. Use a typed `FooID` for a root's stable domain identity;
   child identity may be local to that root. Decide who creates, removes and modifies
   each child. A public child mutator or a returned mutable child can defeat a root
   even when its collection is unmodifiable.
4. **Implement intention-revealing transitions.** Prefer `order.submit(...)` or
   `order.changeQuantity(lineID, quantity)` to public field setters. Validate the
   proposed result before publishing it into the aggregate. Expected validation
   rejection must preserve state, audit values and pending events. A notification
   handler collecting errors must cause the command to reject before mutation;
   merely invoking `validate(handler)` does not enforce the invariant.
5. **Separate creation, rehydration and persistence.** Creation (`newFoo(...)` in the
   reference convention) establishes a new identity and valid initial state.
   `with(...)` or an explicitly named rehydration
   factory restores persisted identity, audit data and version without registering
   new events, generating identifiers or reading the current time. The persistence
   adapter restores state; it must not replay command methods. When editing these
   paths, read [Java lifecycle pattern](references/java-lifecycle-pattern.md).
6. **Close the concurrency boundary.** Every write affecting a root invariant,
   including child-only changes, must participate in its concurrency protocol.
   Verify root version checks/locks and persistence of children in the same
   transaction. Incrementing an audit or revision counter in memory alone cannot prevent a
   lost update. Do not claim Java thread safety from database optimistic locking;
   ordinarily confine a mutable aggregate instance to one command execution.
7. **Verify the changed behavior.** Reuse relevant tests, then add the missing
   counterexample: rejected command leaves state/events unchanged; a caller cannot
   mutate an internal child; rehydration preserves stored facts without new events;
   or two writers cannot both violate an invariant. Run concurrent persistence
   checks against the actual adapter/database when that guarantee changes. A domain
   unit test cannot prove transaction isolation or ORM version propagation.

## Java conventions and decisions

- Keep concepts under the project's domain package and context-specific subpackages
  (`com.example.domain.<context>` in the illustration).
  Follow the established `Foo extends AggregateRoot<FooID>`, `FooID extends Identifier`,
  `FooValidator extends Validator` and `ValidationHandler` vocabulary when that
  foundation exists. Reuse `validation.Error`, `Notification`,
  `ThrowsValidationHandler` and `exceptions.DomainException.with(...)` where provided.
  For a new model, introduce only the base abstractions that carry a real contract.
  Constructors and method parameters are `final`; stable fields and dependencies
  are `final`. State that transitions legitimately replace need not be final.
- Keep Spring/JPA/HTTP types and repository calls outside the aggregate in this
  architecture. If the project uses a different mapping approach, preserve its
  contract while proposing a scoped change; do not silently move every class.
  Use existing nullability annotations when available; adding an annotation library
  or upgrading the Java baseline is a separate decision.
- Prefer immutable value objects and immutable child snapshots on public reads.
  `List.copyOf` protects the container only. Use private/package-controlled child
  mutation plus root methods, or replace immutable child state through the root.
  Package visibility is useful only if package callers respect the same boundary.
- Keep entity equality stable across legitimate changes. Inspect the existing
  equality/proxy contract before modifying it; do not generate equality/hash from
  mutable fields. A database surrogate identifier and a domain `FooID` can coexist,
  but a generated nullable database key must not silently become domain identity.
- Prefer a smaller boundary only when its true invariants still hold. Read models
  may combine many roots without creating a new write aggregate. An unbounded
  collection or frequent conflicts calls for evidence about ownership and write
  patterns, not an automatic split or disabled locking.

## Deliverable and limits

For an implementation, deliver the root/child ownership decision, affected commands
and focused changes with executed checks. For a review, identify the write path that
can break the invariant and the smallest justified correction; an adequate model may
need no changes. State unresolved business consistency requirements separately from
observed code defects. Report whether validation covered domain behavior, persistence
concurrency or only a design sketch. Do not claim a boundary is correct without the
business rule, or that a version annotation protects child writes without evidence.

Files in this skill

  • SKILL.md7 KB
  • references/boundaries-and-concurrency.md7.9 KB
  • references/java-lifecycle-pattern.md9 KB
  • skill.yaml1.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…