Saturday, September 22, 2007

Below is a review of Daniel Spielwak's ActiveObject for Java, as presented in an article on JavaLobby. Refer to the link to reference the original article.

Dynamic proxy vs byte code enhancement

ActiveObjects is interesting but could be improved by being implemented using byte code enhancement tools instead of Java dynamic proxies. Ruby, et al, are fine with taking the hit of dynamic binding overhead (people expect such overhead with scripting approach, as it's a conscious trade-off with respect to benefit of rapid development). Java is a compiled language, though, where performance is emphasized (and prized) for the purpose of building industrial strength solutions for enterprise class applications.

The author's phobia regarding byte code enhancement only serves to undercut his credibility. Byte code enhancement is well proven as many systems have been in wide use for several years now. In years of working with such tools, libraries, frameworks, languages (AspectJ), etc, byte code enhancement has never once been the cause of any issue or point of grief. Others have like experience or else the forums would be full of complaints.

Convention over Configuration

Convention over configuration is a utopian concept given that in practice enterprise development has to give sway to schema that is legacy and/or dictated by DBAs (and for good reason as relational database schemas need to be designed to perform well - not accommodate idealized object-oriented design).

In the end, for ActiveObjects to be realistically useful, there will need to be a way to use things like annotations in order to map the object perspective to the underlying database perspective. Or else the ActiveObjects entity interfaces could always be strictly generated by a tool that takes the database schema as its input (but event then there will be things that need to be customized via mapping overrides, etc.).

Creating Java interfaces for entities as the starting point only works out for sample apps, the simple Ruby-esque contacts CRUD app, or the occasional (but highly infrequent) green-field situation. Yet even there, a serious app of some complexity can get in trouble if database scheme is directly based on idealized object-oriented design. There are a lot of special things one does in the database to make operations perform well that would never have come from generating off of the object-oriented design of entities. Plus a pure, idealized object-oriented design could lead to pathological constructs in the database - from a relational database perspective.

When in Rome, do as the Romans. When living in the RDMS, do as the RDMS does things and life will be more pleasant.

Lazy-Loading

Lazy-loading seems like a fine idea from a naive (inexperienced) Java programmer's perspective, but in practice one has to work to minimize discrete trips to the database - or else will get thrashed on performance. Trying to always default to a simple heuristic, such as lazy-loading, is another concept that falls down in practice.

Business Logic in Entity Interfaces

Placing business logic methods into entities is pretty much a bad idea.

Often times it is desirable to convey entities over the wire (90% to 98% of the time) - that is, between the middle-tier and client-tier of 3-tier or n-tier distributed applications.

One of the very worst sins that one can commit is to pollute a distributed application with the anti-pattern of "distributed object interfaces". Attempting object-oriented programming that transparently spans across the network is discomfiting as the network is neither reliable nor deterministic.

Sticking with DTO approach to entities and then create services that operate on or with DTOs avoids such morass. By tossing objects with behaviour and going strictly data-only, there are then some great enterprise messaging patterns that become possible. Those patterns will more than make up for the abandonment of OOP over the network.

The problem with OOP and network is that OOP as we understand it today is build on synchronous assumptions of behaviour interactions. Synchronous operations and the network mix like oil and water - bad combination. The second (or is it the first?) big problem with OOP over the network is tight coupling. Tight coupling is bad news for distributed application. Either one of these issues by itself is sufficient to doom this concept.

Summary

ActiveObjects needs to have the perspective of another five to seven years experience developing real-world enterprise applications.

The shear rapid ability to write working code, ala Ruby and RoR, focuses on a very narrow part of the overall problem spectrum. When you concentrate so much on this part of the equation and neglect/ignore the others, then the end result is something of limited applicability.

The serious-minded tools/solutions that exist out there have endeavoured to address the wider range of issues that professional developers (at least those in the enterprise arena) confront.

3 Comments:

From the top: byte-code enhancement. I haven't made a firm decision about whether or not activeobjects will use this approach in future. I'll probably experiment a bit with it for the 2.0 release, but for now, dynamic proxies work fine. Also, if you benchmark it, dynamic proxies on Java 6 produce comparatively little overhead. They're no longer the efficiency killers they used to be.

I'm not sure there are any schemas that ActiveObjects couldn't work with. TableNameConverter(s) and FieldNameConverter(s) allow custom conventions to be imposed, and manual mappings have always been possible through the use of annotations (since like, 0.1). Also, in the latest trunk/ version, it's even possible to use a custom primary key field (since not everyone uses the "id" convention). So in short, AO isn't really limited in this respect. What it *does* do is make assumptions about what the default conventions should be, meaning that you don't have to specify configurations that it can guess.

I agree on the lazy-loading thing. That's why AO offers preloading and manual field-load overrides to enable the eager loading of specified (or even all) fields. This strategy keeps memory down, allows for high-performance SELECTs, and minimizes round-trips to the database. I'll freely admit that AO probably performs more trivial queries than Hibernate, but amortized over your application's lifecycle, I think the difference is probably minimal.

> Placing business logic methods into entities is pretty much a bad idea.

I disagree, and so do a lot of developers now-a-days. The age of the pure POJO is gone. Both dominant database access patterns (Active Record and Mapper) allow (and even encourage) the placement of model-specific logic within the mapped entities themselves. This is a much more object oriented approach, and it doesn't actually cause any problems in practice (unless you really go crazy). As for your point about sending objects over the wire - who does this with their entities?? IMHO this isn't really a valid complaint. In any case, it would apply to any other ORM as much as it applies to AO.

Applying business logic in DTOs is missing the whole point of the pattern and Object-Orientation itself.

DTOs are objects specialized to be sent through a network (or other medium that makes procedure calls expensive). You should have a business object (what you call 'entity') that has (like an object has to, in the first place) business rules AND data over a business concept. Than you assemble a DTO from this object and the others you'll probably will need only when you need to send those through the network.

Look at Fowler's picture for an example:

http://martinfowler.com/eaaCatalog/dataTransferObject.html

And a nice quote from that page:

"The solution is to create a Data Transfer Object that can hold all the data for the call. It needs to be serializable to go across the connection. Usually an assembler is used on the server side to transfer data between the DTO and any domain objects."

Well, a lot of the software I build (or now am dev mgr over) is distributed, and transferring DTOs about is a constant theme.

In some cases I have very streamlined processes where the producer publishes a DTO, and the MDB that processes it unmarshals it into an object graph that directly comprise the entities that are persisted.

However, these days, in the interest of striving for improved loose coupling, this is the approach used:

About

Make a living shoveling bits doing .NET client-side development and Java J2EE server-side development. Self- appointed JMS evangelist - well somebody needs to do it.
http://www.vossnet.org/jms-links.html