It seems that ‘Bounded Context’ (from Eric Evans’ Domain Driven Design) has become one of the terms that have to be included in every microservices talk (along ‘Conway’s Law’, of course). And in fact, it’s an important concept, and although not really hard to understand, there are different approaches to implement relations and communication between bounded contexts. In this blog post I describe how I extended my movie-database system with another bounded context for the concept of movies. I added a non-ROCA self-contained system for shop functionality using AngularJS, grunt, bower on the client side and Spring Boot REST with JPA on the server side, and I am using server side includes (SSI) for integrating the navigation bar into the frontend.
This blog post is a follow-up to ‘Self-Contained Systems and ROCA: A complete example using Spring Boot, Thymeleaf and Bootstrap’, so reading that blog post would probably help to understand this one. It explains the theory behind my movie-database system made up of several self-contained systems using technologies like Spring Boot, Spring MVC, Spring Security, Thymeleaf, Bootstrap, jQuery, nginx and Redis. You can find the sources along with installation directions here on Github. As a small reminder, here is the architecture of the original systems:
So, what’s the new bounded context?
Okay, before I added the new self-contained system there were two systems, one for movies, one for actors. They had their intersections, and we dealt with them, but the separation was easy, because they were really different things from a business point of view.
Now I want to add a shop system where you may buy movies. The same movies the movies system deals with, where we may add movies, change descriptions, post comments etc. We need a few more attributes now, for example the price and the number of copies we have in stock, so let’s just extend the model and the database tables and – wait! We are sliding down the alluringly easy path to the monolith. Let’s step back for a moment and think about why that may not be such a good idea.
We already agreed that selling movies and maintaining movie information for a movie database are two very different things. The business logic is very different, so building two systems for it is definitely a good idea. Both systems have the concept of a movie, but the model attributes are different:
Here we have two bounded contexts for movies, and depending on the context, the models differ. We have some attributes in both models, in this simplification it’s the title and the description of the movie which we need to display in a shop system, and an id. We really need some relation between those models, because we want to be able to link to a movie from the shop system and vice versa, so what do we do now? We need to make some decisions:
- We use the same IDs in both systems to be able to link between those models.
- The shop system may need the title and the description for display, but it’s not its purpose to maintain them. So we decide that only the movies system is responsible for updating those attributes.
- Whenever we want to sell a movie with the shop system, it needs to exist in our movies system, so our movies system is the system responsible for creating and deleting movies. This simplifies our use case.
Each system gets its own persistence, which leads us to the next question: how does the shop system know about created/updated/deleted movies in the movies system? We could create a REST/SOAP service that needs to be called synchronously by the movies system on creation and deletion of a movie, and then the movies system could create a REST/SOAP service that takes an id and returns description and title, and the shop system could call that service whenever it needs to display that data. So what do we get? A lot of interfaces to hold meetings over, and a strong runtime coupling. And it gets worse and worse with each new system that needs movie data. So is it the best solution? Obviously not.
Eventing / Messaging
There are different types of messages, two important types are event messages and command messages. While event messages inform their recipients of a change that has happened command messages want the recipient to actually do something. The naming naturally reflects this difference, event messages usually are something like ‘MovieCreated’, ‘MovieUpdated’ and ‘MovieDeleted’, while command messages would be ‘DeleteMovie’ etc. In our case we only need event messages.
The movies system emits an event whenever a movie is created, updated or deleted, and any other system may register to get these events, in our case just the shop system. The event includes the movie’s data, so in our simple use case the shop system creates a movie entity with the same id and some default values for shop-specific data when it receives a MovieCreated event.
The shop system also persists the title and the description in its persistence layer, and only MovieCreated and MovieUpdated events are used to actually change those attributes.
This is implemented with Redis messaging (creating events in this service, receiving events here). Note that Redis pub/sub capabilities (like I used them here) aren’t suitable for a production environment, because messages are lost if a receiving system is not online when the event gets emitted.
Wait, did you say NON-ROCA self-contained system?
Yes. Although integrating several self-contained systems via links has some preconditions, them being ROCA-style applications is not one of them. The two most important things are adressability of resources (different URLs for different resources) and full control over HTML markup and CSS, and you can achieve that with a lot of technical solutions. Here I am using AngularJS – simply because it’s a framework you need to know these days, at least to be able to judge architectures based on it. And I didn’t know it. AngularJS is template-based with full control over HTML markup and CSS, and it offers the adressability of resources via the routing module. When navigating the movie-database you’ll notice the fact that AngularJS is used only by the hash in the URL (and the absence of a full page reload).
Of course, doing a single page app instead of server side rendering (hiding the web vs. embracing it) is another topic with advantages and disadvantages on both sides, and it’s not the topic of this blog post. My point here is only that you’re not bound to any approach when doing self-contained systems.
The shop system has two parts: a Spring Boot / Spring MVC / REST backend (including the topic listener for movie events) built with Maven, and an AngularJS frontend built with bower and grunt. The static Angular app is delivered directly by nginx, while the backend is a Java application, obviously. The index.html of the Angular app includes the navigation bar by using server side includes (SSI).
It should be clear now what a bounded context is and how you may implement communication between systems that have different bounded contexts for some entity (a movie in this case).
It also should be clear that the concept of self-contained systems is not bound to ROCA-type applications.