“I'm a pretty lazy person and am prepared to work quite hard in order to avoid work.” Martin Fowler
Now that represents me extremely well. I'm always striving towards working less 😝
For me one of the best tools for accomplishing that goal is refactoring. Not just refactoring but making refactoring a habit, and including that habit as part of my work.
What is refactoring?
I'm guessing that most of you already have a good understanding of what refactoring is, though I will explain in case you don't. This is what Wikipedia has to say:
"Refactoring is the process of restructuring existing code without changing its external behavior. Refactoring is intended to improve the design, structure, and/or implementation of the software (its non-functional attributes) while preserving its functionality (more).
My take
I like Wikipedia's description, though it's missing an important concept, that in my opinion is one of the most important things about refactoring. And that's "TIME".
For me refactoring is a function of improvements over time (R = I/T
). Refactoring will happen over time, iteration over iteration making improvements making sure nothing breaks along the way.
That's the reason why I made refactoring a habit, rather than something I only do once each couple of weeks or months. This has proven quite effective for me (emphasis on me, as I'm sure each one of you has their own way).
I also use refactoring intentionally as part of my development cycle, it is not limited to the daily habit or periodical refactors. It's usually at the end of the development cycle, after the initial, somewhat naive and probably not the cleanest solution. But the solution works, and makes me pass all the tests and meet all requirements.
After having a working solution I do a couple of refactoring passes, focusing on DX (Developer Experience) mostly, making code as clear and simple as possible.
What's my point?
My point is, that I've made refactoring a daily habit and it's working quite well. As developers, habits are one of the most important tools at our disposal, they can make sure we don't screw up, or making our life easier over time by enforcing good behaviours. But, habits can also be a bad thing, enforcing bad behaviours or ways of doing things (yes, I'm looking at you, the one who uses +
to convert strings to numbers in js)...
For me, refactoring as a habit has been one of the most effective ways to work less. I started working hard, consistently improving the projects, and directing the efforts towards working less. As a side-effect the codebases become a pretty nice place to work and maintain.
I've been doing this for 4 years straight. These are some of the things I do:
- Reorganize code to be as clear as possible
- Rename stuff to make sense (hopefully, I'm crap at naming)
- Extract parts of monster functions into separate functions
- Keep related things together and unrelated things apart
- Delete my colleagues' ugly code, and... cough... sorry, I mean, celebrate my colleagues' code, yes.
- ...
Quite a short list, compared to all possible improvements.
Let me end it with another quote
This quote is from FunFunFunction's host Mattias, I think (please tell me if I'm wrong). It said something like this:
Remember to leave the code around you better than you found it
This quote stuck with me for some reason, I tried to apply it as often as I could, and after probably 4 years, it has become such a habit that I don't even realize I do it until I review my PR or something.
So yeah, maybe it works for you to. With this approach, the improvements and refactoring you do should be small, to reduce the amount of damage/side-effects (hopefully minimal if you do it correctly). Small changes each day of the week over 1 year amounts to quite a bit of improvement.
A short post from me this time, explaining really briefly my thoughts and approach to refactoring.
Top comments (24)
A good programmer is a dialectic tension between OCD and lazy. Take care of every detail, but do not make details you do not need!
However, procedures and loops that do not fit on the screen are hard to diagnose. Pushing hunks of related details into a subroutine solves that, and allows individualized subroutine testing, which avoids debugging/supporting a huge procedure or loop! It's not much work. It protects you and future maintainers (if your code lives through the ages, which would be amazing) from lots of work!
Code is suprisingly longlived ;-)
100% this
I definitely agree with little and often refactoring - BUT - I also think there are times to take the 50,000ft view and say I could do a major thing here - and do some very serious moving around of stuff perhaps to make things more obvious.
My day job is building a ThingBuilder - a builder of things with literally 100s of plugins etc and quite a few devs. We recently completely restructured the code base for our plugins and after I am so happy, I must save minutes every hour finding the right code section now. We also refactored all of our file names into a new convention which is much easier to find in WebStorm search everywhere. Of course if you move a lot you'll need good tests :)
Totally agree, as I mentioned in the post I also do refactoring periodically and from time to time I tackle major things that can't be done with the litle and often approach.
That's always such a good feeling, and can relate quite a bit. As we recently re-wrote an app I was put in charge of, it was so bad we had to re-write it from scratch, no room for refactoring there. Working on that project now is so much nicer, easier to maintain, etc... I enforce refactoring on the project and don't allow the "I will do that later" syndrome that @inhuofficial pointed out!
And of course we do have tests, not the best but quite good :)
Refactoring is an art, as much as programming itself. If you do it wrong though, you will be changing the code for worse. That's why most managers hate that word - its a lot of time spent with no gain whatsoever.
However, when done correctly, not only it saves money (because time is money and refactored code takes less time to mantain), it also makes the devs happier because the work gets done easier and this ends up saving even more money.
I believe refactoring should be part of the daily dev routine, but taken with a grain of salt. Learn the technicques and understand the true reasoning for it, or else you will just be wasting time.
Yeah I totally agree. As many things in life, if done incorrectly or without knowledge, can result in bad outcomes.
I also think good refactoring skills go side by side with your coding ones, like any other skill it's gained over time and practice. So we should try, as managers or not managers, to not hate on it and try to teach it better 😅
Thanks for the addition!
Little and often is an old saying, or if you are a chef “clean as you go”.
The “I will clean it up later” syndrome has cost me a lot of money over the years in having to unravel what i wrote years ago. Keep on top of it and it is easy!
Great article with a very important message ❤️🦄
Thanks, I too believe it's quite important.
My company too, has lost loads of time and money for this very reason. Just as an example, we had a project that at one point scored around 3.5 years of tech-debt, when the project was around 1.5 years old 😂. The reason? Saying “I will clean it up later” (if they even thought that) and not coming back and cleaning.
My experience is that amount of refactoring is inversely proportional to the amount of people working on the code base and directly proportional to the freshness of the code.
In other words, I refactor so much more the fresh code to make it as good as I can, as I know for sure that other devs wouldn't be resolving conflicts as a result of my refactoring. On the other hand, the more people are working on the shared code, more "differently" old branches the code base has, the more chances that even the smallest refactoring could lead to other developer's pain, or maintenance pain, or production pain. I tend not to refactor as much in that case, or rather prefer the approach of write new and replace, as bigger chunks are easier to resolve than a conflict spaghetti.
To me the refactoring is a delicate balance between empathy to other developers, freshness of the code and the size of the team.
With large teams it is better not to refactor much if you want to keep delivering usable software, hence over time the codebase begins to smell like a pile of turd.
I like this one, and can relate.
I work in many projects, some small, some big and some personal. And yeah, it's a lot easier when you're alone or in rather small and new projects. But I think it's important to do it in such projects, as to make them be in the best shape possible before it becomes a big project or many people start working on it. As later on it's harder to do as you mentioned.
I have a couple of those at our company, they smell from 5 miles away lol
I agree with you Keff.
Refactoring is one of the most important things, actually a gift that one developer can give to himself.
It doesn't save just your money and time, it's also one of the best ways to learn more efficient about what you are doing.
Refactoring is actually a life's thing.
It should be a part of everybody's life, not just codding.
As Ray Dalio said: "Pain + Reflection = Progress"(youtube.com/watch?v=i4wXCv4GLU0), and yes, reflection in life is refactoring in development.
As Steve Jobs said: "You can't connect the dots looking forward; you can only connect them looking backwards."(brainyquote.com/quotes/steve_jobs_...), and yes, looking backwards is actualy a reflection (refactoring).
Encouraging everyone to do it.
I usually try to avoid words like "clean" or "clear", even "understandable". Although there are books written about it, they are quite subjective.
Instead I speak about "explicitness", "expressiveness", "no surprises", etc.
I also try to keep a mental track of how much time I need to understand some code, for example from stack overflow, and i put that in a balance with writing a less smart code that requires less time to understand. And therefore less comments.
Interesting point of view. I kinda agree, and I like the words you use though they express mostly the same thing.
But I'd say that yes it is subjective, as almost anything in life. But many of the "clean" code guidelines are quite objective, like cyclomatic comlexity, separation of concerns, keeping functions and methods small, just to name a few. These have proben quite efective in reducing the complexity and increasign what you call "expressiveness" and also reducing surprises.
I'd also like to add my grain of salt to the comments thing. It might be controversial, but I hate comments in code (speaking of comments explaining a piece of code, public apis should always be commented and documented), they add an unnecesary layer of complexity and one that needs maintaing like other parts of the codebase. Code should be readable/understandable by itself, comments should not be needed (most times) to explain how the code works, the code should be expressive.
Yes I totally agree with you on the comments! And that is totally my point: avoid comments with less smarter and more expressive code!
Its just that... Have you ever worked with a developer who will twist and bend the rules? Or just focus on 1 rule (usually code duplication)? Of course cyclomatic complexity is hard to bend, but out of the multiple rules in the Clean Code, a fair amount of devs I worked with knew just a few and applied them in a questionable way.
So I had to adapt :)
The main use for refactoring is not to improve bad code, but to reduce/eliminate redundant code.
Redundant code is often the result of copy-paste reuse (the worst kind of reuse), for very short-term gains. Instead of functional abstraction, code is copy-pasted and slightly changed, building up technical debt that can slow development to a crawl, often 10 times slower or worse.
Yup, I totally agree. I have seen that kind of technical debt, a project of ours which was done in a copy-paste way without much thought, ended up with a tech-debt so big it would've taken us 2.5-3 years to remove. This project was 1 year old at the time
If you compare technical debt to your credit card bill, you are making your monthly payments, plus a little. That is a wise and entirely-reasonable thing to do, IMO.
(Granted, paying the whole thing off every month is the best; but, if you can't, this will get you there much more quickly than if you just did the bare minimum.)
I generally agree.
But I'll point out that there are a lot of us who work on quirky foreign systems and codebases without much if anything in the way of testing. It's very easy to slip in a new bug when refactoring, and unless you have good tests for before/after, you might end up doing more harm than good.
I know, I know, that's a terrible point of view. But it's the practical one sometimes.
Yeah, good point. I've had a couple of those 😅
I agree, because although there are some ways of refactoring that reduce the possibilities of harmig the system, it will never be totally safe. I would say that having tests gives you a lot more freedom and safety to refactor (but tests must be done correclty)