Refactoring for Fun and Profit
A while back when I was excitedly telling my wife about my achievments of the day, she asked me what this “refactoring” that I’ve been up to means. “Well, it’s when you change a bunch of stuff in your code, but what your program actually does stays exactly the same.” Luckily, she’s a very organized person, and immediately understood the point when I tried to explain it through the old keeping your tools organized and building a house metaphors. But it made me wonder a bit myself - was this really a productive day? After spending almost all of last weeks’ development time on refactoring, I feel confident in saying: yes, a refactoring day is a productive day.
In the realm of software development, maintaining clean, efficient code isn’t just a nicety — it’s a necessity. This post delves into why refactoring is crucial and provides practical examples of the methodology. Plus, a sneak peek into some exciting upcoming features at statichost.eu made possible by the last round of refactoring.
Why Refactor? i.e. clean code is good code
High quality software is cheaper to produce
- Martin Fowler, martinFowler.com
Every developer knows that clean code is good code. The problem is that clean code is not as easy to define as a clean workshop where all the tools are well organized. You of course need the equivalent of a clean and organized workshop, but you need more. It’s also like the building a house metaphor. When you start out, you need something that enables you to live in a specific spot - so you start with a tent. You can develop your living situation using the tent by creating a fireplace and raising the tent off the ground with a floor of some kind. But at some point you need walls, and the tent needs to go.
This metaphor is of course not perfect, as metaphors seldom are. In the tent metaphor, your trigger for building walls might be that you live in Sweden and it’s November and you’re freezing. But when it comes software development, your trigger for refactoring is very often a feeling. A feeling that something is not flexible enough, not efficient enough, not elegant enough. For me, it boils down to something being hard to work with. This is the why: making your code base easier to work with even though features and requirements are added.
Sidenote: recommended reading
The quote above is from the article “Is High Quality Software Worth the Cost?” by Martin Fowler, which you absolutely should read. Even seasoned developers tend to weigh development speed against quality (such as a good software architecture). The thing is, this is a fallacy: high quality leads to high speed, while low quality leads to low speed. Anyway, just read the article! (This is not to say that e.g. throwaway prototypes should not be utilized.)
How to refactor? i.e. refactoring methodology
Refactoring isn’t about making big, sweeping changes. Spending weeks refactoring is not the way to do it! Unless six-months-ago-you didn’t really do much refactoring, in which case you might have to… Instead, make refactoring part of your workflow. Not just TDD-style function refactoring, but higher-level architectural / model refactoring.
- Small, Iterative Refactoring: Instead of overhauling everything, make small changes. Over time, these accumulate to produce a robust, efficient system.
- Break Tasks into Manageable Pieces: Decompose complex problems. It’s easier to tackle smaller pieces than a monolithic task.
- Testing, Testing, and More Testing: Every small change should be accompanied by tests. It ensures that the new code plays well with the old.
- When you refactor, this is the only thing you should do. This means no simultaneous feature development. If a new feature requires refactoring code, do the refactor first, and then proceed with the new feature.
I’m going to say this again, as plainly as I can: do not refactor everything at once, or develop new features at the same time! I know this is extremely hard, but just don’t.
Practical example and what (not) to do
An anticipated upcoming feature of statichost.eu is to be able to roll back a site to a previous build. This requires being able to configure the edge servers without actually building the site from source, and as such, is a relatively big change. Here is several days worth of development related to this:
- Implement API-based configuration of edge servers as opposed to file-based configuration.
- Create new staging servers that support this configuration pattern.
- Start testing these edge servers.
- At the same time, change where public files are copied to on the edge servers.
- Change from an rclone-based file copy to just copying over a complete tar archive.
- Change the data model for sites to reflect builds that can be rolled back to.
- Build the UI for rollbacks in the dashboard.
This sounds like a bunch of feature branches coordinated over a many sprints,
right? Yes, that is what it sounds like, but it’s not what it was. It was one
item (“implement build rollbacks”) that became such a mess that this branch is
now somewhere deep in the caves of the
This was the new approach, with every item as its own branch and release (with status at the time of writing):
- Completed refactoring: Abstract the way servers are configured so an API-based configuration can be added later if needed.
- Completed refactoring: Upload public files to a build-specific directory and use that directory as the site root when deploying.
- TBD: Implement a check to see if a specific build exists on the edge servers so that rolling back to a non-existent (legacy) build doesn’t break the site.
- TBD: Add a “roll back to this build” button to the dashboard.
(Related, but completely separate to this, public files are now uploaded directly over SSH as a tar archive. But this was done because those occasional weird rclone errors started showing up way too often because of growing scale.)
The moral of the story is that now refactoring and new feature development are separated, and specific items as well. Instead of building and changing everything all at once, only the smallest possible meaningful change is made at a time. This meant that the very large and scary big change became just a few tiny understandable changes.
Refactoring has paved the way for exciting new features. We’ve made improvements in server locations, refined our deployment pipeline, enhanced caching mechanisms, and improved our dashboard user interface. Each of these, though distinct, was made feasible through refactoring.
After refactoring, introducing changes or new features is much easier. It’s like having a well-laid foundation for a house. Want a new room or a window? It’s easy to add without risking the entire structure.
Refactoring might seem tedious, especially when there’s the allure of new features or pushing out code rapidly. However, the investment in refactoring pays rich dividends in the form of code longevity, reduced errors, and easier feature additions. We will definitely spend more time doing refactoring in the future!
Speaking of features, have you checked out statichost.eu? It’s not just another hosting service. With a deep commitment to privacy and strictly European servers, we’re a top choice for many. And with our recent refactoring, we’re rolling out some fantastic features. If you’re looking for a trustworthy hosting solution, look no further!