Refactoring helps to move towards cleaner code that is easier to understand and maintain. It takes practice and experience to recognise code smells: symptoms of bad design which indicate deeper problems in the code. Tools can be helpful to refactor in small steps and prevent breaking the code.

Halima Koundi, apprentice at Codurance, spoke about refactoring and code smells at SwanseaCon 2016. InfoQ is covering the conference with Q&As, summaries, and articles.

Koundi quoted Martin Fowler’s definition of code smells:

A code smell is a surface indication that usually corresponds to a deeper problem in the system.

The quality of code can go down if not enough attention is given to properly maintain or improve it. In her talk Koundi summarized different kinds of code smells and explained how to recognize them. One category of code smells she mentioned is "object orientation abusers"; these smells have to do with incomplete or wrong implementation of object oriented design. Recognizing object orientation abuser code smells helps you to find code that is possibly violating object orientation principles which can lead to wrong behaviour of the object.

Another category of code smells that Koundi mentioned is "change preventers", where one chance in the code (for instance to implement a new feature or adapting an existing feature) impacts many classes and requires extensive changes throughout the code. Examples are code smells like "parallel inheritance hierarchies" or "divergent change".

Koundi gave a demo using ReSharper from Jetbrains on how to safely refactor code. In the demo she showed how you can adapt code when a new payment method has to be added. She explained how you can refactor the code in small steps and what you can do to make sure that changes made won’t break the code.

InfoQ interviewed Koundi after her talk about different kinds of code smells that exist, how developers can recognise code smells, principles for dealing with code smells, practices for refactoring code, what developers can do to assure that they are not breaking the code, when should you refactor and when not, and the benefits that refactoring can bring.

InfoQ: What are the different kinds of code smells?

Halima Koundi: There are several categories of code smells. Some of the code smells emerge over time because they result from lack of care and abstractions in the codebase; these include long methods, long list of parameters etc. Others are due to half baked or badly implemented object oriented principles, for example Refused Bequest is one where we have introduced a wrong abstraction. Code that adds noise to the system is another category. For example you should reduce, if not remove, comments from your code and make your method names more meaningful. Code that is not used should be removed–even if you think that it may be needed later.

InfoQ: How can developers recognize code smells?

Koundi: Code smells can be recognised by their visible, physical and metaphysical signatures. Visible signatures include: long method or function bodies, long parameter lists, groups of variable that appear multiple times in similar patterns–these are symptoms of mixed responsibilities and missing abstractions. An example of physical signature is where change involves navigating-through and modifying many files. Metaphysical signature is when you are asking questions like, "why am I inheriting from this parent class when I do not share the same behaviour". It takes practice and experience to recognise code smells. There are many exercises and katas to help you practice. Code smells are a symptom; they generally reveal that you are breaking some design principles. Knowing these principles helps understand what is wrong with your code base.

InfoQ: Which are the general principles for dealing with code smells?

Koundi: Refactoring means improving the design of the code without changing the behaviour, and it is platform independent. Code smells are symptoms of bad design. My advice is to read Martin Fowler’s book, Refactoring: Improving the Design of Existing Code. It is important to note that refactoring to abstractions is not always the right course of action because it could cause more complexity in the system and may become a code smell in itself. The code may not be complicated enough to benefit from certain abstractions.

InfoQ: You talked about practices for refactoring code and gave a demo. Can you give some examples how code can be refactored?

Koundi: Refactorings that I find very powerful yet quite simple to apply are: Extract Method: Let’s say you have some function that is doing too many things and want to make the code easier to read. Break the algorithm by the steps it is doing and extract them in their own methods and name them according to their behaviour Rename method: unexpressive code is hard to work with, for example, when you find yourself looking at a method and taking more than 10 minutes to understand what it is doing. If you do find a better way to explain what it is doing then you should rename that method, providing that the method in question is not exposed as a public API. As I showed in the demo, the tool is as important as the knowledge of the refactorings themselves. Knowing your development environment makes the exercise of refactoring a lot easier, faster and safer. There are great resources out there to help you learn how to refactor. Matthew Butt is putting together a series of refactoring screencasts where he shows how to refactor code in simple steps.

InfoQ: What are the things developers can do to assure that they are not breaking the code?

Koundi: Before you engage yourself in refactoring, make sure: You can check that the rest of the system is not impacted by your refactoring. This is done through tests.

There a clear documentation of how to use this section of the code. That documentation is provided by tests.

The part of the system you’re refactoring will not suffer regression. This is the job of, guess who? Tests! Always make sure you have tests before you refactor the code.

InfoQ: When should you refactor? When not?

Koundi: Refactoring, just like writing tests, should be part of the same activity of implementing a feature. It is not a standalone activity. You refactor when you want to prepare your code for change, where it was not ready for it yet. Refactoring is a major step during test driven development (TDD). Code reviews are also good candidates for a refactoring exercise. On the other hand, doing a lot of low-value refactoring across the whole codebase in an attempt to achieve "perfect code" is called gold plating. It is harmful to clean code, as it dilutes the genuine need of refactoring with the zealous blindness of refactoring for the sake of refactoring. If the code works and does not need to change, don’t touch it.

InfoQ: What are the benefits that refactoring can bring?