Last year, Range got a fresh coat of paint! Our designer Taylor shared about the design process here. As the engineer who took on implementation of the new design system, I wanted to share a bit about the approach and process from the engineering side.
Before the rollout of the new design system, our codebase had drifted quite a bit from our original “defaults,” and engineers pretty liberally overrode styles on specific pages to match the designs.
For example, our default font size was technically 16, but somewhere in the last few years, more and more places drifted into 14 — we overrode the font size in so many places that I didn’t really consider 16 the default anymore. Similarly, border radii for similar components could be anywhere from 2 to 10 pixels. Inconsistencies like these seem small, but the accumulation of many inconsistencies add to an engineer’s mental load when implementing or iterating on features.
Rolling out a new design is one of those things that companies can spend months on with a dedicated team, but as an early-stage startup, we didn’t want it to completely stop product work. With that in mind, I spec'd out some options.
The two main options I considered were:
The first option would require supporting both the existing design system and new design system, as well as making the codebase messier before it was cleaner. Additionally, we would have to coordinate timelines — if other engineers were building something new, they’d need to decide if they should build it with the new design system. On the other hand, multiple engineers could help out with the design refresh, and initial internal progress would be swifter, as we could easily flip the flag to see ongoing progress.
The second option was to do it all in one go. With this approach, other product development could continue as usual. And with just one person rolling out the change, communication overhead was drastically reduced.
Given our team size and codebase complexity, I decided to take the second approach.
The benefits of having several engineers working on this together was not worth the coordination overhead (trying to reduce merge conflicts, spec’ing everything out first, figuring out who was working on what, how all the pieces fit together, etc.).
An additional bonus of having one person do it all was that I ended up looking at every piece of frontend code, and was able to pull out and standardize a lot of mixins, simplifying our codebase even more.
Although this worked well for us and our codebase, for larger teams and codebases, this approach is probably not feasible — in that scenario, I’d have opted for a bottoms-up approach, starting with base components and creating shared css mixins. After setting up all that groundwork, it’d be possible to split the remaining changes between different people all working together behind a feature flag.
With the design system specs and an approach in hand, I started on this change on a Tuesday.
First, I changed and renamed all the colors to match the new design system colors. Everything looked a bit funky.
For the next few days, I bit off parts of the app, iteratively making components on every page consistent with the new design system.
Since the left nav bar was looking the most funky (and because it shows up everywhere), that’s where I started.
Then I moved to the top nav, and then the homepage — which actually had a lot of lower-level components, so this is where I started updating the card components, buttons, etc.
For each page in the app, I opened popups, clicked on all the buttons, did all the things — to migrate it over to the new design system. Each subsequent page had less and less work, since components that we already use across pages were being converted at every step.
As I went, I also kept track of where I’d be able to unify styles, pull out standardized mixins, and do general cleanup.
At the end of it all, I also implemented a component library, where we can easily visually see all the components we use — a good reminder for our designer as well, when designing new pages and features.
Just a week later, I pushed my mega-pull-request to staging on Wednesday, and it went live that Friday — just a week and a half from first code change to being live in production.
My biggest surprise is that it didn’t take longer. I had originally envisioned a more bottoms-up approach of handling base styles first, and building up from there. But when I just started hacking away at it, without the need for communication overhead, it went surprisingly well and quickly.
As the engineer who fully implemented this design refresh, I also had relevant context to make a lot of improvements to make the codebase much more consistent and reduce ongoing mental load for engineers.
I particularly enjoyed being able to standardize types, clean up custom implementations of core components and unused code.
With the new design system fully in place, not only does Range look better, but the mental load for each engineer is significantly lower. With standardized options, there are fewer decisions to make around, allowing all of us to build more quickly.