Domain Driven Design: the basics
Last week @yreynhout, @jefclaes, @mathiasverraes, @tojans & I presented a series of short sessions on strategic design at DDDBE. While these strategic patterns are at least equally important than the tactical patterns, the feedback we received was often like “yeah, cool and all, but what does it mean in practice?”
So, let me start by saying that it’s very difficult to state that “you’re doing DDD”. On our way home Jef said that DDD is mostly a mindset to him and I have to agree. You’ll pick and choose the things that will work for you and sometimes its value is in the small things.
Let me give an example:
I’m currently working at fifthplay who’s building soft- & hardware for smart homes (amongst other cool things). Let me take a scenario from their domain I encountered last week: there’s an updated version of a smart thermostat and we were asked to see how we’re going to deal with the replacement of an old one with the new type (when it broke down for example)
Since I’m pretty new and I don’t know how they do this kind of things yet, I just overheard them how it could be implemented. The conversation was like:
- It’s possible that the set point of the thermostat is used in a ‘scene’ (like ‘Empty House’ or ‘Cozy Evening’)
- So we need to add the new one first and replace the relation in the scene (if there is any)
- Then we need to update the new one with settings from the old one (but not all of them)
- Then we can delete the old one.
Pretty common when you hear a bunch of developers talk about a technical solution. So, if I had to implement this, how would I do that?
First of all: is there any need for the scene to know about the thermostat that’s currently used. Sure, it’s pretty stupid to set a temperature on a scene if you can’t control it through your system, but wouldn’t it be possible to disable this on the user interface? Next to that, is anyone going to get into trouble if there is a temperature set on a scene? Bottom line: Try to keep your aggregate’s small so you can protect consistency inside that boundary. A scene has hardly anything to do with a thermostat, it’s just interested in a temperature
Next: Adding the thermostat. Let me start with a quick overview of the system (copy-pasted from here)
So, when a broken thermostat is replaced, the old one will be unplugged from the HAM and the new one will be connected. Every so many seconds/minutes, the HAM is sending information to “us” (the “e-core” backend)
However, this “information” is pretty abstract. Let’s look at a telegram (I completely made this up)
How could we make the implicit explicit here? At some point in the pipeline, there’s probably a place where we can analyze the message. With Single Responsibility Principle in mind, I would try to work with many small “analyzers”, each designed for its own purpose.
Let me draw attention to the fact that I’m not doing very much here. I just raise a Domain Event if the reported thermostat is not the same than the one we know (the configured one). What’s changed and how we’re going to handle that change is work for some other part of the system.
What’s important here is that there’s a Domain Event with the name ThermostatReplaced. We are using a word from the Ubiquitous Language in code and by raising an event we’ve expressed the change very explicit.
Handlers of these event are also great candidates to give a name from the UL. I’m pretty sure everyone can imagine what the UpdateScenesWithNewThermostatSetpointsHandler does without reading the code?
To summarize: is this DDD? I’m not going to argue about naming but to me this is code is written with a DDD mindset. So my advice if you don’t know how to get started: take small steps and keep doing that. You might be able to sell it someday :)