In a previous post I discussed some of the talks I attended at the DDD Europe conference in Amsterdam. This conference has offered a lot more amazing content and I'd like to continue to tell you about it.
Lately I've been thinking about why Domain-Driven Design (DDD) has such a great attractive force on me. In particular when at the same time I'm strongly attracted by technology like Docker and its surrounding ecosystem of tools that are finally helping us to fulfill the ideal of continuous delivery, with relative ease. Configuring servers, deploying them, connecting them, etc. is what we previously would have called "operations" work. Now that developers themselves get to do more and more operations work, a movement was called to life: devops, where two previously separated responsibilities are merged into one: writing software and running it in production is part of the same, single task: shipping working software.
Domain-Driven Design shows a certain symmetry with the devops movement. DDD is to be considered a movement too. Aside from all the technical advice we get from it, which is the easiest to focus on for us developers, the main message is more like an encouragement, a call to action for the group of developers as a whole: immerse yourself in the business domain. Know the people and try to understand what their work is about. You don't need to be a domain expert yourself, but you need to talk to the people who are. Only then will you be able to create meaningful software, that isn't just great with respect to the technical aspects, but contributes to the success of the organization you've created it for. It should help them accomplish things they are not able to accomplish with a spreadsheet and a telephone alone.
Looking back at my own career as a software developer I can see that for many years my focus has solely been on technical excellence. I remember my girlfriend asking me several years ago: "But don't you care about the users of your software?" I answered: "No, as long as I can work on solving interesting technical problems!" This attitude is by far not sufficient, and learning about DDD has been a real wake-up call for me. Software development isn't about design patterns, or knowing all about your programming language or framework of choice. It's about delivering proven-to-work software that is meaningful to a group of people and helps them accomplish extraordinary things. I'm not saying you shouldn't learn all you can about the tools you're working with. It just shouldn't be your sole point of focus.
Nick Tune: Aligning Organisational & Technical Boundaries for Team Autonomy
Although I was aware that all the talks were being recorded, I usually get the most out of a conference by simply attending a talk and think it through. It's much less likely for this mental process to occur while I'm watching a talk at home, it just doesn't come with the same kind of special focus I have in a conference room, if I sit down to watch a video at all...
Another interesting talk I attended was one by Nick Tune, whose style of presentation I really love - and so did the entire audience I think. In previous talks I saw by Nick it became very clear that DDD is the perfect area for him to be operating in. As a developer he has a strong awareness of the business world surrounding him (us).
He started out with a call to action: to not wait for management to fix issues you recognize with a software system. Instead, we don't need to seperate between technical and management issues, since they are tied to each other and often amount to the same underlying problem. An important take-away from this talk to me was that instead of taking refuge in a chapter in "the blue book" or something, you should also consider more mundane solutions, like redistributing the work, relocating teams, or relieving the workload of a team in order to speed up partnerships between teams.
If you have some DDD background, you already know that DDD offers us the idea of a bounded context to help us separate our system into multiple different services, each with their own domain model. Finding the right boundaries for such a context is the hardest part of course. Accoring to Nick (quoting Udi Dahan), there are no rules for determining service boundaries. The main heuristic for determining the correct course though, is that every decision with regard to the boundaries should help the organization towards achieving its goal.
In practice, the best thing you can do is strive for autonomy. Hence Nick's suggestion to let go of "microservices" or "bounded contexts" and fight about if you got them right, but focus on "autonomy contexts". We should align our services in the way that reduces the lead time to positive business impact, and having autonomous teams working in autonomous contexts, thereby reducing the number of dependencies, is the best way to do so.
Though there are no rules (of course), Nick offers several heuristics that may be worth mentioning here:
- Look for contextual language. Language that you will only find to be used in certain contexts; you can put boundaries around those contexts (thereby even allowing the contextual language to be further developed).
- Data uniqueness. You can look for places where certain data naturally resides and put the context boundaries around that data.
- Exclusive domain experts. If there are multiple subdomains in play and each of them come with their own domain experts, this might reveal where context boundaries can be placed.
- Business process steps. When the business process gets divided in several natural phases, they can often be separated by context boundaries.
- Existing team boundaries. A more conservative option: find out how the teams are currently being divided. If that works well and teams are pretty autonomous already, the boundaries may already be in place.
- Bottlenecks. If things aren't working well between teams (they have to wait for each other, they ruin another team's life), those are bottlenecks and resolving them may lead you to better context boundaries.
Whatever you decide, don't go for the theoretically ideal solution (like aligning bounded contexts with subdomains), but for the solution that improves customer responsiveness.
Udi Dahan: If (domain logic) then CQRS, or Saga?
I'd never seen Udi Dahan speak, but now I know it's the right thing to do. Speaking is natural for him, and his talk's journey from start to end, making a very interesting point, was impeccable.
The main point was that even when we have familiarized ourselves with domain events and state being like a snapshot, we still rely on current state to protect domain invariants in a very short-sighted fashion. The simple example around which the talk revolves is that of a product getting added to a basket. Between the moment of looking into the details of a product and clicking "add to cart", there is a small chance that the product itself has been deleted, or has been sold out. So we add
if-statements in our code to verify that adding the product to the cart is still a valid thing to do. We hereby think that we successfully implement the "domain invariant" that "you can only add existing products to a cart, and only those that aren't sold out".
Udi calls the scenario a race condition, which hints to the fact that the domain of e-shopping is in fact a collaborative domain. This calls for a more careful approach. Even more things can go wrong: what happens if a product becomes unavailable for sale after it was added to the shopping cart? Udi warns us to always be prepared to loose.
We have gotten ourselves into trouble by verifying domain invariants using simple
if-statements. But whether or not the answer of the expression is yes or no depends on at which point in time you ask it. Since the example domain is a collaborative one, we should (one of Udi's heuristics) choose CQRS as an implementation pattern anway. And with it comes the rule that commands don't fail.
Instead of trying to cover every failure scenario in our application services, we should be prepared to loose after we've handled the command. This is in fact another case of eventual consistency. We often use that term in a technical context to describe that the state of our domain objects is not immediately consistent across the entire system. Here it means that our application can't have total knowledge of everything that's happening in the real world and that instead it should be able to keep up with those events. An example would be: when a user has a product in their basket which gets sold out, the product will be removed from the basket and the user gets a nice message about it. Or maybe taking a product out of sale is something that could happen within a certain timeframe, instead of immediately, allowing customers to finish their order.
I found this a very interesting talk, and I'm certain that this will change my perspective on domain invariants and how to enforce them in code.
This concludes my report of day 1 of DDD Europe. I still have more to say about what came by on the second day. Not sure when I'll come around to publishing that post though...