| Download Free Chapter Excerpt:
Chapter 4 - Design Techniques and Coding Standards for J2EE Projects
Rod Johnson is the author of Expert One on One J2EE Design and Development, which uses a practical focus to show how to use J2EE technologies to reduce, complexity. This book will help you to solve common problems with J2EE and avoid the expensive mistakes often made in J2EE projects.
What are the greatest sins you think J2EE developers commit?
There are a lot of good developers out there, so I don't want to begin by disparaging the developer community. However, there are some problems I keep seeing in J2EE projects. I'd say the top three problems are over-engineering, neglecting performance considerations and inflexibility.
Over-engineering seems endemic in J2EE. I think it's because there's so much infrastructure on offer. Developers tend to think that because complex technologies like EJB exist, they ought to use them whether it's really necessary or not. Good engineering practice doesn't mean using the most complex approach. The more complex an application is the longer it takes to develop, the harder it is to maintain and the worse it's likely to perform. I think there's a valuable lesson from XP here, which values simplicity.
The debate about the .NET Pet Store has brought performance into the spotlight, but I've always been worried by the attitude many J2EE developers have to performance. For example, several benchmarks have indicated that using entity beans usually leads to poor performance, yet many developers simply ignore this. Performance is an important business requirement, and systems that don't perform don't meet business expectations. There's no reason that J2EE is inherently slow, yet many developers seem content to concede the speed debate to Microsoft because of how they insist on using J2EE.
Many J2EE developers are too inflexible in pursuing what they regard as being prescribed design patterns, even if they produce poor outcomes. For example, many J2EE developers won't consider using stored procedures, regardless of their potential benefits in a particular case. For example, it's sometimes possible to implement some persistence logic-not business logic-in 10 lines of PL/SQL or Transact SQL that might require dozens or even hundreds of lines of Java to do far less efficiently with entity beans. We need to approach problems with an open mind, and should be prepared to use the simplest and most efficient approach. I think it's always a mistake to let technology choice, rather than business requirements, drive a solution.
In the book I take a very practical and pragmatic approach. I look at the real-world tradeoffs architects need to make. I pay a lot of attention to performance and maintainability. I also emphasize sound OO design principles: sometimes I think developers lose site of them when they get caught up in the complexity of J2EE APIs.
Where is the J2EE spec lacking?
The J2EE specifications are pretty comprehensive. They cover most areas of middleware. So I don't see any major omissions.
If anything J2EE gives you too much, rather than too little. In contrast to platforms like .NET, the J2EE specifications give you several ways to do just about anything. While this means that we can deliver the best possible solution to any problem, inexperienced developers can be overwhelmed by the choices on offer or can get carried away trying to implement irrelevant technologies. This is why J2EE is often used badly.
One or two parts of the J2EE specifications frankly haven't worked very well. I think entity beans are the most obvious case. I think the basic premise was flawed, and the EJB spec is piling on complexity (such as inventing a new query language) trying to make them work. In EJB 1.1 around a fifth of the specification was devoted to entity beans. In EJB 2.0 it's well over a third of a much longer specification, and there are still loads of things you can't do properly with entity beans. Chapter 8 in the book discusses the arguments around entity beans in detail. I think the J2EE community isn't very good at walking away from things that aren't right about Java and J2EE. I would love to see entity beans dropped, with JDO coming into the J2EE fold to replace them. But I know that won't happen. I think as a community we should be confident enough to say "J2EE is a great platform, but there are some mistakes and we can acknowledge them."
Finally, the specs don't solve all your problems. J2EE can be hard to use out of the box. Take JDBC and JMS for example. Using either or these APIs is quite verbose, and they're quite low level. So we need a higher level of abstraction. However, this isn't a deficiency in the specs so much as an indicator that we need to build applications on frameworks simplifying the use of J2EE.
How important are patterns in a developer's arsenal?
Patterns are valuable, but I've seen a lot of developers go pattern-crazy. They look for opportunities to apply patterns, rather than concentrating on actual requirements. I think we need a more mature approach. We should understand patterns and use them where appropriate, rather than shoehorning them in if they don't fit. Patterns should be used as parts of good solutions, rather than driving solutions.
I'm a bit skeptical about the "J2EE Patterns" bandwagon. True design patterns should be applicable across different languages, such as C++, Java or Smalltalk. They shouldn't be tied to a particular technology, such as EJB. I think some of the "J2EE Design Patterns" we've seen are more reactions to shortcomings in the technology. Take for example the "Fat Key" pattern, in which all the data is included in an entity bean's primary key. This is a clever workaround for the serious problems with finders in BMP entity beans, so it's a hack rather than a pattern.
My advice to developers is: read the Gang of Four patterns book from cover to cover at least once a year. This contains 90% of what you need to know about patterns and is guaranteed to make you a better OO programmer every time you read it. You can-and should--apply "classic" design patterns in J2EE applications. Read the Core J2EE Patterns book. And read my book to keep your feet on the ground. I discuss how GoF patterns can be applied effectively in J2EE development, and the strengths and weaknesses of some well-known J2EE patterns.
If there was one thing you wished all J2EE developers understood completely, what would it be?
How to use J2EE technologies to build the simplest possible solution to a given problem
In your book you have a pretty sceptical view of some of Sun's suggestions - how has J2EE been hindered and helped by Sun?
Sun has done a pretty good job with Java over the years. And the J2EE platform has been a great achievement. So I certainly don't want to disparage Sun.
The problem I see is that Sun is a bit of an ivory tower. Their approach is sometimes too theoretical and not practically grounded. While it's great that the JCP is open, there is a danger in the way the specification process works that production implementations aren't available under after a specification is out there. This means that we can't be totally sure a technology will work as well as it should until it's too late to make major changes. I think this is a two-way street. I'd encourage more Java developers to get involved in the JCP, if they think they can make a real contribution. Sun are very keen to get input from application developers, so it's up to us to become involved.
Sun employs a lot of very bright people, but not that many of them are involved in day-to-day application development, so they're not always trying to solve the problems you or I need to solve for our bread and butter. Take working with databases. The J2EE specs stress database independence. But most people want to work efficiently with relational databases. They aren't going to take an application that's written with Oracle and migrate to an object database tomorrow. Database independence is a fine goal in theory, but I'm not convinced it adds much business value in most cases.
Perhaps the worst thing Sun has done in the history of the J2EE is produce the Java Pet Store and advance it as an example of best practices for J2EE. The Pet Store is bloated, inefficient and has given Microsoft a perfect target to attack J2EE.
Of course it's easy to highlight mistakes with the benefit of hindsight. I think what Sun has done in creating a truly open platform for enterprise applications is a tremendous achievement. It's just that some things could be done better.
What do you think of .NET?
.NET is a good platform. It's a big advance for Microsoft. But I don't see anything that would make me want to move from J2EE to .NET. I'm more taken by .NET's similarities to J2EE than its difference. Microsoft borrowed a lot from Java and J2EE. .NET is no radical advance on J2EE. In fact, it endorses the basic approach of J2EE.
C# is a very good language. I have reservations about some of the features, but there are some very interesting things, such as "attributes"-meta-data included at language level. This means that some of the things we need to put in deployment descriptors in J2EE, such as transaction attributes, can be included in a source file in any .NET language.
I don't think cross-language support is a great idea. IT managers I speak to find this frightening. They're worried about maintainability, and they aren't convinced that they'll be able to leverage existing skills. Learning frameworks and class libraries can be harder than learning language syntax, so I don't see VB6 developers becoming confident in VB.NET without a lot of work. If I were running a .NET project, I would standardize on C#. A project that contains code in Managed C++, VB.NET, C# and perhaps a third-party language such as Oberon-F is a terrifying prospect.
ASP.NET is easy to use, and a big improvement on the old ASP. However, it doesn't give as complete conceptual separation between control code and presentation that you can get using an MVC framework with J2EE. So I think the Servlet API is still a richer model. In ASP.NET, the request goes first to the page, which may then forward it elsewhere. I think this is the wrong way around: a control component should forward to pages, not the reverse.
Finally, I think there's a real problem in tying enterprise solutions to a Microsoft platform. I don't think we'll see all of .NET on other platforms any time soon. For example, the Mono project [an open source implementation of the .NET framework and APIs] have given up on trying to implement some parts of it, because they're tied to Win32.
I think any professional J2EE developer should be conversant with .NET. The two models are similar enough that there are lessons in what works and doesn't work in .NET for J2EE. I'd love to see some cross-pollination between the two platforms. I think this would be beneficial for the whole industry.
You make fairly extensive use of your own application frameworks in the book - how important are third-party frameworks, and in particular open source, to the advancement of the J2EE community?
I think a huge amount has been done in this area and there's a lot still to be done. I'm glad that the commercial world is accepting open source products such as JUnit, Struts and Log4j. I think it's fantastic that JBoss is available, and works well. I think there'll always be a premium market for commercial application servers, but it's healthy to have a competitive open source product.
The book comes with its own generic infrastructure code for several reasons. Firstly, the book is intended as a resource for developers. So I wanted to offer an alternative to and a supplement to some existing open source products. I also wanted to provide an example of the coding standards and design approach I discuss in the text. So it's more a case of "use what I've done if you want" than "do as I do, and write your own framework." The framework accompanying the book was an evolution of code I've developed over the last couple of years, so I felt I had something to offer readers.
Some of the most important parts of the framework used in the book aren't available in existing projects. For example, the JavaBeans packages are more sophisticated than existing equivalents such as the Apache BeanUtils that came from Struts. I would have loved to find a similar JDBC abstraction layer but I couldn't.
Do you actually like EJBs?
I think EJB is the right tool for some jobs, but is overused. I don't see EJB as the core of J2EE. It's just one technology that can solve some kinds of problems.
I think there are very real downsides in that EJBs are complex to implement and hard to test. On the positive side, you have container services such as container-managed transactions that can simplify complex problems.
I think some aspects of EJB are showing their age. I think if it had been designed for J2SE 1.3 or 1.4, where you have dynamic proxies and where reflection is a lot faster, the whole approach might have been different. Dynamic proxies could be used instead of container-generated implementations of component interfaces. They are anyway in servers such as JBoss and Orion/Oracle. This would have avoided the need to keep three source files in synch and made EJBs easier to develop and more intuitive. The .NET way of doing things, in which any class that implements the ServicedComponent interface can use some of the same features as EJBs, such as declarative transactions, is more like this.
There seems to have been a real backlash against EJB in the last year. In my book, I've tried to get past the rhetoric of the "EJBs are great" and "EJBs are evil" schools of thought and take a dispassionate look at the strengths and weaknesses of EJBs. I think if you read Chapters 1 and 6 you'll be well equipped to decide when to use EJB, and how to choose between local and remote interfaces if you do. These are such important decisions that I'm disappointed that most books don't say much about them.
As I said before, I don't much like entity beans. There are very few situations in which I'd use them.
How much of an improvement will J2EE 1.4 be?
I think it's more an incremental improvement than a dramatic shift. It's good to see J2EE mature and stable. I don't see much of significance in Servlet 2.4. JSP 2.0 is a real step forward-much more significant that JSP 1.2. It effectively brings the JSTL into the core and provides more options for custom tags. The timer service in EJB 2.1 is welcome, and I think the support for web services endpoints reflects an industry-wide shift to open, interoperable standards. I think it's inevitable that J2EE will move away from proprietary remoting protocols like RMI towards web services. We've already seen Microsoft trying to move away from COM/DCOM.
Which particular problem areas of J2EE will you be addressing next?
I'm interested in a lot of things, and J2EE is a big area! Right now I'm very interested in the idea of a lighter-weight alternative to EJB, for applications that need some of the services EJBs provide (such as CMT) but don't need the full power of EJB. I'm still developing my ideas in this area, but I may extend the infrastructure framework that comes with the book to road test such a solution.
There is a lot of talk about using an Aspect Oriented Programming (AOP) approach to enterprise development. Can you tell us your thoughts on this?
I'm very excited about AOP and how it will affect enterprise development. AOP offers a more elegant solution to many of the problems that EJB is currently used to address. Take CMT. Transactions can be modeled as an aspect. With AOP there's no need to use EJB to enjoy declarative transaction management.
EJB offers a very limited form of AOP. Only a few aspects, such as transactions and security, can be managed by the container, and there's little flexibility in how these are managed. The fact that the container intercepts all method invocations on EJBs isn't fully leveraged. With AOP, we can potentially enjoy the benefits EJB currently provides without a heavyweight EJB container. And it opens up many more possibilities. With a widely adopted AOP infrastructure, we could have libraries of aspect interceptors, both application-specific and third party. Instead of accepting the baggage of an EJB container every time we want something like CMT, we could just chose those services we need. If EJB is a degustation menu where you get everything the chef prepared whether you want it or not, AOP is a la carte. I think in five years time we'll probably view EJB as a transitional technology towards true AOP.
So I think the question is not whether AOP will impact J2EE, but what proves to be the dominant approach to implementing AOP. There's a choice between changing the language, as with AspectJ, and a standard Java approach, which uses dynamic proxies to add any number of "interceptors" around a method invocation.
The dynamic proxy approach is less powerful than the custom language approach, but it's much easier to sell in an organization, and I think it's powerful enough for the vast majority of real applications. Arguably AspectJ is too powerful, allowing the potential for buggy aspects to cause strange behavior across a system. There's currently a lot of work going on on the dynamic proxy approach. The Nanning project has already released code to Sourceforge. Rickard Oberg is working on his own implementation, and I've also been doing some work, extending the framework that comes with the book to add AOP capabilities. JBoss 3 already uses an AOP-ish chain of "interceptors" around EJB invocations, and JBoss 4 is going to open that up in a more flexible way.
Do you think that the AOP approach will displace stick-to-the-spec J2EE methodologies?
Tough question. As I said before, I think EJB is looking dated. I think a really good implementation of AOP could be a superior technology to EJB for most applications.
However, this doesn't mean that it will be widely adopted. The J2EE specs and the EJB spec have a tremendous head of steam. Even if a superior technology appears tomorrow from within the J2EE community, it will have an uphill battle for acceptance. I find that people get very worried and defensive when I suggest that there is very little that can be done with EJB that couldn't be done better with AOP.
The new Adventure Builder sample app for J2EE 1.4 replaces the Pet Store and addresses some of the points you raised. What do you think about the app and architecture? Is this what Java developers should be following?
I don't think much of the Adventure Builder. Some things are good: the use of the JSTL, the use of unchecked exceptions for fatal data access exceptions, the use of J2SE 1.4 logging, and the fact that it doesn't use EJB unnecessarily.
However, there are a lot of problems.
For example, the web tier classes depend on facade classes, not interfaces. So it's impossible to change how business logic is implemented: for example, to introduce EJB if it were ever necessary.
As I say in the book, I think web services protocols have the potential to displace proprietary protocols such as RMI. However, there's no good reason to use XML RPC in the Adventure Builder to contact the EJB tier. Again Sun have fallen into the trap of using a technology just because it's there, not because it makes sense for the supposed application.
At a code level the Adventure Builder is very poor. There are virtually no comments, and many sloppy coding practices. There's a lot of cut and paste code. There are chains of if/else statements on hard-coded strings that could have been much better handled through an external mapping. Several classes lose stack traces when catching and rethrowing exceptions, although the Adventure Builder is written for J2EE (and hence J2SE) 1.4, which guarantees the ability to nest exceptions. The JDBC error handling is also broken; if an attempt to close a statement fails, the connection won't be closed. Overall it's a good advertisement for the kind of coding standards I present in Chapter 4 of the book. These go well beyond the Sun coding conventions, which are basically formatting and simple naming conventions.
So I don't think J2EE developers are going to learn much from this new sample app. It's not realistic and it's not well implemented. Although it ignores a lot of real-world problems, it's unnecessarily complex for what it does.
It's sad that Sun doesn't devote enough resources to creating a decent J2EE sample application. It is important, and Sun have people who could do a good job of it. Unfortunately the applications Sun produce look like they were knocked out quickly by people who had better things to do.
You mentioned checked versus unchecked exceptions. This is something that you talk about in Chapter 4. Can you explain your position on this?
I think that Java developers over-use checked exceptions. It's easy to forget that Java is the only mainstream language that uses checked exceptions. J2EE developers tend to assume that Java offers the best way of doing everything, but this isn't always the case.
The problem is that in typical applications that use checked exceptions exclusively, we end up catching, wrapping and rethrowing exceptions throughout the code base. As with the Adventure Builder, it's easy to forget to wrap the root cause, meaning that we lose the stack trace. The catch and rethrow problem is particularly severe in J2EE, where we have to deal with remote exceptions, JNDI and EJB-related exceptions etc.
I think checked exceptions are a good feature of the language, but should only be used when all clients should be forced to handle the problem. For example, take an InsufficientFundsException if a user attempts a withdrawal from a banking system. It's logical to model this as a checked exception. All clients should be forced to deal with this possibility. In contrast, consider an exception thrown if a data access operation fails. Most business objects don't gain from being forced to catch such exceptions: as far as they're concerned, they're fatal. If the data access layer doesn't know how to retry, business objects are unlikely to. If we're dealing with EJBs, we would need to throw an (unchecked) EJBException on catching the data access exception. By modeling such usually fatal exceptions as checked exceptions, we end up with lots of catching and rethrowing that adds no value. It makes more sense to let the unchecked exceptions propagate-even to let the application server deal with them. But we retain the ability to catch any exceptions we can handle.
The JDO API is a good example of appropriate use of unchecked exceptions. It's one of the reasons JDO is much nicer to work with than JDBC, which has poorly thought out exception handling. In my experience, appropriate use of unchecked exceptions leads to much less code overall, much more readable code and no loss of correctness.
Despite my personal preference, I think it's very important to achieve consistency in a project. So if I come onto a project and everyone has standardized on using checked exceptions, I wouldn't attempt to change that without very good reason.
There are many views on this, but I think an increasing number of developers are starting to move towards greater use of unchecked exceptions. All I ask is that people read the section on exceptions in Chapter 4 with an open mind. It's also worth looking at the exception hierarchy in the JDBC framework discussed in Chapter 9.
You mentioned the design of Java versus other languages. What features would like to see added to the Java language?
Java is a good language, but it's not perfect. As I say in the book, I think the Java community is a bit insular and conservative. I'm all for shameless appropriation of good features from other languages and platforms.
Java is certainly improving. Java 1.4 added assertions, which can be a big help in writing bug-free code. By adding assertions at language level, Java 1.4 gives the power to disable them at runtime (down to individual classes) without recompiling code. This is great, although I imagine it will take a while before assertions are used as a matter of course in most projects.
Java 1.5 (Tiger) looks like it will be a major release, with more new language-level features than we've seen since 1.1. It will add many of the things I miss in Java. I've always missed enums-it's far too easy to make typos when defining constants. I think it's clear now that omitting enums in the original Java language specification was a mistake. Generics are also long overdue: the thing that I most dislike about working in Java is the number of type casts I have to write. I'm less passionate about C# style boxing, but I think it is a worthwhile feature.
I think the most important addition in Tiger for J2EE is likely to be metadata attributes (JSR-175). Earlier I mentioned how .NET uses attributes. Metadata attributes provide a perfect hook for AOP, and could be used for a range of other things. There are some things that XML deployment descriptors, as used in J2EE, aren't very good for. Metadata attributes could handle many of these.
The only problem is that Tiger is about a year away (late 2003). Ideally I would like to see more innovation: for example the introduction of "using" syntax (a simpler alternative to try/catch/finally for simple blocks) as in C#, and properties on interfaces (another C# feature). The C# way of handling properties makes the JavaBeans naming conventions look a bit clunky and ad hoc. Switches on strings (at least) would also be nice.
There was a thread on the proposed Java 1.5 enhancements on TSS a few weeks ago: it's an interesting read for anyone interested in the language. There have also been quite a few blogs lately about possible enhancements to Java, with some interesting suggestions.