Why is it in Application Layer then?
As far as I can tell, because this is an application service -- more specifically, because the consumer of this service is the application, not the domain.
For example, take a close look at BookingService.assignCargoToRoute, if we strip away the logging and exception handling, we see
public void assignCargoToRoute(final Itinerary itinerary, final TrackingId trackingId) {
final Cargo cargo = cargoRepository.find(trackingId);
cargo.assignToRoute(itinerary);
cargoRepository.store(cargo);
}
That's a classical pattern for an application to interact with the domain.
- Obtain a handle to an aggregate root, with a local copy of state
- Send a command to the aggregate root, allowing it to update the local state
- Commit the local state change back into the shared repository, so that the changes are visible outside of this particular thread.
BookingService.bookNewCargo is similar; but confused by the fact that (a) creation patterns are weird and (b) this particular design is a bit anemic; the domain model, specifically the Cargo aggregate root, should be doing more of the work.
If you work through the call graph, you'll notice that
So the consumer of the BookingService is the application (indirectly, the CargoAdminController); this thing isn't a domain service at all. The domain model never knows it exists.
That's not a great argument by itself. Another hint that we are dealing with an application service here is that the implementation knows about Repository
, which is not a domain concept. Given that domain services are sometimes used to bridge a gap between the rest of the domain model and some application or infrastructure service, we can conclude that heuristic isn't particularly good either.
How to distinguish between application and domain services?
My advice: don't get caught up in the labels. Pay attention to cohesion. Pay attention to what other components change when you change the service. Watch your dependency graph like a hawk -- if you find your "domain" services getting polluted with application dependencies, that's a hint that you haven't quite gotten the separation of concern properly aligned.