0
0
Microservicessystem_design~7 mins

Anti-corruption layer in Microservices - System Design Guide

Choose your learning style9 modes available
Problem Statement
When integrating a new microservice with an existing legacy system, direct communication can cause the new service to inherit the legacy system's design flaws and complexity. This leads to tight coupling, making the new service fragile and hard to evolve independently.
Solution
An anti-corruption layer acts as a translator and adapter between the new microservice and the legacy system. It isolates the new service from legacy models by converting legacy data and operations into a clean, consistent interface that the new service can use without adopting legacy design issues.
Architecture
┌───────────────┐       ┌───────────────────────┐       ┌───────────────┐
│ New Microservice│──────▶│ Anti-Corruption Layer │──────▶│ Legacy System  │
└───────────────┘       └───────────────────────┘       └───────────────┘

This diagram shows the new microservice communicating only with the anti-corruption layer, which in turn interacts with the legacy system, preventing direct coupling.

Trade-offs
✓ Pros
Prevents legacy system design flaws from spreading into new services.
Enables independent evolution of new microservices without legacy constraints.
Improves maintainability by isolating legacy complexity.
Facilitates gradual migration or replacement of legacy systems.
✗ Cons
Adds extra development and maintenance effort for the translation layer.
Can introduce latency due to additional processing steps.
Requires deep understanding of both legacy and new system models.
Use when integrating new microservices with complex or poorly designed legacy systems where direct coupling would hinder maintainability or evolution, especially in systems with high complexity or long-term migration plans.
Avoid when legacy systems are simple, well-designed, or when integration is minimal and unlikely to cause coupling issues, or when project timelines do not allow for the extra layer development.
Real World Examples
Amazon
Used anti-corruption layers to integrate new microservices with their legacy monolith, allowing independent service evolution without inheriting legacy constraints.
Netflix
Applied anti-corruption layers to isolate new streaming services from legacy billing systems, enabling faster feature development without legacy system dependencies.
Uber
Implemented anti-corruption layers to connect new dispatch microservices with legacy databases, preventing legacy data model pollution.
Code Example
The before code shows the new service tightly coupled to the legacy data format, using legacy keys directly. The after code introduces an anti-corruption layer that translates legacy data into a clean, consistent model. The new service interacts only with this layer, preventing legacy model pollution.
Microservices
### Before: Direct legacy coupling
class LegacySystem:
    def get_user_data(self, user_id):
        # Returns data in legacy format
        return {'usr_id': user_id, 'nm': 'John Doe', 'addr': '123 St'}

class NewService:
    def __init__(self, legacy):
        self.legacy = legacy

    def get_user_profile(self, user_id):
        data = self.legacy.get_user_data(user_id)
        # Directly uses legacy keys
        return f"User {data['nm']} lives at {data['addr']}"


### After: Using Anti-Corruption Layer
class LegacySystem:
    def get_user_data(self, user_id):
        return {'usr_id': user_id, 'nm': 'John Doe', 'addr': '123 St'}

class AntiCorruptionLayer:
    def __init__(self, legacy):
        self.legacy = legacy

    def get_user_profile(self, user_id):
        legacy_data = self.legacy.get_user_data(user_id)
        # Translate legacy data to clean model
        return {
            'id': legacy_data['usr_id'],
            'name': legacy_data['nm'],
            'address': legacy_data['addr']
        }

class NewService:
    def __init__(self, acl):
        self.acl = acl

    def get_user_profile(self, user_id):
        profile = self.acl.get_user_profile(user_id)
        return f"User {profile['name']} lives at {profile['address']}"
OutputSuccess
Alternatives
Strangler Fig Pattern
Gradually replaces legacy system functionality by building new services around it, rather than isolating it with a translation layer.
Use when: Choose when planning a phased migration to fully replace legacy systems over time.
Facade Pattern
Provides a simplified interface to a complex subsystem but does not necessarily translate or isolate legacy models.
Use when: Choose when simplifying access to legacy systems without needing to prevent model corruption.
Summary
Anti-corruption layers prevent legacy system design flaws from affecting new microservices by translating legacy models.
They isolate new services from legacy complexity, enabling independent evolution and maintainability.
This pattern is essential when integrating with complex or poorly designed legacy systems to avoid tight coupling.