Andrei Mackenzie

Andrei Mackenzie

Principal Software Engineering Manager at Microsoft

17 May 2022

Forward Compatibility

Martin Kleppmann’s excellent Designing Data-Intensive-Applications includes much wisdom for how to evolve applications without incurring downtime. A key concept is backward-compatibility: the idea that a new application version should be compatible with data and/or interfaces that the previous version supported. This concept is understood widely enough to be known to most developers, particularly because it comes up a lot when migrating application code relative to relational database schema and data. This is a common use case across many domains and professional settings, and it is therefore intuitive to most developers. Kleppmann also describes forward-compatibility, which is less common and intuitive.

What is Forward Compatibility?

The summary of chapter 4 includes an incredibly useful insight to help make sense of this. The insight is based on putting the application code in the center of a visual model: backward-compatibility is “old data, new code” while forward-compatibility is “old code, new data”1. The latter scenario typically happens during a deployment of a new application version to a distributed system. It is impossible to upgrade all application instances in an instant while maintaining service. Rolling deployments are typically performed, and this results in some application instances running the old application version while some others have been upgraded to the new version. The upgraded instances can produce new data, and it is desirable for old application versions to be compatible with this data. This is often necessary because the full pool of application instances (including old and new versions) are treated as equivalent peers by an upstream client, for example an upstream load balancer calling into a pool of web servers. The load balancer can be simpler if it doesn’t need to reason about which instances can handle data produced by old or new application versions.

This is the visual I find useful when thinking about these problems:

(old) data  <--backward compatibility-- (new) code
                                        (old) code --forward compatibility--> (new) data

1: Kleppmann, M. (2018). Designing Data-Intensive Applications (4th ed.). O’Reilly. p. 139.