Inside Paulo Abrantes' head
[ start | index | login or register ]
start > 2007-01-14 > 1

Software Developing: Domain Driven Design

Created by pabrantes. Last edited by pabrantes, 3 years and 181 days ago. Viewed 4,637 times. #6
[diff] [history] [edit] [rdf]
labels
attachments
3-tier-arch.png (5097)
uml-example.png (7653)

Software Developing: Domain Driven Design

Being a fan of Domain Driven Design and using that kind of design daily at my work I thought it would be interesting to write about it. Even if some still think it's just a buzz word it's not, and at >>FenixEDU I think we have proved that. Keep in mind that what's written it is my opinion only and it may not reflect the opinions of my co-workers nor my employers.

3-tier-arch But if it's not only a buzz word, what is it?
To understand what Domain Driven Design is first you need to know how an application is usually divided. Most of the time, it's used what we call a >>3 tier architecture where each tier - or layer - has a different responsibility:

  • The lowest one is what we call the data layer (or prevalence layer) and it is responsible for storing and retrieving all the application data in a certain way, which can go from database storage to live storage in memory (if you're interested in knowing more about memory storage, you can check, for instance, >>Prevlayer);
  • The second layer is responsible for the business logic, anything related with the problem itself should be there. Examples are: how many objects Y object X can have, or method M can only be accessed in the context C should be here;
  • Finally, on the top you have the presentation layer which is responsible to display the processed information to the user.
Domain Driven Design is not a technology nor a methodology, but a way of thinking on how to develop within the business logic layer. Such way of thinking consists in the following:
  • Finding a model for your problem;
  • Creating objects and their relations according to the problem (this is what we call the domain model);
  • Creating the business logic inside those objects.
Nowadays such architecture is not widely used, instead an Anemic Domain Model is used having most of the logic - or all of it - within a set of services.
An Anemic Domain Model, is a model which has the objects and the relations but lacks the business logic. It acts mostly like >>Data Transfer Objects (DTO) which find most (or all) the logic within the services, you can read more about such domains at >>Martin Fowler's bliki.
In this kind of approach, you're not actually doing a purist Object Oriented design, since the object behaviour is not within the object but rather on the service - almost like an utilitary class - and the domain objects itself are mainly data structures. With such design it's also easier to have replicated code (although this one can be avoided using good practices).

But do not think that the problem is the existence of a service layer. This layer is also present with Domain Driven Design, but instead of a thick layer filled with logic -which in my opinion is one of the biggest problems in the Anemic Domain Models-, this layer becomes a thin one which is used to give transactional context to safely operate with your domain objects. With such approach the services stop having the domain logic.
Service layer may also give you some sort of access control policies, although following a true OO philosophy you should put such logic within the object using techniques like code injection.

Having the business logic centred on the domain objects is good, because with that you centralise all the behaviour within each object. So when you need, for example, to change some sort of behaviour you just need to change the code inside the object and it's most of the time self contained.

With Domain Driven Design you have to ask yourself, "I have this model, and these functionalities, in which object do they belong?". Then in the thin service layer that exists there's only the need to call the methods within the objects that map those functionalities.

Then at the services you just have to call the methods within the objects that map such functionalitys.

uml-example Another property of Domain Driven - although Anemic Domain Models also have it - is the ability to navigate in the domain, this is possible due to the relations between objects that have been created to construct the domain model. So this for example if you have the two objects, for example, Department and Person with a model like the one in the figure. The Department object should have the methods that allow you to list, add and remove Person objects to the Department and vice-versa for the Person object.
With such a simple example, it doesn't seem that handy although when you start having complex domains with many relations such navigation turns out really handy.

Even being an enthusiast about such kind of architectures, I'm not obsessed with it, so if you have a really simple application with a small model probably there's no need to implement such kind design, a simple architecture with DTOs, and >>transactions scripts should do the trick, though such solution is not very scalable.
Another thing I know is that creating all the relations, along with their persistence, is difficult. My suggestion, is that if you want to go for this kind of design, use a domain model generator. At >>FenixEDU we have our own domain generator, which reads the domain model - includes objects from the model and their relations - and generates all the code of those objects, along with their relations and persistence code, you can read more about it in our >>wiki.

Some people might think design doesn't really matter, but after being for one year and an half developing with domain driven - and also getting totally addicted - I have to say that it does matter! I'm not saying it's the best way of developing, but at least is the best way i know to develop.

The idea of this post is not only to show about the main ideas of what domain driven design, but also to generate questions and discussion about it. So please feel free to comment. I'm looking forward for it.

Icon-Comment jff, 3 years and 230 days ago. Icon-Permalink

Hi!

You say that the business logic is "anything related with the problem itself", like "how many objects Y object X can have, or method M can only be accessed in the context C should be here". Then you say that "ADM is a model which has the objects and the relations but lacks the business logic".

My first question is very simple: if the model lacks the business logic, then it doesn't have anything related with the problem itself (I am just using your previous definition). But aren't the relations and the objects related with the problem? I think that your article leaves this concepts very unclear.

Also, you say that "So when you need, for example, to change some sort of behaviour you just need to change the code inside the object and it's most of the time self contained.". My question is to what extent can you claim that it is most of the time self contained. I would say it is very common to have the behaviour of certain objects dependent on other different objects (and by very common, I really mean the general case).

Finally, you say that "Some people might think design doesn't really matter, (...)" and I have to agree with you, except that I don't know anyone who claims that it doesn't matter smiley

As a final remark, let me just say that I wasn't able to completely understand the article. I think the problems were some undefined concepts that I don't know and I'm also confused about the context of DDD -- when can I use it?

Thanks for the article, and I hope I can get some answers and comments from other users as well.

Cheers, Joao

Icon-Comment jff, 3 years and 230 days ago. Icon-Permalink

Hi again!

I forgot to ask something. You say that DDD is "a way of thinking on how to develop within the business logic layer" You add that, "Such way of thinking consists in the following:

  • Finding a model for your problem;
  • Creating objects and their relations according to the problem (this is what we call the domain model); (...)"
The question is: what do you mean by finding a model for your problem?

As you already know (and who doesn't know can read in my blog -- >>http://www.joaoferreira.org ), I follow a mathematical approach when modeling problems. Mathematical models are nice, because you can manipulate the model and derive new/desired/interesting properties. So, my interest is in knowing how do you represent your problem.

Icon-Comment pabrantes, 3 years and 230 days ago. Icon-Permalink

Hello jff,

Well thanks for such great feedback let's see if I can answer your questions!

Then you say that "ADM is a model which has the objects and the relations but lacks the business logic".

Attention that when I say lacks the business logic doesn't mean that there is no logic at all. It means that the objects that model the problem don't have the business logic in them, the logic is somewhere else like in services.

My first question is very simple: if the model lacks the business logic, then it doesn't have anything related with the problem itself (I am just using your previous definition). But aren't the relations and the objects related with the problem? I think that your article leaves this concepts very unclear.

Yes, the relations and objects are not only related to the problem but part of the model itself! Maybe I just have written the following instead, the logic that should be inside the domain objects it's somewhere else.
But I think the best way is to give you an example!

Imagine that you have a system that manages a library. I think we both agree that two domain objects may be Book and LibraryUser. Now imagine two simple rules:

  1. A Book can only be reserved by one LibraryUser each time
  2. A LibraryUser can have at any given moment a maximum of three reserved Books
On an Anemic Model, where the domain objects have no logic you could have something like the following:

public class ServiceToReserveBook extends Service {

public void run(Integer libraryUserId, Integer bookId) { LibraryUserId user = readUserById(libraryUserId); Book book = readBookById(bookId);

if(book.isReserved()) { throw new ServiceException("Book is already reserved by a user"); } if(user.getRevervedBooks().size()>=3) { throw new ServiceException("Cannot reserve more than 3 books"); }

user.getReservedBook.add(book); book.setReserved(true); } }

Now as you can see the objects Book and LibraryUser do exist! They even have a relation from 1 to many, since the getReservedBook method returns a list of books. But the logic is not inside the domain objects, but on the service.

In the case of the DDD you would have the following:

public class LibraryUser extends DomainObject {

// more code here public void addReservedBook(Book book) { if (getReservedBooks().size()>2 || book.isReserved()) { throw new DomainException("error"); } getReservedBooks().add(book); } }

public class ServiceToReserveBook extends Service {

public void run(Integer libraryUserId, Integer bookId) { LibraryUserId user = readUserById(libraryUserId); Book book = readBookById(bookId); try { user.addReservedBook(book); }catch(DomainException e) { // code here } }

}

Now in this case the logic is self contained in the domain objects and the services only need operate the domain objects. This is good, because you stop replicating code on your services. If your business logic changes - for example, users could start reserving 5 books instead of 3 - you only needed to change code on the domain object and not on services!

Also, you say that "So when you need, for example, to change some sort of behaviour you just need to change the code inside the object and it's most of the time self contained.". My question is to what extent can you claim that it is most of the time self contained. I would say it is very common to have the behaviour of certain objects dependent on other different objects (and by very common, I really mean the general case).

In such context when I mentioned self contained I wanted to say that even after code modifications the object will preserve its interface and behaviour. If this happens, other objects using the modified object won't notice modifications. I see such kind of modification as a self contained one.

As a final remark, let me just say that I wasn't able to completely understand the article. I think the problems were some undefined concepts that I don't know and I'm also confused about the context of DDD -- when can I use it?

I'm thinking in starting to write more about DDD and design in general so you might catch up all the missing concepts. But when is DDD used? Well mostly when you have big complex domains because DDD is scalable.

what do you mean by finding a model for your problem?

With "finding a model for my problem" I mean finding a good abstraction of the problem and a way to map it in objects.

The main idea is to identify the entities involved on a certain problem (remember Book and LibraryUser on the previous example?), along with the functionalities (reserverBooks). Then create objects that represent those entities and methods on each object that represents the functionalities.

You may ask if there's a constructive way of finding such models, well I really don't know. I've learned to do it by feeling.
When you have a "draft version" you start asking questions regarding functionalities and see how the model behaves, most of the time you'll need to change it a few times until you reach a fixed point.

Icon-Comment balhau, 3 years and 229 days ago. Icon-Permalink

Nice post! I would like if you talk a litle more about this kind of philosophies… Have a nice day!

Icon-Comment pabrantes, 3 years and 228 days ago. Icon-Permalink

Thank you balhau!
You can read more about domain driven design in the next post, >>Software_Developing: More About Domain Driven Design.

Icon-Comment jff, 3 years and 226 days ago. Icon-Permalink

"In such context when I mentioned self contained I wanted to say that even after code modifications the object will preserve its interface and behaviour. If this happens, other objects using the modified object won't notice modifications. I see such kind of modification as a self contained one."

Isn't this encapsulation?

"You may ask if there's a constructive way of finding such models, well I really don't know. I've learned to do it by feeling. When you have a "draft version" you start asking questions regarding functionalities and see how the model behaves, most of the time you'll need to change it a few times until you reach a fixed point."

Do you know if someone is working on formal ways of doing this? Feeling and intuition get in your way quickly...

Thanks for the comment, things are more clear now. I still have to read the second post smiley

Icon-Comment pabrantes, 3 years and 226 days ago. Icon-Permalink

Isn't this encapsulation?

Yes, it is smiley

Do you know if someone is working on formal ways of doing this? Feeling and intuition get in your way quickly...

Thanks for the comment, things are more clear now. I still have to read the second post smiley

I really don't know if someone is working on formal ways, but I'll look into it and get back to you.

Thank you, for all the suggestions and comments about this article! Hope to have more comments from you on the next article.

Icon-Comment pabrantes, 3 years and 226 days ago. Icon-Permalink

Oh and jff, you can use the {quote} macro to quote, like the way I do, in my opinion it's better than using "".

Icon-Comment pabrantes, 3 years and 40 days ago. Icon-Permalink

Hello Richard,

Thank you for the link, it's quite an interesting lecture, although in my opinion he did left an important point out, the domain modelling language. He does talk about a domain specific language, but that's not the same.

The Domain Specific Language as Ramnivas Laddad presents it it's a way of programming that has the objective of giving semantic and better reading of the created code.
A Domain Modeling Language on the other hand, is a language where you declare abstract concepts of domain entities and how entities relate between each other, then a code generator takes care of actual object creation.

I didn't quite understand why he only wanted to use factories to create objects thought.

Icon-Comment pabrantes, 3 years and 40 days ago. Icon-Permalink

Oh and Richard I forgot to tell you, may be you're interested in checking also the follow up posts: Regards,

Paulo

Icon-Comment Setya, 3 years and 39 days ago. Icon-Permalink

Hi,

Thanks for the DDD articles.

From your example about Library system, is it really LibraryUser's responsibility to validate number of reserved books / book reservation status? Shouldn't we add another domain model called LibraryOfficer to do the validations ?

Best Regards,

Setya

Icon-Comment pabrantes, 3 years and 39 days ago. Icon-Permalink

Hi Setya,

From your example about Library system, is it really LibraryUser's responsibility to validate number of reserved books / book reservation status? Shouldn't we add another domain model called LibraryOfficer to do the validations ?
Setya

You've put up a interesting question, the logic you are pointing out is actually domain logic from the relation between LibraryUser and Book not the LibraryUser or Book entities itself.

I wouldn't go for another entity that would just validate, because it's something that the relation between the two objects, LibraryUser and Book, should be able to tell by itself.

In my opinion, there are various approaches to deal with these cases, one is to actually put the relation logic coupled to nee of the ends of the relation - which was what I did in this example- (attention, not saying it's the best way), use listenners or generate a "relation class" for each class that actually contains semantic.

The first approach you already seen it, because it's the one I presented on the example on the comments.
The second approach, is to create a listenner on the relation - using for example the >>Observer Design Pattern and check the domain login when the relation is changed. Finally the third one, where the relation itself is a entity, this happens because, as you identified the relation as logic. So we would have a new entity named Loan where the constructor would, for example, look like:

public class Loan extends DomainObject { public Loan(LibraryUser user, Book book) { if (getReservedBooks().size()>2 || book.isReserved()) { throw new DomainException("error"); } user.getReservedBooks().add(book); } }

The idea is that Library stops having a direct relation with book, but actually with Loan. So:

  • LibraryUser as a 1 to many relation with Loan.
  • Book as a 1 to many relation Loan.
And all the logic regarding the relation stays in the Loan class.

Icon-Comment Setya, 3 years and 38 days ago. Icon-Permalink

pabrantes,

The reason why I come up with my logic is because I think DDD should represent what happens in the real world.

And AFAIK that's what happens in the Library System.

When you go to a library where you're registered as Library User, after finding the books that interest you than you hand them over to Library Officer which do all the validations you've mentioned.

And I believe Library Officer's responsibilities are not just validate like you said but a lot more than that.

But I basically understand why you came up with your example because you just meant to simplify things and didn't really mean to address my use case.

Anyway, that's how I learn things sometimes, by trying to present my own idea and hear what people think about it, and I surely learn a lot from what you've said.

Once again, nice article, pabrantes.

Best Regards,

Setya

Icon-Comment pabrantes, 3 years and 36 days ago. Icon-Permalink

Hello again Setya,

The reason why I come up with my logic is because I think DDD should represent what happens in the real world.
Setya

I do agree with you in this point, DDD tries to come up with a model that represents the business process.

In my opinion the library officer does that verification because he knows the semantic of the relationship between LibraryUser and Book. I would model the scenario you are presenting the following way:

The Person object would start havinga 0..1 relation with LibraryOfficer object. If a person as a LibraryOffice object associated then, that person can create Loan objects. So the verification wouldn't actually be in LibraryOfficer's logic, but would be triggered by him while trying to create a new Loan.

I think this would be a good solution.

Anyway, that's how I learn things sometimes, by trying to present my own idea and hear what people think about it, and I surely learn a lot from what you've said.
Setya

It's probably one of the best ways to learn, exposing and discussing ideas with others. I'm also fond of such method.

Thank you for all the feedback. I really hope you've learned something with the three articles about DDD.

Best Regards,

Paulo

Please login to www.pabrantes.net.
Who am I?
paulo-roca2My name is Paulo Abrantes AKA pabrantes and I'm a software developer. I'm currently employed at >>CIIST working as a Java developer in >>FenixEDU.

This blog is mostly about Java programming, domain driven design and snipsnap bliki developing. Everything written in this blog is my personal opinion and it may not reflect the opinions of my employer and co-workers.


Blog subscription
subscribe by rss subscribe by email

Links
>> Home
>> Paulo's Profile
>> Post History
>> Add to Technorati Favorites
>> Paulo's Photo Gallery
>> WishList
>> Posting without Login

Search Blog
Fellow Bloggers

Recent Posts

Blog: Almost an year since last post
Java Programming: Bytecode Injection
Intermission: Sorry For Downtime
Software Developing: Studying The Bliki Domain Model
SnipSnap Developing: Trying to settle a roadmap
System Administration: Load Balancing with Apache
Blogging: Two years have passed
Software Developing: The SnipSnap Saga
Java Programming: Getting your code spicy with Groovy
Software Developing: Fluent Interfaces
Software Developing: Implementing a ShoutBox on SnipsSnip
Software Developing: SnipSnap, SnipIt and SnipSnip
Java Programming: Proxies and Access Control
Java Programming: Proxies and References
Java Programming: References' Package

For older posts, please refer to post-history for a complete Post History

Logged in Users: (0)
… and 3 Guests.
This is a modified version of snipsnap.org created by >>Paulo Abrantes