Saturday, February 27, 2016

Domain Driven Design: a "hands on" example (part 2 of 3)

I am glad that this series introducing Domain Driven Design has pleased you readers. Thank you guys for all the positive feedback I have received. So, let's start the second part!

Just to remind you, I ended up with the following solution in the first post of this series:

Picture 1: A DDD approach to the e-Commerce Domain

I am going to pick only two Bounded Contexts as examples for modelling. As I said before, some of these contexts can even be supported by off-the-shelf applications, as the intent here is not to develop the whole solution basically from scratch. I thought it would be a good thing if I worked on the contexts of  the "Product Catalog Website" (the Core Subdomain) and a Support Subdomain (my choice was the "Orders" one).

Concepts for creating Domain Class Models in a DDD fashion

First of all, I would like to state here that any OOD (Object Oriented Design) know-how is useful for constructing Domain Class Models, it doesn't matter if you are a DDD enthusiast or not. For example, I like to use concepts from, GRASP (General Responsibility Assignment Software patterns - Craig Larman) and GOF patterns when I am creating my models. A solid understanding of UML is very useful too. Let's take a look in some core concepts that you must know when modeling a Domain Class Model.

Entity

It is possible to find many definitions for "Entity" in literature. It can represent many different things. However, for DDD, the meaning of Entity is very clear. Vernon's book, "Implementing Domain Driven Design", has an excellent definition for Entity:

"We design a domain concept as an Entity when we care about its individuality, when distinguishing if from all objects in a system is a mandatory constraint. An Entity is a unique thing and is capable of being changed continuously over a long period of time."

Mutability and unique identity are the two main characteristics entities have.

Value Object

Your capacity to identify Domain concepts and model then as "Value Objects" is one of the most powerful tools you can use in order to succeed in creating DDD models. Why? Well, if you are not able to identify them, you tend to model everything as an "Entity".

It is hard to portray all the nuances of it in a post as short as this one. Let's try to make it clear in the class model (further). For now, keep in mind that "Value Objects" do not need to be treated as unique. Normally, they are immutable and their methods (when available) should provide a "Side-Effect-Free" behavior (not changing the object state).

Aggregate

Think in an Aggregate as a block composed for different pieces and, even that these pieces might exist by them self inside your context, it would not make any sense using them separately. Let's see this again in the class model section.

Modeling

Well... it is time to start modeling and I have one important tip: when modeling, FORGET about data models (relational models) and do not think about persistence! It can really harm the way you see your modeling scenario. If you want to succeed in applying DDD, this mental approach is necessary.

These are just hypothetical models which I created in order to support our example. Please, do not expect fully functional models!

The "Product Catalog" context model

Based on everything that has been discussed above, this is my solution for the "Product Catalog" context:


Picture 2: The "Product Catalog" context model

Now, let's dig into the details of this simple class model. First of all, it is possible to notice that there is only one class modeled as "Entity", regardless of the fact this model is a small one. Why?

The Classes "Weight" and "Dimension" are very similar: both represent a value and how it should be interpreted. If you look at these classes' methods, you will notice that there are no "set" methods. An instance of "Weight", for instance, should have all of its attributes set when it is constructed. In order to achieve this, I might use a Constructor with all the parameters or a kind of "Creator" method.

Remember what was said about "Value Object" above? I don't need to change its data once it has been created. It works well being immutable and consequently allows me to be free of all the complexities related to "Entities".

In the case of the class "Review", well... I believe most people would model it as an "Entity". But I think it fits well as a "Value Object". Its relationship with "Product", does not have a strong meaning inside the context. A "Product" does not depend on "Review" to be available in the catalog. Once a instance of "Review" is created, I do not see any reason to change it. So, I decided to model it as a  "Value Object" too.

Finally, the "Product" class. It is an "Entity" for sure because I need it being uniquely identifiable. Also, I must be able to change its state and might even want to track changes on it. It is an "Aggregate Root" too because it aggregates both "Shipping Weight" and "Dimension" in a composition relationship.

The real meaning of aggregation here is: you should see those objects as inseparable. For example: once a instance of the class "Weigh" is created and set to a instance of "Product" as the "Shipping Weight", every time you load "Product" from your persistence layer, it should contains the "Shipping Weight" too. That is why you should be careful when modeling aggregates in order not to create monsters which will bring you problems (probably related to persistence complexity and performance).

Now the "Product" class methods. Can you explain why it is apparently missing some set methods? Why doesn't it have a "get" method to return the list / array of pictures? What the hell are those methods "activate()" and "deactivate()"?

In order to create an instance of "Product", you must supply at least the product ID and the inventory code (product identifier coming from another bounded context, the inventory context). This data is a kind of immutable data and it would not make any sense to allow a "Product" instance creation without it.  Before you ask, I prefer not to use database features like identity columns, sequences and so on for ID generation. This way, I've got my "Entity" classes not dependent on persistence in order to get an unique identifier.

Moving on, I modeled "Product" having the following "Status" state machine:


Picture 3: The "Product" class "Status" state machine

This way, the system would support a product registration for future data input without resulting on it automatically appearing in the catalog.

Without exposing the list / array of pictures, the "Product" class has total control over any business logic regarding product pictures. Maximum number of pictures, position, duplicated pictures, etc; all these kind of rules can be managed and ensured by the expert class. So, I've got more cohesion and, in some cases, low coupling too.

The method "activate()" is crucial: it must guarantee that, before changing the state of an instance to "Active", all required data have been provided and there is no violation regarding machine status flow. The "deactive()" method should play a similar role on treating its pertinent business rules.

In this manner, applying all of these concepts, you avoid what many authors call of "Anemic Domain" (Fowler, Martin) once your classes provide real business functionality and not only data.

The "Orders" context model

All concepts previously discussed are valid for the "Orders" context too. So let's take a look at the model:


Picture 4: The "Orders" context model

The "Order" class is an "Entity" and "Aggregate" by same reason explained above (in the "Product Catalog" model). It has methods to control all its pertinent business rules like, "cancel()", "close()", "calculateTotal()" and so on; it controls how new instances of "Item" are created, added and removed. Therefore, we can say that it is an expert and has high cohesion.

The "Product" class here represents a totally different concept. It basically represents an "Order Item". I modeled an interface "Item" just to add a little bit more of "low coupling" to the solution. Imagine that product data will come from other context ("Product Catalog" context), but the "Order" application logic should be unaware of this.

In this manner, application classes interacting with the "Order" class don't need even know about the existence of the "Product" class, even though it has a different meaning and its own context. I haven't talked about application logic classes before and I will explain it in the last part of this series.

Conclusion

I tried to be succinct and clear as much as possible in order to share how I usually think when I model using DDD concepts. I hope these tips and insights might be useful for you guys. I would love to be in touch by email, comments, etc. with anyone who wants to discuss about this subject. In the third and last part, I will show some code examples. Best regards!

Related posts:
Domain Driven Design: what is it really about? 
Domain Driven Design: a "hands on" example (part 1 of 3)

Friday, February 12, 2016

Domain Driven Design: a "hands on" example (part 1 of 3)

I have received feedback from some readers of my last post "Domain Driven Design: what is it really about?". Some of them mentioned that it is pretty difficult to get the hang of it, once DDD concepts seem to be very abstract. I must admit: it was not easy for me! Therefore, I believe there is no one who is the owner of the truth. I am still learning... and probably it will never end.

This way, my goal here is just to try helping others to understand some of the core concepts of DDD and how to apply it. Please, do not expect any kind of good practices handbook coming from this post! I will share with you guys part of my knowledge and experience on approaching software modeling problems using the DDD philosophy.

The problem

I will pick an example from an "e-Commerce" System. You will find a pretty similar one (but not evolved as the one presented here) in the book "Implementing Domain-Driven Design", by Vaughn Vernon (which I recommended in my last post). Vernon's book can be a little bit hard to follow and understand at first, so I recommend that you fight yourself and read the three first chapters. There are a lot of concepts and things that seem to be weird and confusing, but might become clear at the end.

So, let's go to our hypothetical example. You have to build a whole new system in order to support the e-Commerce operation of the company where you work.  Your solution must include:
  • Product search, Catalog: users on your website must be able to search and see information about products.
  • Orders, Payment and Delivery: your customers should be able to place orders, pay for it and receive their goodies.
  • Inventory: your solution must provide inventory control for each product that is available to sell.
  • Authorization, Authentication: your solution must be able to identify and authorize valid users; the same for customers.
  • Customer management: your solution must be able to manage customer registries.

A non DDD approach to the problem

Given the information above, without applying DDD, we could approach the problem this way:

Picture 1: a possible solution (not a Domain Driven Design one) 

I have used that package notation but it is not important. It could be anything, such as drawing circles in a white board. The important thing to notice is: this solution is intended to tackle the problem using a single Bounded Context.

This way, you will have to use all your knowledge of OOD (Object Oriented Design) in order to construct a Domain Class Model that supports all these business  challenges. This task can be very, very hard! It would be necessary to represent many business requirements and behavior in a single Domain Model. Believe me: it can be a pain in the ass even for those more experienced professionals.

I will not dig in architecture details about how this system / application could be built. The fact is: we have only one Domain Class Model and we can develop a single application for this. Have you noticed what Bounded Context means here? Having only one Bounded Context means: a single view of the problem = a single Domain Class Model to solve all that business challenges. We are going to talk more about Bounded Contexts further in this post.

Applying DDD

Let's start applying some DDD to this problem. We should start identifying possible Subdomains inside our Domain. What the hell does it mean? Basically, a Domain is the business itself. It is what your company do and, consequently, it is the "problem" you want to solve. As we have to build an e-Commerce System, our Domain is the e-Commerce business. A Domain has its own strategic challenges which can be seen as Subdomains.

In other words, a Domain can be split in several Subdomains (a small specific view of part of the problem). Each of them can be classified as Core, Support and Generic. Once you have split your Domain in Subdomains, it is a good practice and actually desired that you set a Bounded Context for each Subdomain. I have explained concepts like "Bounded Context" and "Ubiquitous Language" in the post which has led me to this one (see the link on top), but I will try to reinforce now. 

According to Vernon's book (see the link on top again), the following description would be a good definition for "Bounded Context":

"A set of specific software models, a specific solution expressing its own ubiquitous language.
It is a desirable goal to align Subdomains one-to-one with Bounded Contexts.
Does not necessarily encompass only the domain model. It often marks of a system, an application and / or a business service."

This way, my sense tells me that a good solution for the problem, applying these DDD concepts, would be:
Picture 2: DDD approach to the problem

As it is possible to observe, I took strategic business challenges which are pertinent to the Domain and figured out some Subdomains. For each of them, I set a Bounded Context and classified it accordingly (Core, Support or Generic). Usually, there is only one Core, that represents the main part of the Domain. In this case, I think that the "Product Catalog" Subdomain is the Core because it is what customers will be interacting and, therefore, is from where the revenue will come (customer shopping). Others Subdomains were classified as Support and Generic.

Support Subdomains are like auxiliary ones. In practice, you set a Bounded Context to it and create a specific application. It will work as a support application for the Core Domain application, however, support applications will have its own model.

Generic Subdomains are like support ones, but they have a strong particularity: they are so generic solutions that they could be used not only in the Domain it was created, but they could be used by others Domains too. It is completely reasonably that your "Acces Control Application", when well designed, can be reused to support other Domains which not the e-Commerce, for instance. That is why they are called Generic.

It is not difficult to realize that I have just organized my ideas about how I intend to approach the problem, and I have used DDD concepts in order to accomplish that. So, I ended up realizing that I would get a bunch of applications to develop. Perhaps, for some of these applications (like the Inventory one), an off-the-shelf software application would fit well. Also, it is perceptible that and integration between all these applications would be necessary.

If you imagine a real life scenario in a big e-Commerce company, it is possible that more than one team is allocated to support this operation. Possibly one team per Bounded Context.

DDD offers a way to classify and treat relationships between Bounded Contexts. If you have heard terms like "Partnership", "Shared Kernel", "Customer-Supplier", "Conformist", "Anti-corruption  Layer", "Open Host Service", "Published Language", "Separate Ways" and "Big Ball of Mud" (my favorite one), you probably know what I am talking about. The details of these concepts are out of scope of this "hands on"  example, but all of them can be found in the recommended book above (see the link on top).

Conclusion

We have just seen a problem description, a very simple and traditional way to approach it and a Domain Driven Design approach too. In this manner, we figured out that we will have several applications, very specialized applications, and that it is going to be necessary some effort in order to integrate them. In the next post, I will explore more technical examples regarding the Domain Class Model of some of these applications. For each Bounded Context, we should build a Domain Class Model. It is there that your OOD (Object Oriented Design) knowledge shines :)

Related Posts:
Domain Driven Design: what is it really about?
Domain Driven Design: a "hands on" example (part 2 of 3)