Journal of Distributed Software Engineering, Architecture and Design
The Power of Adapters in Service Architecture:
<div class="cs-rating pd-rating" id="pd_rating_holder_1819065_post_2839"></div>
<p class="wp-block-paragraph">When building a service architecture, understanding the significance of each component is paramount. Among these components, the <strong>Adapter</strong> stands out as an element that often prompts contemplation and inquiry. Questions arise: “Is this additional layer truly necessary?” “Does it introduce undue complexity?” “How does it fit within the overarching structure?” Drawing from extensive experience and insights garnered from industry leaders, this article aims to demystify the role of adapters. We will delve deep into their essential contribution, emphasizing their instrumental role in crafting a responsive, streamlined, and forward-looking service architecture.</p>
<p class="wp-block-paragraph">From an architectural standpoint adapters are essential for standardisation, anti-corruption and decoupling systems, however from a business perspective they can be the difference between <em>autonomy</em> across disconnected teams through a clean architecture or<em> running a 3-legged</em> race due a complex intertwined integration architecture</p>
<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><a href="https://alok-mishra.com/wp-content/uploads/2023/09/high-leve.png"><img src="https://alok-mishra.com/wp-content/uploads/2023/09/high-leve.png?w=470" alt="" class="wp-image-2856" style="width:269px;height:auto" /></a><figcaption class="wp-element-caption">A high level view of consumer application and services</figcaption></figure>
</div>
<p class="wp-block-paragraph"><strong>Boundaries </strong></p>
<p class="wp-block-paragraph">A service architecture with different systems/applications consuming a set of services (APIs and events) can have different contexts each with their own specific language, logic, model and actors. Boundaries can be hard to find especially when the problem is stated as an end-to-end solution, for example: when we hear “we need data from system x” instead of “we need to consume this domain data” we imagine a point-to-point solution</p>
<p class="wp-block-paragraph">One way to imagine boundaries is as shown below, each system is in its own context using the heuristic “new system / application” is a different context. This is represented as a DDD context map like this</p>
<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><a href="https://alok-mishra.com/wp-content/uploads/2023/09/context-map.png"><img src="https://alok-mishra.com/wp-content/uploads/2023/09/context-map.png?w=1024" alt="" class="wp-image-2857" style="width:424px;height:auto" /></a><figcaption class="wp-element-caption">Context map </figcaption></figure>
</div>
<p class="wp-block-paragraph">When we add command, queries and events our DDD context map gets richer</p>
<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><a href="https://alok-mishra.com/wp-content/uploads/2023/09/context-map-with-relationships.png"><img src="https://alok-mishra.com/wp-content/uploads/2023/09/context-map-with-relationships.png?w=1024" alt="" class="wp-image-2859" style="width:447px;height:auto" /></a><figcaption class="wp-element-caption">Context map with cross-context relationships and see exchange of information via command, queries, events </figcaption></figure>
</div>
<p class="wp-block-paragraph">Key then is to realise these boundaries exist as we draw our end to end solution diagrams and view the world differently – contexts do not go away when our perspective shifts to a specific outcome, boundaries exist and we need ways to ensure things pass in and out of the boundaries without corrupting internal context logic</p>
<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><a href="https://alok-mishra.com/wp-content/uploads/2023/09/boundaries.png"><img src="https://alok-mishra.com/wp-content/uploads/2023/09/boundaries.png?w=1024" alt="" class="wp-image-2853" style="width:678px;height:auto" /></a><figcaption class="wp-element-caption">Solution context contain boundaries</figcaption></figure>
</div>
<p class="wp-block-paragraph">Boundaries are also important because we want the things (technology components) within the boundary to have high cohesion which things across boundaries to be as lightly tied together as possible (loose coupling</p>
<p class="wp-block-paragraph"><strong>A Practical Dive: The Student Management System</strong></p>
<p class="wp-block-paragraph">Let us use an example of a “Student Management System” which has interface for student query (query), enrolment (command), fetching student related data like courses (query) etc and events for student data changes ( state-change events and data events) </p>
<p class="wp-block-paragraph">Now, let us imagine we have 3 consumers C1, C2, and C3 with different requirements </p>
<ul class="wp-block-list">
<li><strong>C1</strong>: Bulk data ingestion, lots of reads and require data authorization </li>
<li><strong>C2</strong>: Requires near real-time events from core system and real-time APIs to query the back end for the latest and it deals with time-critical business functions</li>
<li><strong>C3</strong>: Is a web or mobile channel which requires real-time reads and commands. Perhaps it needs a one-way command the most on the busiest days of the year ( submit enrolment etc)</li>
</ul>
<p class="wp-block-paragraph">Using consumer adapters we can then handle these concerns in the specific adapters instead of baking them in the domain services</p>
<ol class="wp-block-list">
<li><strong>Connection</strong>: A flawless handshake with the “Student API,” irrespective of the consumer’s quirks.</li>
<li><strong>Security</strong>: Tailor-made security protocols for each consumer’s peace of mind.</li>
<li><strong>Performance</strong>: Data retrieval and processing that’s not just fast, but also efficient.</li>
<li><strong>Aggregation</strong>: Merging data from diverse sources, delivering a comprehensive dataset.</li>
<li><strong>Customization</strong>: Crafting data and services to match the exact whims and fancies of each consumer.</li>
</ol>
<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><a href="https://alok-mishra.com/wp-content/uploads/2023/09/connsumer-adapter-alok-mishra.png"><img src="https://alok-mishra.com/wp-content/uploads/2023/09/connsumer-adapter-alok-mishra.png?w=1024" alt="" class="wp-image-2847" style="width:580px;height:auto" /></a><figcaption class="wp-element-caption">A sample C4 container view of consumers, consumer adapters and domain APIs</figcaption></figure>
</div>
<p class="wp-block-paragraph">Using the adapter pattern can appear to add an extra layer and while we recommend being pragmatic about this we recommend serious considering this pattern as it adds flexibility and de-couples the solution. </p>
<p class="wp-block-paragraph">The key point is that we keep consumer and downstream system logic our of our core domain services especially when building them at the same time. When components are “born together” in projects there is a stronger tendency for the boundaries between them to be more permeable leading to stronger coupling between them. Given the funding models are most often project based vs product based we find having a consumer adapter between an application and a core business service in a domain API can help build stronger boundaries and better separation of concerns leading to lower coupling</p>
<p class="wp-block-paragraph">Consider in our example, if system C1 was released with Domain API first a then other systems C2 and C3 were released at a later time through two subsequent projects. Without consumer adapters, each system would imp</p>
<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><a href="https://alok-mishra.com/wp-content/uploads/2023/09/option-2-directly-couple-copy.png"><img src="https://alok-mishra.com/wp-content/uploads/2023/09/option-2-directly-couple-copy.png?w=1024" alt="" class="wp-image-2852" style="width:633px;height:auto" /></a><figcaption class="wp-element-caption">Without adapters, consumer concerns push into a core business service incrementally which leads to inherent coupling across the consumers through the domain service </figcaption></figure>
</div>
<p class="wp-block-paragraph">Adapters help establish these boundaries and act as an anti-corruption layer across boundaries preventing external formats from leaking into internal implementations and internal system details leaking out to external services</p>
<p class="wp-block-paragraph"><strong>Conclusion</strong></p>
<p class="wp-block-paragraph">In the sophisticated realm of service architecture, adapters are indispensable. They orchestrate harmonious interactions, tailor experiences, and drive growth. Recognizing their pivotal role, it’s imperative to fully understand, embrace, and leverage their capabilities. Their integration ensures that our architectural frameworks are not just robust for today but are also geared to meet the challenges of the future.</p>
<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><a href="https://alok-mishra.com/wp-content/uploads/2023/09/boundaries-1.png"><img src="https://alok-mishra.com/wp-content/uploads/2023/09/boundaries-1.png?w=1024" alt="" class="wp-image-2863" style="width:687px;height:auto" /></a><figcaption class="wp-element-caption">Adapters enforce boundaries and help with context isolation. Directly integrating systems to core services or other systems without adapters can lead to very tight coupling which leads to slower change and poor value delivered to end consumers </figcaption></figure>
</div>
When building a service architecture, understanding the significance of each component is paramount. Among these components, the Adapter stands out as an element that often prompts contemplation and inquiry. Questions arise: “Is this additional layer truly necessary?” “Does it introduce undue complexity?” “How does it fit within the overarching structure?” Drawing from extensive experience and insights garnered from industry leaders, this article aims to demystify the role of adapters. We will delve deep into their essential contribution, emphasizing their instrumental role in crafting a responsive, streamlined, and forward-looking service architecture.
From an architectural standpoint adapters are essential for standardisation, anti-corruption and decoupling systems, however from a business perspective they can be the difference between autonomy across disconnected teams through a clean architecture or running a 3-legged race due a complex intertwined integration architecture
A high level view of consumer application and services
Boundaries
A service architecture with different systems/applications consuming a set of services (APIs and events) can have different contexts each with their own specific language, logic, model and actors. Boundaries can be hard to find especially when the problem is stated as an end-to-end solution, for example: when we hear “we need data from system x” instead of “we need to consume this domain data” we imagine a point-to-point solution
One way to imagine boundaries is as shown below, each system is in its own context using the heuristic “new system / application” is a different context. This is represented as a DDD context map like this
Context map
When we add command, queries and events our DDD context map gets richer
Context map with cross-context relationships and see exchange of information via command, queries, events
Key then is to realise these boundaries exist as we draw our end to end solution diagrams and view the world differently – contexts do not go away when our perspective shifts to a specific outcome, boundaries exist and we need ways to ensure things pass in and out of the boundaries without corrupting internal context logic
Solution context contain boundaries
Boundaries are also important because we want the things (technology components) within the boundary to have high cohesion which things across boundaries to be as lightly tied together as possible (loose coupling
A Practical Dive: The Student Management System
Let us use an example of a “Student Management System” which has interface for student query (query), enrolment (command), fetching student related data like courses (query) etc and events for student data changes ( state-change events and data events)
Now, let us imagine we have 3 consumers C1, C2, and C3 with different requirements
C1: Bulk data ingestion, lots of reads and require data authorization
C2: Requires near real-time events from core system and real-time APIs to query the back end for the latest and it deals with time-critical business functions
C3: Is a web or mobile channel which requires real-time reads and commands. Perhaps it needs a one-way command the most on the busiest days of the year ( submit enrolment etc)
Using consumer adapters we can then handle these concerns in the specific adapters instead of baking them in the domain services
Connection: A flawless handshake with the “Student API,” irrespective of the consumer’s quirks.
Security: Tailor-made security protocols for each consumer’s peace of mind.
Performance: Data retrieval and processing that’s not just fast, but also efficient.
Aggregation: Merging data from diverse sources, delivering a comprehensive dataset.
Customization: Crafting data and services to match the exact whims and fancies of each consumer.
A sample C4 container view of consumers, consumer adapters and domain APIs
Using the adapter pattern can appear to add an extra layer and while we recommend being pragmatic about this we recommend serious considering this pattern as it adds flexibility and de-couples the solution.
The key point is that we keep consumer and downstream system logic our of our core domain services especially when building them at the same time. When components are “born together” in projects there is a stronger tendency for the boundaries between them to be more permeable leading to stronger coupling between them. Given the funding models are most often project based vs product based we find having a consumer adapter between an application and a core business service in a domain API can help build stronger boundaries and better separation of concerns leading to lower coupling
Consider in our example, if system C1 was released with Domain API first a then other systems C2 and C3 were released at a later time through two subsequent projects. Without consumer adapters, each system would imp
Without adapters, consumer concerns push into a core business service incrementally which leads to inherent coupling across the consumers through the domain service
Adapters help establish these boundaries and act as an anti-corruption layer across boundaries preventing external formats from leaking into internal implementations and internal system details leaking out to external services
Conclusion
In the sophisticated realm of service architecture, adapters are indispensable. They orchestrate harmonious interactions, tailor experiences, and drive growth. Recognizing their pivotal role, it’s imperative to fully understand, embrace, and leverage their capabilities. Their integration ensures that our architectural frameworks are not just robust for today but are also geared to meet the challenges of the future.
Adapters enforce boundaries and help with context isolation. Directly integrating systems to core services or other systems without adapters can lead to very tight coupling which leads to slower change and poor value delivered to end consumers
Alok brings experience in engineering and architecting distributed software systems from over 20 years across industry and consulting. His posts focus on Systems Integration, API design, Microservices and Event driven systems, Modern Enterprise Architecture and other related topics
View all posts by alokmishra