Enterprise CSS Refactor
A Front-end Developer's Descent into Madness
In 2017 I began a journey into the hell that is technical debt, namely, how to un-screw up a CSS repo that had 8 years of bloat dragging down our users' experience. The project was for a GOTS (Government-Off-The-Shelf) product so specifics will be limited. Oh, to be a government contractor.
My Head Hurts
When I first came on the project and started to familiarize myself with the codebase, let me tell you, it was a CSS specialist’s worst nightmare. I’m talking every CSSLint sin you could think of was everywhere and invisible dependencies abounded. Want to try and maintain a consistent look and feel? Good luck buddy. I was constantly battling specificity and discoverability in a CSS file with 9k plus lines felt hopeless. If this sucks so much for me (someone who actually loves CSS) what on earth are the other developers feeling?
So I Know We Have A Problem
Great, that benefits no one. Where the hell do you start with a problem that has apparently been ignored for the better part of 8 years and affects 270 some odd views? Analysis!
When you’re responsible for a large scale application it can be overwhelming to get any momentum moving forward. It’s kind of like when you were a kid and you let your room get real messy. I’m talking about that mid-school year, can’t see my carpet, textbooks and notebook paper everywhere kind of messy. You stand there and look at this living nightmare and think to yourself, how the f am I going to fix this?
My approach for fixing the CSS was the same as cleaning my room. Pick a corner and work your way out from there. So what does that look like when sifting through Solution Explorer in Visual Studio.
First we should understand what our problems are (bloated hacky CSS, poor performance/delivery, inconsistent design patterns, disorganized structure, etc.) Literally translated to me sitting at my machine and reading each line of CSS and cursing under my breath. Then came the searches. I just grepped through the files for all the things that irked me. Massive amounts of resets, over 141 unique colors (I just stopped counting, point proven), overqualification (hmm, html problems?), ultra high specificity, absence of naming conventions, duplication and the list just goes on. I mapped all this out in graphics to present to our leads along with performance measurements of page loads.
Now Here’s What I’m Going To Do About It
Next step was to come up with an actual maintainable solution. Establishing some goals and guiding principles serve to aid in filtering through the myriad of methodologies and paradigms for dealing with the problem at hand.
My core values for this effort were:
- Abstraction - If a rule turns text red why is it name td.WidgetExpirationDate and not .textRed or .errorText?
- Maintainability - We clearly have an issue with maintenance so making something that all developers can pick up is a top priority.
- Discoverability - Cleverness be damned, I want people to be able to find the classes they need.
Putting Together My Toolkit
I’ve got 99 problems and I’ve rationalized them. I picked some guiding principles that inform my decision making, now what tools are available to me that align with those principles and resolve or mitigate my core issues?
I zeroed in on two key pieces to fix my broken puzzle. BEM and Sass. I know it’s not exactly novel but it fit the bill so I worked on outlining how we would use each bit of tech. Throw in some intentional utility classes, a modern grid system, add a sprinkle of SMACCS categorization and we’re off to the races!
- Fixes specificity
- Emphasizes abstracted “component” level thinking
- Structured naming helps with understanding what/how things are affected so the fear of touching existing CSS is minimized
- Vars help makes things consistent
- Partials support organized/discoverable code
- We agree to limit nesting to control output
- Mixins help us have consistent expectations and apply all browser pre-fixes
In a living breathing agile environment, refactoring your CSS in one fell swoop just ain’t going to happen. So this is how I chose to break it down across minor releases so we had solid testing to make sure any unanticipated side effects could be addressed. My strategy was to try and shrink the problem incrementally so we would have a clean baseline to convert to Sass.
- Grep every rule and toss out things no longer in use
- De-lint the existing CSS
- Consolidate duplicative rules
- Design a new card style framework and upgrade views with the new structure
- Purge out obsolete classes round two
- Convert and organize code with Sass
All told I’m pretty happy with how things turned out. We achieved a perceivable increase in page load performance, things were in places with names that informed the team about what they do, we established helper libraries with commonly used scales and colors to increase consistency and the app got a minor face lift.
If I were to do it all again I would have invested more time evangelizing Sass and BEM across the team. If I had I may have been able to get a little extra support in the implementation phase and could have spent more time testing before commiting the code. I would have also tried to decompose the refactoring process into smaller tasks so that when the pull request went in for peer review the diffs would not look like I touched every line of code in the file when that wasn’t the case.