Re: Persistence Strategies [Was: Open source WO - offer]

Lenny Marks <[email protected]> Tue, 5 Sep 2006 20:37:19 -0400
Newsgroups gmane.comp.web.webobjects.general
Message-ID <[email protected]>
On Sep 5, 2006, at 12:27 PM, Andrus Adamchik wrote:

> On Sep 5, 2006, at 7:31 PM, Lenny Marks wrote:
>> Just to expand, the benefit of POJO model objects is in the fact  
>> that they have no dependencies on the persistence framework(in  
>> this case Hibernate), which means any business logic can be easily  
>> tested with a Plain Old Unit Test in isolation without loading  
>> configuration files or connecting to a database, or any other  
>> complication.
>
> I think the above is an argument for POJO vs. EJB. Not POJO vs.  
> EO's or Cayenne DataObjects that are both actually POJO's from the  
> unit testing perspective. I.e. if you manually inflate your object  
> with test data values prior to testing the business logic, all ORM  
> frameworks should work the same.
>
Well, yes and no. I can't speak about Cayenne, but you can't do much  
with EOEnterprise objects without editing contexts and the model  
bundles loaded. I remember seeing a lot of'  
java.lang.IllegalStateException: Unabled to find an  
EOClassDescription..' exceptions if the EOModels weren't loaded. Just  
getting all the dependent frameworks and models loaded outside of a  
WOApplication is non-trivial. Hibernate imposes nothing on your model  
classes. You won't even see hibernate in an import statement. We used  
to have all our unit tests extending a base test class that took care  
of the dirty work, but in Hibernate POJO means POJO. Also, in EOF,  
most unit tests look something like this:

<code>
EOEditingContext ec = new EOEditingContext(); //has dependencies

Employee emp = (Employee)EOUtilities.createAndInsertIntance(ec,  
"Employee");

Department department = (Department)EOUtilities.createAndInsertIntance 
(ec, "Department");
department.addObjectToBothSidesOfRelationshipWithKey(emp, "employees");

assertEquals(...something)
</code>

I would argue that POJO looks like this:

<code>
Employee emp = new Employee();

Department department = new Department();
department.addToEmployeesRelationship(emp); //granted I would have  
had to write this method in hibernate

assertEquals(..something)
</code>

Prettiness only goes so far, but the dependencies of EOF are a bigger  
problem. I just ran an experiment running a single test method, EOF  
version vs POJO version. The EOF version takes about 1030  
milliseconds and the POJO version takes about 300. Doing test first  
development, this adds up.

> But not having a framework-mandated superclass can be good (or bad)  
> in different situations, that's for sure. A framework superclass  
> saves you time coding many things (and attach/detach thing IS  
> annoying), but can have unpredictable consequences during  
> serialization (e.g. when the objects have to cross the wire), and  
> makes it impossible for another framework to dictate a superclass :-)

Yes, there is a good and a bad. Having model classes with no  
dependencies on the ORM solution makes them really lightweight and  
portable, but you also lose things like automatic validation before  
saving. Hibernate allows you to implement an interface of callbacks  
to do such stuff, but its not recommended because of the leakage of  
concerns.

>
>> Its also good for re-usability and maintainability not having your  
>> business entity classes and business logic tied to a particular  
>> ORM solution.
>
> True in general. Still if you code your business logic only relying  
> on public properties of the entities, the two approaches are  
> equivalent.

Except that you can't re-use or test them without  all of EOF and its  
dependencies.

>
>> The reason you have to make sure the Hibernate session is either  
>> closed or at least disconnected after each request is so the JDBC  
>> connection is released. In EOF, you don't need to worry about this  
>> because there is for the most part, a single open database  
>> connection shared by all editing contexts across the entire  
>> application or at least each EOF stack.
>
> You don't have to worry about it in Cayenne either, and it is fully  
> multithreaded with a connection pool (javax.sql.DataSource) behind it.
>
>> Speaking of caching. As I mentioned above, this was another place  
>> I found EOF to be flawed. Our experience wast that, EOF is great  
>> for read mostly applications or single instance applications that  
>> handle all database updates, or for applications without fresh  
>> data requirements. IMO, EOF applications get way too complicated,  
>> if this is not the case, for example if for whatever reason you  
>> have database updates happening outside of your app(legacy system)  
>> or because you have more than one instance of your app, or  
>> multiple apps manipulating the same data, or whatever...
>
> Stale data is a problem with any system that has a cache, period.  
> Not sure how Hibernate implements caching, but if you refetch  
> everything from scratch with EOF and/or Cayenne on every request,  
> you get fresh data, if you don't - you can end up with stale data.
>
As you mention below, its in the granularity of the caching. Stale  
data is a problem is any system with a cache, so that's why you  
wouldn't want to cache data that is frequently modified. Also in  
EOF,  you can't refetch everything from scratch without the pretty  
severe side effect of tying up the EOF stack(path to database)  
blocking out all other requests. If you decide to give each request  
its own EOF stack, then each request has to open its own database  
connections. Also, EOF was definitely not intended to be used this  
way and so is still doing a lot of extra caching and notifications,  
which I would imagine have some impact on memory and performance.  Of  
course you can start pooling EOObjectStoreCoordinators(I believe  
Wonder has support), but like I said, in EOF it just gets more  
complicated than it should be. I was actually the implementor of the  
JavaPoolingJDBCAdaptor framework posted on WOCode long ago, which was  
partially picked up in the latest Wonder release. I originally  
implemented that with great pain for a XML-RPC service that needed  
fresh data for every request so that all EOF stacks could share a  
pool of JDBC connections.

> What EOF is missing is user friendly cache management facilities.  
> Expanding on your point - one size doesn't fit all, so making it  
> easier to implement alternative caching strategies is needed.  
> Cayenne is half-way there - we are doing some work on it in 3.0.


>
>> I'm not too familiar with Cayenne. We checked it out about a year  
>> ago, but thought it might be a little too much like EOF
>
> Not in the threading part ;-)

Is Cayenne similar in architecture with something that looks like an  
EOF stack(Object store hierarchy)? If so, do developers have to  
manage locking/unlocking it like in EOF. Bottom line, can more than  
one request do database access without blocking others(by default)?

>
>> and at the time did not support POJO's which have been of  
>> substantial benefit. I'd be interested to here comments if Cayenne  
>> addresses some of these issues.
>
> DataObjects (and more so Persistent objects used in the remote  
> layer) are POJO's, except for the framework callbacks in the set/ 
> get methods. We just need to replace them with runtime class  
> enhancement (we still want lazy faulting and automatic reverse  
> relationship connection/disconnection, don't we?).

Lazy faulting is definitely a good thing . Not sure what you mean  
exactly by reverse relationship connection/disconnection. If that  
means persistence by reachability, then also a good thing. One note  
about the runtime class enhancement. This is one of those complaints  
I have about Hibernate. It may just go with the territory, but the  
runtime class enhancement adds a substantial amount of startup time  
which hurts developer productivity. There seems to be some technical  
reason why Hibernate can't give an option to to build time class  
enhancement during development, which could be done only when a  
mapping has changed. Maybe you can avoid that when the time comes.


>
> Since we are targeting full JPA spec compliance, you'll see lots of  
> things familiar from Hibernate (and TopLink) world - again, attach/ 
> detach/getTransaction and other fun stuff.

Ah. Thats sounds good. I didn't even go into transaction management,  
which is another place IMO, Hibernate wins over EOF. Doing  
declarative transaction management with Spring is really nice.

-lenny