Monday, 16 February 2009

Factories and Repositories

In my last post I talked about entities, the domain objects that have an identity and a life. In this post I want to talk about the management of the lifetime of entities. We start at the beginning.

Creation of objects

Creation of objects could be very simple:
new RadioProgram(); // C#
or
RadioProgram.Create; //Delphi
But what when it is not that simple and there are a lot of extra dependencies and relations that should  be connected? We can use the Factory pattern for this purpose. When we use a Factory we use an object to create another object.

class RadioProgram
{
    public RadioProgram()
    {
    }

    public RadioStation { get; set; }
}

class RadioProgramFactory
{
    private RadioStation defaultStation = new RadioStation("DutchRadio");

    public RadioProgram CreateProgram()
    {
        RadioProgram program = new RadioProgram();
        program.RadioStation = this.defaultStation;
        return program;
    }
}

In the code above I create a RadioProgram which is only valid when there is a radio station assigned to it. (actually, normally this is not needed and added later, but I lack the fantasy to think of an original example). So to get a valid RadioProgram we will have to create a RadioProgramFactory and call the CreateProgram method.

Repositories

Now that we have a nice domain object, we need a place to store it. There are several places where we can store objects. We can store them in databases, in XML files, in binary streams and in a dozen of other places. But why should I (read the domain) should care about storage or persistency? We shouldn't care about it. In Domain Driven Design we create the domain with Persistence Ignorance in mind. The objects in the domain don't have to know when, where, why or even if they get persisted. The only thing we can/should do in the domain is to register the domain objects to Repositories.
A repository can be a big thing. We can use it to store objects, we can use it to find objects (in several ways) and we can use repositories to delete objects. But in the domain we won't actually do these things. Hmm. that is confusing.
OK, on one site I say that the domain should be able to talk to the repository. On the other side I say, the domain should not know anything about Persistence. To solve this problem we can say the following: The domain should create the definition (an interface) for the repository, it will tell what the domain expects from a repository.
Outside the domain we can have multiple implementations of a repository interface. With one implementation we talk to a legacy database, with another implementation we talk with a newly created database. During run-time we can say to the application which implementation it should use. This technique can be used for other things as well and is called Dependency Injection (although it has also some other names).
So how does a repository looks like? Here is an example of the interface that is in the domain:
public interface RadioProgramRepositoryInterface
{
    void Add(RadioProgram program);
    void Update(RadioProgram program);
    void Delete(RadioProgram program);

    RadioProgram GetProgram(string programName); // programName is the identifier in this case.
    List<RadioProgram> All(); // Get a list of all available RadioPrograms.
    List<RadioProgram> GetProgramQueueForStation(RadioStation aStation); // Get the program queue for a specific station.
}
So basically you can do anything in a repository that you can also do with a database, but the different is that you don't know what kind of database it is, it could also be an In-Memory stack or some files somewhere on the Internet. The last method is used to get a specific list of radio programs (programs that are queued for a specific station) This is a pretty easy selection, but it could be possible to get very complicated selections. In that case we can use Specifications or some kind of Query language. I will not go further into those topics, because they are to complicated to handle in short and I don't have any experience with them.

Dependency Injection

Before we can really use the persistent specific repositories we need to be able to find out which repository we need to use. This part of domain driven design can be difficult and it is easier said than done.
In my current project we maintain a list of interfaces and implementations that can be injected. (ie. RadioProgramRepositoryInterface - MemoryRadioProgramRepository, where the later is the implementation). The list is created at start-up time by a bootstrapper and this list is stored in a domain object called "World". This World object is a static object so every other object can reach it when necessary.
Of course this is not the best solution there is, but it works in our project. For more information about dependency injection you can read the following article: http://martinfowler.com/articles/injection.html
Closing words
Recently someone else also started a series about the basics of DDD, although is not very organized in the topic order, he is better organized in the topics itself. You can find his articles here (starting here)

Friday, 13 February 2009

Domain entities and value objects

Three weeks after my last post, it is time to go on with the DDD series.
In this short post I will talk about entities and value objects. These concepts are not new, but are the very important in DDD.

Value Objects

Value Objects are very simple objects which are in the domain for convenience. Nobody cares about the lifetime of these objects because they are very simple to build up again. Some examples of value objects are:
  • Color
  • Date/time
  • Money
The reason why they don't have a lifetime is because we don't care what instance we have. new Euro(10); and new Euro(10); have the same value, we don't care that they don't have the same reference, as long as we can say "We have both 10 euro" it is fine.

Entities

Entities are different. Entities have an identity. new Person("Jan"); and new Person("Jan"); are not the same. They have the same name, yes, but they don't have the same age, or the same length, perhaps they don't even have the same nationality.
This means an Entity is unique and a lifetime should be maintained (even when the application is closed). This means that we should be able to store the entity somewhere and request it again when we need it. And when we request the same entity twice, we need to get the same object.
In my monitoring system Devices and Services are entities. One device can only exist at one place and one Service can only be on one device (even though services can look the same, how we can solve this I will explain in another post :))

Lifetime management

Because entities have a lifetime we need some lifetime management. Although I will explain the following concepts in detail in another topic, I will mention them now to avoid some questions.
The lifetime of an entity is as follow:
  • An entity is created, this can be done by using the constructor, or, when it is more difficult and more than one entity has to be created, a Factory can be used.
  • An entity is registered to a Repository
  • To get a registered entity, we ask the Repository. We can also ask for a list of entities or search through entities.
  • When we want to delete an entity we tell the Repository to delete the entity.
In the next post we will talk more about the Factory and the Repository.