On Refactoring

Imagine your bedroom. You sleep, you change your clothes, you do lot’s of things there.

One day you decide to shuffle furniture around. New place for bed, for closet, for carpet.. It looks and feels great now! You still sleep, change clothes and perform all the stuff as before. You have successfully refactored your bedroom!

After a few days, you do the shuffling around once more. Now you decide that you do not need closet. You will keep your clothes on the stool. What a genious move! For three days, it seemed like glorious decision – life went on smoothly.

Then you got invited to the suit party. But stool has no suit, only shirts and jeans. 🙁 Your refactoring activities have ruined “dress me up with a suit” feature.

Now let’s take a look at the definition of refactoring: Refactoring is an activity during which one does not change behavior of code, just the structure.

In the first shuffling of furniture, nothing changed behaviourly. You were able to achieve same objectives as before. Only layout of your furniture (aka structure) has changed. On the second shuffling, you were no longer able to dress up with a suit. Technically it was not refactoring, it was something else.

I always loved in school to solve factorization problems during math classes. For example, factorizing \( a^2-2ab+b^2 \) will produce \( (a-b)^2 \). The most important part is that only expression changed, value didn’t. Put any a or b value into both expressions and you will get the same result.

This is the beautiful thing. It means you can arrange things however fits your case best. There is no best form, only what’s best for your needs.

It aligns with refactoring very much.

Example

Let’s examine function that calulates area of the square:

func areaOfSquare(x int) int {
    return x * x
}

Fairly quickly you observe that it needs integer x. What is this x thing? Name of the function indicates it has something to do with area of square. If you remember your math classes, then you are golden – it’s side length.

But what if you didn’t? What if thousands of engineers didn’t, but needed to understand the code?

Let’s perform rename variable refactor by changing the variable name from x to sideLength:

func areaOfSquare(sideLength int) int {
    return sideLength * sideLength
}

Now, just taking a look at return statement, it is immediately clear what is going on here. Engineers can talk with product managers about “side lengths”, not “x”. Not only for you, but also for your fellow engineers. Such simple and technical action makes your code more maintainable.

Now add 60+ refactorings, do 5 each day and imagine how much better your codebase would be in a year.

I highly recommend checking https://refactoring.com/ for more examples on different refactors.

Why refactoring is needed? Or is it?

Refactoring can be considered as a maintenance task.

In general, you perform maintenance on your systems so that they can function better for longer periods of time.

For example, you are regularly bringing your car to mechanic to change oil or perform repairs. You do that because you want your car to serve you as long and as well as possible. You want to take that long trip with your family without thinking if breaks are working.

However, your child gets sick and you have to drive to the hospital.

Would you care that you need to change your oil?

I wouldn’t. I would get into the car and get into hospital as soon as possible. I would definitely take the risk of blowing the engine. Children are more important than cars.

It is very similar in software business. Early startup that struggles to keep the lights on may choose not to refactor. Focus on new features, marketing and sales to build business might be better choice. If business is not around in 3 months, then how well-factored codebase is useful?

Let me share a story from my career. I have joined one small company which had built it’s product. The codebase was horrible from technical point of view – no automated tests, lots of duplication, many N+1 selects.. I was hired to clean that up. In 3 months company was out of money.. Great time to have CI/CD with metrics that indicate progress, huh?

On the other hand, if business is around after 10 years and code has not been refactored, then it may be an issue.

I have worked on a system that was not given love for refactoring. Our team has inherited the codebase. The features had been built one upon the other. Also individual features were developed for top customers. It was a complete mess, but it allowed for company to stay in business. Everyone was aligned that something needs to be done. It simply just took too much time to implement new features, ensure quality and do any changes. But we didn’t know where to start. We had some rules to add tests whenever an opportunity appears, but that was very slow. We decided to implement distributed tracing. It was a fun exercise to instrument the code. 🙂 It uncovered that some of the RPC calls had cyclical dependencies.

I hope this example shows you how code can deteriorate if it is not refactored for a long time. It hurts all the company.

If your software is constantly being reshaped to fit requirements instead of squeezing it somehow with glue and sticks on top, then you can expect pretty smooth ride in new feature development. It gives you a sustainable speed and predictability.

I guess this could be considered a competetive advantage.

Prerequisites for successful refactoring

Good automated test suite. That’s it.

Once again, refactoring focuses on improving internal structure of software while keeping external behaviour the same. If you have ability to quickly verify external behaviour, then you are on a path of successful refactoring.

For example you perform an extract method refactor. Then you run your awesome high-quality test suite. It’s green! You should be able to go to production with just that without worries.

Next actions

I highly encourage you to swift around your codebase:

  1. Try to find variables which one you change and future you and your team would thank you.
  2. Do the same with classes, methods and functions.
  3. Try to find functions that are too big to be easily understood. And then figure out a way to make it better.

At least take a look at what you have. Or better, get into the groove and future will be brighter than you think.

Leave a comment

Your email address will not be published. Required fields are marked *