One of the most promising reasons to use an model-driven approach to software engineering was the ease of broad architectural migrations. Now, as EJB 3 is final, Java 5 runtimes are available for the OSes our customers prefer, and app servers are also available, we can get the chance of migrating the whole software architecture to the current version of our middleware standard.
The benefits of EJB 3 are:
In our system we've got approximately 500 entity beans and 70 session beans. So, with EJB 3 we get rid of about 1'500 classes for our entities and about 350 classes for our session beans. Resulting in 1'850 saved classes!
Step 1
Because there's no budget for a solid architectural renovation we choose to get rid of as many classes as possible without changing our software architecture. In the first small step we'll keep our data transfer objects as they are, although we could get rid of them easily with JPA, the latest Java persistent mechanism. We still use data access objects in addition to the entity beans for complex queries.
Step 2
Afterwards we inline the data access objects' functionality into the JPA-entities. JPA has a very powerful mechanism for queries, which makes our DAOs obsolete.
Step 3
If the backend is streamlined, we'll have saved more than 2'200 classes. In the end we'll remove our data transfer objects and replace them with the entities itself. While this could be quite a problem in some architectures it's quite seemless in our approach.
That should lead to savings of about 3'200 classes in total! - That's quite a big deal... (and more than 50% of our classes...)
The next post will provide some information on our approach.
Posted by Phillip Ghadir at 3:36 PM
When I was discussing some major issues with one of the engineers in my project, we had to investigate some existing code in order to check for the feasibility of several options.
I was shocked when I saw the implementation of one method, which was obviously the one to be enhanced for our purposes. I'll give you a short statistics on the method:
There was no tracing throughout the method's code, and due to the inappropriate exception-handling there's no chance to figure out, what happened in case of any problem with this method:
try {
// very long implementation
// spread on multiple branches
// with various assumptions
// about 100 lines of code
// without tracing which branch was executed
} catch (Exception e) {
throw new SpecialPurposeException( "some arbitrary text" );
}
There are always discussions about the need for tracing. Personally, I prefer static program or trace analysis over debugging. Also, usually I write very few trace statements in my code, because most often they're not necessary to figure out what happened. The stack trace should easily document the execution path.
To achieve that, it's necessary to separate concerns and to write single purpose methods (on one level of abstraction). For example, the refactoring of that one very overloaded unfocussed method, that almost accidently provided it's service at the end in an else branch, came up with a 7 line method like this:
if ( <method-precondition met> ) {
executeTheMethodImplementationThatsNowInANewlyCreatedPrivateMethod();
} else if ( <wasAlreadyExecuted>) {
handleAlreadyExecuted();
} else {
handleTheCondition();
}
If an exception occurs in this implementation it will be easy to find the cause, if
I was surprised that the former code existed for quite a while, although it has already caused some trouble before and was investigated by some engineers without being refactored. Due to that, I ordered a copy of Code Complete immediately. I strongly recommend this book for every developer.
Posted by Phillip Ghadir at 8:38 AM