Skip to main content

Refactoring for Performance

Posted by giovanisalvador on April 28, 2008 at 7:36 AM PDT

I was working on a kind of Outlook entirely based on the web and written 100% in Java. I was part of a team responsible for maintaining that application for thousands of users and performance was a critical piece. Actually, still is a critical piece because the application still exists and it is there for almost ten years.
I joined the team after the application has been released and being used for about 20,000. At that time, the team was not fully aware of helpful frameworks or design patterns that could help themselves to build a reliable, scalable software. Application was performing well but one of the parts of the application (a listing) was taking too long to process. Some users were complaining on that piece and I joined to help team specially on that part of the application.
First thing I decided to do was to put in place some tool to help us understand what was going on. At that time my IDE was Jbuilder Enterprise Edition and I had a license of Optimizeit. By plugging in it to the application I quickly noticed that building and access to lots of HashMaps instances were the culprit.
Then I had to understand the application's architecture:
The data layer was responsible for processing SQL statements sent to it, create HashMap instances for each record found and add each instance to a collection. Each column of the records found turned to a pair of column name and value.

The problem was that the application didn't have in place Transfer Objects or Value Objects. It was relying on maps and the application was facing performance problems on building those maps and suffering when accessing get methods of those maps, specially in those days where the load was so huge. That's what Optimizeit was telling me.

So I decided to make a small refactoring in my local environment after assessing the application with Optimizeit. I switched from maps to Transfer Objects in all layers of that piece of the application. Instead of making maps and collection of maps I created Transfer Objects and made them being accessed by the listing page. The Facade was responsible for returning the collection of Transfer Objects instead of a collection of maps.

When I ran Optimizeit again I noticed a gain of 20% in performance. After showing the results to the team we decided to release to production after some tests in Development Environment.
One day later I received a call from one of the users who originally complained about the performance:

- User: Hey, have you guys modified anything in the application?
- Why Sir?
- User: Because the listing is performing much better now.
- Actually, we did sir. We did a small modification on that piece.
- User: Alright, I will notify other users about that. Thanks for the work performed.

You guys may be surprised with this. Today, almost all applications rely on Transfer Objects, not on hashmaps. But at that time, with the knowledge of the former team, that's what was being used. The bottom line here is that small modifications may affect user experience. We don't need to make big refactorings to achieve that. Simple is better.
And you guys know the value of an user calling you to congratulate you. This is the most important piece.
Also, to put in place profiling tools like the one I had used is also key for the success of the project. You guys may be surprised with lots of things such tools may reveal about your code.

but I would like to know from you:
Has any of you some example on small refactorings that made the difference? Simple modifications that helped applications to improve performance. Please, share over here some real world facts about refactoring.

Related Topics >>


That was my last event like the ones you describe: Caching expensive-to-create objects has usually been the case in my code. So I first start doing it the "normal" way and then see if there is anything like that that can be improved. S!

Hey Greeneyd. awesome post. bottom line in you case was the cost for object creation. And it was a very simple modification that made the difference. Best regards

Simple or not, what I see as interesting is that the change you made not only improved performance but also improved the structure of the code, making it more understandable and more maintainable. I wish I'd known the performance aspect in a project where I tried to get this kind of change accepted for maintenance purposes.

Along similar lines, I recently found that by using the state pattern to make a class easier to understand and then making it thread-safe by having an AtomicReference to immutable instances of state, it actually improved performance over the synchronization I'd been doing earlier. (see )