The Challenge and Opportunity in Inheriting Someone Else’s Code
You can learn almost everything you need to know about inheriting someone else’s code from the Seattle Underground.
When I moved to Seattle in 2014, I learned a lot about the city’s history. This is mostly because in the year and a half that I spent living there, several of my friends and family came to visit. And they wanted to see things.
Of all the tourist attractions I took my friends and family to in Seattle: Brunch at the top of the Space Needle, Ride the Duck tours on Lake Union, a spin around the Great Wheel, catching fish in Pike Place Market, chilling with the harbor seals at the Seattle Aquarium, the tourist t̶r̶a̶p̶ attraction that quickly became my favorite was the underground tours.
From what I’ve been told on these tours when settlers first colonized the Puget Sound, they built their new city, and consequently also, its sewage system, a little too close to the body of water we now call Elliot Bay. So, unfortunately, when the tide rose so did the city’s sewage, which people quickly grew tired of.
After the Great Fire of 1889, Seattle had a second chance at building a town better-suited for living (and plumbing) and they re-built all 29 city blocks 12 to 30 feet above where its first streets were originally constructed.
Seattle 2.0, as I like to call it, was built on top of the foundation that survived the fire, meaning there were and still are underground passages, buildings, bank vaults, and of course, trap doors, sitting beneath the high-trafficked streets of today’s downtown Seattle.
Guided tours of this “underground” are a big attraction in Seattle’s first neighborhood, Pioneer Square, where I leased my first apartment in the Emerald City.
I loved these tours. The first reason being that these secret corridors gave my new home a real Gotham City/underbelly feel. The second reason was because the tour guides who lead us through them were never anything short of amazing. They made surprisingly funny puns and cracked jokes while we traveled through underground Seattle. They reveled in telling us stories about the seedy post-reconstruction underground scene, where prostitutes threw johns through trap doors after cleaning out their pockets (very my aesthetic) and Seattle’s first madame ran everything south of the byline and accumulated more political influence in her lifetime than any actual politician (also my aesthetic). I’m paraphrasing, but as someone who rarely gets nostalgic about the past, and who often points out that doing so is extremely suspect, our tour guide’s depiction of a woman-run underground sounded like my kind of place. It lit up my imagination and connected me to a new city I had no roots in.
CSS at Clef
I consider myself extremely lucky, my teammates at Clef have done a pretty excellent job of writing CSS over the past few years. They started with a strong foundation (no literally, Foundation), they’ve continued to use sane and practical naming conventions, and everything in our /SCSS directory is well-organized. By the time I joined the team 5 months ago, we were already using a z-index scale à la Medium, we had well-defined and reusable color variables, and things were feeling generally object-oriented. Fresh.
This all said (and deeply, deeply appreciated) our CSS ecosystem continues to grow in complexity with each line of code we commit.
The great/amazing/excellent thing about front-end frameworks like Bootstrap and Foundation is that they give programming-focused teams, especially those without designers, a starter kit for front-end design and CSS. What can quickly become frustrating about them, however, is that in order to deviate from their pre-packaged styles, and furthermore, to do so without ripping the framework completely out of your app, you wind up having to “override” them.
I can’t tell you how many apps out there have styles overriding styles, overriding more styles, overriding even more styles. But I’d be willing to bet it’s a significant number of them. Overriding styles can be a slippery slope. And one that can have a big impact not only on front-end performance, but also on your team’s ability to track down and fix bugs.
Take styles affected by state changes for example. What does a typical nested block of CSS for something like a unique hover state transition on an element or displaying an element on top of varying background colors look like? As front-end engineers, sometimes we’re asked to write CSS that does both of these things, increasing the complexity of the CSS we’re writing by an order of magnitude.
“Overriding” styles to hack together new ones can generate a ton of CSS that’s deeply-nested, over-engineered, and difficult to both read and debug.
Almost every codebase I’ve ever finagled my way into has a measurable and significant amount of technical debt with regards to its CSS. Now that I think about it, assuming and inheriting technical debt is probably the only truly equitable thing about the technology industry.
Throwing it all away and starting completely over starts to look really, really appealing to a problem solver like myself. But let’s take a moment to be super honest with ourselves: Rewriting all of the code in a codebase is rarely a practical thing to do.
Rewriting all of the code in a codebase is rarely a practical thing to do.
Instead, we can consider how the architects of Seattle 2.0 capitalized on the sturdy foundation the Great Fire left behind and proceeded to build a better, stronger city on top of it. Sure, they could have started from scratch in a new place with more protection from the rising tide of the Bay, but in weighing their options and the cost of relocation, they chose to work with what they had. They raised the city almost two stories over the next 17 years, and the Seattle they finished in 1906 is the one that still exists today, sordid tunnels and all.
Instead of tearing or ripping out Foundation from our app and re-writing our CSS from the ground up, we’ve decided to write down a set considerations and standards for our CSS that we can work towards and aspire to. Our very own CSS 2.0, if you will.
Carefully Carving Out Considerations
From now on whenever we commit to our CSS we’re going to focus on following a specific set of considerations. These considerations are a mix of things we’ve learned as a team and things people in our industry have documented or written about.
One specific styleguide I want to give a huge shout out is Sezgi Uluçam’s CSS Best Practices. In it, Sezgi steers away from stylistic preferences and fads and instead focuses her best practices on writing clean, easy-to-read, and scalable CSS. To me, focusing on clean and scalable CSS is what allows a group of people to write CSS better as a team.
So, when I started writing our front-end styleguide at Clef, I made these things my focus as well. Front-loading the effort of writing clean and scalable CSS and asking programmers, who may or may not be passionate about CSS, to apply a set of considerations when contributing to your app’s front-end code is, in my experience, always worth the work.
But I’m also writing these things down to hold myself accountable to them too.
Sometimes it’s easy to write a bunch of really poorly written CSS and to not comb through your code, especially if you’re in a hurry or you simply need to make something work. But writing these considerations or best practices down means that they’re real and that, as the Head of Design, and our resident CSS expert, I need to hold both my team and myself to a higher standard.
Hopefully, going forward, this will allow our team to move quickly, debug efficiently, and update styles easily. It should also make it easy to dive right in and contribute as we grow our engineering team.
A Few Important Tenets
Our styleguide is open-sourced on GitHub here. Below are some of my thoughts around best practices and things I believe will help you and your team write better CSS too.
Rule #1 to be a boss ass bitch: Write semantic and descriptive class selectors.
“Follow the rules of semantics — make classes descriptive and not reliable on appearance of the given element.” — The &yet Styleguide
Rule #2: Specificity over brevity. As noted in Sezgi’s CSS Best Practices, research has found that the delta, or difference, in the best and worst cases of class selector performance is actually only 50ms.
“Keep performance in mind, but don’t worry too much about it. The main advantage of using performant selectors is that it increases readability and modularity. For example, .container * is terrible not just because of performance, but also because it hurts flexibility and requires future styles to use hacky overrides.” — CSS Best Practices
I 100% believe that by prioritizing specificity over brevity we can write better CSS as a team. A unit. For every engineer who is currently contributing CSS to our codebase, as well as for every engineer who we’ll add to our team, ideally this styleguide should help them jump right in and start writing (objectively good and scalable) CSS.
A little more on naming class selectors: We use the BEM, or “block__element — modifier”, naming convention. The blocks we name our class selectors after should be reusable and component-based and not specific to the page or template where a component is being displayed. While we can have page-specific CSS file names, our actual CSS should be modular and reusable.
Pro Tip: We’ve also found that using the BEM naming convention has paired nicely with React.js’s JSX templating. However, we’ve decided not to mimic JS syntax in class selectors that use two words in one block name or descriptor. Instead of camel-casing class names, we hyphenate them so they’re easy to scan or read.
Beyond these considerations, there are behaviors we want to try to avoid all together. Here’s a few of them:
- Using the !important declarative
- Styling IDs
- Targeting descendant selectors
“The descendant selector is the most expensive selector in CSS.” — Dave Hyatt
- Excessive nesting (eventually I’d like us to avoid doing this completely)