On the 12th of June the Domain Driven Design eXchange took place in London. Intracto was there and we’d like to recap the points we found most interesting here. Should your interest be piqued while reading the following, be sure to check out our jobs.
We could state that code is “living” and documentation is “dead”. Code is always kept up-to-date and changes constantly. Documentation on the other hand, usually starts out as a pretty accurate bundle of information on the code, but a lack of maintenance nearly always renders it outdated and incorrect in a record amount of time. This way, it loses most of its value and stops being used altogether.
Cyrille Martraire proposed some solutions under the banner of living documentation, a topic he is also writing a book on. The purpose of documentation is the passing of knowledge. In the first place, this knowledge should flow by way of conversation because it has a much higher bandwidth than text written in advance. Also, conversation is ‘just in time’: information shared when talking is not prepared in advance so no time is wasted on writing things that turn out to remain unused. Pair and mob programming is therefore a highly efficient way of getting people on the same mental page.
Although this is an ideal situation, usually there isn’t room within a project for such an approach. The next best thing is to find a way to spend as little time as possible writing documentation while keeping it up to date anyway. The solution proposed by Cyrille is to create some tools that generate the documentation you need from your code. This way the documentation will never become incorrect or outdated because it evolves automatically with the code itself.
In most cases, we’re already doing this by using some third party software that reads our annotations and converts it to a “document”. This, however, still relies on the developer keeping his annotations up-to-date with the changes made in code. If we could generate actual documentation from the code itself, this wouldn’t be a problem and we would have another huge advantage: We can use our documentation to validate our domain!
A powerful way to achieve this is through naming conventions and namespacing: we could leverage our package structure to build a tool that generates a diagram visualizing dependencies between our domain and the rest of the system. It’s important to keep a particular diagram’s purpose in mind and visualize only relevant components. A humongous diagram of your entire project is neither pleasant to look at nor useful, you should generate visuals that tell you something meaningful. One picture should tell one story.
For example, you could visualize the dependencies of your domain model on external classes:
Domain classes may have dependencies on other domain classes.
Outside classes may have dependencies on other outside classes.
Outside classes may have dependencies on domain classes.
If you find any dependencies that don’t adhere to these rules, we know for a fact we have made a mistake in our model. A failure to generate proper documentation from your codebase is a smell that probably indicates architectural issues.
We all know microservices are “hot” today and David Dawson was here to shine some more light on the subject.
The most important aspect of microservices is isolation. Isolation forces us to make sure a system has everything it needs to work autonomously, by splitting up a system in proper microservices you can prevent creation of a monolithic system (or Big Ball of Mud). Nice theory, but in practice we are not home free just yet: microservices are still very young and there are a lot of difficult issues left to tackle, like service discovery, authentication, ...
My take-away from #dddx: be careful with hypes, keep thinking for yourself, microservices are no walk in the park. Yet.
— Jeroen Moons (@JeroenMoons) June 13, 2015
Because microservices stand on their own, there is a lot to be taken care of. Usually all this is handled within a project, but by splitting it up into microservices we need to make sure every service can handle every situation the project depends on.
A lot of important issues are related to its domain design. This is where the DDD community should step in, because a lot of these issues have been handled by them years ago (maybe in a different context). In a way, microservices could be considered a re-launch of SOA.
Eric states that a microservice is a bounded context by nature, but we absolutely need to remember that a set of microservices (or a group of bounded contexts) can have their own encapsulating bounded context. A microservice does not necessarily correspond 1 to 1 with a bounded context.
Next, we had a look at how multiple services communicate with each other and how that communication influences the design of the services involved. Let's say there are 2 services: A and B. These two need to talk to each other, and it has been decided that B will conform to the language A speaks, that is, it will use the same language as A in its API. So far so good, but this situation introduces some real architectural risk.
Let's say the development team of service A is now replaced with some inexperienced developers. They start fixing things on the fly and the model A uses becomes muddy, which shines through in the language it speaks to the outside world. So now service B, which has to accommodate any changes to the language service A speaks, needs to conform to the muddiness of service A and in doing that becomes muddy itself.
To amend this type of situation there are multiple strategic patterns DDD provides, like a published language (PL) or anti corruption layer (ACL). A PL involves maintaining a stand-alone language all services need to stick to. An ACL is a translation buffer between a service’s internal model and the outside world, any structural changes in incoming messages are accounted for in the ACL and have no impact on the rest of the service.
Eric finished his talk with some good advice and a killer quote wrapped into a nice little ball of eloquence:
"Not all large systems are designed well, but that doesn't prevent some aspects of the system to be designed well. If you try to make everything nice, nothing will be!"
By now most of us have read the theory on DDD and got some inspirational information from the community’s modelling gurus, but how is this all implemented in a real project?
Konstantin Kudryaschov sees two translation steps taking place: converting business language into developer language (which is what BDD does, in his eyes) to converting developer language into computer language (that’s the domain of DDD). The key here is that, throughout the process, computer language and business language should be one and the same (DDD’s ubiquitous language).
Conversation (BDD) is your lead designer. Pass knowledge by creating living documentation #dddx
— Tom Van Looy (@tvlooy) June 13, 2015
Another point Konstantin made was on the development direction chosen in many applications. It seems logical to start from the UI going "down" to the layers below, because this is where the user interacts with the business. You can see how this does not really make sense, because now the user interface is dictating the way the business should work. Instead, one should start with defining the business layer, and make the user interface interact with its rules.
Although Konstantin took us through an example in a language we feel at home in here at Intracto, PHP. We will use Scott Wlaschin’s illuminating talk on the F# type system to illustrate how the functional approach fits in with the unification of languages DDD holds dear.
Some functional languages provide a type system that is really well suited to represent business constraints in a natural and concise way. Scott Wlaschin has chosen F# type classes to explain the power of this approach.
Let’s start with defining a type “Person”:
What do we know about how ‘Person’ operates when we see this? Nothing really, only the properties that make up this type.
Let’s add some type information:
We have a lot more information now. Both the business expert and the developer will have an idea what is expected of these variables. However, this still leaves a lot of wriggle-room for interpretation. How long is a FirstName? What happens if a Person changes his email, is it still verified?
Scott has the silver bullet: “Whenever you have a problem in F#: create a new type!”. He makes particularly powerful point using the Email aspect (and how to keep track of its validity) of a Person. You will see that the design adapts to the domain language:
At this point, an Email can be Verified or Unverified, based on the type of the value. We don’t use a flag field to keep track of an email’s verification status anymore, that approach is vulnerable to programming mistakes. In the new situation, only VerificationService can convert an EmailAddress into a VerifiedEmail so we can be sure that whenever we encounter a VerifiedEmail it was created by VerificationService and hence is valid.
By the way, the type String50 used above would be defined like this:
And this is the function to obtain a String50 object:
Same principle applies: when we encounter a String50 object it must be valid because it can only be created by createString50 and that function does not return invalid String50 objects.
You could do something similar using an OO language by using classes and inheritance, but you would end up with a lot of classes, interfaces, exceptions, constructors, getters, setters, toString methods, ... By using the type system of a statically typed functional programming language like F#, this becomes a lot simpler and cleaner, the way business constraints are applied within a domain model is a lot more obvious.
Our conference concluded with a talk by Udi Dahan. Udi made some strong points on why we shouldn’t jump on every bandwagon that passes by.
He started his talk ‘proving’ reusability is not the holy grail and why many attempts at getting there have failed in the past:
“Reuse means use
use means dependencies
dependencies mean coupling”
Imagine a situation where validation is applied to an object. In most cases these restrictions have to be duplicated in multiple places: the user interface, the form handler and in the database. This is where dependencies outside of the bounded context start to grow.
These kinds of situations grow from the start of a project. In the beginning a lot of time and effort went into structurizing the domain model. When the actual development starts, eventually some functionality is needed from other parts of the domain and more coupling ensues. This is because most initial thought has been focussed on dependencies between layers and not on dependencies between objects within the same layer, where 90% of complexity usually resides.
When solving problems, a good place to start is usually to look for ideas that have worked in the past. History will tend to repeat itself and Udi claims solutions are re-invented roughly every 10 years. We should learn from what came before and not fall into the trap of using promising ideas that have never ever worked in the past. You will fail again.
New techniques are not always what they're cracked up to be. Don't use it just to use it. Find the best solution for YOUR case. #DDDX
— Roy Van Ginneken (@royvanginneken) June 13, 2015
A final point relating to microservices and how they are supposed to mitigate coupling and scaling problems: The word "monolithic" is thrown around a lot these days, and often incorrectly. The term refers to a logical property of a system, not physical one. It means 'impossible to divide into parts'. A Big Ball of Mud certainly qualifies but a single system might well be organised in a perfectly decomposable way and not deserve this qualification in the slightest.
The day was rounded off by a park bench panel discussion where everyone was welcome to share his or her opinions and put any of the days questions to the experts. DDDX 2015 was a most interesting conference which gave us lots of insights and food for thought. We would be happy to talk with you about these subjects one of the Belgian DDD user group meetings.
Note that in January 2016 the first ever DDD Europe, a two day conference, will be held in Brussels. A lot of the big names in the field have already confirmed their attendance so this will surely be worth your while! Be sure to have a look at the website for more information and to get your early bird tickets!