Moandji.blog

homemade thoughts

{ CODE } 

Java coders distrust their neighbours

Here's a dysfunctional flow I came across today at work and that seems to pop up fairly often.

  1. Query some entities from the database
  2. Extract the IDs and put them in an array
  3. Pass the array to another method
  4. Load each entity from the database, but by ID this time

Ludicrous. If we're lucky, the by-ID lookups will only hit the first-level cache, but those calls shouldn't even be happening at all. What is to blame?

Stupidity? No, my colleagues aren't stupid at all.
Large codebase? This is a fairly big application, but not *that* big.
Laziness? In a sense. There is one case in which the ID array is passed in directly from the client without having been loaded on the server-side first. It could be that the author didn't want to write a second method.
Paranoïa? Probably. Java developers are prone to that.

A lot of Java developers seem to resist thinking in overall flows in favour of treating every method as an island that can be attacked on all sides by anything at any time. So, each method is front-loaded with a bunch of Assert.notNull(someValue), objects are copied "just to be sure no-one else is messing with them". The code just gets cruftier.

It seems to me that much of this is nonsense and could be alleviated:

  • Apply strong validation at the beginning of any flow, then the strict minimum afterwards. The database should have the strongest constraints possible.
  • Enforce the convention that methods neither accept nor return null values.
  • In the single-threaded context of, say, a typical web request, there's no mystery about who is manipulating your objects. Don't worry about it.

These don't always apply, but are pretty good rules of thumb.

{ CODE } 

Object-XML Mapping in Spring 3.0: when indirection gets out of hand

how many layers?

Meet the Object/XML mapping support in Spring is an introduction to the Marshaller and Unmarshaller interfaces that have been rolled into Spring 3.0 from Spring WS.

In summary:

  1. Application code uses the two interfaces and delegates the object-to-XML-and-back (or OXM) work to them.
  2. The application context is configured to use Spring’s wrapper around an OXM framework.
  3. The wrapper is injected into the bean.
  4. The OXM framework also needs to be added to the classpath and configured.

To me, there are two levels of indirection too many here, already. Add another level if the application wraps this up in an XmlService interface and corresponding implementation.

Furthermore, it turns out that the abstraction is leaky! From the Spring WS docs:

Although the marshal method accepts a plain object as its first parameter, most Marshaller implementations cannot handle arbitrary objects. Instead, an object class must be mapped in a mapping file, registered with the marshaller, or have a common base class. Refer to the further sections in this chapter to determine how your O/X technology of choice manages this.

Despite all that indirection, you still need to know which OXM is being used. If you have to know what you’re using, why not work more directly with the OXM and avoid the abstraction theater?

I would go so far as to argue that, not only is the indirection not buying you anything, it’s probably going to end up costing you, by making the application’s wiring more difficult to understand and maintain.

I’ve been working with Guice of late. Its focus on programmatic configuration encourages you to ”touch” 3rd-party APIs directly. This feels lean and natural compared to Spring’s often unnecessary infinite indirection.

Apply DAO design to XML and you’ll find that a few simple methods are enough to decouple you from your OXM in the same way a DAO decouples your from your ORM. For example:

void save(Object entity) // serialises to XML
<T> T get(Class<T> myClass, String xml) /* converts from XML to object of type T
Replace String with File or InputStream as needed */

Even if for some bizarre reason you need two OXM frameworks at the same time, the XML DAO should be injected with both OXM classes and decide which one to use based on the class of the object passed into the save() method.

To be really fancy, apply the Interface Segregation Principle (PDF): have the XML DAO implement two interfaces and let clients choose the one they’re interested in. These might be drawn from the problem domain (UserXmlDao, ArticleXmlDao) or the solution domain (CastorXmlDao, JaxbXmlDao) [1].

In conclusion: indirection has advantages, but it also has a cost. Using it indiscriminately for trivial things leads to accidental complexity and confusion through over-engineering.

[1] See Tim Ottinger’s paper on variable naming for the concept of problem and solution domains.