Foundations of Programming – pt 2 – Domain Domain Domain

Intruduction
Starting this kind of series by talking about domain driven design and object oriented programming is rather predictable. At first I thought I could avoid the topic for at least a couple posts, but that would do both you and me a great disservice. There are a limited number of practical ways to design the core of your system. A very common approach for .NET developers is to use a data-centric model. There’s a good chance that you’re already an expert with this approach – having mastered nested repeaters, the ever-useful ItemDataBound event and skillfully navigating DataRelations. Another solution which is the norm for Java developers and quickly gaining speed in the .NET community favors a domain-centric approach.

DDD2
What do I mean by data and domain-centric approaches? Data-centric generally means that you build your system around your understanding of the data you’ll be interacting with. The typical approach is to first model your database by creating all the tables, columns and foreign key relationships, and then mimicking this in C#/VB.NET. The reason this is so popular amongst .NET developers is that Microsoft spent a lot of time automating the mimicking process with DataAdapters, DataSets and DataTables. We all know that given a table with data in it, we can have a website or windows application up and running in less than 5 minutes with just a few lines of code. The focus is all about the data – which in a lot of cases is actually a good idea. This approach is sometimes called data driven development.

Domain-centric design or, as it’s more commonly called, domain driven design (DDD), 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 has a FirstName, but also on the fact that he or she can get a Raise. The Problem Domain is just a fancy way of saying the business you’re building a system for. The tool we use is object oriented programming (OOP) – and just because you’re using an object-oriented language like C# or VB.NET doesn’t mean you’re necessarily doing OOP.

The above descriptions are somewhat misleading – it somehow implies that if you were using DataSets you wouldn’t care about, or be able to provide, the behavior of giving employees a raise. Of course that isn’t at all the case – in fact it’d be pretty trivial to do. A data-centric system isn’t void of behavior nor does it treat them as an after though. DDD is simply better suited at handling complex systems in a more maintainable way for a number of reasons – all of which we’ll cover in following posts. This doesn’t make domain driven better than data driven – it simply makes domain driven better than data driven in some cases and the reverse is also true. You’ve probably read all of this before, and in the end, you simply have to make a leap of faith and tentatively accept what we preach – at least enough so that you can judge for yourself.

(It may be crude and a little contradictory to what I said in my introduction, but the debate between The MSDN Way and ALT.NET could be summed up as a battle between data driven and domain driven design. True ALT.NETers though, ought to appreciate that data-driven is indeed the right choice in some situations. I think much of the hostility between the “camps” is that Microsoft disproportionately favors data-driven design despite the fact that it doesn’t fit well with what most .NET developers are doing (enterprise development), and, when improperly used, results in less maintainable code. Many programmers, both inside and outside the .NET community, are probably scratching their heads trying to understand why Microsoft insists on going against conventional wisdom and clumsily playing follow the leader with a 5+ year lag (witness the recent announcement of a MVC pattern slated for 2008)).

Users, Clients and Stakeholders
Something which I take very seriously from Agile development is the close interaction the development team has with clients and users. In fact, whenever possible, I don’t see it as the development team and the client, but a single entity: the team. Whether you’re fortunate enough or not to be in such a situation (sometimes lawyers get in the way, sometimes clients aren’t available for that much commitment, etc.) it’s important to understand what everyone brings to the table. The client is the person who pays the bills and as such, should make the final decisions about features and priorities. Users actually use the system. Clients are oftentimes users, but rarely are they the only user. A website for example might have anonymous users, registered users, moderators and administrators. Finally, stakeholders consist of anyone with a stake in the system. The same website might have a sister or parent site, advertisers, PR or domain experts.

Clients have a very hard job. They have to objectively prioritize the features everyone wants, including their own and deal with their finite budget. Obviously they’ll make wrong choices, maybe because they don’t fully understand a user’s need, maybe because you made a mistake in the information you provided, or maybe because they improperly give higher priority to their own needs over everyone elses (a lot like the big screen TV I bought my girlfriend for her birthday). As a developer, it’s your job to help them out as much as possible and deliver on their needs.

Whether you’re building a commercial system or not, the ultimate measure of its success will likely be how users feel about it. So while you’re working closely with your client, hopefully both of you are working towards your users needs. If you and your client are serious about building systems for users, I strongly encourage you to read up on User Stories – a good place to start is Mike Cohn’s excellent User Stories Applied.

Finally, and the main reason this little section exists, are domain experts. Domain experts are the people who know all the ins and outs about the world your system will live in. I was recently part of a very large development project for a financial institute and there were literally hundreds of domain experts most of which being economists or accountants. These are people who are as enthusiastic about what they do as you are about programming. Anyone can be a domain expert – a clients, a user, a stakeholder and, eventually, even you. Your reliance on domain experts grows with the complexity of a system.

The Domain Object
As I said earlier, object oriented programming is the tool we’ll use to make our domain-centric design come to life. Specifically, we’ll rely on the power of classes and encapsulation. In this part we’ll focus on the basics of classes and some tricks to get started – many developers will already know everything covered here. We won’t cover persistence (talking to the database) just yet. If you’re new to this kind of design, you might find yourself constantly wondering about the database and data access code. Try not to worry about it too much. In the next part we’ll cover the basics of persistence, and in following parts, we’ll look at persistence in even greater depth.

The idea behind domain driven design is to build your system in a manner that’s reflective of the actual problem domain you are trying to solve. This is where domain experts come into play – they’ll help you understand how the system currently works (even if it’s a manual paper process) and how it ought to work. At first you’ll be overwhelmed by their knowledge – they’ll talk about things you’ve never heard about and be surprised by your dumbfounded look. They’ll use so many acronyms and special words that’ll you’ll begin to question whether or not you’re up to the task. Ultimately, this is the true purpose of an enterprise developer – to understand the problem domain. You already know how to program, but do you know how to program the specific inventory system you’re being asked to do? Someone has to learn someone else’s world, and if domain experts learn to program, we’re all out of jobs.

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 you, and your code talks about StrategicOutcome then some of the ambiguity and much of the potential misinterpretation is cleaned up. Many people, myself included, believe that a good place to start is with key noun-words that your business experts and users use. If you were building a system for a car dealership and you talked to a salesman (who is likely both a user and a domain expert), he’ll undoubtedly talk about Clients, Cars, Models, Packages and Upgrades, Payments and so on. As these are the core of his business, it’s logical that they be the core of your system. Beyond noun-words is the convergence on the language of the business – which has come to be known as the ubiquitous language (ubiquitous means present everywhere). The idea being that a single shared language between users and system is easier to maintain and less likely to be misinterpreted.

Exactly how you start is really up to you. Doing Domain Driven Design doesn’t necessarily mean you have to start with modeling the domain (although it’s a good idea!), but rather it means that you should focus on the domain and let it drive your decisions. At first you may very well start with your data model, when we explore test driven development we’ll take a different approach to building a system that fits very well with DDD. For now though, let’s assume we’ve spoken to our client and a few salespeople, we’ve realized that a major pain-point is keeping track of the inter-dependency between upgrade options. The first thing we’ll do is create four classes:

public class Car { }
public class Mode { }
public class Package { }
public class Upgrade { }

Next we’ll fill-in these classes with some safe assumptions:

using System.Collections.Generic;
using System.Collections.ObjectModel;

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()
   {
      //todo
      return null;
   }
}

public class Upgrade
{
   private int _id;
   private string _name;
   
   public ReadOnlyCollection<Upgrade> RequiredUpgrades
   {
      get
      {
         //todo
         return null;
      } 
   }
}

Things are quite simple. We’ve added some pretty traditional fields (id, name), some references (both Cars and Models have Upgrades), and an Add function to the Car class. Now we can make slight modifications and start writing a bit of actual behavior.

using System.Collections.Generic;
using System.Collections.ObjectModel;

public class Car
{
  private Model _model;
  //todo where to initialize this?
  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();
  }
}

First, we’ve implemented the Add method. Next we’ve implemented a method that lets us retrieve all missing upgrades. Again, this is just a first step; the next step could be to track which upgrades are responsible for causing missing upgrades, i.e. You must select 4 Wheel Drive to go with your Traction Control; however, we’ll stop for now. The purpose was just to highlight how we might get started and what that start might look like.

UI
You might have noticed that we haven’t talked about UIs yet. That’s because our domain is independent of the presentation layer – it can be used to power a website, a windows application or a windows service. The last thing you want to do is intermixed your presentation and domain logic. Doing so won’t only result in hard-to-change and hard-to-test code, but it’ll also make it impossible to re-use our logic across multiple UIs (which might not be a concern, but readability and maintainability always is). Sadly though, that’s exactly what many ASP.NET developers do – intermix their UI and domain layer. I’d even say it’s common to see behavior throughout ASP.NET button click handlers and page load events. The ASP.NET page framework is meant to control the ASP.NET UI – not to implement behavior. The click event of the Save button shouldn’t validate complex business rules (or worse, hit the database directly), rather its purpose is to modify the ASP.NET page based on the results on the domain layer – maybe it ought to redirect to another page, display some error messages or request additional information.

Remember, you want to write cohesive code. Your ASP.NET logic should focus on doing one thing and doing it well – I doubt anyone will disagree that it has to manage the page, which means it can’t do domain functionality. Also, logic placed in codebehind will typically violate the Don’t Repeat Yourself principal, simply because of how difficult it is to reuse the code inside an aspx.cs file.
With that said, you can’t wait too long to start working on your UI. First of all, we want to get client and user feedback as early and often as possible. I doubt they’ll be very impressed if we send them a bunch of .cs/.vb files with our classes. Secondly, making actual use of your domain layer is going to reveal some flaws and awkwardness. For example, the disconnected nature of the web might mean we have to make little changes to our pure OO world in order to achieve a better user experience. In my experience, unit tests are too narrow to catch these quirks while they are plainly visible as you create your real UI.

You’ll also be happy to know that ASP.NET and WinForms deal with domain-centric code just as well as with data-centric classes. You can databind to any .NET collection, use sessions and caches like you normally do, and anything else you’re used to doing. In fact, out of everything, the impact on the UI is probably the least significant. Of course, it shouldn’t surprise you to know that ALT.NET’ers also think you should keep your mind open when it comes to your presentation engine. The ASP.NET Page Framework isn’t necessary the best tool for the job – a lot of us consider it unnecessarily complicated and brittle. We’ll talk about this more in a later part, but if you’re interested to find out more, I suggest you look at MonoRails (which is a Rails framework for .NET) and find out about the new page framework being released by Microsoft in 2008. The last thing I want is for anyone to get discouraged with the vastness of changes, so for now, let’s get back on topic.

Tricks and Tips
We’ll finish off by looking at some useful things we can do with classes. We’ll only cover the tip of the iceberg, but hopefully the information will help you get off on the right foot.

Factory Pattern
What do we do when a Client buys a new Car? Obviously we need to create a new instance of Car and specify the model. The traditional way to do this is to use a constructor and simply instantiate a new object with the new keyword. A different approach is to use a factory to create the instance:

using System.Collections.Generic;
public class Car
{
  private Model _model;      
  private List<Upgrade> _upgrades;

  private Car()
  {
     _upgrades = new List<Upgrade>();
  }
  public static Car CreateCar(Model model)
  {
     Car car = new Car();
     car._model = model;
     return car;
  }
}

There are two advantages to this approach. First, we can return a null object, which is impossible to do with a constructor – this may or may not be useful in your particular case. Secondly, if there are a lot of different ways to create an object, it gives you the change to provide more meaningful function names. The first example that comes to mind is when you want to create an instance of a User class, you’ll likely have User.CreateByCredentials(string username, string password), User.CreateById(int id) and User.GetUsersByRole(string role). You can accomplish the same functionality with constructor overloading, but rarely with the same clarity. Truth be told, I always have a hard time deciding which to use, so it’s really a matter of taste and gut feeling.

Interfaces
Interfaces will play a big part in helping us create maintainable code. We’ll use them to decouple our code as well as create mock classes for unit testing. An interface is a contract which any implementing classes must adhere to. Let’s say that we want to encapsulate all our database communication inside a class called SqlServerDataAccess such as:

using System.Collections.Generic;
internal class SqlServerDataAccess
{
  internal List<Upgrade> RetrieveAllUpgrades()
  {
     //todo implement
     return null;
  }
}

public class Sample
{
  public void SampleMethod()
  {
     SqlServerDataAccess da = new SqlServerDataAccess();
     List<Upgrade> upgrades = da.RetrieveAllUpgrades();
  }
}

You can see that the sample code at the bottom has a direct reference to SqlServerDataAccess – as would the many other methods that need to communicate with the database. This highly coupled code is problematic to change and difficult to test (we can’t test SampleMethod without having a fully functional RetrieveAllUpgrades method). We can relieve this tight coupling by programming against an interface instead:

using System.Collections.Generic;
internal interface IDataAccess
{
  List<Upgrade> RetrieveAllUpgrades();
}

internal class DataAccess
{
  internal static IDataAccess CreateInstance()
  {
     return new SqlServerDataAccess();
  }
}

internal class SqlServerDataAccess : IDataAccess
{
  public List<Upgrade> RetrieveAllUpgrades()
  {
     //todo implement
     return null;
  }
}

public class Sample
{
  public void SampleMethod()
  {
     IDataAccess da = DataAccess.CreateInstance();
     List<Upgrade> upgrades = da.RetrieveAllUpgrades();
  }
}

We’ve introduced the interface along with a helper class to return an instance of that interface. If we want to change our implementation, say to an OracleDataAccess, we simply create the new Oracle class, make sure it implements the interface, and change the helper class to return it instead. Rather than having to change multiple (possibly hundreds), we simply have to change one.

This is only a simple example of how we can use interfaces to help our cause. We can beef up the code by dynamically instantiating our class via configuration data or introducing framework specially tailored for the job (which is exactly what we’re going to do). We’ll often favor programming against interfaces over actual classes, so if you aren’t familiar with them, I’d suggest you do some extra reading.

Information Hiding and Encapsulation
Information hiding is the principle that design decisions should be hidden from other components of your system. It’s generally a good idea to be as secretive as possible when building classes and components so that changes to implementation don’t impact other classes and components. Encapsulation is an OOP implementation of information hiding. Essentially it means that your objects data (the fields) and as much as the implementation should not be accessible to other classes. The most common example is making fields private with public properties. Even better is to ask yourself if the _id field even needs a public property to begin with.


Access Modifiers

As you focus on writing classes that
encapsulate the behavior of the business a rich API is going to emerge
for your UI to consume. It’s a good idea to keep this API clean and
understandable. The simplest method is to keep your API small by hiding
all but the most necessary methods. Some methods clearly need to be
public and others private, but if ever you aren’t sure, pick a more
restrictive access modifier and only change it when necessary. I make
good use of the internal modifier on many of my methods and properties.
Internal members are only visible to other members within the same
assembly – so if you’re physically separating your layers across
multiple assemblies (which is generally a good idea), you’ll greatly
minimize your API.


Conclusion

The reason enterprise development exists is that no single off-the-shelf product can successfully solve the needs of a complex system. There are simply too many odd or intertwined requirements and business rules. To date, no paradigm has been better suited to the task than object oriented programming. In fact, OOP was designed with the specific purpose of letting developers model actual systems in code. It may still be difficult to see the long-term value of domain driven design. Sharing a common language with your client and users in addition to having greater testability may not seem necessary. Hopefully as you go through the remaining parts and experiment on your own, you’ll start adopting some of the concepts and tweaking them to fit your and your clients needs.

This entry was posted in Featured, Foundations. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

22 Responses to Foundations of Programming – pt 2 – Domain Domain Domain

  1. Quiziqal says:

    It’s refreshing to read and even-handed discussion of data- versus domain-centric development. Thanks for the post and the series.

  2. Karl, are you planning to write more on the topic of object-relational impedance mismatch, common design patterns / practices for domain objects which correspond to one-to-many, many-to-many, and look-up types of relationships between database objects (tables)? You started to write on that matter in “Domain vs. Data Model” part of The Code Wiki, but it would be great to expand on those issues.
    Which books/articles would you recommend to read?

  3. vkelman says:

    After struggling to find other good articles on N-Tier approach (there is a bunch of junk on http://www.15seconds.com) I finally discovered one more good article: Building Layered Web Applications with Microsoft ASP.NET 2.0 by Imar Spaanjaars http://imar.spaanjaars.com/QuickDocId.aspx?quickdoc=416.
    He uses custom DAL objects, clearly separated from Domain objects.

  4. What About Thad? says:

    Wow. Great article. I’ve been trying to make myself into a decent OO developer for most of my career but I keep getting sucked back into Data Driven Design (or worse)–sometimes for expediency or because of existing team culture, but mostly because of my own limitations. This series is renewing my determination to expand my thinking and helping me refine my direction for doing so.

    Here’s a tangentially related question that has been in the back of my mind for a while. I’m not exactly new to the concept of programming to interfaces, but most of my projects have dealt with a fairly simple and narrow domain, in a predictable environment. I always find myself at the start of a project asking, “OK, what needs to be defined as an interface?” Then as I think through future scenarios I usually can’t see a likely situation where I would ever need to instanciate different implementations of the same interface. In those cases I usually forego the interface definition. Aside from eliminating the ability to easily substitute implementations, what other problems does omitting interfaces in that situation introduce?

    Thanks again for the great article!

  5. joedotnot says:

    Thanks Karl, i will read the rest of your (very sensible) articles when they appear.

    FYI here is a DNA link
    http://www.microsoft.com/technet/archive/itsolutions/intranet/plan/introdna.mspx
    My understanding of it was that it was simply a marketing term, but it encompassed the separation of layers, and first became a buzzword during the days of COM development with microsoft tools.

  6. karl says:

    Joe: I don’t know much about DNA, but I think DNA is tied to specific tools (Microsoft-created tools of course)

    as they say on http://domaindrivendesign.org/,
    “Domain-driven design is not a technology or a methodology. It is a way of thinking and a set of priorities, aimed at accelerating software projects that have to deal with complicated domains.”

    Yes, domain driven design is a lot about a logic layer (domain/business/logic layer are all the same thing in my mind), but also about the things I mentioned in part 1, testability, simplicity, DRY, information hiding and so forth. These are higher level concepts – less about the API, more about the pattern.

    Could be talking out of my ass though … read the rest of the articles and you be the judge :)

  7. NiHique says:

    hi Karl, thanks for this great article series, hope to see next part soon :)

  8. joedotnot says:

    Is Domain Driven Design another fancy term for Business Logic Layer (i.e. typical microsoft Windows DNA architecture), or is there some extra meeting to DDD that i am missing?

  9. karl says:

    Renaud: that’s a good point. I hadn’t planned on addressing UI in this series, but I agree that it could be useful to approach these concepts from that point of view. I’ll think about it…I have considered expanding on this on DDD and OOP and your suggestion might be the right angle…

  10. Nice intro on DDD.

    I think an interesting aspect to explore, in complement to what you say here, is : how will the UI actually use the domain.

    For instance, if we must develop a screen that will list the cars currently in the dealership, what class will have to be called to retrieve the proper Cars collection.

    I believe that would made the domain more understandable to a lot of developpers if they can figure out how it plays out with all the other parts of the application.

  11. mattcalla says:

    I’ve read these sorts of articles many times before, but the way you explain it is excellent.

    Thanks for your contribution – I look forward to the remaining posts in the series.

  12. DaRage says:

    Thanks Karl, I already know RoR. will definetly check that book. Right now data driven design is the only way i know and althought I always read about DDD i’m not really sure how to apply it. However, i would like very much to give it shot since i know first hand how data driven end being very complicated very fast as the number of entites are usually are multiple of the number of tables and the code becomes blotted very fast.

    Thanks again.

  13. Tom Pester says:

    Thanks for sharing your ideas Karl. You make all of this very understandable and the examples you use are very good.

    I’m looking forward to your next posts!

  14. karl says:

    jhunter:
    That’s a good question, and I agree the article missed the boat a little with respect to that (although it’s hard for me to address without sounding like I have nothing good to say about data driven design).

    I think, in practice, a core difference is that the code is actually decoupled from the data layer making it possible to unit test and easier to maintain. This is probably possible with data driven design, but not if you use datasets as your actual classes – which to the best of my knowledge cannot be separated in any meaningful way from the underlying DB.

    If you’ve been creating classes like Car and Upgrade and have been write methods in those to express behavior, that you very well may have been doing DDD all along. In this case, you’d likely have a DAL which may or may not make use of datasets. I’ve seen hybrids that use domain objects ultimately are coupled to datasets (typed-datasets are a good built-in example of such a hybrid) and the abstraction always fails – at least when trying to write tests.

    Whether or not this is the official meaning of data driven design I don’t know, but I’d say ASP.NET code that connects directly to the database to pull or store data is a prime example of data driven design. There is no domain (which means you’ve lost the best tool to implement behaviour: OOP) and you’re pretty much dealing in data – passing it back and forth. You might validate, you might have helper methods that enforce certain rules and relationships, but it was designed with the goal of getting property X into column Y.

    I know..still vague …

  15. puz says:

    Thank you for sharing your knowledge! The article is wonderful, keep on writing…

  16. karl says:

    DaRage:
    Probably the best one is Jimmy Nilsson’s Applying Domain-Driven Design and Patterns (http://domaindrivendesign.org/books/index.html#DDD_apply)

    I actually think The Pragmatic Programmers Agile Web Development with Rails is a perfect example of how to intermix an API/Framework book with a design concept. After reading it, you realize that almost every (maybe all??) ASP.NET book is just prettied up version of MSDN documentation…Although I wouldn’t recommend that book unless you wanna learn RoR as well.

  17. jhunter says:

    Either I don’t understand domain driven design or I’ve always done it?

    How is it different than data driven design in practice?

  18. DaRage says:

    Great read.. looking for more. I liked the recommendation for the user stories book. What book(s) do you recommend for DDD? I know that Bruce Eckel (the author of thinking in java) has a CD course series but it’s $500.

  19. Greg says:

    This is a great post Karl. I love it!

    Too often we focus on very complex edge conditions and forget that our first and foremost goal should be to teach by example!

    You can count on an extension from me in the next few days….

    Cheers,

    Greg

  20. Stacy says:

    Great stuff, thanks. Gonna refactor bigtime after we launch.

  21. sugar says:

    This is exactly the type of stuff the alt.net’ers should be doing. Thanks

  22. Sonu Kapoor says:

    Great article Karl.