Refactorings - An overview

Why is refactoring important?

Do you know this? Your code works, but after a few months nobody understands it anymore - not even you. This is where refactoring comes into play: it improves readability and maintainability without changing the functionality.

What is refactoring?

Refactoring refers to changes to the code that improve the quality of the code base while maintaining functionality. Above all, we must ensure that no new errors arise, as the external behavior of the software must be maintained. Automated tests are the best tool for this.

Refactorings can also create the basis for adding tests at a later date. What sounds like a chicken-and-egg problem often begins with Integration tests. These ensure the correctness of a larger area of the code base. On this basis, we can then refactor within the test-covered code in order to efficiently supplement unit tests. Without tests, refactoring is risky - but old code is often not tested. Therefore, we start with integration tests to create an initial safeguard. Then you can continue to optimize step by step.

In software development, it is essential to ensure that the code is always readable. This is not necessarily achieved immediately when the code is first written. Here too, subsequent refactorings are used to simplify code that was originally complex and thus improve maintainability.

When writing new functions, refactorings are often the starting point to give developers the opportunity to extend the existing implementation.

Martin Fowler in his book Refactoring: Improving the Design of Existing Code many examples. Since then, the topic of refactoring has become standard in agile software development.

How do you refactor code?

The aim is to increase the quality of the code base without changing the behavior of the software. Simplifications to the code, with the aim of improving comprehensibility, are best implemented in small steps. Refactorings such as renaming classes, methods, parameters or variables are very easy to implement with today's tools. The simplifications provided by modern development environments (IDEs) are enormous. Thanks to AI and IDEs such as Cursor or Windsurfing the topic of refactoring is making another huge leap forward. But here, too, it is important to have automated tests ready to check for correctness.

Refactoring improves the quality of the code in terms of the two values Changeability and Correctness. Whether small changes or major restructuring. In the end, it must be about achieving these values. Eliminating violations of principles is important. However, when using all refactoring techniques, the values must be at the forefront.

Refactorings should always be carried out with one goal in mind. Either a new feature or the elimination of a bug. If refactoring is done "with a watering can", the time required is often too high and the risk of causing damage is too great.

Examples of refactorings that are frequently used:

  • Extract Method (e.g. divide large method into several small ones)
  • Rename Variable (better readability)
  • Inline variable (remove unnecessary variables)
  • Replace Magic Numbers with Constants

I have a few ideas on how to proceed in this blog post described.

What are the advantages of refactoring?

Ultimately, there is no way around making code easier to understand through many small refactorings. However, the goal of refactoring must be taken into account in each case. Refactoring is a discipline that can take a lot of time and therefore increase costs. If refactoring is used to improve the extensibility of the source code, but this extensibility is not actually needed, it backfires.

The advantage is therefore not usually to make the code even more flexible and generic. On the contrary, the refactoring process should be geared towards making the existing code simpler so that it can be understood more quickly. In terms of efficiency, the advantage of refactoring therefore often comes more from simplifying things and making them clearer. The cognitive load that I have to apply as a developer in order to understand the code base must be reduced. It is therefore about simplifying the structure.

Are there also disadvantages to refactoring?

In my observation, there are two problems with refactoring measures:

  • They take too long
  • Correctness suffers

When it comes to time and effort, it is important to remember that refactorings are not an end in themselves, despite their importance. As a rule, extensive refactorings should only be carried out in the context of a new feature or a bug fix.

Small refactorings to the existing code are possible thanks to the Scout rule covered: "Always leave a place better than you found it". However, the time required here should really only be in the region of a few minutes. Extensive structural changes are not covered by this.

If I realize during refactoring that it is taking too long, I can decide to abort. As long as I used version control at the beginning, I can discard all changes at this point with a revert. However, this requires me to remain present and reflect during the restructuring process. Sometimes it is better to abort than to invest more and more time with perhaps dubious results in the end.

If something breaks during refactoring, this is usually due to insufficient test coverage. If in doubt, you should therefore carry out a coverage analysis before refactoring in order to obtain an overview of whether the lines affected by the refactoring are sufficiently covered by tests. Manual or automated tests are essential here.

What's the deal with technical debt?

The term was originally coined by Ward Cunningham. The transition from waterfall to agile software development has shown that the (deliberately!) narrower scope means that some decisions regarding the structure of the software have to be reconsidered later. In this respect, refactoring is part of agility. Because with every iteration with new requirements, you may find that the previous structure is not suitable for accommodating the new requirements.

So if a team develops in a truly agile way, a refactoring measure is potentially due before a new feature. This must ensure that the originally appropriate structure now also meets the new requirements. New features that are added must not drastically increase complexity.

How should I proceed with refactoring?

A drastic change is currently taking place in programming as a result of AI. Code can now be generated by AI. However, the quality is by no means always such that you can accept the AI's suggestions without checking them. In this respect, refactoring is also part of a developer's work with this new way of working.

Refactoring can cause software errors. Therefore, the first step is always to check the test coverage. If the original functionality is to be extended, the code is redesigned to meet the new requirements. Code is often extracted from methods in order to be able to use this existing functionality elsewhere. The purpose of refactoring here is to avoid duplication. In the end, I want to simplify the code so that everything remains easy to understand despite the new features.

If this goal is clear, you can start with simple refactorings, which are tool-supported by definition. The test coverage can also be somewhat lower because the IDE ensures that the measure does not lead to new errors.

Version control should be used before starting to make changes to the code. A commit of all pending changes ensures that the initial state can be efficiently restored with a revert. A commit should be made after every major step.

When fixing bugs, refactorings ensure that the knowledge I have gained about the code is manifested in the code. For example, extracting a few lines from an extensive method can ensure that the meaning of these lines is communicated through a well-chosen method name. In this way, the cognitive load is reduced.

Conclusion

First of all, the differences between simple and complex refactorings should be clear to me. Simple refactorings are those that can be carried out completely tool-supported. The risk of reintroducing errors in existing code is rather low. The pathfinder rule is best applied entirely to simple refactorings.

For complex refactorings, you can use the Mikado method use. However, there must always be a primary objective here, which is characterized by economic considerations. New features or bug fixes are the two most important reasons. Clean code is not an end in itself. Unclear code is annoying, but not always avoidable. The structure of the source code should be constantly monitored and improved, while at the same time keeping an eye on the costs and benefits for users.

Our seminars

course
Clean Code Developer Basics

Principles and tests - The seminar is aimed at software developers who are just starting to deal with the topic of software quality. The most important principles and practices of the Clean Code Developer Initiative are taught.

to the seminar "
course
Clean Code Developer Trainer

Conducting seminars as a trainer - This seminar is aimed at software developers who would like to pass on their knowledge of Clean Code Developer principles and practices or Flow Design to others as a trainer.

to the seminar "

Leave a Comment

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

en_USEnglish