Java Application Layered Architecture – My Way Of Doing Things

Before I stood in the Java world with both feet, I’ve been having many doubts of how to do things in Java when programming web applications. I mean, Java is a general purpose language and one of its strengths is modularity. There are different modules (libraries) for accessing data – Hibernate, Eclipse Link -, presentation frameworks – Sitebricks, Wicket, Google Web Toolkit – and there are even dependency injection frameworks that help you to glue everything together, like String Framework or, my favourite, Google Guice. Not to mention the basic building blocks like Java standard library itself and all those JSRs.

No doubt, those who criticize Java are correct – the learning curve is pretty steep because, in contrast, other languages have frameworks that handle it all together – like Django for Python or Ruby on Rails.

I guess, there is no more discussion that the correct way of writing applications is to use layered approach instead of spaghetti coding everything together. Applications have:

  • a data layer,
  • a service layer,
  • and a presentation layer.

When coming to Java world, the hardest part for me was understanding how to program the service layer because, well, noone actually tells you how :).

Use Data Transfer Objects

Or, DTOs in short. I have killed too much time figuring out how to transfer my Hibernate Proxy data object to the client, there are too many questions asked about this, and there are too many libraries invented to do this. Just don’t, or you’ll end up with all those IllegalStateExceptions when accessing a lazy property of a proxied entity while generating a view when the Hibernate session is already closed or you’ll just generate too much traffic by transferring the information your views do not require.

Better – identify the use cases and the exact portions of data you actually need in each one of those. For example, let’s say we build a contact manager application. Our core data entity, of course, is PersonEntity with fields like id, firstName, lastName, address, phoneNumber etc. There are at least two natural cases for using these data entities:

  1. displaying person entities in a list
  2. and displaying a detailed view of each entity.

In the first case we probably will need just a person’s id, the firstName, and the lastName – just to show a list entry. Actually, that’s how we are going to call this view – PersonEntry. Moreover, we could be interested in just a single textual representation of this entry, let’s call this a title which on the server side might be a concatenation of both firstName and lastName properties. So, considering everything abovementioned, here’s the interface of our people list entry view:

public interface PersonEntry {
    int getId();

    String getTitle();
}

Case #2. This is quite staightforward. This is a view of full information on a person, let’s call this view PersonDetails:

public interface PersonDetails {
    int getId();

    String getFirstName();

    String getLastName();

    String getAddress();

    String getPhoneNumber();
}

Again, having such kind of DTO for your data entities gives you the opportunity to transfer only those properties, that information, you want, thus minimizing data traffic and tightening the system’s security.

Now, let’s define the interface of our service with two elementary methods for getting list of people and getting information on an individual person:

public inteface PersonService {
    List<PersonEntry> listPeople();

    PersonDetails findPerson(int id);
}

Don’t create your DAOs

Commonly Data Access Objects are interfaces to the system’s persistence mechanism, in our case, a relational database. They support the basic CRUD operations, typically through interfaces like these:

public interface PersonDAO {
    void save(PersonEntity person);

    PersonEntity get(int id);

    void delete(int id);
}

Commonly, implementations of those interfaces use Hibernate or other object-releational mapper and provide more options like finding entities by more criteria, not just a person’s id.

And that’s actually the problem: where is this line where you stop writing DAO methods for retrieving entities and move these to the corresponding service, i.e., choosing to put something in PersonDAO or PersonService.

Moreover, look at the main JPA interface, the EntityManager. Doesn’t it already provide the operations for [storing](http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#persist(java.lang.Object), [retrieving](http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#find(java.lang.Class, java.lang.Object), [updating](http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#merge(T), and [deleting](http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#remove(java.lang.Object) your data in a platform-independent manner? JPA has already given all the DAOs you’ll ever need.

Of course, one might argue that DAOs are great when you switch your data storage completely, like migrating from a relational SQL database to NoSQL, because, theoretically, your service classes then could remain intact. But what’s the difference then between completely rewriting DAO implementations or completely rewriting your Service implementations? You’ll end up rewriting at least something either way.

So, instead of creating a single class that loads everything, inject EntityManager directly in your service implementation and do all the querying you need.

Clearly define boundaries of your transactions

To maintain the data integrity, we use database transactions, i.e., we either update and retrieve all the data necessary for an operation, or, in case of an error, we update none. This is typically done in the following manner:

EntityTransaction txn = entityManager.getTransaction();
txn.begin();

try {
    //do stuff with the data
    txn.commit();
}
catch (SomeException e) {
    txn.rollback();
}

Gladly, most dependency injection frameworks save you from doing this every time, by providing a @Transactional annotation which indicates your service methods you want to do in a transaction. However this annotation can be also misused, like being placed not on an individual method, but on an entire class. Hence, do not do this (source):

// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {

  Foo getFoo(String fooName);

  Foo getFoo(String fooName, String barName);

  void insertFoo(Foo foo);

  void updateFoo(Foo foo);
}

I highly doubt that in a method, clearly indicated as a data retrieval method, you will need a transaction. Better, do this:

// the service class that we want to make transactional 
public class DefaultFooService implements FooService {

  Foo getFoo(String fooName);

  Foo getFoo(String fooName, String barName);

  @Transactional
  void insertFoo(Foo foo);

  @Transactional
  void updateFoo(Foo foo);
}

Don’t be afraid of the interfaces

Actually, this is optional, however I have found that the following approach to writing service operations makes my code clearer:

public interface PersonService {

    public interface AddPersonRequest {
        String getFirstName();

        String getLastName();

        String getAddress();
    }

    public interface AddPersonResponse {
        boolean isSuccessful();

        int getNewId();
    }

    AddPersonResponse addPerson(AddPersonRequest request);

}

To illustrate my point, consider the following example:

public interface PersonService {
    int addPerson(String firstName, String lastName, String address);
}

Of course, this looks shorter, however it also poses at least two questions:

  • What does the int returned by addPerson method actually means?
  • What if there is more data to be added? Does the method signature int addPerson(String firstName, String lastName, String address, String homePhone, String workPhone, String mobilePhone, String homeAddress, String workAddress) would look good?

Also, the approach above makes object mocking easier, when you get to writing your unit tests.

Final words

Java is hard, however it gives you also many benefits like compile-time error checking, large array of mature and stable libraries you can use and, arguably, better performance than, say, a Rails webapp. On the other side, Java is quite notorious for the boilerplace writing it requires. This article shows some ideas how one can eliminate certain portions of this boilerplate like eliminating the necessity of writing specific DAOs and … suggests adding the boilerplate somewhere else instead 🙂 – like defining interfaces for service requests or interfaces for Data Transfer Objects.

However, this boilerplate code actually improves your code, and is actually … not a boilerplate any more, because if serves a good purpose.

Leave a Reply

Your email address will not be published. Required fields are marked *