The Convergence of API’s and Microservices at the Process Layer Utilizing Hexagonal Architecture Patterns

Combining API-Led and Domain Driven Design to Govern Your Microservices Architecture (MSA)

API-Led Connectivity is a technique of organizing the API's microservices expose into three categories: System, Process and Experience. In previous blog posts I've covered how System API's act as an Anti-Corruption Layer on top of systems-of-record and how Experience API's enable business agility through modern development platforms. In this post I'll consider the role Process API's play in Service Meshes and Application Networks, and how leveraging hexagonal architectural patterns and Domain Driven Design (“DDD”) for identifying and managing microservices that will be surfaced as API’s.

Determining the granularity of microservices and API's is a challenge when adopting Service Mesh and Application Network-style architectures. DDD thankfully provides us a lot of guidance in this respect, particularly through the Bounded Context pattern. Identifying Bounded Contexts within a Subdomain provides a good starting point in identifying candidate microservices and their respective API's.

Organizing microservices within a Service Mesh is also important. As we identify microservices, either as part of a green field initiative or when decomposing a monolith, we also need to take into consideration the following topics to ensure the proper level of microservice granularity:

Microservice Design Considerations (these will be covered in detail in a separate blog post)

Contract design of the microservice's API

Consider how the microservice's API might be reused

Decide the priority in implementing each potential microservice

Estimate level-of-effort and identify resources for implementation

Determine the appropriate governance and controls around the microservice's API.

How you plan data movement across microservices in different security domains

Process microservice's generally capture logic in an organization's Core Domain. An organization's Core Domain concerns itself with differentiation from a business standpoint; it represents the "crown jewels" that makes an organization successful. Some examples include:

  • A microservice which uses a trained machine learning model to make product recommendations for customers
  • A collection of related microservices that deliver streaming video content globally
  • An event-driven microservice that monitors financial transactions and emits domain events when fraudulent activity is detected
  • A microservice that determines whether particular drugs interact negatively for a patient

It's important that this business logic is insulated from both systems-of-record (“SOR’s”) as well as different experience channels that need to consume it. For instance, we shouldn't need to retrain machine learning models because of a CRM upgrade or refactor how video data is surfaced because a manufacturer introduces a new version of television's operating system. System API's and Experience API's act like firewalls that protect the core domain from these potentially corruptive systems. This allows business logic to reside safely insulated within an Process API.

Leveraging Hexagonal Architecture to Determine Microservice Boundaries

In monolithic applications this approach is very similar to Hexagonal Architecture, so much so that hexagonal monoliths are generally straightforward to decompose into microservices. Hexagonal applications have objects in the core domain, and their associated domain logic, surrounded by a series of ports and adaptors. The ports and adaptors act as anti-corruption layers that transform data back and forth from the external systems to the Ubiquitious Language captured in the core domain. The following diagram illustrates this approach in a monolithic application:


The Ports and Adaptors in this diagram represent Anti-Corruption Layers that decouple the business logic in the Core Domain from both the systems-of-record as well as the different view layers. Refactoring this monolithic using API-Led connectivity becomes obvious. The ports and adaptors could incrementally become microservices fronting System and Experience API’s. The Core Domain capturing the business would become the Process API layer. The following diagram demonstrates this:


In this scenario a Bounded Context that captures differentiating business logic is implemented via a microservice fronted with a Process API. When the Process API needs to surface data from a system-of-record it does it by invoking a System API, or by reacting to domain events the System APIs may be emitting. Similarly when an Experience API needs to invoke the business logic, perhaps using data it has obtained from a System API, it does it via the Process API.1

1. Note that the implementation of the Process API will likely use its own anti-corruption layer to translate data from the System and Experience API's into its own internal Ubiquitous Language.


Process API Implementation

I've previously discussed how modern High Productivity Development frameworks like Mule can accelerate the implementation of System and Experience API's. Business logic, however, is not easily or succinctly captured in these tools. It's also difficult to apply the full breadth of the Tactical DDD patterns in an integration focused framework. Most importantly, if our System and Experience API's contracts are correctly designed it shouldn't be necessary for a Process API's implementation to be overly concerned with integration, orchestration and complex transformation. Freeing the Process API of these concerns lets the developers focus on correctly capturing the business logic in the given subdomain.

As such it generally makes sense to use a traditional object-oriented development stack for Process API's, like Java or .NET. Within these stacks frameworks like Spring Boot, Akka and CQRS/Event Sourced approaches can be used to accelerate development. For highly choreographed approaches the Process API layer is a good place to implement Process Managers(fundamentally keeps track of the overall process for decoupled domain events).

Process API's are also a good way to leverage specialized tools like BPM and rules engines in a way that cleanly "plugs into" the rest of the architecture. A BPM workflow, for instance, can be defined by orchestrating System API's without conflating integration logic into the process. Similarly a rules engine might be encapsulated within a Process API and invoked by Experience API's.

Finally, and somewhat ironically, an Application Network or Service Mesh might not have any Process API's. This is particularly true if the microservices aren't part of the Core Domain. Microservices to support an initiative in a marketing group, for instance, might only be concerned with easily surfacing data from systems-of-record and presenting it to different front-ends for consumption.

In Conclusion

Domain Driven Design and API-Led Connectivity provide a lens through with we can determine and organize microservices in an Application Network or Service Mesh. Hexagonal Architecture, while generally applied to monolithic applications, can also be applied "in the large" to a broader microservice approach. Well designed System and Experience API's provide a foundation to capture the business domain in Process API's while leveraging advanced frameworks. This ultimately allows you to focus your best developers on delivering differentiating value to the business, freed from the concerns of integrating with hairy systems-of-record or having to deal with delivering experiences to different engagement channels.