I will try to put forward a step by step strategy for domain layer design. This article will be a practical approach to establish a philosophy while designing domain layer. You should already know the domain layer design to solid your knowledge with this article. First and the foremost; lets assume we are pretty sure about what our domain needs and a domain expert are ready to help us forward!
In this article, I didn't go through every detail of the domain layer. Rather than that, I tried to tell core concepts of a domain layer. At the same time I tried to give a learning path to the user for further reading.
Hope it helps your first steps through the domain driven design.
Bounded context is a logical space for a model with the same terminology, concepts, rules and one ubiquitous language. Lets say we are working on one bounded context. Also we can assume that we have numerous tables and relationships among these tables.[As we discussed previously; our first goal in domain layer will be implementing an understandable hierarchy inside.]. One bounded context might be too big to catch at the first sight or it might need a separation inside to clarify its inner workings. In that situation we divide our bounded context into modules. These modules are like database schemas where we simulate some certain parts of the database. If we still have difficulties on understanding; we could give an example of a payment module inside our CRM software's bounded context. Well, now we find ourselves inside a bounded context's module and curious about what is next..?
Now we aim to standardize relationships inside our domain layer module elements to reduce communication overhead. For our example; we are inside the payment module now and we will use aggregates to group highly cohesive entities and make sure they communicate each other through the root entity's interface.[We can communicate with aggregate's child entities through the root entity, and every aggregate element can hold the reference of other aggregate's root entity.]
After we start the implementation of our entity classes inside aggregates, we will also make sure putting necessary logic inside these classes. There are some design methods that forces developers to use classes without any logic inside[POJO], yet it falls short if we consider object oriented principles. All classes comes with necessary logic to resemble a real world element. [Please check out this article for further reading, http://www.martinfowler.com/bliki/AnemicDomainModel.html].
What would be inside an aggregate?
- There might be a constructor. If there is a constructor, you explicitly force consumer of the class to set some variable for the class construction. If there is a constructor, there should also be a default constructor for the entity framework. There might not be any constructors inside it, that way you don't override the default constructor and you don't need to put any parameterless constructor inside your class.You could use a factory pattern for your root entity class' construction. For child entities you will use root entity for construction in order to be consistent on aggregate pattern.
- There could be validation code inside your aggregate classes. You can check fields' values to be set to expected range. [You may implement IValidatableObject to deal with validation inside your entity]
- Author of the class will put 1 to 1, 1 to Many etc. relations inside the classes. You can mark them virtual if you want to enable lazy loading or go default with the eager loading.
- These entity classes are either be a subclass of Entity or Value Object. [For deeper explanation about value objects, please check out Martin Fowler's blog.]
- You will have rules in your domain. According to these rules you filter your data to present it inside a UI element. In that case you deal with conditions in your queries. This is where you should check out the specification pattern. [http://martinfowler.com/apsupp/spec.pdf] For example you have a bank account. It should be 14 characters long and also starts with certain letters. You can specify these conditions and use them together, in other words AND them, to filter a specific set from a pile of data.
- There will be repositories. Because your class shouldn't take care of persisting itself to the database. This is called separation of concerns principle. [Think of and engine that is responsible for giving momentum to a vehicle. Does it build itself? No.] So what we do in here is, we create a repository class for every root entity inside aggregates and escalate its crud operations to the infrastructure layer. That way, we are not aware of any underlying database persistence technology. You can ask now how to do such a separation and answer will be found in dependency injection pattern.
Now we have every single element with also some extra features inside our aggregates and it is time to talk about domain services where we group simple operations to establish domain related complex operations. To begin with, we aren't holding any state information or transaction logic inside the domain service. Domain service only knows the operations about domain; if you put any infrastructure logic inside it, it won't confront the principles of domain layer design. Lets think of a situation where we assign a commodity or aspect of one entity to another. In this case, we create a service to check if the assignment could be made for the destination entity. Then we get the necessary data from one instance and assign it to another. Here we will have the origin and destination objects and transferable commodity as inputs. As you can see; our domain service aims to group module oriented operations to perform complex tasks.
What else we can need inside our domain layer? Answer might be a unit testing module. I personally recommend unit testing strategy especially for domain layer ever since its operations are core concepts that should be verified. That way we can keep the boundaries and consistency inside the domain layer and prevent corruption in the future.
In this article, I didn't go through every detail of the domain layer. Rather than that, I tried to tell core concepts of a domain layer. At the same time I tried to give a learning path to the user for further reading.
Hope it helps your first steps through the domain driven design.