Dec 3, 2013

Plain Java EE Architectures: Rethinking Best Practices?

I recently attended a session at the W-JAX13 in Munich on plain JEE architectures. It was an interesting and amusing talk. But, the speaker made a few comments on how you should be developing Java enterprise software that got me thinking and I definitely disagreed with. So I went home and borrowed an E-book on Amazon about Java EE patterns. Again, this book got me thinking. Here are my thoughts.

One big WAR only. Seriously?

In the session the speaker's point was that nowadays you should stick everything into one big WAR file. In JEE6 there is no need for dedicated EJB-JARs or even EARs anymore (as long as you don't need sophisticed classpaths or JCA connectors. And who does?).

Even though this is technically true, this doesn't mean you should do it only because you can. For trivial applications this might be perfectly reasonable. But for a professional business application with several 10ks of  LOC, this would just be insane.

The speaker also argued for more business-oriented components rather than technical-oriented. I totally agree. You achieve this by using dedicated Java packages for your business concerns (e.g. customer management, price calculation, shipping workflow, and so on). In my opinion the next logical step would be to encapsulate these components in individual artifacts: JARs. Tools like Maven and Gradle provide an easy means to do so, using multi module projects. In a complex system this allows you to control the allowed dependencies between your business components. If you had one big WAR only, it would just be too easy to produce a highly tangled design. Effectively a Big Ball of Mud. So even in the dawn of JEE, I still think it's a good idea to have individual deployment units for your business components.

No Interfaces. Really?

Yes, in JEE 6 and 7 you don't have to write a lot of boilerplate XML or Java code anymore. Great. For most cases you have suitable annotations available. Development has become easier and the code is more compact.

Technically, a business interface for your EJB3.x components is not required anymore; you automagically get a view of all public methods of an Enterprise Java Bean. But, even though this is possible, that doesn't mean it's always a good idea to do so.

Again, for simple components or applications this approach might work well. I don't say that every class needs an interface, but in my experience the real world is just not as simple. Here are some important reasons to use interfaces:

  • Contract first. Before you start implementing the business logic of a new component it is always and still good practise to think about its interface first. The interface states the contract between the caller and the callee. What methods are supported? Which parameters need to be passed? What is the outcome? Are there any pre- or postconditions and invariants?
    If you are working with co-located teams, once you have your interface everyone can start coding. In feature-oriented, agile teams the UI and backend developers can implement their specific part of an user story almost independently. All that is required is a well designed interface. 
  • Alternative implementations. An interface usually is technology neutral. You could decide to implement it using EJB, CDI or even Spring. OK, in practice this is esotheric, since the overall architecture of your system will probably only ever use one of these technologies and never change.
    But the chance that you will have alternative implementations of an interface is still pretty high. For local development you might have an in-memory version of the component, for full-blown deployment a database implementation and for testing a simple stub implementation. By using feature flags (such as Togglz) you can easily swap the different implementations.
  • Emergent design. Interfaces are also an excellent enabler for emergent design. You might not know yet if a component needs to support persistence or if an in-memory implementation is sufficient. Or does it need to be async in the future? The usual unknown unknowns.
    By using interfaces your components can evolve anyway the business requirements needs them to. Your calling code does not need to change a bit. Awesome.
  • Easy Testing. The speaker mentioned that this point would not be valid anymore. A JEE component is a simple POJO and testing is easy enough without having interfaces. I beg to disagree. Try mocking a final method of a collaborating class and you see my point. It just doesn't work as you might expect (at least not with the mocking frameworks I know). So if you don't want to have a hard time testing your code: use interfaces.

DAOs are dead. Are they?

An interesting section in the book is about obsolete J2EE/JEE patterns. Apparently, Data Access Objects aka DAOs are dead. For most cases. Mainly because of the following two reasons:

  • Overuse: the idea of decoupling from the database is neither realistic nor necessary in most cases.
  • Abstraction: a complete abstraction of the underlying data store is only possible for simple use cases.

Apparently, the usage of a JPA EntityManager is all the abstraction you need in a JEE environment. In my opinion the DAO pattern is still very useful and vital, even for JEE.

I agree, the ability to swap out different persistence technologies transparently by using a DAO interface is mostly esotheric. Regarding the leaky abstractions: since you can't avoid them, you have to live with them anyway. But all this doesn't render DAOs useless. The main purpose and value of a DAO lies in one fundamental concept: separation of concerns.
In a well designed system your components usually fall into one of the following categories:

  • T-components are independent of the actual business domain model, and deal with some technology or API such as JDBC or low level async I/O.
  • A-components are independent of any technology, they are determinded by the business domain and are responsible for the actual application logic. 
  • 0-components are basic and usually reusable building blocks, comparable to the classes found in the java.lang or java.util packages. Libraries like Commons Lang or Commons Collections also fall into this category.

A data access object is a typical T-component. No business code, just pure technical interaction with some persistence API or framework. Do you really want the code required to call JPA named queries or the Criteria API pollute your A-components? I don't think so.

Instead you encapsulate the required code into a nice data access object. Call it differently if you don't like the name. Usually, you don't have to write this sort of code manually anyway. For example, you could use or write an annotation based lightweight code generator to do this for you. Testing your data access code and named queries also becomes a lot easier. Write some integration tests to verify your DAOs, and test your business code using simple mock implementations of your DAOs.

Unit tests without value. Pardon?

All patterns in the book have a dedicated section on Testing. In an agile, test driven development world this section is almost mandatory. But wait: for several patterns you read something like "... for this pattern a unit test does not provide any value ...". The reason being the simplicity of the implementation.

Again, I disagree. In my experience, you can not be thorough enough! Nothing is more annoying than getting a NPE in really simple methods for some corner cases. If you are developing test driven then you should be writing the test alongside the actual implementation without any real additional effort. The foundation of your testing strategy should be loads of unit tests (Test Pyramid). Relying on manual system or integration tests to cover all possible cases is just plain careless.

Rethinking? Yes, but in moderation.

Even though I might disagree in a few points with the speaker and author I still think reading the book was worthwhile. A novice developer gets a good introduction into JEE and CDI, and a load of usable design patterns that show how to apply these technologies to real world problems.

For the more experienced Java developers, the Rethinking sections usually contain a good critical appraisal of the well known and established J2EE patterns. Like me, you might not agree with all the points, but at least they got you thinking about your day to day work once more. And that is valuable on it's own.

But don't throw your best practices in JEE architecture and development over board just yet. Moderation.