Imagine a bacon-wrapped Ferrari. Still not better than our free technical reports.
See all our reports

Reducing Technical Debt through Refactoring

I propose you an exercise: when you come back to work tomorrow morning, navigate through the source code of your project and try to find opportunities of refactoring. Do it even if your boss didn’t ask for it. Do it because you want some exciting time at work.

Refactoring is the art of changing what is already working fine. But to do refactoring you need an excuse. It could be design improvement, performance issues, security roles, and many other reasons. That’s a risk you take to reduce the technical debit of the application, making it more stable and, somehow, improving your own productivity in the future.

This is not about being nice with the company or with the boss, but being nice with yourself. Why? Because problems tend to accumulate and, at some point, you will lose the control of your code. You will face hard times to deliver results and it will ruin your career.

Well, let’s see this from a brighter perspective instead. You will learn a lot in the process and will soon realize that you are producing better code than you ever did before. The more refactoring you do, the more clever you become until a point where you may reach the level of innovation. But, what does it mean and how do you know you are getting there?

Innovation happens when you find a clear opportunity for improvement on what you are doing and you realize nobody else did it so far (at least you couldn’t find it). That’s not easy, but it usually happens when you do something repeatedly and you find yourself thinking about what would you do to do the same thing faster or cleaner. Let me illustrate this with a true story.

It was about String concatenation in Java: a classical issue stressed by numerous specialists throughout the years and probably ignored nowadays. Before JDK 1.5, despite its readability and simplicity, String concatenation using the operator “+” could produce a very inefficient code. Behind the scene, this operator was replaced by the bytecode equivalent of StringBuffer, which actually implemented the concatenation. The more you used the “+” operator the more instances of String and StringBuffer you would have in memory as well as a good amount of processing time to manage all those objects. Because of that, developers were pushed to use StringBuffer straight away and ignore the “+” operator. Look at the following example:

String title = “Mr.”;
String name = “John”;
String familyName = “Smith”;

String message = “Dear ” + title + ” “ + 
                 name + ” ” + familyName + ”,”;

Developers were used to write like that, but they were pushed to write this instead:

StringBuffer sb = new StringBuffer();
sb.append(“Dear “);
sb.append(title);
sb.append(” “);
sb.append(name);
sb.append(” “);
sb.append(familyName);
sb.append(“,”);

You may agree with me that the first example is more readable than the second one. It’s just natural for developers to use the “+” operator when concatenating strings, thus it was unfair to abandon that syntax. Fortunately, compiler guys did something about it, making sure that the JDK 1.5 would optimize concatenations. Instead of using StringBuffer, a thread-safe class, they created a new one called StringBuilder (non thread-safe, thus faster) and they made sure that a single instance of it would handle all concatenations as illustrated in the first example. That’s an important move because they favored elegance instead of technicalities. The first example is automatically transformed at compile time into something like this:

StringBuilder sb = new StringBuilder();
sb.append(“Dear “).append(title).append(” “)
  .append(name).append(” “).append(familyName)
  .append(“,”);

However, concatenations within a non trivial logic still require you to write StringBuilder in your code because the compiler is not that smart yet. For  example:

List<Student> students = studentBean.findStudents();
String intro = “The following students were approved:\n”;
String listedNames = “”;
String separator = “”;
for(Student student: students) {
  if(student.approved()) {
    if(!listedNames.isEmpty()) {
      separator = “, “;
    }
    listedNames += separator + student.getName();
  }
}
String msg = intro + listedNames;
messengerBean.sendMessage(msg);

would be more efficient if written like that:

List<Student> students = studentBean.findStudents();
String intro = “The following students were approved:\n”;
StringBuilder listedNames = new StringBuilder();
String separator = “”;
for(Student student: students) {
  if(student.approved()) {
    if(!listedNames.length() > 0) {
      separator = “, “;
    }
    listedNames.append(separator)
               .append(student.getName());
  }
}
String msg = intro + listedNames.toString();
messengerBean.sendMessage(msg);

Oops! Did you noticed anything strange up there? It might not be obvious at a first look, but see how they check if the variable listedNames is empty before defining the separator. The class String has a nice readable method isEmpty() introduced in JDK 1.6, but StringBuilder still uses that pretty old way of comparison. Why didn’t they do it for StringBuilder and StringBuffer as well?

Discussing the issue at the core-lib-dev mailing list, it turns out there is no apparent reason why they didn’t do that before. Perhaps they simply forgot it :-) Thanks to a large refactoring, trying to improve inefficient uses of string concatenation, it was possible to find such inconsistency. I believe they still have time to fix that for Java 8, which is coming out next year. And they would fix that by adding the method isEmpty() in the interface CharSequence to make sure that every other implementation will be equally elegant.

That might be a simple thing, but every single detail matters when Java is under heavy criticism for being such a verbose language. So, go for some refactoring and find opportunities to improve your code as well as the language you use to write it! Let’s move Java forward!

###

This technical post was brainstormed by RebelLabs contributor Hildeberto Mendonça, architect, hacker and leader of CEJUG. Follow him @htmfilho.

  • nagkumar

    >I propose you an exercise: when you come back to work tomorrow morning, navigate through the source code of your project and try to find opportunities of refactoring. Do it even if your boss didn’t ask for it.

    Very nicely put, this is what we preach and do it every day.. but many in Services and so calle product business don’t get it right.. (Based on my experience with 2000+ indian IT client services and product teams..)

    > do it because you want some exciting time at work.

    If we don’t do it this way.. we miss even min excitement of monthly pay.. as everyone ends up in fire fighting, endless debugging.. Every new features tells how the code should have been to see that the new feature in very very smoothly..i.e without regressions and additional complexicity

    In TejaSoft we have a saying that.. ‘Don’t Manage the Deliveries.. they should happen..’ – underlying skill is refactoring …refactoring with unit testing… to add new features seamlessly..

    Mantra for Modern IT Business Scale (Scaling by Selling Intelligence) is ‘Code Quality’.. which can’t happen by adding bodies.. we need brains with deep professionalism and respect & fixes around where their own time is getting killed..

    Regards,
    Raja Nagendra Kumar,
    C.T.O
    http://www.tejasoft.com
    – Uncompromised Code Quality – Which evolves while we deliver to business needs..