By Peter Bell

Storing Instance Data in Beans vs. IBOs

As part of my generic getters and setters I like to put my instance data for all of my beans into a struct so there is no chance that instance data and methods will overwrite each other (which might otherwise be a possibility if both ever had the same names). But when I start to play with IBO's, I have two types of data to store - instance/object data and class data . . .

A single bean has a number of different properties - some of which needs to be gettable and settable. I store such information in a structure within the (private) variables scope of the CFC. But with an IBO, there are two types of data that need to be stored. For the lack of a better term I call them class data and instance data.

Let's say we have an object that we are passing to a generic admin list screen. We might want to write: "#Object.get("Title")# Admin" to display "User Admin" or "Product Admin" or whatever else the name of the object is.

However, we also want to be able to get instance data for the collection of objects within the IBO, which might also have a Title property. So, how do we distinguish between accessing class data (of which there is only one value per property within a given IBO) and instance data (of which there is one value per object contained within the IBO)?

Clearly we need to either have different methods or to complicate the methods by adding an additional class/instance property. Personally I don't relish writing get("FirstName", "instance") all the time, so it seems to be more appropriate to have two different getters and setters.

The vast majority of the time, when getting and setting data from an IBO I'm interested in the object/instance data, so I'd like to leave get("FirstName") (or for the oMM() afficianados getFirstName()) as it is. The question then is what do I change my get("Title") code to to return the title of the class?

At first I tried calling it metaGet() because you could think of it as metadata, but I think on balance the least bad name I have come up with to date is classGet() and classSet() on the basis that we're dealing with class data rather than object/instance data. What do you think? Any better ideas for the naming of this?

Then the question is how/where to store the metadata behind the scenes. For now I'm leaning towards two structs within the variables scope. classData would contain the class data for the IBO and instanceData would be an array of structs containing the instance data for all of the records.

Historically, to allow me to use the same getters and setters between IBOs and regular business objects, I've stored instance data in variables.instanceData[1] for single instance beans - treating the single instance as a special case of an IBO but where the iterator record is always 1. That was efficient from a code perspective, but I don't love the approach conceptually, because thinking of all beans as being special cases of IBOs where number of instances = 1 isn't very accurate.

Instead, I think I'm going to go to just storing instance data for regular beans directly in a variables.instanceData struct. It'll mean I have to overload the getters are setters for my IBO, but I think it's worth the extra little bit of code for the cleaner approach conceptually to the regular beans. (Any input appreciated though!)

Comments
Your question of how to access class vs instance data is really one that is limited to ColdFusion or similar languages. In a heavily typed language such as Java or Flex, this distinction is already made for you by calling ClassName.variable for class data instead of myClass.variable for instance data.

In ColdFusion, though, it would seem you could just add the second parameter to your get() method as you suggested, but have it default to "instance." Thus you can, in most cases, still call myObj.get("Title"), and when you specifically want class data, you can call myObj.get("Title", "class")

Am I being obtuse?
# Posted By Jeremy French | 4/14/08 12:41 PM
@Jeremy, Not obtuse at all. On balance though, because most people in CF don't think of class properties, I think I'm going to add the separate classGet/Set() methods to make a clearer signal that it's something they want to check out and understand.

Nice idea with the optional property though - may play with that elsewhere!
# Posted By Peter Bell | 4/14/08 12:49 PM
It doesn't look as though this has anything to do with class vs instance to me. The IBO doesn't look like a class, it looks like an instance of a collection type which happens to add cursor semantics by proxying for an (implied) instance of the BO class.

The namespace collision problem is generic to proxy/delegate implementations. You can get around this by explicitly nominating the delegate - afficionado.getDelegate().getFirstName() - and dealing with the dirty looks from Demeter, or ameliorate it somewhat by ensuring the proxy is ruthlessly cohesive. Having a collection type hold a page title seems to me to be way out on the lunatic fringe of low cohesion, but I really am a novice when it comes to this whole dynamic/generated code thing, so maybe it makes perfect sense.
# Posted By Jaime Metcher | 4/15/08 1:05 AM
Hi Jaime,

While the IBO is indeed a collection rather than a class, the information I want relates to the class. If I just pass an IBO collection to a generic form or list, I need to know things *about* the object such as the kind of objects that are contained within it. While I agree that conceptually this does seem pretty low cohesion (one object being both an object, an iterator through object instances and providing class/metadata about the kind of objects) from a practical standpoint it just seems to work really well to solve the problem of providing all of the information I need that relates to a collection of objects (including information about the kind of objects they are) with a very concise syntax as I'm not looking it as a collection object containing objects within it, but a "collection object" which is both a specific object instance and the means of navigating between object instances.

It's funny. The more I write about it (especially from the starting point you provided), the worse it sounds in terms of cohesion, but the more I use it in practice, the better it works to solve the pragmatic problems of encapsulating all recordsets within a syntax that allows for custom getters and setters to be added without having the performance penalty of instantiation an array of objects and a separate iterator. And from a practical standpoint, calling an object within the iterator object just isn't concise enough - even just pulling an object from within the iterator (so there would be two objects - the iterator and an instance object that the iterator would update using it's next() method) adds an extra step to every single loop, and I don't know that I'm willing to add that just to put my iterator API into a separate class file.

Definitely something to think about though as you're right that the IBO is taking on some pretty disparate concerns. Let me ask you one question. If you were designing a solution, what would contain the metadata - if I want to know what *type* of object (User or Product or Article) and perhaps even information about the gettable properties or the titles of its various properties, what kind of object would provide you with information about that?
# Posted By Peter Bell | 4/15/08 7:09 AM
Hey Peter,

First, a disclaimer: Our use cases couldn't be more different. My core app is a large single-instance hosted system - highly modular and highly configurable, but a single system nonetheless. So getting a really precise static object model is well worth the effort, as is strictly layering the architecture. Furthermore, my UI components are all hand coded - whereas you need to define the relationship between the data model and UI in metadata (e.g. property titles), I just hard code that information into the specific UI component that needs it. I may define common UI components for DRY-ness, but it's still firmly in the UI layer.

Having said that, the issue you're talking about in this post is totally generic to any design where one is crunching disparate APIs into one object - e.g. the proxy/delegate pattern - and the generic solution is to un-crunch into separate objects, then traverse the object graph to get to the APIs you need. Given that one of your themes seems to be streamlining your system by crunching the data model and UI layer as close together as possible, the solutions are all going to add overhead.

So, where would I put the metadata? I would probably split out the IBO into:
1. The IBO proper, which implements the BO interface plus (package scoped) cursor semantics.
2. An IBO collection object, which contains the IBO and implements collection semantics
3. A UI metadata object, which contains the IBO collection and provides names, prompts, titles, validation message mappings etc.

Then I would obtain type names and gettable properties from reflection on the IBO (i.e. on the BO interface), and the rest via method calls on the UI metadata object.
# Posted By Jaime Metcher | 4/15/08 6:16 PM
@Jaime, Yeah, sounds about right. I'll probably do a blog posting as I agree the IBO violates Single Responsibility Principle and the idea of a cohesive set of functionality. On the flip side, given the particular use case I'm not convinced that maintainability suffers. Main reason for SRP and cohesive classes is to reduce the number of different ways a class might have to change based on orthogonal concerns and because the iterator semantics and metadata interface are unlikely to change I'm actually not having any practical maintenance problems with the code the way it is.

Definitely something interesting to ponder though, as I agree conceptually it's a bit of a monstrosity! It just works so darn well . . .
# Posted By Peter Bell | 4/15/08 6:26 PM
Hey Peter, how you doin' these days?

I am working on something extremely similar right now - something you would find quite interesting, actually. We should chat, do you have Gtalk or Skype?

Given your question, I have a question for you: how is it that the BO's properties are first order methods in the IBO? Do you generate a separate IBO for every business object, like UserIBO, RegionIBO, etc. Or is it simply an onMM thing?

I think Jaimie's suggestion, put simply, is it to have a MetData.cfc object composed into your IBO. Sounds about right to me.

I don't think there are any cohesion problems with what you are doing. Without seeing the code, it seems like you are building a well structured iterator. That's what iterators do, iterate over other stuff.

Cheers,
Baz
# Posted By Baz | 4/15/08 7:18 PM
Hey Baz,

I take a specific philosophical position that a business object IS AN IBO where an IBO (and for that matter a BO) isn't a traditional business object but is this concept of an Iterating (collection) business object where a single BO is just a special case of a collection of BO's where the number of instances = 1. It's a way of justifying why a BO extends rather than composes the iterator and why an IBO has both instance methods and iterator methods (and metadata methods). It's incredibly convenient and while it bends a couple of rules, I don't actually see any harm in the bending of them for a cleaner, simpler interface, but I'll definitely do some more soul searching.

As for whether I have a separate IBO for each business object, the answer is kinda sorta. In theory there is an IBO for each business object in the model. In practice, if there is no custom code required I just instantiate the BaseIBO using a kind of reverse Liskoff Substitution Principle to have the base class stand in for what would have been the subclass. I do the same for my service classes and DAOs and while it sounds a little hoaky it actually works really well for my use case where the vast majority of application functionality is described in XML config files and only the stuff I haven't yet been able to fit into DSLs ends up as code in a cfc. It's a different way of doing things but for my use case it really rocks.

Also, instead of oMM() (although I've just added that as an option for code running on CF8), I use generic get(), set() and call() methods, so I don't have to gen all of the getters, setters or methods described using XML. Again, for highly generic screens that works out better as you can't use the Product.get#PropertyName#() syntax without using cfinvoke (which doesn't work in a cfrscript block) so syntactically I actually prefer the Product.get(PropertyName) as it allows me to loop through property name lists and the like more easily.
# Posted By Peter Bell | 4/15/08 9:43 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.005.