Can you list 10 JEE best practices from your experience?

Core Java best practices and JEE best practices can reveal a lot about your experience as a Java developer.

Q1. Can you list 10 JEE best practices from your experience?
A1.

#1: Using datasources with JNDI lookups

DataSources make the code more portable than using the DriverManagers. For the DriverManagers you need to tightly couple the details like host, port, username, password, and driver class to connect to a database with the code, and even externalizing those in a properties file doesn’t give you the flexibility that the JNDI lookup give by configuring the DataSources on the application server.

DriverManager approach

For the Datasources you need to know only the JNDI names to be used in your code,

DataSource with JNDI lookup approach

where the database details like host, port, username, password, and driver class will be configured on the application servers like JBoss, Weblogic, Tomcat, etc. This configuration varies based on the type of server you are using. For example, in Tomcat, you need to configure the “conf/server.xml“. You can configure the connection pool sizes, connectivity details, and test the database connectivity independent of the code that use them. The code has to only know the JNDI name.

Datasources also pool connections to give you scalability and the application server manages the connections for you.

#2: Using PreparedStatements over normal Statements

Reason 1: Prepared statements offer better performance, as they are pre-compiled. Prepared statements can reuse the pre-compiled execution plan for different arguments rather than creating a new execution plan every time. Prepared statements use bind arguments, which are sent to the database engine.

Reason 2: Prepared statements are more secured because they use bind variables, which can prevent SQL injection attack.

The most common type of SQL injection attack is SQL manipulation. The attacker attempts to modify the SQL statement by adding elements to the WHERE clause or extending the SQL with the set operators like UNION, INTERSECT etc.

The attacker can manipulate the SQL as follows

The above “WHERE” clause is always true because of the operator precedence. The PreparedStatement can prevent this by using bind variables as shown below:

Parsing the query just isn’t such a significant part of the work involved, hence performance is not the key consideration in using a prepared statement. Protection against SQL injection attacks must be the key consideration as it far outweighs the performance improvement.

#3 Keep it simple

Distributed enterprise applications are good, but the organizations don’t need 100+ modules to manage. Keep your code and your projects together until it becomes too big and hard to manage, then create a second application and let the two big apps communicate via RESTful web services. Don’t bloat your war and ear files with patterns. Use the latest JEE possible. JEE 6 or JEE 7 are free of patterns. JEE patterns were created to solve pre JEE 6 issues and caveats. Keep your app simple and stupid with the KISS principle.

#4 Good layering will make your application more maintainable

Always use MVC layering. Cleanly separate business logic (Java beans and EJB components) from controller logic (servlets/Struts actions) from presentation (JSP, XML/XSLT). With the advent of JavaScript based frameworks like angular js, backbone, etc this become more of MVW (Model View Whatever) layering. In addition to MVW, good layering encompasses service layer, DAO (Data Access Object ) layer, BusinessDelegate layer, Facade layer to reduce network round trips, etc. Always build a vertical slice for a typical use case to validate your layering and architecture.

Java Enterprise Vertical Slice

Java Enterprise Vertical Slice

#5 Favor stateless services to make your system more scalable and easier to fail over

When using HttpSessions, store only as much state as you need for the current business transaction and no more. HttpSession’s intend is to maintain temporary user state, and not to be an arbitary data cache. Since sessions are persisted, it can be very expensive to force unnecessary serialization and writing of the data. Instead, use an in memory ConcurrentHashMap to cache the data and just keep the keys to the data in the session.

Stateful services can scale linearly with a policy known as the “sticky routing“, but if the service dies, the session status will be lost. The stateful services can also fail over, but each server needs to not only return its own SESSION ID, but also the fail over server’s SESSION ID. So, stateful services get a bit more complicated in terms of load balancing and failover.

#6 Use DI (Dependency Injection) to loosely couple your classes

For example, Java EE6 CDI (i.e. Contexts and Dependency Injection) annotations @Named and @Inject. Use appropriate scopes for the components to maximize memory usage. Make judicious use of the conversation scope.

Java CDI scoped

Java CDI scoped

#7 Use Interceptors & decorators for the cross-cutting concerns

Use interceptors (i.e., @Interceptor), which decouple your system level cross cutting concerns like deadlock retry, auditing, logging, service retry, etc from the business logic. Use decorators (i.e. @Decorator) to perform tasks that are complementary to those performed by interceptors. Decorators perform business logic by intercepting business methods of beans. So, the decorators instead of being reusable for different kinds of applications as the interceptors are, their logic is specific to a particular application.

A decorator enahnces the behavior of the class it is decorating. The CDI specific annotations are used like @Decorator to mark the decorator implementation. A decorator should always have a delegate, which is the class that we want to enhance by decorating, and is marked with the @Delegate annotation at the point of injection).

The beans.xml file specifies both the decorator and the interceptor:

#8 Services need to be secured with proper authorization & authentication

Every application needs to be properly secured and it is imperative to understand and implement relevant data encryption and access controls. Some of the key terminologies get thrown around are SSO, one-way SSL with basic authentication, 2-way SSL, user authentication, role based authorization to restrict access, etc. This is covered in detail in “Key Area: Security” with lots of diagrams and examples.

JEE cross cutting concerns

JEE cross cutting concerns

#9 Transaction Management

ACID based local or distributed transaction management and compensation based transaction management. For example, designing applications with Java Message Service (JMS) requires a good foundation in “transaction management” and “message redelivery”

If you have received a message from a JMS provider, and Database insert fails then how are you going to manage the transaction?

JMS and transaction management

JMS and transaction management

Learn more about this at “Kay Area: Transaction Management

#10 Exception handling, service timeouts and retries

The modern enterprise applications are highly distributed and service oriented. Hence, when designing an enterprise application, proper planning must go into exception handling, service timeouts & retries, asynchronous store and retry, etc. For example,

Spring’s @Transactional does not rollback on checked exceptions. You need to throw unchecked exceptions to rollback Spring managed transactions. Similarly, EJB CMT does not roll back the transactions automatically on an application exception (that is, a checked exception other than java.rmi.RemoteException). The roll back is automatic only on unchecked exceptions.

#11 Writing unit, integration, automation & performance tests

It is important to write tests to develop more robust and quality code. Use code coverage and code quality tools to proactively identify & fix issues. Use BDD & TDD techniques. Test exceptional scenarios.


Categories Menu - Q&As, FAQs & Tutorials

Top