惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threatpost
博客园 - 叶小钗
T
The Blog of Author Tim Ferriss
Recent Announcements
Recent Announcements
D
DataBreaches.Net
The Cloudflare Blog
阮一峰的网络日志
阮一峰的网络日志
罗磊的独立博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
N
Netflix TechBlog - Medium
Microsoft Azure Blog
Microsoft Azure Blog
Microsoft Security Blog
Microsoft Security Blog
B
Blog
U
Unit 42
有赞技术团队
有赞技术团队
博客园 - 聂微东
GbyAI
GbyAI
宝玉的分享
宝玉的分享
F
Full Disclosure
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
MyScale Blog
MyScale Blog
Jina AI
Jina AI
Martin Fowler
Martin Fowler
IT之家
IT之家
酷 壳 – CoolShell
酷 壳 – CoolShell
D
Docker
P
Proofpoint News Feed
A
About on SuperTechFans
I
InfoQ
博客园 - 【当耐特】
C
Check Point Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Privacy & Cybersecurity Law Blog
T
Threat Research - Cisco Blogs
Y
Y Combinator Blog
Project Zero
Project Zero
WordPress大学
WordPress大学
小众软件
小众软件
AWS News Blog
AWS News Blog
博客园 - 司徒正美
T
The Exploit Database - CXSecurity.com
L
LINUX DO - 热门话题
I
Intezer
Engineering at Meta
Engineering at Meta
C
CXSECURITY Database RSS Feed - CXSecurity.com
J
Java Code Geeks
T
Tenable Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Last Week in AI
Last Week in AI
C
CERT Recently Published Vulnerability Notes

CSS Wizardry

Front-End’s Missing Metric: The TBT Window Meet Your Users Where They Are with Obs.js Better Browser Caching with No-Vary-Search font-family Doesn’t Fall Back the Way You Think What Is CSS Containment and How Can I Use It? When All You Can Do Is All or Nothing, Do Nothing Obs.js: Context-Aware Web Performance for Everyone Low- and Mid-Tier Mobile for the Real World (2025) The Fastest Site in the Tour de France Making Sense of the Performance Extensibility API Why Do We Have a Cache-Control Request Header? HTML Is Not a Programming Language… Build for the Web, Build on the Web, Build with the Web Licensing Code on CSS Wizardry A Layered Approach to Speculation Rules Designing (and Evolving) a New Web Performance Score Core Web Vitals Colours The Ultimate Contract Templates for Tech Consultants: Protect Your Business and Get Paid Optimising for High Latency Environments Cache Grab: How Much Are You Leaving on the Table? blocking=render: Why would you do that?! Correctly Configure (Pre) Connections The Three Cs: 🤝 Concatenate, 🗜️ Compress, 🗳️ Cache What Is the Maximum max-age? How to Clear Cache and Cookies on a Customer’s Device The Ultimate Low-Quality Image Placeholder Technique Core Web Vitals for Search Engine Optimisation: What Do We Need to Know? The HTTP/1-liness of HTTP/2 In Defence of DOM­Content­Loaded Site-Speed Topography Remapped Why Not document.write()? Speeding Up Async Snippets Critical CSS? Not So Fast! Measure What You Impact, Not What You Influence Optimising Largest Contentful Paint Measuring Web Performance in Mobile Safari Site-Speed Topography Speed Up Google Fonts Real-World Effectiveness of Brotli Performance Budgets, Pragmatically Lazy Pre-Browsing with Prefetch Making Cloud.typography Fast(er) Time to First Byte: What It Is and How to Improve It Self-Host Your Static Assets Tips for Technical Interviews Cache-Control for Civilians Bandwidth or Latency: When to Optimise for Which ITCSS × Skillshare What If? CSS and Network Performance The Three Types of Performance Testing Getting to Know a Legacy Codebase Image Inconsistencies: How and When Browsers Download Images Identifying, Auditing, and Discussing Third Parties My Digital Music Setup Measuring the Hard-to-Measure Finding Dead CSS The Fallacies of Distributed Computing (Applied to Front-End Performance) Ten Years Old Relative Requirements Airplanes and Ashtrays Performance and Resilience: Stress-Testing Third Parties Little Things I Like to Do with Git Writing Tidy Code Configuring Git and Vim Base64 Encoding & Performance, Part 2: Gathering Data Base64 Encoding & Performance, Part 1: What’s Up with Base64? Code Smells in CSS Revisited Typography for Developers Moving CSS Wizardry onto HTTPS and HTTP/2 Ack for CSS Developers A New Year, a New Focus Preparing Vim for Apple’s Touch Bar Choosing the Correct Average CSS Shorthand Syntax Considered an Anti-Pattern CSS Wizardry Newsletter Nesting Your BEM? Improving Perceived Performance with Multiple Background Images Continue Normalising Your CSS Pure CSS Content Filter Pragmatic, Practical, and Progressive Theming with Custom Properties Refactoring CSS: The Three I’s Speaker’s Checklist: Before and After Your Talk Improving Your CSS with Parker The Importance of !important: Forcing Immutability in CSS Mixins Better for Performance Managing Typography on Large Apps White October Events Workshop Partnership BEMIT: Taking the BEM Naming Convention a Step Further Travelling Like You Want to, When You Have To Contextual Styling: UI Components, Nesting, and Implementation Detail Subtleties with Self-Chained Classes Cyclomatic Complexity: Logic in CSS Immutable CSS Can CSS Be Too Modular? More Transparent UI Code with Namespaces When to use @extend; when to use a mixin The Specificity Graph CSS Wizardry Ltd.: Year 1 in review CSS Guidelines 2.0.0
Refactoring Tunnels
Harry Roberts · 2017-06-02 · via CSS Wizardry

Written by on CSS Wizardry.

In my work, I tend to get involved in a lot of refactoring projects. From small-scale tweaks of work-in-progress frameworks or styleguides, right through to full-scale refactors of years-old legacy projects. In fact, I do so much work with clients who need to refactor that I spent much of 2016 speaking about it.

There are many interesting things about refactoring—from technical to logistical to cultural—but two points that are most relevant to this article are:

  1. The business is almost always hesitant to fund refactoring work. Nearly every development team I have ever spoken to has told me that their manager or client is the main reason they do not get to refactor as often as they would like to. This is understandable: the cost of moving developers away from product work to rewrite code with no discernible benefit to the user1 is a cost that most managers would rather not incur.
  2. Refactoring can be scary. On a sufficiently large or legacy application, there can be so much fundamentally wrong with the codebase that many refactoring tasks will run very deep throughout the whole project. This puts a lot of pressure on developers, especially considering that this is their chance to get it right this time. This can feel debilitating: Where do I start? How long is this going to take? How will I know if I’m doing the right thing?

A concept I came up with to help my clients and their teams tackle these two problems was the idea of a Refactoring Tunnel.

A Refactoring Tunnel is a metaphor in which the length or size of the refactoring task is represented by a tunnel of a corresponding size: long tunnels represent large refactoring tasks; short tunnels represent small ones.

A more developer oriented way of looking at or defining the size of a refactoring task might be to describe its surface area: how much of the codebase does the body of work touch?

The Refactoring Tunnel metaphor works like this:


On day one, you pick your refactoring task: you step into the tunnel. At this point, you can see the light at the tunnel’s entrance behind you, but you can’t see the light at the exit—perhaps it’s close but around a sharp bend, or maybe it is just that far away. At this point, we don’t know, but it doesn’t concern us because we have only just started.

Day two: we continue working on our refactoring task, and proceed further into the tunnel. Just like yesterday, we can still see the light at the entrance behind us, but the light at the exit still evades us. That is to say, we have a good idea of where we’ve come from, but still don’t know how far away the exit is: is it another week? Two weeks? Three days?

We press on, day after day making our way further into the tunnel, until day nine. All of a sudden, the light behind us has disappeared. We know we did nine days of work, but we’ve now lost the security of being able to see a fixed point behind us.

To compound the problem, we still can’t see the light at the exit either. The panic sets in; we’re lost. The site is broken around our feet. The quick find-and-replace for the class names didn’t work as we’d hoped, and now some JavaScript has stopped working. Many of our tests are failing, but we’re not sure why. We’ve tried to keep merging master into our topic branch, but we see more and more merge conflicts. And we still have no idea where the exit is. Is it quite close? Would it be worth continuing another day or so? Or is it still many days—or even weeks—away from us? We have no way of knowing. The uncertainty is stressful; it is a gamble. We begin to wish we’d never started, and in total desperation, we do this:

$ git reset --hard origin/master

We just throw everything away. We hard reset ourselves to a point in time we knew to be safe—and we do begin to feel safer again—but we have to face up to the fact that we just spent nine days of time and money getting to precisely nowhere. That’s going to be a difficult one to explain at your stand up, and will likely reduce the chances of the business trusting developers with refactoring time in future.

I’ve done this, and seen it done, more times than I would care to remember (or admit). I’m sure you’ve done it at some point as well. This is the danger of entering long Refactoring Tunnels.


Tasks with a large surface area—and thus, a long tunnel—might be things like

  • rewriting all of your Sass as PostCSS;
  • renaming all of your classes from BEM to BEM(IT), or;
  • moving your entire project’s layout from floats to Grid.

While each of these may be worthy and worthwhile changes to make, they’re relatively large. They will affect and modify the entire project’s codebase, which means a few things:

  1. It will take a lot of time to implement and test. Even if you get it right first time, it’s a significant spend that you will have to be able to justify.
  2. The likelihood of introducing new bugs and regressions increases. It stands to reason that if you’re impacting large and far-reaching parts of your codebase, you are far more likely to introduce new or different faults along the way inadvertently.
  3. The chance of pesky merge conflicts goes up. As oddly-specific as it might seem, this is a real issue. Diverging from your colleagues’ codebases on such a massive scale means you’re going to run into workflow issues.
  4. It may well become overwhelming. Scary, even. The most drastic outcome is that you realise you’ve bitten off more than you can chew and you have to bail out completely.

Don’t enter a tunnel whose end you can’t see, or that you can’t exit from quickly and cheaply.

Short Refactoring Tunnels

Resist the temptation to refactor anything that runs right the way throughout the project. Instead, identify smaller and more manageable tasks: tasks that have a much smaller surface area, and therefore a much shorter Refactoring Tunnel.

These tasks can still aim toward a larger and more total goal but can be realised in much safer and shorter timeframes. Want to move all of your classes from BEM to BEM(IT)? Sure, but maybe just implement it on the nav first. Attacking the problem this way has many benefits:

  1. You’re minimising your liabilities. The maximum risk at any given time is significantly reduced. Even in the worst case scenario, we only need to abort a much smaller piece of work.
  2. The shorter tunnel can be used as a test-bed for larger bodies of work. This will help you work out projected overall cost based on a smaller sample. It will allow you to stress-test certain new techniques, methodologies, or approaches in a smaller sandbox. The upshot of this is that the overall refactoring project can be defined based on a more trivial task up front.
  3. You can move back onto product work much sooner. This keeps managers happy—the fact that you’re only out of action for a few days, rather than many weeks, at a time is a hugely attractive proposition and is more likely to get approval than the alternative.
  4. It’s a chance to encapsulate. By working in these smaller units, it becomes almost necessary to begin defensively encapsulating code as you refactor it. This means that your codebase will gradually become more robust as a result, which will help with almost all future work.

Your overall goals for the project can remain the same but try to identify and isolate the sub-tasks into much smaller and safer units. Make sure you only ever step into short tunnels.