On Sat, Oct 1, 2011 at 8:45 AM, Matthew Woodward <[email protected]> wrote:
> And be SURE and read the "ORM is the Vietnam of Computer Science" link Sean
> provided. Required reading if you're even considering using ORM.

And Ted Neward's original article, linked from Jeff Atwood's blog, if
you want more depth.

> ORM is a big, hairy, complex problem to solve and even with a best-of-breed
> tool such as Hibernate, if you do decide to use it you better buy a couple
> of the big-ass books on it (Java Persistence With Hibernate is an excellent
> one) and learn the tool inside and out.

Agreed. I first used Hibernate with Spring and Groovy back in 2008 to
create the back end of a Flex/AIR app. We ran into a lot of the
problems that CFers are now seeing with the Hibernate-backed ORM
(session management, detached objects, bidirectional relationship
complexities). The lure is great: "never write SQL again" but
Hibernate only differs from arf!, objectBreeze, Reactor, Transfer etc
by being more robust and somewhat more performant. Those problems are
core to ORM because it's an abstraction that tries to hide the mapping
between two very different models (objects and tables).

At World Singles, we started out with Reactor back in 2009 (Reactor
lead, Mark Drew, was involved with the project before I got involved,
which was why Reactor was picked over Transfer - but the decision to
use ColdBox + ColdSpring + an ORM had been made by the then CTO) and
we're still slowly weaning ourselves off it because of performance
(primarily).

As the project has progressed, I created a very simple object mapper
that handled relationships by convention**, instead of within the
object mapper itself. That helped, taking care of CRUD while pushing
object relationship management up into the application model. Later I
created an even simpler mapper in Clojure, as a thin CRUD layer around
the clojure.java.jdbc library, and moved to data-as-maps (structs in
CFML). A thin "bean" wrapper around a struct provided the benefits of
objects and perpetuated the convention-based relationship handling.
The result is great performance (structs and records are essentially
identical so there's really no "mapping" so the generated SQL is about
as simple as it can be), good flexibility and the ability to expose an
object-like API even over complex joined queries (using the Iterating
Business Object pattern which seems to be attributed to Peter Bell).

**The convention is implemented by onMissingMethod() as follows:
* If you ask a Thing for getFooIterator() (or getFooArray()) and
there's no field called fooIterator (or fooArray), then a query is
done on the foo table, looking for bar.thingId = Thing.getId() and the
result is stored in Thing.fooIterator (or Thing.fooArray) as an IBO
(or array of "objects").
* If you ask a Thing for getBar() and there's no field called bar but
a field called barId exists, then a query is done on the bar table,
looking for bar.id = Thing.getBarId() and the result is stored in
Thing.bar as an "object".

If you want to avoid the on-demand object-by-object joins, you can do
a direct SQL query and still wrap it in an IBO of the base object
type. The wrapper handles dirty data by writing to one struct in the
"bean" and reading from the dirty struct or the "clean" struct as
appropriate - that way the whole dirty data struct can be persisted
easily as an update on just the columns that have changed. The wrapper
exposes basic Active Record methods and delegates to the Clojure CRUD
wrapper around clojure.java.jdbc.

The nice thing about this approach has been that the actual storage is
encapsulated in our CRUD wrapper and we are now able to migrate data
from MySQL to MongoDB without changing application code that depends
only on the mapper (obviously code that does raw SQL needs to be
reworked). Because the relationships are already in the "application
layer" (in the IBO / bean wrapper), the convention-based relationship
handling still works even when one object is stored in a table in
MySQL and the related objecta are stored in MongoDB!

> The best way to not have to write SQL for your applications? Use a NoSQL
> database. :-) Totally different topic but I've been using CouchDB a great
> deal lately and that actually *removes* the object-relational impedance
> mismatch as opposed to giving you a complex tool to deal with it for you.
> That to me has felt like a huge weight lifted off my applications, whereas
> ORM never felt that way.

Agreed. And that's part of what's driving our migration from MySQL to
MongoDB. We also like the freedom to store structured data (an
arbitrary struct containing arrays / structs can be stored directly in
MongoDB - which is also true for Clojure maps and vectors) and the
ability to store additional fields for some objects without needing to
worry about schema structure or migrations.

> Or if you do your homework and decide you love Hibernate you can write your
> model in Java. Ultimately that'd probably give you far fewer headaches.

And be much more performant than using CFML and the built-in ORM :)

At World Singles, we're moving to an MVC architecture where the Model
is Clojure and the View-Controller is CFML (and will ultimately be
FW/1 + DI/1 instead of ColdBox + ColdSpring). Although, as a side
project, I'm also porting FW/1 to Clojure and if I can cleanly solve
the View templating aspect, we may ultimately migrate entirely to
Clojure...
-- 
Sean A Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/
World Singles, LLC. -- http://worldsingles.com/
Railo Technologies, Inc. -- http://www.getrailo.com/

"Perfection is the enemy of the good."
-- Gustave Flaubert, French realist novelist (1821-1880)

-- 
official tag/function reference: http://openbd.org/manual/
 mailing list - http://groups.google.com/group/openbd?hl=en

Reply via email to