Maintaining backward compatibility

I've recently decided I'm going to open source Build Configs tool that I use to generate build configuration files for Drupal, Sculpin and Fractal projects.

Inspired by Workspace and others, and based on previous versions of similar tools - most recently by TheAltF4Stream's project with the same name (which is written in Rust and supports different template types) - I've been using this tool to manage configuration files for various personal, client and open-source projects.

Before I open-source it, there are some changes I'd like to make, such as renaming some template types and updating the format and keys within the configuration file.

Changes to the configuration file would be a breaking change and, whilst it's only me using it, I want my other projects to keep working and for me to continue supporting the prior versions - at least for now, so I want to make sure any changes are backward compatible.

How it works

There are four steps performed when generating files for a project:

Create a final configuration object from the project's configuration file as well as any defaults.

Validate the final configuration.

Create a list of files to generate.

Generate the files.

If I change sculpin to sculpin-site in a configuration file, for example, it will fail the validation step.

But, I have an opportunity within the first step to perform any normalisation that's needed and to provide a compatibility layer - such as changing sculpin-site, which is an invalid value, to sculpin.

I also renamed symfony to symfony-cli by performing the same step.

This means the validation step will receive valid data that it can use and the new changes have been encapsulated within a single step of the process. I haven't needed to change any code elsewhere.

I can also add deprecation warnings if legacy values are used.

Here's the thing

Similar to feature flags, this is temporary code that will later be removed when I'm ready to remove the compatibility layer, similar to how drupal_set_message() was deprecated and changed to use the Messenger service before being removed in Drupal 9.

In the future, I can refactor the internal logic to use a different approach and when I'm ready, eventually remove the compatibility layer and tag a new major version with the breaking changes.