Parottasalna

AI, Backend Engineering & Architecture Guides

Learning Notes #46 – Expand Contract Pattern | Refactor Pattern

Today, i learnt about Expand Contract Pattern from Raul Junco on a linkedin post. This pattern is particularly useful during system migrations, feature rollouts, or refactoring of large systems. It ensures that new functionality can coexist with existing functionality temporarily, allowing for seamless transitions and safe rollbacks if needed.

In this blog, i jot down notes on Expand Contract Pattern, for better understanding.

What Is the Expand-Contract Pattern?

The Expand-Contract Pattern is a two-phase approach to making changes in software systems.

1. Expand Phase: Introduce new functionality alongside the existing functionality without removing the old implementation. This ensures backward compatibility and allows the system to adapt to the new functionality gradually.

2. Contract Phase: Once the new functionality is validated and deemed stable, deprecate and remove the old implementation to streamline the system and reduce technical debt.

    The pattern is often used in environments where downtime, disruptions, or complete rewrites are not acceptable, such as production systems, APIs, and distributed architectures.

    Key Benefits

    • Backward Compatibility: Ensures that existing functionality continues to work during the transition.
    • Reduced Risk: Allows for testing and validation of new functionality in a real-world setting without fully committing.
    • Safe Rollbacks: Enables quick reversion to the old functionality in case of issues with the new implementation.
    • Incremental Changes: Encourages smaller, manageable changes instead of large, risky overhauls.
    • Improved Collaboration: Facilitates smoother handoffs between teams during feature rollouts.

    Workflow of the Expand-Contract Pattern

    The Expand-Contract Pattern typically follows these steps,

    1. Expand Phase

    In this phase, the focus is on introducing the new functionality without disrupting the existing system.

    • Add New Code: Implement the new functionality in parallel with the old functionality.
    • Feature Flags: Use feature toggles to control the activation of the new functionality.
    • Shadow Testing: Run the new implementation in the background to compare its outputs with the old implementation (if possible).
    • Data Duplication: If changes involve data, ensure both the old and new data models are updated in sync.

    2. Validation and Monitoring

    During the transition, monitor the system to ensure the new implementation works as expected.

    • A/B Testing: Gradually route a portion of traffic to the new implementation.
    • Metrics Collection: Track performance, error rates, and user feedback for both implementations.
    • Iterative Fixes: Address issues in the new implementation while keeping the old one operational.

    3. Contract Phase

    Once confidence in the new functionality is established, the old implementation is phased out.

    • Deprecate Old Code: Mark the old implementation as deprecated.
    • Remove Legacy Code: Clean up and remove the old implementation after sufficient validation.
    • Optimize New Implementation: Refactor and optimize the new implementation, reducing complexity.

    Practical Example: Using the Expand-Contract Pattern

    Let’s look at an example of applying this pattern to a database schema migration,

    Scenario

    You need to rename a column username to user_name in a production database without downtime.

    Step-by-Step Implementation

    Expand Phase

    1. Add the new column user_name to the table.
    2. Update application code to write to both username and user_name.
    3. Read from username for backward compatibility.

    Validation Phase

    1. Backfill existing data from username to user_name.
    2. Shadow test the application to ensure it reads correctly from user_name.
    3. Monitor logs, metrics, and user feedback for anomalies.

    Contract Phase

    1. Update application code to read from user_name only.
    2. Remove references to username in the codebase.
    3. Drop the username column from the database.

    References

    1. https://www.prisma.io/dataguide/types/relational/expand-and-contract-pattern
    2. https://www.tim-wellhausen.de/papers/ExpandAndContract/ExpandAndContract.html
    3. https://www.thoughtworks.com/en-in/radar/techniques/api-expand-contract

    Discover more from Parottasalna

    Subscribe now to keep reading and get access to the full archive.

    Continue reading