Adam Bien's Weblog

Why stateful and local anti-facades are KISS

The Gateway exposes rich and persistent domain objects directly to the presentation logic. Because the domain objects are well encapsulated already - it is rather an advantage, than a shortcoming. Because of simplicity and built-in aspects, an EJB 3.1 happens to be the simplest and leanest candidate for a Gateway implementation.

Why local (to JSF 2, Wicket or a Fat Client)?

  1. Rich domain objects (JPA 2) contain business logic per definition. A call to method can change the state not only of the target entity, but of the whole connected graph. In the local case the EntityManager will correctly recognize the changes and compute deltas (change sets) and persist all changes at the end of the transaction. In remote case you will have to implement the same functionality - what is actually duplication.
  2. In local case you don't have to care about lazy loading. The entities gets just loaded on demand.
Why stateful (means: keeping the entities attached between requests)?
  1. In complex scenarios the data synchronization between layers becomes a challenge. If you keep you entities managed between requests, there is nothing left to do. You can even bind them directly to the UI - and it will still work.
  2. For every request you will have to build the domain graph again and again. This is not only complex, but it does not necessarily scale better, than a stateful solution

Local, stateful facades are not necessary the silver bullet, but the resulting architecture is very lean. It mainly consists of only domain objects, with a few Gateways.
Before you start prematurely "improving" the scalability and start with bloated applications, it is more reasonable to concentrate on the core business logic and stress test continually the application. In some cases a stateful architecture wont't scale. In this case you will have to provide the synchronization, delta-computation afterwards - with demand documented with stress test results.

[See Gateway, page 101 in "Real World Java EE Patterns Rethinking Best Practices" book for more in-depth discussion]


NEW workshop: Microservices with Java EE 7 and Java 8, January 26th, 2015, Airport Munich

A book about rethinking Java EE Patterns

Comments:

Adam,
I think your are right: using session beans and stateful EJBs is really a good solution to reduce the complexity in RIA / WebApps. Perhaps the AppServer Vendors will find a better way to handle so many "fat clients" on their server. This would ease developers life a lot.
But even more complicated IMO is the impedance between my logical / business objects and the ui-objects. There are so many controls, (view) tables, event listeners.
JEE6 became so powerful: the fighted has now mainly been shifted to GUI. We still need one of these Web-Frameworks or implement some MVC pattern. Binding this presentation layer stuff to the application objects is still a pain. We need simpler, more object oriented frameworks here as well.

Posted by Bernd on August 07, 2010 at 03:02 AM CEST #

A like the idea, but there is a problema: we host our aplication in a server that are very eager do passivate session bean. The problem arrises when the managed entities become passivated, then, when they becone activated, they loose the persistence context.
Is there a way to solve it?

Posted by Flávio Henrique on September 14, 2010 at 04:23 PM CEST #

@Flavio,

yes - just disable passivation. It isn't needed and possible on most application servers I know...

thanks!,

adam

Posted by adam-bien.com on September 14, 2010 at 04:24 PM CEST #

Come on,
and what about performance

<citation>
1. Rich domain objects (JPA 2) contain business logic per definition. A call to method can change the state not only of the target entity, but of the whole connected graph. In the local case the EntityManager will correctly recognize the changes and compute deltas (change sets) and persist all changes at the end of the transaction. In remote case you will have to implement the same functionality - what is actually duplication.
</citation>

Try the above mentioned pattern on system with 1mil+ rows per table with just moderate load (50 transactions per second) and you will find that without careful ordering of DB SELECTS and UPDATES the system is overloaded.
On MDM (Master Data Management) like systems will Your approach "mostly" function, but only after tweeking such knobs as flushingModes, cacheModes, autocommit etc. Even then you will find some exceptions where you must manually order the access to the DB.

<citation>
2. In local case you don't have to care about lazy loading. The entities gets just loaded on demand.
</citation>

This will bring performance problems even in so simple case as rendering 2 interconnected DB tables in 1 HTML table (half of the columns from one DB table, half from the second one).
With automatic lazy loading you get the classical 1+n queries to DB, which is on slightly larger tables unacceptably slow from the user's point of view (don't forget the connection delay between App and DB server).
Even in the "local" case you would better write specially crafted manual query which will load all the data in just one or 2 DB requests (see e.g. FETCH JOIN in the JPA spec)

Don't forget TANSTAAFL :)
And "Object relational impedance mismatch" is lurking out there too :)

Posted by Cybernet Sauvignon on September 17, 2010 at 03:11 AM CEST #

'Stateful' doesn't necessarily mean that the entities need to remain attached. I usually work with the EntityManager-per-Request pattern (@Produces @RequestScoped EntityManager) thus all entities stored in some CDI managed JSF backing beans will become detached at the end of the request.

This is also the only way to really be able to have good cluster support without wasting tons of resources (which @Stateful SessionBeans do). And if it comes to real clusters, you need to manually implement @PrePassivate and @PostActivate to do all this stuff anyway (EntityManagers and DataSource are not Serializable).

Of course this means that you need some clever setup to automatically em.merge() the entities if needed (see my GenericService<T> in my lightweightEE sample on github).

Btw, a big problem with all the serialisation is still that the JPA TCK don't seem to cover serialisation good enough. In some JPA providers you might loose the information about _dirty and _loaded flag which has a few bad side effects. And with the working ones you need to enable some cracy provider specific properties in persistence.xml.

LieGrue,
strub

Posted by struberg on January 08, 2012 at 12:35 PM CET #

Post a Comment:
  • HTML Syntax: NOT allowed
realworldpatterns.com
...the last 150 posts
...the last 10 comments
License