Knowledge base‎ > ‎

What is the price to pay for developer productivity?

posted Apr 20, 2010, 4:39 AM by Szabolcs Szádeczky-Kardoss   [ updated Apr 22, 2010, 1:40 AM by István Soós ]
I would like to share some thoughts with you about an untold tale in software engineering. Most probably you have already read or seen quite a few marketing-oriented documents or events with a similar message:
  • Use configuration instead of coding
  • Change system behavior or business rules without recompiling
  • Increased developer productivity...
All of these (let's call them dynamics) are nice, however I've never seen (not even in a footer with a tiny font) what is the price you have to pay for these features. And there's sure a price to pay compared to the "old" approach where you didn't put much of your program in configuration, and you had to recompile it for even the smallest changes. Well let's have a closer look at one very common one, the usage of JavaBeans.

A JavaBean is primarily meant to be a "data-holder" (or business object if you like that terminology better), with no or very little application logic included. Their main purpose is to hold data that are set through their setter methods and return those when needed via their getter methods. With some simple rules defined (for an attribute named attribute there must be a getAttribute and a setAttribute method) it is possible to dynamically explore and use any JavaBean with the help of the Java Reflection API (java.lang.reflect package). Well in most of the cases told in the beginning this is the backing concept, and the one that makes a developer's life easier (at least in the development phase). Let's have a look at a simple JavaBean:
public static class Person {
private String name;
private int birthyear;

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getBirthyear() {
return birthyear;
}
public void setBirthyear(int birthyear) {
this.birthyear = birthyear;
}
}
This is a very simple JavaBean. If you want to work with it the "old" way, you call those getter and setter methods directly, but then you have to explicitly write those at compile time, making your app not very dynamic. The "new" way is this:
java.lang.reflect.Method setNameMethod = Person.class.getDeclaredMethod("setName", String.class);
setNameMethod.invoke(person, "James Bond");
Even better is if you explore the methods and their parameters beginning with "set" and "get" dynamically, and store them in a Map for later use. More or less this is the way all of today's frameworks function, from JSP's Expression Language to Wicket's PropertyModel binding. Since this - not very nice - code can be put in the framework, the developer will see only the nice and easy configuration of ${person.name}="James Bond" or something similar. Ok, but what will the developer see at runtime (with an emphasis on time)?

Well, attached below is a small little tester app, that shows the runtime difference between direct and indirect (reflective) call of a JavaBean's setter and getter methods. The test performs a typical scenario when some dynamically configured behavior of a framework reads and/or updates all the fields of a JavaBean. Please note that the solution used is probably the most simple solution for indirect method invocation, most frameworks use something more complex for example via the java.beans package, but in the end it always comes down to java.lang.reflect.Method.invoke(...)! You can easily run the app yourself, so I only show some interesting results:

Test cycles: 10 50 200 1000 5000 20000 100000 500000
Direct calls (average in ns) 5700 5800 5700 5700 5800 5100 4500 4300
Reflective calls (average in ns) 32000 60000 32000 36000 18000 12000 6300 5100

We can see that there are situations, when it is 10 times slower to call the same method(s) reflectively than directly. This is a huge difference! And the average doesn't even contain the discarded maximum values, which would make the gap even bigger. By increasing the number of test cycles well above 1000, the difference melts down to about 20%. However I think the reason for this is the HotSpot optimization in the JVM when it sees that the same cycle is repeated for an awful lot of time. I am sure that in a normal application where such code is not executed in a cycle like this, JVM optimizations are not likely to be so effective. Most probably in a normal application it can be said that the similar developer-friendly features (dynamics) take up to 5-6 times more cpu time to accomplish for the JVM.
    Well, what do you think: is this a big price to pay for developer productivity?


published: 2009-09-11, a:Szabolcs, y:2009, l:java, l:productivity, l:profiling
ċ
ReflectionTester.zip
(4k)
István Soós,
Apr 20, 2010, 4:47 AM
Comments