OO Design Patterns and IBO

OO Design Patterns and IBO

Posted by Brad Wood
Sep 10, 2008 23:29:00 UTC
If you missed it, Jeff Chastain put up a very interesting post over at Alagad's Blog. Also good was the "spirited" discussion that followed between Barney and Peter Bell. I don't know how I feel about all of it, but the entire thing is very fascinating.I've been wrestling with the same concepts recently. It seems a lot of CF OO design patterns don't seem very object oriented. At least not compared to the OO stuff I've seen in Java code. I've seen Java patterns where your DAO is the only thing that ever sees a result set. Your business logic and display all just deal with collections of objects. Of course, Java can instantiate a few trillion objects and not break a sweat. CF8 is allegedly over 20 times faster than CF7 at instantiating CFCs, but apparently still not fast enough to make everything an object. So what do we do? We create gateway objects that simply return a result set. Or IBOs (Iterating Business Objects described in the Alagad post) to handle umpteen theoretical objects with one actual object. I definitely like the IBO approach over the gateway which often times feels like a pseudo-OO skin wrapped around some procedural code that does the same basic thing an inline cfquery tag would have done for you. The IBO allows you to still encapsulate any special login in getters and setters. There are benefits to the gateways too I suppose. We do get the encapsulation bonus of having all the code in one place, and SORT of abstraction from our database. Of course, when you deal with a result set, you are pretty much tied to your database schema anyway. This doesn't bother me that much though. I don't know that I subscribe to a lot of the talk around a DAO separate from your business logic. I'll believe the whole "you can change your database around and not bother your middle tier" thing when I see it. Seriously-- how often do people move from a flat text file to xml to MySQL, and how often does a column get renamed for the fun of it? I modify my data structure regularly-- but it is because the business model changed which means middle tier change is inevitable regardless of a DAO. At least all my queries are in the same place... My other problem with objects is I seemed cursed to be doing basic CRUD 90% of the time. The result is a pile of beans that do nothing. Well, don't forget the obligatory getters and setters, but onmissingmethod can make light work of them. One of the much heralded benefits of your getters and setters is when you have extra logic around the access of data. For instance a getAge() method which calculates age on the fly from the birth date field and today's date. That's a wonderful example, but I seem to only have 1 of those for every 100 fields that my bean just robotically serves up without touching. Have I saved myself any trouble by creating a CFC to encapsulate a query row when it doesn't do anything the query wouldn't? I'll tell you what it does-- it gives you one more layer to go back and update when you add a new column to your database. :) Yeah I'm being heavy-handed, but bear with me. I haven't given up on OO by any means; I'm just venting stuff on my mind. Here's my other problem with objects: AJAX. Despite the bridges that have been built (cfajaxproxy, AjaxCFC, JSON, WDDX). There is still a gaping chasm between my web server and the browser. In the simple old days, I could just create my HTML on the server and send it off to the browser. The browser was dumb and it was ok. Now, we have RIA web 2.0 value-added crap, and suddenly the client needs to know things. It needs to take data and figure out what to do with it. Communication of basic constructs like strings, arrays, and structs are pretty easy with WDDX and JSON serialization, but my CFC instances are still back on the deck of the server waving goodbye as the HTTP boat cruises away. Apparently they are too complex to get on board, and they don't speak the destination's language anyway. In my utopian dream world, I should be able to have a cfgrid and bind it to an array of objects and define the getters to call for each column. Cfgrids only bind to structs or result sets though and it's impossible to get an instance of a CFC to the browser anyway. The data might fit into a struct, but the logic-- well that's unfeasible. I could manually create a JavaScript object that matched my CFC (to the extent possible) by duplicating JS code for the equivalent getters and setters, but there's no direct way to create and populate it and I don't think it would be worth the time to do so not to mention the duplication of code. Further to that point, representing has-a relationships can be tricky too. The data part of it can probably fit nicely inside of an array of structs contained in a struct, but should I hit up the database, create an representation of the data with CFC's containing instances of other CFC's, and then turn it back into array's of structs so it can be serialized for the browser or do I just skip the CFC instances all together and just go straight from database to the serializable structs? The latter seems like the obvious answer, but I don't feel like there's anything truly OO about that, other than the fact that the logic to do so might have been stuffed inside a cffunction. Well, this is the part of the blog where I usually say "I digress", but I'm not sure if I was ever on a track to begin with :) I just had to get some stuff off my chest. Mostly frustrations with trying to decipher what is really OO, how to do it with ColdFusion (and Ajax), and the constant restrictions that make me code things in a way that feels wrong (or at least procedural). Feel free to share any answers to the universe you have. Except 42-- I already know that one.

 


Dave DuPlantis

Brad, I'm in pretty much the same boat you are. I know how I would do it if I were working with Java and Hibernate, but I'm not. I always seem to end up with this extra layer that doesn't add any value now, but will if I have to do this-and-that in the future ... except that when the future doesn't arrive, or takes forever to get here, I feel that I've just made the project take longer than it should have.

On the other hand, I don't want to scatter a bunch of cfquerys here and there and leave them for the next developer to clean up ... I know there is a middle ground, but I just can't seem to find the right one.

Jeff Chastain

First, thanks for the link back and second, everything you are saying is perfectly understandable. With regards to comparing CF to Java, I still don't see why people do this. While ColdFusion is written on top of Java now, its OO capabilities are much more like SmallTalk than Java - that is loosely typed instead of strong typed. This gives you a whole lot of other options on how you can do things, but people still want to try to shoehorn CF into Java's constraints.

With regards to handling AJAX, I will typically trying to make my application and service layer independent to the UI. While you may not change your database platform very often, I have seen UI styles change a lot more. So when your service layer returns a collection of business objects or an IBO, what do you do? With an HTML UI and a controller (MG/M2), you can still handle those objects with basic CF. However, like you said with the AJAX components or JSON, you need a basic recordset. This is where a facade comes in. Basically it is a thin wrapper around your application that says translate anything coming out into a given format. So, an AJAX facade would translate the IBO coming out of the application into a recordset by calling the IBO.asQuery() method. We do this quite frequently on the current project we are working on as there are a lot of <cfgrids involved. Along the same lines, you could write a Flex facade that would take the IBO coming out of the application and covert it into a series of simple VOs that are useful to Flex.

Hopefully that helps a bit. The biggest thing to remember with OO is that there is very rarely only one way to do things. There may be one way that is easier or simpler, but it is the old story of asking 2 people and getting 3 opinions.

Peter Bell

@Brad, I feel your pain. The trick of course is to either generate or synthesize your components.I just have a single XMl file per business object. If I want to add a new property, I do it there. If that is a persisted property, I use that to generate the update to the database table as well as to provide the appropriately updated behaviors in the service, dao and business objects. Saves a lot of typing and still allows me to create real custom objects where required. You might want to have a skim of one of my "RAD OO" presos where I present some of the patterns. Works VERY well for apps that have a lot of CRUD but still need the benefits of an OO approach for the objects that are richer.

Brad Wood

@Dave: Sometimes I wonder where the tipping point is. Surely there are projects too small to warrant the full stack of a 3 or 4 tier model. If you write 500 lines of boiler plate code for your 20 lines of actual application code you might as well use Java. That's one thing I like about ColdFusion is the RADness of it, but these deeper methodologies seem to push me away from that. I don't doubt the helpfulness of them in a large enterprise application, but I'm never too sure how much to use if all I'm throwing up is a personal home page.

@Jeff: I had never really thought about it like "shoehorning CF into Java's constraints". I guess I figured that good design patterns should be portable from one language to another. I mainly compare to Java I guess because that is really the only other OO language I've had the chance to see other people's OO code in. People compare CF to Smalltalk a lot, but I don't really know anything about it.

@Peter: I would very much like to see one of your RAD OO" presos. Where might I find one? Charlie A's list of recordings? I kind of like your XML representation of business logic idea. Do you dynamically create CFCs from that XML, or do you just have CFC's smart enough to behave like the XML defines them?
It kind of makes me think of the JAXB libraries in Java. You create a DTD, feed it in, and a whole pile of objects and an object factory come out. If your model changes, you update the XML and recompile it all.

ike

I can honestly say that I've never succum to a number of the tediums you're describing in this article... when I do my own work... When I work for other people, it's usually insisted that I do things "the hard way". I honestly have no idea why my employers want me to be unproductive, but they inevitably seem to be really committed to a lack of productivity. At my last job for every time there was a column added to the database (and it happened frequently), there were FOURTEEN different things that needed to be modified. And that was considered their "best practice" for common CRUD. The way my own software is written, when a column is added to the database, there is usually ONE place that needs to be modified in the code (the form). One change vs. 14 changes: you be the judge.

The ColdFusion community is very gradually learning that these ways actually are hard and unnecessarily so... that there are easier ways to do things. All the things you described as reasons for not liking the unused getters and setters that exist because one of them might need special handling rather than because it does need special handling is a good example... And no I don't think code generation is a good answer -- it's not DRY. But people are learning... slowly... that there's something to the notion of "beautiful code" the way the Ruby folks describe it.

I actually had a solution for getters and setters similar to onMissingMethod() and no it's not recent, this stretches all the way back to just after CFMX was first released. My very first instincts were to do things that are only beginning to become popular in ColdFusion now.

And ironic that I just finished writing a blog article myself that speaks to just the sort of things you're venting about here... and then coincidentally stumbled upon your blog. :)

Check out this one I posted earlier today on the DataFaucet blog: http://datafaucet.riaforge.org/blog/index.cfm/2008/9/10/DataFaucet-onTap-and-setProperties

Speaking of which, I'm curious, have you had a chance to download the latest version of the onTap framework this week? :)

That's supposed to be a jovial ribbing. Forgive me if I've come across as being egotistical. Not my intent, but I know it happens a fair amount because of my poor people skills. :)

Brad Wood

@ike: I'm sorry but I haven't tried ontap yet though I do intend to. I thought being out of work for a month would give me some more free time, but the opposite seems to be true :) I have two deadlines concerning some contracting projects coming up soon and I start full time employment again Friday. I promise I will get around to it soon! :)

ike

Brad says: "I thought being out of work for a month would give me some more free time, but the opposite seems to be true"

Now there's something I can relate to. :) No worries. As I said, supposed to be a jovial ribbing, 'cause I was pretty sure you'd been busy, as is so often the case. :) I've been out of work myself and seem to be rather distracted with a wide variety of different things going on and that's had me putting off finishing up that scaffolding tool I was working on. Though I managed to post an entry on the DataFaucet blog earlier today where I may have managed to offend Scott Stroz. Not sure. Still waiting for the other shoe to drop. :P

ike

And there I go talking about the blog entry as though I hadn't already mentioned it in my earlier comment... Did I mention I'm distracted? :P

Brad Wood

@Ike: If it makes you feel better, I already read your entry and enjoyed the perspective.
I don't know Scott, but I hope for your sake he is cool. :)

I do agree that different design patterns work for different people and different projects. I would cautiously disparage any particular person not knowing all the decisions that led up to their choices.

Peter Bell

@Brad, Sorry - missed your response and question - Christine P just ping'd me so I thought I better respond :-)

> @Peter: I would very much like to see one of your RAD OO" presos. Where might I find one?

Looks like I don't have a recorded version. The slides from SoTR are available from http://www.pbell.com/index.cfm/2008/6/18/CF-United-RAD-OO-Slides

> I kind of like your XML representation of business logic idea. Do you dynamically create CFCs from that XML, or do you just have CFC's smart enough to behave like the XML defines them?

I allow for real CFC's if you want custom behaviors, but if you don't need them, rather than generating the code, I just instantiate a base class and get it to act appropriately using the XML and oMM(). I tried the code gen route, but I actually quite like the code synthesis approach instead.

ike

Thanks Brad... Yeah, for whatever reason I seemed to be having a really tough time with word selection yesterday... Much like is described in this article:

http://ezinearticles.com/?That-Employees-Attitude-Problem-Might-Be-Aspergers-Syndrome&id=1042344

"Thus an individual with an advanced degree may literally forget to smile or greet co-workers in the morning. He may speak to the CEO in the same informal manner as a peer. Questions may be answered too honestly ("I think that's a stupid idea") and instructions taken very literally (jumping up and down when told to "hop to it")."

Although even when I can tell that something I've written isn't worded right, that doesn't mean I have any clue how to fix it. :P I've asked a couple of folks for suggestions of ways to revise it so that I can compare theirs to mine side by side. I'm hoping that will help me learn something about these all important social skills that keep getting me in trouble.

Site Updates

Entry Comments

Entries Search