SOFTWARE ENGINEERING blog & .lessons_learned
manuel aldana
Manuel Aldana

April 17th, 2008 · No Comments

Bashing the refactoring criticism

Refactoring (changing design of existing code while preserving behaviour) is a cruicial daily software engineering practice to make your system able to adapt for typical maintenance tasks like fixing bugs or feature enhancements. Still I perceive that refactoring still is not commonly done. This article presents the most common arguments against practicing refactorings and show why most of them are wrong.

Emphasis on outside visible behaviour

Criticism:
Software enginners are paid to create or adapt a system which offers some direct business value, in this means you are claimed to fix a critical bug as quick as possible (hotfix), to add an eye opening feature or to eliminate a performance bottleneck. All these adaptions obviously focus on outside visible behaviour, and they are the real reason (well, lets ignore the political decisions for now…) why customers use software and pay for it. So the customer is right when not spending money directly on software maintenance.
Disproof:
Simply put: The customer is completely right! It should not be his business to know the insights of how we develop software. In the end the system should work as wanted and he must feel that the system is making his life easier. Never the less that does not mean that we should ignore maintainability. With keeping our design and code clean with refactorings we can react on customers needs much more quickly. If he wants a new feature or a quick bug-fix we are in the very good position to offer a new release after a short time, because the code and design is clean and thus code changes do not need ages. Here we got two advantages: The customer will be more pleased to get a new release soon and we software engineers get more resources to improve the functionality of the system.

The perfect all-solving upfront designed software

Criticism:
I do not need to refactor because my software is designed perfectly in the first place. It regards all extensions from the beginning on and thus can react quickly to changing business needs.
Disproof:
Well, I doubt that… Above assertion claims that you can look into the future where you know all market changes and upcoming requirements. This is quite unrealistic except you believe in crystal balls… The other way to make your software ready for the future is that you try to make your design ready for all possible changes. This won’t work because you are speculating and you are paying the speculation fee with an overly complex system. This harms maintainability because the system contains loads of code which will be never used/run (dead code) and the design is much more difficult to understand. Further more you are wasting resources to make your system pseudo-future ready.

Technology constraints

Criticism:
Refactoring is only doable with statically typed languages like Java or C#. The refactoring tools of respective IDEs (IntelliJ, Eclipse, VisualStudio etc.) are making refactorings possible.
Disproof:
Refactoring is a concept and not based on technologies! It is a way to keep software maintainable. Of course it is correct that especially static typed languages (like Java without use of reflection api) make refactorings easier as dynamic language constructs (Java reflection api, Python, PHP etc.). The meta-data inside your code makes refactorings safer and tool support can be more powerful. Never the less you can refactor with any technology as long as you know your tools well and can overlook the side-effects your refactorings steps can cause.

Blurry view of “good” design

Criticism:
In contrast to real world architecture where you are constrained by physic laws (otherwise your building will collapse somehow) the software-solution set for solving problems is much broader. There are innumerable ways to implement requirements and the judging whether it was done well or not is often quite subjective. Though you can find some objective metrics to measure software structure (lines of code per class/method) they still cannot express all aspects of maintainable software. How the heck could a computed metric tell you whether your namings are good, or if the relation between classes/packages well expresses the domain or requirements? So design generally is too subjective to get all developers under the hood.
Disproof:
Yes, software design and code quality in many ways is quite subjective, never the less there are common agreements what good design is and what principles should be followed: inversion of control, design for testability, open/close principle, encapsulation, maximize cohesion etc.. Some code quality bits can be subjectively measured and be integrated as quality metrics, like a method must not exceed a certain number of method lines of code (MLOC) or cyclomatic complexity should be under 10. But you’re right that metrics themselves will never express the complexity of software as a whole. That’s why design and manual code reviews should be carried out to spread design/code knowledge and to find out areas which should be improved. To summarize: You more or less can “measure” good design/code quality by both using subjective (metrics) and objective (manual review) practices.

System is too big to refactor

Criticism:
We realize that refactoring is a good practice but our system is just to big and we would need to spend just too much effort to make it noticeably better.
Disproof:
It is true that you can feel overhelmed by a big muddle of mud system but improving systems can be done in an incremental way. You could start with little code bits, for instance by refactoring code areas you are touching often. Think it like a desert: There is a lot to do but you can create some little oases which after a while getting bigger and one day will connect each other to form big green forests.

Refactorings are causing performance bottlenecks

Criticism:
When going towards refactoring you often end up with many little classes and methods with mostly little blocks (<15 MLOC). This is having an impact on performance because (to use Java as example) the JVM has to load many classes. The little methods are also causing performance problems because of the delegating calls through stack pop/push operations behind the scenes.
Disproof:
Performance is a very important non-functional criteria, but it is always tricky to speculate what can cause the bottlenecks and to generally write less maintainable code (monster classes, monster methods) for the performance sake. With powerful hardware nowadays in most cases performance problems have other reasons (like database or network calls). This is different compared to former times, where main memory was rare and performance could be hit on language level, too. Today we got better development environment and should focus on developing maintainable code in the first place. If we experience performance issues this should be surrounded by a profiler-test to be able to draw the right conclusions.

Untested legacy Code

Criticism:
In practice you hardly will find green-field projects, where you can follow refactoring practices from the beginning. Generally you start up with a bunch of existing code which you need to adapt. Often test coverage of the system (which is a symptom of legacy code) is not high enough to do manual refactoring steps. There is always the danger that you are unknowingly breaking existing behaviour. Especially refactoring beginners trying to dig into this topic often have to deal with the hardest untested legacy code issues, where usually you need well experienced software engineers to successful accomplish bigger refactorings. Thus the learning curve for refactoring “real world systems” is quite steep and is frustrating.
Disproof:
Well, this is a very hard one in my opinion quite true in reality (so the disproof is a bit misplaced here…). The only solution for that is to face the devil, practicing and reading a lot! For example start to refactor little private projects you coded a few years ago or just get some code being written by others (regarding this the open-source world is like paradise). After a while you get accustomed and refactoring gets a good habit in your daily job. I know the first steps will be hard, but give it some time and you will ask yourself how you could develop software without the refactoring concept. My favorite book talking about doing refactorings with untested legacy code is magnificent book by Michael Feathers. Apart from that one I highly recommend Refactoring in large projects and Refactoring to patterns.

Summary

I presented some issues why many people are sceptical against practicing refactoring. I discussed why respective arguments are non-issues and think that in every organization refactoring should be emphasized. I know getting accustomed to new habits is often uncomfy, never the less give it a chance and believe me that preserving and restructuring existing systems can be a very creative work, you feel much better about your software and after all it’s big fun.

Tags: Software Engineering

0 responses

    You must log in to post a comment.