peshkova - Fotolia
How to fuse domain-driven design and microservices
Domain-driven design helps organizations create business capabilities with the architecture that microservices need. Here's how to merge DDD into your development process.
Developers working on granular microservices, each designed to perform a singular function, should link those services to specific business needs and processes. However, they also must prioritize a distributed, stateless and model-based architecture. Development processes must adapt to serve these two priorities.
Domain-driven design (DDD) instills this focus on business demands by uniting business-matter specialists with software developers. Domain refers to an area of knowledge, and there are core and sub domains in an organization.
To incorporate DDD into a microservice architecture, teams must:
- divide business domains and functions into bounded contexts;
- create a unified, ubiquitous language; and
- separate functional capabilities concerns from architectural considerations.
In DDD, the goal is to divide a business into its broad functions. Then, split these domains further into individual subdomains for specific business activities. These domains and subdomains define bounded contexts: practical divisions of responsibilities that can relate to specific application services.
When used correctly, bounded contexts reveal the structural goals that translate to domain-driven design. Development teams can diagram and map bounded contexts, and then convert those contexts into code that makes up the corresponding business application. Ideally, these bounded contexts focus on singular, simple relationships. Clearer relationships make it easier to test whether you've defined the boundaries correctly.
To make DDD and microservices work together, define user-to-application relationship goals as bounded contexts. For instance, if you plan to expose applications to users via a virtual desktop, that's a business goal that represents a bounded context.
Normal DDD practice calls for the use of a ubiquitous language. However, languages aren't ubiquitous if everyone involved in the software project can't easily read and review the code. And it's not practical to teach domain experts how to program.
Don't start blindly writing code at this point. Instead, write main functional logic flows that reference well-named variables and invoke clearly defined procedures. This will help domain experts achieve the high-level view they need to review the functional flows and play their part in the domain-driven design.
The best languages for domain-driven software are structured and procedural, which permits the object definitions, functions, classes and readable names you need. Proper componentization and naming enables a development language to serve as a truly ubiquitous language.
Also, a good ubiquitous language description should convey the functional flow separate from the structural flow. It should separate the details of how the software will be implemented and deployed from the details that describe what it does. Each high-level flow invokes procedures, and the way you implement these procedures will facilitate -- or accidentally derail -- the effective use of microservices.
Defining sharable components
Again, componentization is the key decision here to make microservices and the domains work. It's easier to create sharable components at the language level, because properly named procedures identify common functionalities just by the name. Then, microservices developers can work to harmonize implementations and meet multiple sets of requirements. Anything sharable is a candidate for translation into an independent component and a microservice.
Some nonsharable functions or procedures are also candidates for microservices. For example, look for functions that are both complex enough to benefit from scaling under load, and independent enough to be considered a parallel process. The benefits of a microservices architecture go beyond reusability.
When all of this is done, rediagram your bounded context map to decompose each context into high-level processes. Also, extract the shared processes into a new context that has a relationship to all the other bounded contexts it contributes processing to. After a final review, refine the ubiquitous language into final application code.
DDD and microservices work together when organizations can blend functional and architectural considerations. This means allowing domain experts to contribute to the functional side, and software architects to control the architecture. Start working together early on, and focus on the transformation from detailed design to code.