Verifying Large Refactors in Production with Sentry
Sentry is excellent at capturing runtime errors in your applications. With the recent additions of performance monitoring and release health, it can further help as you build and ship code. Recently we used Sentry to ensure we didn’t break Sentry while doing a large code refactoring project. When replacing an API or code path with a new implementation you'll likely 'deprecate' the old path, but how do you know when that old path is finally not in use? If your code is running on a server, you could use metrics or logs, but even with them, it can be challenging to capture the required context to pinpoint where deprecated code is still in use. If your code is on the frontend logs are not an option, and you’ll need to be more creative.
Code Refactoring Case Study: Replacing Icons
I was recently in the exact situation described above. I had been working on a sweeping refactor of the icons in our application alongside Dora Chan, product designer, and Billy Vong, fellow frontend developer. The three of us were upgrading our buffet of icon implementations with a new system based on React components. With 600+ call sites and three deprecated forms of icons, we had our work cut out for ourselves.
The first style were icons defined as class names on elements. An example would be
<p><i class="icon icon-warning" /> Something dangerous<
These were simple to fix as we could find all instances with grep
. The next form was our <InlineSvg />
component. Updating this component was simple. Again we could use find and replace to remove <InlineSvg >
and add the new icon component.
The final form was icons passed into our Button
and Alert
components as strings. These were more challenging as we use property spreading in many parts of our application. Property spreading defeats static code searching, as the source and destination of a value are often in different files. For example
<Button icon="checkmark">Click Me</Button>
Is easy to fix, whilst
<Button {...props}>Click Me</Button>
is much harder to track down.
Updating the Alert and Button components
Our first step in updating the Alert and Button components was to allow their icon prop to accept either a string or one of the new Icon components. This lets us update all the call sites where we had literal icon values.
// This
<Button icon="warning">Click me</Button>
// Would become
<Button icon={<IconWarning />}>Click me</Button>
With all the simple to locate call sites updated, we needed a better way to track down all the dynamic call sites and swap in the new icons.
Enter Sentry for Deprecations
Brazenly removing the string icon path would have resulted in a broken user experience and errors in our browser application which we didn't want. What if we captured what would be an error after our change and made it into an warning ahead of time? This would let us have customers track down any code paths we missed silently behind the scenes.
In both our Button and Alert components I added code that looked like:
// String icons are the old form that we want to make sure is gone.
if (typeof icon === 'string') {
withScope(scope => {
scope.setLevel(Severity.Warning);
scope.setTag('icon', icon);
// This would vary based on the component that was being used.
scope.setTag('componentType', 'alert');
captureException(new Error('Deprecated SVG icon referenced'));
});
}
After deploying this change we started capturing events and by correlating the route being used and the new componentType
and icon
tags we were able to track down the remaining call sites and fix them. After each fix was deployed we were able to watch the volume of events being captured drop. Once we had a few days of zero events we knew were finished and that the old paths could be removed safely.
Sentry is great for helping you fix the mistakes you've made, but it can also be a powerful tool in helping track down scenarios that are otherwise hard to find with other methods. From code refactoring to performance monitoring, Sentry can help you ship better software