Philosophy and Design

Non-blocking refactoring

Bronto takes a "non-blocking" approach to code transformation. Let's explore that idea with a simple example of renaming a function. A classical "blocking" approach would be to change the name of LegacyFunction to NewShinyFunction, and then go find all of the callers of LegacyFunction and update them as well. This approach is "blocking" in the sense that you must find and replace every reference to LegacyFunction before the code will compile again. In other words, uses of NewShinyFunction must wait until all references to LegacyFunction have been changed.

Consider a different four-step approach.

Create a copy of NewShinyFunction with an identical body to LegacyFunction.

Update the implementation of LegacyFunction to simply call NewShinyFunction.

Replace all calls to LegacyFunction with the body (the call to NewShinyFunction).

When there are no more callers, delete LegacyFunction.

Notice that immediately after step 1, NewShinyFunction is usable. You don't have to complete the entire refactor before users can gain the benefits of the new feature, no matter how many callers LegacyFunction has. Moreover, Bronto automates step 3 so it can happen in the background. After Bronto finishes step 3 across all your callers, codebases, and dependencies, you can come back and handle step 4.

Intent as source code

The non-blocking approach to refactoring can tackle much larger refactoring problems than a blocking approaches allow. It gracefully handles other developers making simultaneous changes (potentially even adding new usages of LegacyFunction!). It handles these new changes as they are added, by recording the intended refactoring directly in the code, so it can be seen across repositories and centrally administered. This is the key insight for Bronto's overall design.

The changes you intend for your codebase should be a part of your codebase.

Rather than living in a developers brain or IDE, intended refactorings should be tracked in version control. Allowing engineers to understand not just the current state of the codebase but where it is headed and how that direction has changed, all with commit messages explaining why.

This stronger model for refactoring applies normal development practices to refactoring problems. Allowing automation to manage much larger refactorings than traditional approaches that lack a central source of truth.