Combining TDD/BDD with DDD

Its not unnatural to think that the prototypical xDD combinations (TDD, BDD, DDD, and friends) are somehow in competition with each other. If you are unsure of their exact meanings, why wouldn’t you believe that TDD is in opposition to BDD and DDD? I mean, they all mean “Hmmhmm Driven Design/Development”. How many things can really drive design or development at the same time?

But, luckily, this turns out to be a misconception. At least in this case: Domain-driven design (DDD) can be very well applied together with Test-driven development or Behaviour-driven development. This post describes one way you might think about this. You may find a much better way for your situation.

What unites them?

TDD and BDD are obviously closely related. It used to be said that BDD was simply “TDD done right”. I don’t think that is true. Yes, people who were experienced with TDD had learned the hard way that TDD was not really about testing. What you do in good TDD is that you describe some behaviour using a test and then implement that behaviour. BDD, in that respect, basically changed the name from “test” to “spec” to make this clear. Of course, the difference in attitude resulting from this leap is huge.

ATDD has also been improved upon by BDD. Now you can write executable scenarios for a story, with a customer, in the ubiquitious language of the domain. This means, natural language, in a slightly controlled form to allow it to be read like a script and executed. This could be done before, using tools like Fitnesse, but to be honest, most acceptance tests were fairly data-oriented.

To sum this up, BDD is clearly very closely related to TDD/ATDD. We may view BDD as TDD and ATDD together, using a more suitable terminology, stricter focus on customer collaboration, and designing outside-in in a mock-heavy style.

The similarities between TDD/BDD and DDD are more subtle, but we have already touched upon one: Both BDD and DDD are preoccupied with finding the most appropriate concepts, or “getting the words right”. To be able to talk effectively with our customers we need to learn and use their language. And this is exactly the idea behind the “ubiquitous language” in DDD.

DDD doesn’t mandate this, but normally when you start modelling in code, you write a little test program, using the words of the domain, and how you would like to use them to model behaviour. This is clearly a very similar idea to ATDD and BDD since it is a high-level test putting it all together. Also, the way that this is written first as if we already had everything in place is an example of programming by intention the same way you do it in BDD and TDD.

What differences exist?

What makes DDD go so well together with TDD/BDD is they both focus on design but from two very different angles. From DDD we great thinking tools about modelling, especially outside code, but it does not offer much when it comes to code techniques. TDD/BDD comes from the other way; from the coding, up towards an emergent design.

Another obvious difference is the direction of design work. Clearly, in DDD the focus lies on the domain. Therefore, DDD is often described as a middle-out approach. You start by modelling the domain, then you move out towards the GUI, databases and integration. As we have seen, this is different from BDD, where the imperative is pretty clear: Outside-in.

I think these differences should not be exaggerated. They are more two different approaches of where to start than absolute dogma. Sometimes one works better than the other. Most of the time, personally, I lean towards the BDD approach. There is simply to much speculation going on, developing a rich domain model without any validated indication that these features are actually needed. To validate, we need feedback from users. We need a user interface, however small, to know.

Needs should drive design

So, what should drive the design? The domain, the tests or the behaviour? On the surface it seems we have to chose, but I really don’t think that is necessary. When creating the domain model, DDD specifies that we should use important user stories to illuminate the use we will have of the model. BDD starts with user stories and TDD as well. User stories are the common denominator. Of course, this is not strange in any way, since user stories are the agile equivalent of a user need or requirement. Really, in all cases, the requirements are driving our design. This is good! We want our design to be a mirror of it’s intended use (no overdesign, no underdesign).

Combining DDD with BDD and TDD

If you want to do TDD/BDD but also build great domain models with DDD, I suggest the following approach to combining them: Use a BDD approach, going outside in, but combining that with DDD when the domain layer is reached. Here is one idea of how it can be done:

  1. [DDD] Conduct one or more domain modelling workshops with domain experts and/or users to understand and model the domain. This will be our initial idea of our design and it will most likely be wrong, but this will give us a basic understanding and a common vocabulary.
  2. [BDD/ATDD] For each story, write acceptance test scenarios to understand its implications. This can be done in a requirements writing workshop using our ubiquitous language. Often, this will lead to modifications to the model.
  3. [BDD/ATDD] For each test scenario, implement an executable example that fails, since that behaviour is not supported by the system. Then, use outside-in development, with an extensive use of mock objects, to flesh out the behaviour specified in the executable example.
  4. [BDD/TDD] Each behaviour, in each layer, is specified with an executable spec first, implemented, and refactored for understanding and maintenance. Use the DDD model as a mental starting point, but let TDD steer you towards a design that also works great in source code.
  5. [BDD/TDD/DDD] After completing a scenario, we look to the whole and performing refactoring on a higher level, e.g. moving responsibilities between classes.
  6. [DDD] As we have likely discovered points where our initial model felt wrong, update the domain model accordingly. It has to be correct to be relevant.

One Final Point

I believe software development has deeply underestimated the needs of the users and agile methods sadly continue in this tradition. I hope this can change. To our users the GUI is the application. A GUI can make or break an application. Did the iPod prevail because it had the strongest technical specs? Certainly not. To create effective user experiences you have to be able to answer questions like: “Does the user understand how to use the system?”, “Can it support the user in achieving her goals?”, “Is it usable for daily work?”, “Does it make her smile?”. It is certainly true that the domain model (in code) is our most important design artifact, but to the customers and users it’s what you can do with the program, how you do it, and how you feel when doing it, that counts. As a counter example: The Zune may have a great domain model underneath, who cares? To reduce the user interface to mostly an “implementation detail” is a serious mistake. Therefore, I mostly lean towards the BDD approach, even when I have the opportunity to work with rich domain models.

2 thoughts on “Combining TDD/BDD with DDD

  1. Hi,

    I enjoy you writing very much, as I am an xDD evangelist myself. I would like to add some of my perspective on DDD though: the way I see it, DDD is about meeting the challenge of managing the complexity of the domain, inside the software. Where BDD takes the outside-in approach with pre- and postconditions on behaviour at a level as high as the user interface, DDD is a way to manage /how/ we actually accomplish the task of providing the expected answer.

    Example: “Given a polynomial x^7 + x^3 – 247 = 0, when I click Show zeroes, then all the zeroes to the polynomial should be listed”. This is probably exactly what a user is looking for, but it deals very little with the intricacies of numerical analysis, the domain at hand.

    Also, one should not equate the user with the domain expert (not saying that you are, I just want to stress this). Collaboration with the domain expert (DE) is not mainly for aligning the feature set or ways of interaction of the product with one or more of the users of the end product, but rather a way to transfer knowledge. The DE may or may not be one of many end users of the system, but the role of a user is very different from the role of a DE.

    I think TDD and BDD are invaluable tools when working at the domain layer level, and complement DDD very well. End user focus if of course extremely important in its own right, and a well-functioning domain model will make it easier to consistently deliver features in a complex domain.

    • Hi Peter!

      Thanks for some great input and clarifications. From what I can gather, our views are very similar. I think that I am afraid that it’s a little too easy to misunderstand DDD to mean “start by designing the domain” (since it’s “domain-driven, right?), when I really think it means “understand and model the domain really really well, but only when you need to” (as driven by the requirements from users and outer architectural layers).

Comments are closed.