CFArgument: The Iterating Business Object
This is the first entry in a planned series of discussion between myself and Peter Bell where we will discuss hot topics in the ColdFusion community (thus the label CFArgument). Today's topic is Peter's own iterating business object, which has been the source of some discussion lately.
Peter Bell:
An
Iterating Business Object is a ColdFusion specific design pattern
allowing you to write OO code without worrying about the performance
overhead of creating arrays of objects in ColdFusion. In ColdFusion, if
you're not using an IBO, you're not really writing OO code.
Brian Rinaldi:
An
IBO is a workaround to a ColdFusion specific performance issue, and
that is the high cost of object instantiation. That issue has improved
in ColdFusion 8, but when dealing in large sets of objects the cost can
still be a killer. That doesn't mean that the IBO isn't a reasonable
workaround, but without this issue the IBO has no intrinsic value. For
example, if they fix performance on object creation in ColdFusion 9,
the IBO ceases to be useful.
Peter Bell:
I agree that
if object instantiation was faster, the IBO wouldn't be necessary. I
certainly wouldn't propose using an IBO in Java or Groovy, but what I
think is pernicious is the frequent use of Gateway objects that return
recordsets rather than objects. Many CF developers will return a single
record as an object and a collection of records as a recordset. To me
that makes no sense. If you have a User object and you want to have a
getAge() that calculates the age from the date of birth, that method is
equally necessary (and should therefore be equally available) whether
you're looking at one user or a hundred. Same for products with a
getDiscountedPrice() or other potentially complex calculations.
I
would argue that the lack of consistent use of IBOs means that many
developers end up with pseudo-OO code which has all of the costs of OO
programming (more files, more typing) but few of the benefits
(encapsulating data and associated methods into objects) because they
can't encapsulate custom getter logic in their beans since they are
using recordsets for displaying collections of objects instead of an
IBO. They are doing this because of the fear of the cost of the object
instantiation. That to me is the problem with not using an IBO.
Brian Rinaldi:
We
agree that using straight query results isn't optimal in all cases. I
also agree that the IBO is a reasonable response, even though it does
force you to repeat yourself a bit, putting logic in both the bean and
the IBO. It would seem to me there are potential solutions to this that
don't require code repetition. Also, one can argue that in many cases,
simple recordset data meets the requirements. Nonetheless, neither case
is optimal for remoting with Flex.
Peter Bell:
The
thing I love about the IBO is that you don't need to repeat yourself at
all. The way I use the pattern a business object is simply a collection
of n-beans where n=1. At first I thought this was a little hacky (let's
be frank - the IBO *is* a little hacky - violating the single
responsibility principle if nothing else, by duct taping an iterator
onto your business objects), but having used it in a bunch of projects,
I find that it works really well.
With an IBO, I can load up one
record and treat it as a business object or n-records and use it as an
iterator. Perhaps the most useful way of thinking of an IBO is as a
base class that your business objects can extend to allow your custom
getter, setter and validation logic to be written as if you were
writing a regular business object in Java. However, instead of creating
an array of such objects plus a separate iterator, with the few base
methods in an IBO, you simply load up an array, recordset, struct or
collection of value lists into the IBO and then get all of the benefits
of an array of business objects with an iterator - with almost none of
the instantiation cost.
The only cost is the slightly bitter
taste at having to stick iterator logic in a base business object which
I agree is hacky. But it just works so darned well!
There were two other points you made as well that I'd like to respond to briefly.
If
you genuinely have recordsets with no custom getter logic, I agree that
an IBO might be overkill. My problem is that my simple business objects
often get more complex over time so I have found for my use case using
IBOs consistently gives me the room to expand and no real extra
complexity upfront. I'd much rather use IBO's for everything or nothing
than have to try to decide on a business object by business object
basis which one was likely to become complex over time.
As for
Flex, the trick would be to have a simple routine that would loop
through all of the getters of an IBO for each instance, creating a
collection of named structs. That gives the strongly typed VO's in Flex
without the cost of creating an array of objects. I haven't had a need
to write this yet, but it'd be pretty simple to add an asFlexVOs()
method to the IBO - whether it was done in the IBO or handled by a
composed object.
Brian Rinaldi:
Well, I think we can
both agree that the best solution to this issue would be for Adobe to
remove the high cost of object instantiation. I think things like the
IBO, while useful to solve a problem, continue to solidify the idea
that ColdFusion isn't designed for real OO development.
Peter Bell:
I
agree. And there are some problems that an IBO doesn't solve. For
example, very few ColdFusion applications have a truly rich object
model with things like an Address value object for handling Billing and
Shipping addresses composed within an Order object because the cost of
object instantiation makes it impractical. It is interesting to see
that some CF developers are moving to Groovy for their model and others
are looking at other implementations such as Railo where object
instantiation appears to be much faster. Hopefully amongst all of the
great new features in CF 9 there will be some engineering time left
over to address the issue and make ColdFusion a compelling language for
creating dynamically typed OO applications on the JVM.
