GAZAR

Principal Engineer | Mentor

What is Refactoring?

What is Refactoring?

Refactoring is risky. It requires changes to the working code that can introduce subtle bugs. Refactoring, if not done properly, can set you back days, even weeks.

To avoid digging your own grave, refactoring must be done systematically.

WHAT IS REFACTORING?

Refactoring is the process of changing a software system in a way that does not alter the external behaviour of the code yet improves its internal structure. It is a disciplined way to clean up code that minimizes the chances of introducing bugs. In essence, when you refactor, you are improving the design of the code after it has been written.

When you have to add a feature to a program but the code is not structured in a convenient way, first refactor the program to make it easy to add the feature, then add the feature.

THE FIRST STEP

Whenever I do refactoring, the first step is always the same. A solid set of tests for that section. The tests are essential because even though I will follow refactorings structured to avoid most of the opportunities for introducing bugs.The larger a program, the more likely it is that my changes will cause something to break inadvertently — in the digital age, frailty’s name is software.

Before you start refactoring, make sure you have a solid suite of tests. These tests must be self-checking.

Refactoring changes the programs in small steps, so if you make a mistake, it is easy to find where the bug is.

Next step is to commit the change to git. I use a version control system, that allows me to make private commits. I commit after each successful refactoring, so I can easily get back to a working state should I mess up later. I then squash changes into more significant commits before I push the changes to a shared repository.

Any fool can write code that a computer can understand. Good programmers write code that humans can understand.

The great benefit of removing local variables is that it makes it much easier to do extractions since there is less local scope to deal with. Indeed, usually, I’ll take out local variables before I do any extractions.

Naming is both important and tricky. Breaking a large function into smaller ones only adds value if the names are good.

My first reaction is to take shorter steps. In particular, should a test fail during a refactoring, if I can’t immediately see and fix the problem, I’ll revert to my last good commit and redo what I just did with smaller steps

When programming, follow the camping rule: Always leave the code base healthier than when you found it.

The true test of good code is how easy it is to change it.

The key to effective refactoring is recognizing that you go faster when you take tiny steps.

Refactoring (noun): a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior.

Refactoring (verb): to restructure software by applying a series of refactorings without changing its observable behavior.

If someone says their code was broken for a couple of days while they are refactoring, you can be pretty sure they were not refactoring.

The Two Hats

When I use refactoring to develop software, I divide my time between two distinct activities: adding functionality and refactoring. When I add functionality, I shouldn’t be changing existing code; I’m just adding new capabilities. I measure my progress by adding tests and getting the tests to work. When I refactor, I make a point of not adding functionality; I only restructure the code.

Refactoring Improves the Design of Software

Without refactoring, the internal design — the architecture — of software tends to decay. As people change the code to achieve short-term goals, often without a full comprehension of the architecture, the code loses its structure. It becomes harder for me to see the design by reading the code.

Refactoring Makes Software Easier to Understand

Programming is in many ways a conversation with a computer. I write code that tells the computer what to do, and it responds by doing exactly what I tell it. In time, I close the gap between what I want it to do and what I tell it to do.

Refactoring Helps Me Find Bugs

Help in understanding the code also means help in spotting bugs.

Refactoring Helps Me Program Faster

In the end, all the earlier points come down to this: Refactoring helps me develop code more quickly.

1_qRkOUq06TyiFd_lUMsVmYw.webp

Software with a good internal design allows me to easily find how and where I need to make changes to add a new feature. Good modularity allows me to only have to understand a small subset of the code base to make a change. If the code is clear, I’m less likely to introduce a bug, and if I do, the debugging effort is much easier.

WHEN SHOULD WE REFACTOR?

The Rule of Three

Here’s a guideline Don Roberts The first time you do something, you just do it. The second time you do something similar, you wince at the duplication, but you do the duplicate thing anyway. The third time you do something similar, you refactor.

Preparatory Refactoring — Making It Easier to Add a Feature

The best time to refactor is just before I need to add a new feature to the code base. As I do this, I look at the existing code and, often, see that if it were structured a little differently, my work would be much easier

“It’s like I want to go 100 miles east but instead of just traipsing through the woods, I’m going to drive 20 miles north to the highway and then I’m going to go 100 miles east at three times the speed I could have if I just went straight there. When people are pushing you to just go straight there, sometimes you need to say, ‘Wait, I need to check the map and find the quickest route.’ The preparatory refactoring does that for me.” — Jessica Kerr

Comprehension Refactoring: Making Code Easier to Understand

Before I can change some code, I need to understand what it does. This code may have been written by me or by someone else. Whenever I have to think to understand what the code is doing, I ask myself if I can refactor the code to make that understanding more immediately apparent.

Litter-Pickup Refactoring

If it’s easy to change, I’ll do it right away. If it’s a bit more effort to fix, I might make a note of it and fix it when I’m done with my immediate task.

Planned and Opportunistic Refactoring

I do refactoring as part of adding a feature or fixing a bug. It’s part of my natural flow of programming.

You have to refactor when you run into ugly code — but the excellent code needs plenty of refactoring too.

Software should thus be never thought of as “done.” As new capabilities are needed, the software changes to reflect that

Long-Term Refactoring

I’m reluctant to spend the time to do dedicated refactoring. Often, a useful strategy is to agree to gradually work on the problem over the course of the next few weeks.

Refactoring in a Code Review

Code reviews help spread knowledge through a development team. Reviews help more experienced developers pass knowledge to those less experienced.

When Should I Not Refactor?

If I run across code that is a mess, but I don’t need to modify it, then I don’t need to refactor it.

Another case is when it’s easier to rewrite it than to refactor it.

Problems with Refactoring

You need to understand the tradeoffs to decide when and where to apply something.

Slowing Down New Features

There is a genuine tradeoff here. I do run into situations where I see a (large-scale) refactoring that really needs to be done, but the new feature I want to add is so small that I prefer to add it and leave the larger refactoring alone.

Code Ownership

Some organizations like any piece of code to have a single programmer as an owner, and only allow that programmer to change it.

Many people, therefore, argue for keeping feature branches short — perhaps just a couple of days. Others, such as me, want them even shorter than that. This is an approach called Continuous Integration (CI), also known as Trunk-Based Development. With CI, each team member integrates with mainline at least once per day. This prevents any branches diverting too far from each other and thus greatly reduces the complexity of merges.

Testing

One of the key characteristics of refactoring is that it doesn’t change the observable behavior of the program. If I follow the refactorings carefully, I shouldn’t break anything.

Legacy Code

Legacy code is often complex, frequently comes with poor tests. Refactoring can be a fantastic tool to help understand a legacy system.

Databases

The essence of the technique is to combine the structural changes to a database’s schema and access code with data migration scripts that can easily compose to handle large changes.

REFACTORING, ARCHITECTURE

Refactoring can improve the design of existing code but as I said earlier, changing legacy code is often challenging, especially when it lacks decent tests.

REFACTORING AND PERFORMANCE

Refactoring can certainly make software go more slowly — but it also makes the software more amenable to performance tuning. The secret to fast software, in all but hard real-time contexts, is to write tunable software first and then tune it for sufficient speed.

Conclusion

The more experienced you are, you would find yourself doing more refactoring in projects and structure them. Having an idea about what refactoring is and how it’s been done by professionals helps you to be on track.

Most of these contents are coming from a book called Refactoring by Martin Fowler.

Enjoyed the article? Follow me!

Have an opinion or comment? Type it!