Proposed Jakarta EE Design Principlessaturday, june 09, 2018
Jakarta EE is slowly emerging, and with it future enterprise specifications. In order to align the different standards and technology that are about to be formed it might be valuable that the Enterprise Java community agrees upon design principles for Jakarta EE specifications.
I believe that there are a few principles that have made Java EE such a successful technology in the past. The following illustrates my points of view on design principles that I recognized in Java EE, and which might be worth to pursue and record further, as possible guidelines for Jakarta EE.
This blog post was encouraged by Dmitry Kornilov’s proposals on the technical directions of Jakarta EE.
Business Logic First
Java EE’s programming model allows developers to focus on what they should focus on: the business logic. There’s no need to extend API classes anymore; developers can write their domain logic in plain Java and control the application server behavior mostly declaratively, via annotations. This causes the framework to integrate leanly into your code and can, in fact, be removed easily again. Don’t design for reusability, design for removal.
The implementations, however, take as much heavy lifting off the shoulders of developers as possible, namely technical requirements that are not related to the business logic. Examples are threading, transactions, inversion of control, or HTTP request handling. On the application side it’s good to “be boring” :-)
I consider it important that a framework does not get in the way of the business logic but actually empowers developers to get their functionality to production faster. We don’t want the framework to shine, we want your business code to shine. Compare modern Java EE or Spring to the old days of J2EE and I’m sure you’ll see what I mean.
Jakarta EE should continue this trend and should focus on providing specifications that enable developers to ship their business logic as fast as possible.
Convention over Configuration
Java EE minimizes the configuration that is required to define a day-to-day enterprise application. Convention works out-of-the-box for the majority of use cases, with zero configuration. Examples are that no XML files are required anymore to configure a basic Java EE application, or that JAX-RS provides appropriate default HTTP response codes for JAX-RS method return values.
Java EE indeed offers the flexibility to modify the behavior for more complex scenarios, however, the convention doesn’t require it.
Jakarta EE should continue to “make the easy simple and the difficult possible”.
Interoperability of Specifications
Jakarta EE should continue and extend the interoperability of its specifications. Java EE honors existing specifications and functionality thereof that are already part of the standard.
Developers can expect separate specifications to work well with each other, with zero configuration required. The standards required that if the runtime supports both specification A and B, A + B have to collaborate with each other. An examples of this is that Bean Validation, JAXB, or JSON-B can be used in JAX-RS resource classes, without further configuration.
Dependency Injection & CDI
We should not want Jakarta EE to reinvent already existing things, for example CDI’s dependency injection. The specifications should, if possible, use and leverage the power of JSR 330, or if required, CDI.
An example that we have today is the injection of JAX-RS'
UriInfo into resource methods.
It’s not supported yet to use
@Inject to inject this type.
Laying on one mechanism as much as possible improves the developer experience.
As another concrete action, specifications should provide CDI producers, and if necessary, typesafe qualifiers, for types that need to be created.
As of today, an instance of the JAX-RS client, for example, can only be obtained via the programmatic
Producers and qualifiers help improving the experience by enabling declarative definitions.
That being said, the Java EE API heavily enables to define various functionality in a declarative way, by using inversion of control. This means, developers do not invoke the functionality directly; rather than it will be invoked by the container, based on the code definitions. Examples are JAX-RS, JSON-B, or CDI, among most other modern specifications.
Besides offering more exhaustive programmatic APIs, Jakarta EE should continue to enable developers to use declarative definitions and inversion of control.
One big difference, and for me advantage, that Java EE offers is the deployment model that separates the business logic concerns from the implementation. Developers solely code against the API, which is not shipped inside the deployment artifact, and which will be implemented by the application container.
These thin deployment artifacts simplify and speed up the delivery of the software, including builds, publication, and deployments. They are also compatible with container file system layers, as used in Docker. The deployment process only needs to re-build or re-transmit what has been changed.
Ideally, the deployment artifacts only comprise the sole business logic; runtime implementations and potential third-party libraries are delivered in a lower layer, for example in the application server libraries that have been added in a previous container build step.
Jakarta EE should continue to offer thin artifact deployments as a first-class citizen. It may optionally make it possible to further slim down the runtime, based on which specification the application requires. However, Jakarta EE should focus on the business logic and developer productivity first, and on tuning the runtimes second.
Applying the mentioned principles, especially favoring declarative programming as well as dependency injection, improves the testability of the business code. They enable developers to directly instantiate and objects in test scenarios, since there is no requirement anymore to extend API classes or call cumbersome functionality, that would need to be mocked.
An area that should be improved in Jakarta EE, though, is the standardization of code-level integration testing in a vendor-independent way. In the past, this what usually realized with Arquillian. Real-world projects would benefit from a standard that allows to only declare test deployment scenarios and to invoke functionality on one or more components. As I wrote in the past, I don’t consider code-level integration testing, as in executing the application in embedded containers, too important. However, standardizing code-level integration tests will have it’s benefits.
Asynchronous And Reactive Approaches
Java EE typically addresses applications with a transactional, synchronous request model. While many specifications such as JAX-RS already support asynchronous and reactive approaches, Jakarta EE would vastly simplify to interoperate and connect asynchronous APIs from multiple specifications, as well as from external libraries. Especially handling completion, cancellation and errors of events can become challenging.
It would be highly beneficial, especially for applications for which typical transactional use cases are not sufficient, if Jakarta EE’s APIs are developed with asynchronous and reactive use cases in mind, specifically with better integration and interoperability. A good point and more information on this topic can be found under this blog post by James Roper.
I think there’s a reason why Java EE APIs have such a wide usage in real-world projects: well-thought out and well-defined design principles that not only touch a single specification but the overall platform in a uniform way. They enable to use multiple specifications with the same look and feel, to write the application code with less artificial obstacles, and they make, so I believe, enterprise development more enjoyable.
Update 2018-06-13: Added section about testability. Thanks everybody for the feedback!
Update 2018-07-30: Added section about asynchronous and reactive approaches.
Found the post useful? Subscribe to my newsletter for more free content, tips and tricks on IT & Java: