Domain Driven Design, The Repository pattern

I’ve seen so many times a heated discussion about Repositories in Domain Driven Design, there is a kind of misunderstanding and/or confusion about what really a Repository is.

People usually disagree about the role of the Repository, if it should be a kind of  “Data Access Layer”, such as a DAO or if it must be something that is injected in the domain class, then it will talk to the DAO in the beneath layer.

I’ve always wondered why people had these fights, but now I can see why ! The thing is, as far as I read in the book (Chapter 10 : Supple Design),  the examples of Reposotory has been shown almost exactly as a DAO implementation. I even downloaded the source code examples from the Domain Driven Design Community, and the example IS a DAO implementation, as I’m showing below :

package se.citerus.dddsample.domain.model.cargo;

import java.util.List;

public interface CargoRepository {

  /**
   * Finds a cargo using given id.
   *
   * @param trackingId Id
   * @return Cargo if found, else {@code null}
   */
  Cargo find(TrackingId trackingId);

  /**
   * Finds all cargo.
   *
   * @return All cargo.
   */
  List findAll();

  /**
   * Saves given cargo.
   *
   * @param cargo cargo to save
   */
  void store(Cargo cargo);

  /**
   * @return A unique, generated tracking Id.
   */
  TrackingId nextTrackingId();

}

and the implementation

package se.citerus.dddsample.infrastructure.persistence.hibernate;

import org.springframework.stereotype.Repository;
import se.citerus.dddsample.domain.model.cargo.Cargo;
import se.citerus.dddsample.domain.model.cargo.CargoRepository;
import se.citerus.dddsample.domain.model.cargo.TrackingId;

import java.util.List;
import java.util.UUID;

/**
 * Hibernate implementation of CargoRepository.
 */
@Repository
public class CargoRepositoryHibernate extends HibernateRepository implements CargoRepository {

  public Cargo find(TrackingId tid) {
    return (Cargo) getSession().
      createQuery("from Cargo where trackingId = :tid").
      setParameter("tid", tid).
      uniqueResult();
  }

  public void store(Cargo cargo) {
    getSession().saveOrUpdate(cargo);
    // Delete-orphan does not seem to work correctly when the parent is a component
    getSession().createSQLQuery("delete from Leg where cargo_id = null").executeUpdate();
  }

  public TrackingId nextTrackingId() {
    // TODO use an actual DB sequence here, UUID is for in-mem
    final String random = UUID.randomUUID().toString().toUpperCase();
    return new TrackingId(
      random.substring(0, random.indexOf("-"))
    );
  }

  public List findAll() {
    return getSession().createQuery("from Cargo").list();
  }

}

This Repository is used by a class called BookingServiceImpl :

package se.citerus.dddsample.application.impl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.annotation.Transactional;
import se.citerus.dddsample.application.BookingService;
import se.citerus.dddsample.domain.model.cargo.*;
import se.citerus.dddsample.domain.model.location.Location;
import se.citerus.dddsample.domain.model.location.LocationRepository;
import se.citerus.dddsample.domain.model.location.UnLocode;
import se.citerus.dddsample.domain.service.RoutingService;

import java.util.Collections;
import java.util.Date;
import java.util.List;

public final class BookingServiceImpl implements BookingService {

  private final CargoRepository cargoRepository;
  private final LocationRepository locationRepository;
  private final RoutingService routingService;
  private final Log logger = LogFactory.getLog(getClass());

  public BookingServiceImpl(final CargoRepository cargoRepository,
                            final LocationRepository locationRepository,
                            final RoutingService routingService) {
    this.cargoRepository = cargoRepository;
    this.locationRepository = locationRepository;
    this.routingService = routingService;
  }

  @Override
  @Transactional
  public TrackingId bookNewCargo(final UnLocode originUnLocode,
                                 final UnLocode destinationUnLocode,
                                 final Date arrivalDeadline) {
    // TODO modeling this as a cargo factory might be suitable
    final TrackingId trackingId = cargoRepository.nextTrackingId();
    final Location origin = locationRepository.find(originUnLocode);
    final Location destination = locationRepository.find(destinationUnLocode);
    final RouteSpecification routeSpecification = new RouteSpecification(origin, destination, arrivalDeadline);

    final Cargo cargo = new Cargo(trackingId, routeSpecification);

    cargoRepository.store(cargo);
    logger.info("Booked new cargo with tracking id " + cargo.trackingId().idString());

    return cargo.trackingId();
  }

  @Override
  @Transactional
  public List requestPossibleRoutesForCargo(final TrackingId trackingId) {
    final Cargo cargo = cargoRepository.find(trackingId);

    if (cargo == null) {
      return Collections.emptyList();
    }

    return routingService.fetchRoutesForSpecification(cargo.routeSpecification());
  }

  @Override
  @Transactional
  public void assignCargoToRoute(final Itinerary itinerary, final TrackingId trackingId) {
    final Cargo cargo = cargoRepository.find(trackingId);
    if (cargo == null) {
      throw new IllegalArgumentException("Can't assign itinerary to non-existing cargo " + trackingId);
    }

    cargo.assignToRoute(itinerary);
    cargoRepository.store(cargo);

    logger.info("Assigned cargo " + trackingId + " to new route");
  }

  @Override
  @Transactional
  public void changeDestination(final TrackingId trackingId, final UnLocode unLocode) {
    final Cargo cargo = cargoRepository.find(trackingId);
    final Location newDestination = locationRepository.find(unLocode);

    final RouteSpecification routeSpecification = new RouteSpecification(
      cargo.origin(), newDestination, cargo.routeSpecification().arrivalDeadline()
    );
    cargo.specifyNewRoute(routeSpecification);

    cargoRepository.store(cargo);
    logger.info("Changed destination for cargo " + trackingId + " to " + routeSpecification.destination());
  }

}

Well, I cannot deny that I did not dig so deep into the code ( and I did not finish the book ) yet,
but what I can state for sure is that this architecture really looks like this sequence :

Repository Sequence Diagram
Also, the layering :

Layering Repository Diagram
Ok, I know I am over simplifying things here, but my intention is only to communicate my point of view about
the topic. I’m not saying that what is inside this code is wrong at all, I am just skeptical about how “new” or
effective this thing is, because I’ve been developing large scale software systems using the same approach, but with a
different name “DAO”, and so far I could not see anything different from this. I might let you guys twist my arms in the end of the book,
but so far I’m pretty sure the Repository and a DAO pattern are the same thing.

Any idea, suggestions, thoughts and counter-argument are very welcome ! :)

13 Comments

  1. Eric Jan Malotaux:

    The only difference I see with what I’ve been used to is that domain objects have access to repositories. I didn’t do that before because I was taught that domain objects should not have dependencies on technology(JDBC)-specific classes. To make repositories accessable to domain objects without burdening them with a dependency beyond the repository interface, one needs dependency injection for domain objects. This is probably quite doable. I just haven’t come around to actually doing it.


    Eric Jan Malotaux

  2. admin:

    Hi Eric,

    I fully agree with you, and that’s exactly what I said before! I can’t see any advantage of having a domain object accessing a layer that will return new domain objects, instead I use a service layer or a factory to do some fancy things. I strongly believe that the domain objects should only be concerned about doing the business stuff, not worry about any low level machinery or other mechanism than business.

    But, my bigger concern is that there is no reference neither in the book, nor in the samples provided by Domain Driven Design community guys at all. So, from where people picked it up ?

  3. Eric Jan Malotaux:

    I can see why accessing persistent objects via a repository from domain objects could be useful, to be honest. I can think of a business method of a domain object, that can only be implemented in an efficient manner by performing a database query. Think of a count or a sum over a large number of associated objects. However, it should be done in a way that there are no compile-time dependencies on the particular persistence technology used. Run-time is another story of course.

    I can also see why, for instance, sending a message by email from a domain object could be useful. After all, I am also taught that domain objects should have business methods instead of just setters and getters. And a lot of business functionality inevitably involves technology that you want your domain objects to be ignorant/independent of.

    How to implement this is not show clearly, if at all, in “Domain-Driven Design”.


    Eric Jan Malotaux

  4. Tim High:

    Hi Marcio,
    I haven’t actually studied DDD in depth, either. But my understanding of the problem is the following: you want to keep all the business logic in the domain layer, but you need to get all these objects from “somewhere”. Hibernate tries to solve the problem by allowing you to define only OO relationships (association, composition, etc.), and providing the data access totally transparently (e.g. you don’t have to tell anything to save an object – just modify it, Hibernate will notice that it’s dirty, and automatically update the database). In practice, I’ve never seen a system where this was all you needed.

    So, how do you implement business logic if it needs to look stuff up? You create a new BUSINESS concept, called a “repository”, where this stuff is kept. If you want, you can even pretty it up so that it really looks like a real-world entity (“We’re lawyers – we stash our cases in folders in a file cabinet… so let’s call our repository the ‘FileCabinet’”).

    As you’ve pointed out, the IMPLEMENTATION looks almost exactly the same. But by promoting a data-layer entity to the domain layer, you allow your domain entities to access it guilt-free. As you also mentioned, you’re still stuck with database dependencies that you don’t want in the domain layer. How to fix that? It ain’t pretty, but if you really need it, you can place the interface in the domain layer, and the implementation in the data layer, which can be swapped out when the time comes. If you need to go so far as to be able to serialize the whole domain layer for execution in a remote environment (e.g. in a GUI), then you may have to jump through the hoop of providing a remote implementation of the repository. Of course, we know how efficient THAT can be.

    My point (although I’m not an authority) is that the repository pattern is not about implementation, but rather about concepts. It’s how your domain layer can get things done without breaking the rules.

  5. Tim High:

    Also, I’d propose a change to your last diagram: move the repository INTO the domain layer. Rename your “Repository” layer to “Data Access”. The relationships then become: ServiceLayer depends on Domain, ServiceLayer DOESN’T depend on DataAccess, DataAccess IMPLEMENTS Domain.

    Something like this:
    [ServiceLayer], [ServiceLayer]->[Domain], [Domain]^[DataAccess], [DataAccess]->[Database].”>

  6. Tim High:

    Darn… didn’t work. I’m trying to embed a yURL diagram :P
    http://yuml.me/diagram/scruffy/class/Client->ServiceLayer, [ServiceLayer]->[Domain], [Domain]^[DataAccess], [DataAccess]->[Database].

  7. admin:

    Hi Eric and Tim,

    I understand waht you mean guys :)

    So far, I really prefer to retrieve the persistent objects through ServiceLayer -> DAO (or whatever name :D ) -> Domain Objects. It always soved my problems in a such elegant way, and that’s the way they are doing it in the source code I downloaded and published above. They simply load the entities through a Service Layer and a DAO, and if they need something else they load it inside the Service Layer itself and then pass it to the Domain Object :

    final TrackingId trackingId = cargoRepository.nextTrackingId(); // –> Loading the Tracking ID
    final Location origin = locationRepository.find(originUnLocode); // –> Loading the Origin
    final Location destination = locationRepository.find(destinationUnLocode); // –> Loading the Destination
    final RouteSpecification routeSpecification = new RouteSpecification(origin, destination, arrivalDeadline);

    final Cargo cargo = new Cargo(trackingId, routeSpecification); // –> Sending the retrieved information to create the new Entity

    cargoRepository.store(cargo); // –> Saving the new Entity
    logger.info(“Booked new cargo with tracking id ” + cargo.trackingId().idString());

    return cargo.trackingId();

    But this is not the case we’re discussing here, because my MAJOR concern about the concept of the Repositories is that there is NO SINGLE example/reference neither in the book nor in the source code I downloaded about this kind of structure you described me, I mean, a Repository being injected inside a domain class, in order to retrieve something elese. That’s why I’m puzzled, because there is no such thing ( so far ) in the book, and I hear people saying something slightly different.

    But Ok, in my next post(s) I will come up with an example that looks like you guys gave me in your answers. So, we’ll be able to discuss more and analyze both source code ! ;)

  8. Leonardo Borges:

    Hi Marcio,
    Now I’m following your blog.

    As per your question, such an example would generally be based on the ActiveRecord pattern, coined and explained by Martin Fowler in his book ‘Patterns of Enterprise Application Architecture’.

    I have implemented it this way myself in a Java project and I have a couple of old posts about it: http://bit.ly/7xx8zA (in portuguese) and http://bit.ly/7P0mYd

    The formatting on these posts is not the best, since I changed plugins after publishing them, but you can get the idea.

  9. admin:

    Hi Leonardo,

    Thx for you comment !

    Well, I knew all of that :-) Actually my question was a kind of “joke” about what people have been saying about DDD and the Repository pattern itself, because people were claim something that was neither in the book, nor being practiced by the community, as I stated above, where I said that the Repository is a simply DAO like, that I’ve been using since the beginning of ages :-D

    Yes, I have to take care of this website, because I installed a skin that is not compatible with many plugins… I’ll do it soon.

  10. Leonardo Borges:

    Yeah I read the DDD book as well and honestly couldn’t tell the difference between a DAO and a Repository. I guess there isn’t any then… :)

  11. admin:

    Indeed, there are no differences at all !
    I guess at that time Mr. Evans thought “Repository” made more sense than “DAO” :D
    Anyway, the book is really nice, having lots of tips about how to better structure the application, “shielding” the domain layer.

  12. Abhijeet:

    Perhaps this might be of interest:

    http://debasishg.blogspot.com/2007/02/domain-driven-design-inject.html

    A dao is closer to the data layer, while a repository is closer to the domain.
    A repository is responsible for reconstituting the aggregate root.

    To quote the author of the above mentioned link:
    “The methods which the DAO exposes are supposed to be fine grained ones, which need to have higher reusability. OTOH, repositories are domain artifacts and speaks the language of the domain. They provide much coarse grained contracts to the Aggregates.”

  13. Marcio Marinho:

    Hi Abhijeet,

    Thanks for answering here :)

    About your quote : “A dao is closer to the data layer, while a repository is closer to the domain.
    A repository is responsible for reconstituting the aggregate root.”

    This is something that is NOT in the Eric Evans book, you can try to search it there, but you wont’t find a different code rather than I posted here, because my discussion is in light of his book.

Leave a comment