DDD Anti-Pattern #3: Not Taking Bounded Contexts Seriously

My team had the challenge of building a field service automation application that would run on Windows Mobile devices. Availability of the Compact Framework meant that most code that would run on the server would also run on the device. This meant that we could build one domain object model and deploy it on the server and on the client. But in Jurassic Park fashion, we were so preoccupied with the fact that we could, we didn’t spend enough time asking if we should.

The Advantage We Got

We used the Repository pattern and built our domain model out of plain old CLR objects (POCOs). This meant that we could have the same rich domain model both on the client where the user is interacting through a UI and on the sever where changes from the field and from host system integrations are being processed. This allowed us to keep our code DRY. There was no repetition among the entities, behaviors, relationships between entities, and tests. We never had to worry about model inconsistencies between the client and the server. It seemed like a big win, and in some ways it was.

The Price We Paid

As we built out the product, we saw that the object model’s usage patterns were not the same on the client as on the server. We ended up with behavior that only applied on the client or on the server.

In an effort to keep from putting code into our domain that would not be relevant on both the client and server, we started putting logic into little services that work with the domain. Most of this logic was on the client side and got applied through use of the Event Aggregator pattern. This worked, but tended to impoverish the domain model itself.

Fixing It

The problem largely fixed itself when Windows Mobile became irrelevant almost overnight. We rebuilt the client in JavaScript that runs on most modern browsers. This gave us a do-over opportunity and removed the option of sharing model code between the server and client.

If I had the Windows Mobile situation to do over again, I would be more careful to define a common structure that the client and server could share, but compose behaviors relevant to the client and server within each of those contexts.

Split the Team or Split the Backlog?

Small software companies often find themselves trying to do too much with too little. This was certainly the case at Agentek. At one point earlier this year, we had a problem… We were not finished with the current release (call it release A), but we could not wait until it was finished to get a start on our next release (call it release B). There was too much unknown involved in release B. We had to get started on it. At the same time, we had just committed to ourselves that we would not leave our customers with anymore half-finished releases. What to do?

Our team had four fully dedicated developers, a tester, and me. We needed to dedicate 25% of our time to release B. The first option was to simply intersperse the backlog with stories from release A and release B…

Interspersed Backlog

Interspersed Backlog

There were two problems with the interspersed backlog. First, release A has a good bit of reactive work; so, the backlog is unpredictable and tends to consume the entire team’s attention. Second, since stories vary in actual effort to complete, we cannot really gauge or control what percentage of our capacity is applied to each effort.

The next idea, was to split the team and apply 25% of the people to release B….

Split the Team

Split the Team

This is the mathematically cleanest solution and the option that traditional software managers would probably pick every time. However, this option has major disadvantages…

  1. Only one developer will know anything about how release B was implemented.
  2. The many advantages of pairing are lost on both efforts because we have only one developer on release B and an odd number on release A.

This option really just throws the team-based approach to building software out the window; so, not an option for us.

Next thought was to create two separate backlogs….

Split the Backlog

Split the Backlog

This makes the problem we are trying to solve clearer, but we still have the problem of how do we stay united as a team, yet timebox each backlog.

The next step was to designate days of the week for servicing each backlog. To give the forward-looking release one fourth of our capacity, we dedicated one pair to that backlog for half of the week. To simplify things, and give it a little more than 25%, went ahead and gave it three full days instead of two and a half. So this is what things looked like…

Split the Backlog and the Week

Split the Backlog and the Week

We rotated the release B pair so that there would always be one person that worked on that last week for continuity and one new person.

In our first retrospective after we finished release A (and moved onto release B fulltime), the team was convinced of a few things:

  1. One team working on two releases at once is hard.
  2. Keeping the team together was really important.
  3. Splitting the backlogs and the week turned out to be a great way to do both at the same time.

DDD Anti-Pattern #2: Not Getting the Whole Team Educated on DDD Early Enough

The two challenges that drew me to Agentek in late 2008 were interrelated in the same way that the proverbial chicken and egg are. We had to build a complex, composite, occasionally connected, enterprise mobility application to replace the prior practice of custom, one-off solutions. At the same time, we had to bring the existing development group up to speed on current software techniques, practices, patterns, and processes.

I couldn’t hold off on designing and building the new product until everyone had gotten the DDD religion. In reality, I don’t think I would have done that even if I had the luxury of that kind of time. Concepts like DDD are best learned by doing them with someone who has done it before. Reading books and hearing presentations can get you excited about them, but only doing them helps you actually learn them.

As I prepared for the first meetings with the domain experts (folks from across the organization who had implemented multiple custom solutions and had a good sense of the domain of our new product), I sent out a copy of Domain Driven Design Quickly. I wanted to give them as much of an idea of what I was after as possible up front, but it mostly came down to me explaining it as we were doing it.

We had some great sessions. The white board photos we made in those early days formed a remarkably useful and resilient core of the domain model that is still reflected in the product today. We hashed out much of the [soon to be] ubiquitous language, and we all had a vision of what the new product would be.

Shortly after this, we hired a big DDD advocate (I’m still amazed at our good fortune in finding him. They are rare now, even more so in 2009). With Jarrel and me on the development team, we spread the DDD mindset organically as we built out the product. This seemed like a good and pragmatic approach.

In late 2010/early 2011, the entire development organization went through the blue book, chapter by chapter, discussing the pros and cons of Evans’ approach, where we’ve been effective, and where we haven’t.

What I learned was loud and clear: We would have had a better product and stayed out of the technological weeds much better if we had formally gone through the DDD material in 2009 instead of 2011. I underestimated how much more effective the team would have been if we took the time to build a common foundation of the DDD concepts. It didn’t mean we had to hold anything up. I just should have made it a priority earlier. I wont make that mistake again.

Misconceptions about Team Rooms and Open Floor Plans

I see this far too often. Well-meaning software organizations embracing agile software development tear down the walls in order to open up the space and allow easier collaboration. This sounds great, and it’s cheap. An easy win, right? Not if it’s done without some care and thought.

Premise 1: Irrelevant conversations are distractions.

Human beings are trained to pick other human beings’ voices out of the background noise and pay attention to them. There is little that is more distracting to concentration than hearing a conversation that has nothing to do with what you are working on.

Premise 2: A team is a group of people working toward a common goal.

If a team is really acting as a team, there is nothing that one subset of the team could be working on that is irrelevant to the rest of the team.

Imagine Team Green working in an open team room, paired at stations with one monitor and dual mice and keyboards…

Team Room

Let’s say that pair number 1 is having a conversation…

Team Room One Conversation

That conversation is heard by all other members of the team. Because Team Green is a team, the fact that the whole team can hear it is a good thing. I cannot count how many times I have seen this…

Pair #1 overhears pair #2 getting stuck on some problem that sounds familiar. Pair #1 stops and gets involved in what pair #2 is doing. The four people discuss the problem and solve it, based largely on some previous experience that someone on pair #1 had. If one pair had not overheard the other pair struggling, they might have wasted a whole day (or at least until the next stand-up).

Now imagine Team Green is really busy and all working and talking…

Team Room Communication Saturation

I first heard this situations referred to as communication saturation by Jeff Sutherland, but I think he got it from Jim Coplien. Here we have everyone able to hear every other conversation. If a stranger were to come upon this team area, it would sound like noise. But to a high-performing agile software team, it is completely natural because every conversation is related to furthering the goal for this iteration.

Now imagine we have a collaborative, high-performing Team Blue…

Team Room Blue 

Team Blue is enjoying the same open space benefit that Team Green is. Now imagine we take our open-spaces-are-good momentum and co-locate Team Green and Team Blue…

Noise

Now we have green conversations in the blue team area and green conversations in the blue area. This is not good. We now have noise distracting both teams.

If the blue conversations are as useful to the green team as green conversations, then you are not doing team based development.

There are two possible remedies: create more space between the teams, put up acoustically meaningful walls, or both.

Team Room Noise Fix Walls

The bottom line: open spaces and shared conversations are good only within a team, not between teams.

DDD Anti-Pattern #1: Not Accounting for Commands and Queries as Separate Concerns

As a long time object-oriented programmer, I was immediately drawn to the DDD concept of Persistence Ignorance. My initial idea of DDD was to simply express the domain concepts in a C# object model, then one one side, map those objects to a persistent store with a technology like NHibernate and on the other side, build a UI without any business logic in it.

Naive DDD Initial Transition

Figure 1: The Naïve Transition to DDD

This was a big improvement over the traditional techniques on the Microsoft stack. Databases are inadequate for expressing domain models and business logic in UIs or databases makes unit testing nearly impossible.

How the Naïve DDD Approach Fails

What I didn’t see was that this naïve solution traded one set of problems for another. The new solution looks like Figure 2 below.

Naive DDD

Figure 2: The Naïve DDD Approach

This looks OK until you try to build anything remotely complex with this model. The first bit of friction we ran into involved populating some of the screens on the UI. Many screens don’t map smoothly to our rich object model. We get by with technologies like LINQ and lazy loading, but it still feels awkward to spin up a rich object model to simply copy properties to a view.

Things really turn south when we start to have multiple interfaces to the application. Imagine we have our UI and add a SOAP-based API to allow other programs to drive the application.

Naive DDD Multiple Interfaces

Figure 3: The Naïve DDD Approach with Multiple Applications

Now the CRUD layer really starts causing trouble. First, notice that because our domain model is defined in an assembly (or package or library), it gets deployed to each separate application that needs it. We have a layered architecture, however, all but the database layer get replicated to multiple applications.

CRUD-Based Models and Meaning

Imagine that a user makes a update to the comments on order 0123 through the UI at the same time that an external program calls GetWorkOrder(“0123”), updates the order description, then passes the updated order into SaveWorkOrder. Now both components are instantiating order 0123, copying the updated property values and saving it back to the database.

We lose the intent of each of those two actors. We are left to sort out any conflicts on simply timing and the intelligence of our ORM tool.

You could avoid the replication in Figure 3 by creating a application server, but you would still have the loss of semantically meaningful information that comes with a CRUD-based object model.

Request/Response: Good for Some Things Not for Others

Our Figure 3 architecture is inherently synchronous request/response. Consider the GetWorkOrder Web service method. Our external system calls that method and gets back the specified work order. This is what we want. The calling code cannot continue until the request comes back.

On the other hand, imagine any method that makes any kind of change to the system (like SaveWorkOrder). We would like to be able to queue these changes and allow the system to process them as compute capacity is available. We also don’t want to have to write code to handle the case where the Web service is temporarily not available. 

The Old Way Had Some Things Right

Notice that the bad old traditional system does not exhibit some of these problems:Smart UI

Figure 4: The Old Smart UI Approach

What the traditional system did right was account for updates being different from queries. Reads used SQL queries or stored procedures and views to get exactly what the screen needs—no more, no less. The write side used SQL inserts and updates to make just the changes necessary to accommodate the user’s actions in the UI. You couldn’t test it and you wouldn’t want to be the one to have to maintain it or enhance it, but it performed well and got the job done.

It did, however, have all the same request/response limitations.

Getting it Right with DDD

Fixing this problem meant an overhaul of the architecture, but the result was well worth the effort. In a nutshell, we redesigned the system to follow the Command Query Responsibility Segregation (CQRS) pattern.

Now all changes to the system are expressed as commands. Anytime the system changes, one or more events are published. Everything is commands in and events out. For reads, we added an Open Data Protocol feed that allows any application to query the data.

CQRS

Figure 5: CQRS Design

Each of the applications and integration points is now sending commands to a central processing module (which may be dispatching to several machines). The commands express the precise intent of the sender of the command. So, UpdateWorkOrder becomes SetWorkOrderComment or SetWorkOrderDescription. Sending the command allows semantic meaning of the action to follow all the way through. We now log both the commands and the resulting events, creating a detailed audit trail of what happened within our system. This also allows us to better avoid merge conflicts because changes are more targeted with the specific commands.

Asynchronous Messaging versus Request-Response

Another huge win for this design improvement is in how it can scale. Building out the “write” side of the system with NServiceBus means that we can ditch all of the home-grown queuing, retry, and pub/sub logic between components. Now, all of our writes are async, forcing us to learn to deal without getting return codes or statuses from our calls. It took some getting used to, but is liberating in the end.

Our load testing shows that the system is now resilient to peak loads. The message queues swell temporarily, but everything continues to function.

Domain Driven Design Anti-Patterns

[Note: I was going to call this post How to Fail with Domain Driven Design, but that just sounded too pessimistic.]

I’ve been developing business applications on the Microsoft platform since the mid 1990s. The years since then have involved a continual process of learning to be more effective in architectural approach. Along the way, there have been key points where I made leaps forward. Two such examples include object-orientation in the 90s and my first Web service in 2000 (anyone remember SOAP Toolkit2?).

Each of these leaps forward also came with some initial stumbles as I grappled with the promising new approach. Pushing the envelope of productivity means trying new things. New things always create risk. Software is hard. The path of progress in software is never a straight line (unless you are creating commodity level software). However, stumbling when taking on new approaches can be minimized if you learn from other peoples mistakes instead if just your own.

Another big leap forward for me started with my reading of Domain Driven Design in 2005. Since that time, I have been putting DDD principles into practice. I have learned a lot-much of it by my own mistakes. What I offer here are some concrete examples of mistakes I made. I’ll show the mistake I made and how I later fixed it so you can compare and contrast the before and after. Sometimes I learn a pattern best by seeing examples of its anti-patterns. I hope these articles will help you create better software and add to the growing awareness of DDD.

  1. Not accounting for command and queries as separate concerns.
  2. Not getting the whole team educated on DDD early enough.
  3. Not taking bounded contexts seriously.
  4. Allowing implementation decisions to drive the domain model.

The above list will serve as the table of contents for the series. I’ll enable the links as I write the articles. I’ll probably add an article or two to the list as I go.