Friday, October 5, 2012

Domain Driven Design - An Introduction.

 
Hi there,

I hope everyone is having a great week and that you are ready for the weekend. I this post I would like to explore a interesting programming concept and technique called Domain Driven Design and/or Domain-Centric programming.

Let me go in more detail into this concept. Data-centric generally means that we build a system around an understanding of the data you’ll be interacting with. The typical approach is to first model a database. The second step is to then take the model (the database) and make sure that resembles the domain (the business). The third step is to take a multi-tier approach to the model and the business where the UI, business Logic and database live in different layers.

At this point you might be thinking, well, Microsoft Dynamics AX is built like this, and the answer is yes. AX, in my opinion, uses a domain driven approach as it has been build for a large number of business models. In turn, the actual business domain (a business that just purchased AX) can be coupled to AX and vice-versa.

Domain-centric design focuses on the problem domain as a whole, which not only includes the data, but also the behavior. So we not only focus on the fact that an employee entity has a First Name, but also on the fact that the entity can get a vacation, or a raise.


The tool used is object oriented programming (OOP), which relies on the power of classes and encapsulation. The idea behind domain driven design is to build a system in a manner that’s reflective of the actual problem domain we are trying to solve. This is where business users come into play. For example, they’ll help you understand how the actual system currently works (even if it’s a manual paper process. and/or existing AX process) and how it ought to work. .

Anyone who’s gone through the above knows that learning a new business is the most complicated part of any programming job. For that reason, there are real benefits to making our code resemble, as much as possible, the domain.


Essentially what I’m talking about is communication. If your users are talking about Strategic Outcomes, which a month ago meant nothing to us, and our code talks about Strategic Outcomes then some of the ambiguity and much of the potential misinterpretation is cleaned up.

Ultimately, this is the true purpose of an enterprise developer – to understand the problem domain.

 


Doing domain driven design (DDD) design doesn’t necessarily mean we have to start with modeling the domain but rather it means that we should focus on the domain and let the business (domain in this case) drive our next steps. We may agree at this point that we should start with our data model (or existing data model such a AX).

DDD extends our organizational toolbox and borrows from well-known industry patterns. For example, In AX modules help us organize a larger single model into smaller chunks.
 
In most enterprise systems there are course-grained areas of responsibility. DDD calls this top level of organization a Bounded Context.
 
Let's take workers' compensation insurance policies as an example. These need to be concerned with elements such as:
  • Quoting and sales
  • General policy workflow (renewals, terminations)
  • Auditing payroll estimation
  • Quarterly self-estimates
  • Setting and managing rates
  • Issuing commissions to agencies and brokers
  • Billing customers
  • General accounting
  • Determining acceptable exposures (underwriting)

We could incorporate all of this into a single system, but in doing so leads us to many issues down the road. Business users might understand general workflow versus a policy in the context of payroll auditing in two very different ways. If we use the same policy class, we are pushing the limitations of that class and getting away from best practices such as the Single Responsibility Principle (SRP).

Systems that fail to isolate models often fall into an architectural style called The Big Ball of Mud. Also, DDD nudges you toward identifying contexts and constraining your modeling effort within particular contexts. We can use a simple diagram, called a context map, to explore the boundaries of our system.
 
 
Source: Microsoft
 

This is why when writing the code for our model, we need to understand the domain and resemble it (a representation of the model that is) in our code. For example, let’s assume for a minute that we are doing an implementation for a car dealership and that we've talked to our client and a few salespeople, and we’ve realized that a major point is keeping track of the inter-dependency between upgrade options.


Then, in code (and remember this is conceptual and does not have to be taken to AX and/or .NET) we’ll create four classes/objects to support the theory of "-dependency between upgrade options":
 

public class Car
{
private Model _model;
private List<Upgrade> _upgrades;
public void Add(Upgrade upgrade){ //todo }
}

public class Model
{
private int _id;
private int _year;
private string _name;

public ReadOnlyCollection<Upgrade> GetAvailableUpgrades()
{
return null;
}

}

public class Upgrade
{
private int _id;
private string _name;

public ReadOnlyCollection<Upgrade> RequiredUpgrades
{
get { return null; }
}

}

public class Car
{

private Model _model;
private List<Upgrade> _upgrades;

public void Add(Upgrade upgrade)
{
_upgrades.Add(upgrade);
}

public ReadOnlyCollection<Upgrade> MissingUpgradeDependencies()
{

List<Upgrade> missingUpgrades = new List<Upgrade>();

foreach (Upgrade upgrade in _upgrades)
{

foreach (Upgrade dependentUpgrade in upgrade.RequiredUpgrades)
{

if (!_upgrades.Contains(dependentUpgrade)
&& !missingUpgrades.Contains(dependentUpgrade))
{

missingUpgrades.Add(dependentUpgrade);

}

}

}

return missingUpgrades.AsReadOnly();

}

}


As you can see in the above code, we first implemented the Add method. Then we implement a method that allows us to retrieve all the missing upgrades for a specific car. The code should reflect all concepts exposed by the model. Classes and methods should be named according to the names defined by the domain.

Furthermore, associations, compositions, aggregations and sometimes even inheritances should be extracted from the model.  Sometimes, during implementation, we realise that some of the domain concepts discussed and added to the model don't actually fit well together and some changes are necessary. When it happens, we should discuss the problems and/or limitations with the domain experts and refactor the domain model in order to favour a more precise implementation, without ever distorting the business significance of the design.

Ultimately, the code is the most important artefact of a software project and it needs to work efficiently. Regardless of what many experts in the subject say, code implementation will have some impact on the design. However, we need to be careful and very selective about which aspects of the code can influence design changes. As a rule, try as much as we can to never let technical frameworks limitations influence our design, but as we know, every rule has exceptions.
 
Again, the code above is just conceptual for argument's sake, and it is a good exercise for now to highlight how we might get started and what that start might look like. The main idea behind the above code is that "simulates" the business need.

Becoming proficient with object-oriented programming is not an easy task. I believe is within the reach of most people, but it takes dedication, book learning, and practice. It also helps if you adopt an attitude of craftsmanship and continual learning.

Well folks, I hope you found this article interesting, and that it has helped you in any way to remind you of the basics of programming.

Until the next time.



 

9 comments:

  1. First you start of by explaining the Data-centric approach and say:
    "At this point you might be thinking, well, Microsoft Dynamics AX is built like this, and the answer is yes."
    In the very next sentence you say:
    "AX, in my opinion, uses a domain driven approach as it has been build for a large number of business models."
    This is a bit confusing.
    In my opinion AX is built using the data-centric approach. There isn't any domain-driven design artefacts (maybe at the kernel stuff that we cannot see). As you can notice, even the PurchTable doesn't have a reference to its PurchLines. I haven't seen any aggregates, value objects, services or repository objects in the design, all of which are the building blocks of DDD.
    The approach taken by AX isn't a bad design. It makes development really easy and fast, but in terms of programming concepts forced upon the developers there are none. I would even say that AX promotes bad programming. It all reminds me of WebForms that .NET still promotes.
    Everything in AX is done using static methods which makes it harder to test anything. I really doubt that the AX team does any automated testing in the business logic (again, things might be better in the kernel).
    There is very little or non-existent documentation, except for incomplete training materials, forums and blogs like yours (btw, thank you very much for sharing your knowledge ;)).

    Bojan Milenkoski

    ReplyDelete
    Replies
    1. Hi Bojan,

      Thanks for sharing your thoughts. They are appreciated here. With this in mind, I would also challenge you a bit.

      First: "Everything in AX is done using static methods which makes it harder to test anything"

      I would have to disagree with you as not everything in AX uses static methods. As a matter of fact, AX uses a amazing OOP model that involves abstract classes, the use of inheritance in both classes and tables, the use of interfaces, and aggregation. Just take a look at the SalesFormLetter class and you'll notice that there is a clear OOP design, which in turn uses a DDD (This is just my opinion).

      Second: "even the PurchTable doesn't have a reference to its PurchLines"

      I'm not sure what do you mean by reference in your response. For me a reference exists between these two tables through a PK and FK. It would be great if you could explain if this is not what you meant to bring more flavor to the conversation.

      Again, I look forward to hearing from you and thanks for sharing and challenging me.

      Delete
  2. Bojan, sir. There are relations between PurchTable and Purchlines. There are aggregates in the OLAP and services in the AIF. The development platform inherited from former Axapta invited to a quick and easy development, and there are code artifacts inherited from previous versions that might appear "outdated", but that is the life of a huge solution like AX.
    The sentence "Everything in AX is done using static methods which makes it harder to test anything" doesn't make any sense to me, because there are more instance-methods than static methods, I am sure. Unless you're referring to something else.
    AX might not be a school-book example of a DDD solution, but it is definitely getting better and better for each version. With the latest release (AX 2012) it delivers an even more scalable and widely supported platform than before.
    Sorry to hear you've been unable to find good training and learning material. AX is a steep learning curve, but I'd argue that you should be able to get up to speed with most of the necessary bits within a year of training, maybe sooner.

    ReplyDelete
    Replies
    1. Hi Skaue,

      Thanks for sharing your thoughts with us. In addition, thank you for the clarification and objective view.

      I hope all is well.

      Delete
  3. Hi again!

    I might have come a bit strong with my words in my previous comment :). So, a disclaimer from me is needed. I do think that Dynamics AX is a great peace of software engineering. If I was part of the development team I would be really proud.

    With that in mind, I want to clear up on some of my thoughts. I think that the post as a whole is a nice introduction to DDD concepts. But setting Dynamics AX as an example of DDD would add confusion to the term itself.

    First: "Everything in AX is done using static methods which makes it harder to test anything".
    OK, not everything is done using static methods. I was mostly referring to table methods like find(), findByXXX(), exist(), etc. These methods belong to a Repository object.

    Second: "even the PurchTable doesn't have a reference to its PurchLines"
    Yes, there are FK, but in DDD, having the PurchTable as Aggregate, I would usually write something like:

    1. I wouldn't need to write a query to get the lines.
    List<> purchLines = purchTable.getPurchLines();

    2. When I save the Aggregate (PurchTable object), the lines are also saved.
    purchTable.addPurchLine(purchLine);
    purchTableRepository.save(purchTable);

    So again I would conclude that while AX is a greatly written software (excluding some areas), it does not follow the DDD approach. And saying that it does, just adds to developers' confusion about DDD.

    And about the "good training and learning material", I did find them, but as all training materials they are incomplete. If there were no blogs, like John's, I wouldn't know how to do a lot of things. My real disappointment comes from the code documentation. Just have a look at MSDN. There are rarely any documentation for anything. For example: http://msdn.microsoft.com/en-us/library/aa870426(v=ax.50).aspx. You cannot find out what 90% of non-inherited methods in the PurchTable are doing. What are the parameters? What does the method return (not just the return type)? What are the possible exceptions? Does it make any changes to the system? There are numerous examples.

    If I have missed anything that requires further discussion, please write it out.

    Thanks to John for making this a good place to have these sorts of discussions.

    ReplyDelete
    Replies
    1. Hi Bojan,

      I see where the confusion can be when talking about DDD. Thanks for sharing your thoughts about this. They are clear and bring a good base for further discussion.

      By the way, who is John?

      Delete
    2. I thought that was you. But, it seems like you are not :D.
      The header of your blog has that name, but now I realize that it is a guy with a famous programmer quote. Although I couldn't find who the guy is/was?
      I also see that you are Eduardo. Nice to meet you :).
      You can edit my posts and rename John to Eduardo (I cannot edit myself).

      Cheers

      Delete
    3. Hey Bojan, nice to meet you too. That was funny!

      Anyway thanks for your thoughts and I hope you are well.

      Delete
  4. I was able to find good advice from your articles.



    My web-site - IT Managed Services ()

    ReplyDelete

Thank you for your thoughts. Your comment will appear in my blog shortly after review.

Have a great day!