Cargo Shipping Domain Model
Explanation
Section titled “Explanation”The cargo example comes from Eric Evans’ book on Domain-Driven Design. A sample application reuses it. Eclipse Cargo Tracker, a Jakarta EE application, is based on that sample. See the articles Domain Model and Domain-Driven Design for the general idea.
Cargo as an entity. Cargo has a stable identity, the tracking id. It also has a life cycle with state changes that the business cares about. That makes it an Entity (see the article Entity). The life cycle begins at booking, when the tracking id is assigned.
Handling events. A HandlingEvent records something that really happened to the cargo, such as loading, unloading or customs clearance. It is a Domain Event (see Domain Event). These events feed the cargo’s delivery status.
Goal versus actual. In the evolved model, Delivery is the actual transportation. The RouteSpecification is the customer’s requirement. The Itinerary is the plan. This echoes the original split between a goal and what actually happened.
Routing. The RoutingService gives the domain access to an external routing system. It is used to find possible routes. See Domain Service.
Later evolution. The sample application adds aggregates. They decouple large structures by setting rules for relations between entities. Repositories exist per aggregate root. Cargo Tracker lists entities, value objects, aggregates, services, repositories and factories as its building blocks. See Aggregate and DDD Building Blocks (Tactical Patterns).
The sample’s building blocks are described in Evans’ book, except Domain Event, which was added later.
Example
Section titled “Example”A team building a parcel service could follow the same pattern. A parcel gets a tracking id when it is booked. The customer’s wish, “deliver to Zurich by Friday,” is kept as one concept. The chosen route is a separate concept. Scans at depots are recorded as events. Staff can then say “the plan no longer matches what was handled” without talking about tables.
Trade-offs
Section titled “Trade-offs”The facts describe the example, not its costs. One point stands out: the model keeps requirement, plan and actual delivery as separate concepts. That adds more concepts to learn. In return, each business question has a clear home. The sample also grew over time, with aggregates and repositories added later. A first model does not need to include them.
Diagram source
@startumlclass Cargo { trackingId}class RouteSpecificationclass Itineraryclass Deliveryclass HandlingEventCargo --> RouteSpecification : requirementCargo --> Itinerary : planCargo --> Delivery : actualHandlingEvent ..> Delivery : feeds@endumlChecks
Section titled “Checks”- Entities such as Cargo have a stable identity (for example a tracking id) and a documented life cycle.
- Real-world events, such as loading or customs clearance, are recorded as domain events that feed delivery status.
- The customer requirement, the plan and the actual delivery are kept as separate concepts.
- Access to an external routing system goes through a dedicated domain service.
Related
Section titled “Related”- Domain Model
- Domain-Driven Design
- Entity
- Domain Event
- Domain Service
- Aggregate
- DDD Building Blocks (Tactical Patterns)
- Ubiquitous Language
Sources
Section titled “Sources”- DDD Sample Application - Characterization of building blocks. — dddsample.sourceforge.net, accessed 2026-11-09
- Domain-Driven Design: Cargo Shipping Example | O&B Insights — insights.orangeandbronze.com, accessed 2026-11-09
- Eclipse Cargo Tracker — eclipse-ee4j.github.io, accessed 2026-11-09