Viewing By Entry / Main
March 3, 2009
There, I said it!

I said it in a post to the cfcdev mailing list and Henry Ho felt it deserved a mention on his blog.

The topic came up because John Whish, manager of the Devon CFUG over in England (where I spoke last September on design patterns), is running a series of presentations on OO and patterns for the group. He wondered how to approach the fact that CFers tend to have separate DAOs and Gateways whereas that distinction does not exist in non-CF languages or pattern literature.

I feel responsible for that distinction so I replied with my thoughts and an explanation of why I had suggested it nearly six years ago but why I don't think it's good advice these days (and, frankly, hasn't been good advice for years - I no longer had access to the guidelines document that enshrined the advice!).

I recommend you read the thread on the Google Group (cfcdev). Henry quotes part of my reply and links to the thread for more detail.

Comments

By god I was waiting for someone with some reputation to come out and say this. I have always been befuddled with the whole "5:1 syndrome" as you tagged it. When I first started tackling MachII (and I read that dev guide in question) I felt like it was sooo overkill to have so many objects all really dealing with the same concepts (e.g. talking to the Users table).

I now work with ActiveRecord (via Rails) on a daily basis and absolutely love its simplicity. Diving into ColdBox and Transfer and back to the DAO/Bean/Gateway/Service approach just makes me want to run for the hills.

I think all this 5:1 stuff steepens the learning curve for CFers that are trying to get their feet wet using frameworks.


@Cody, I've been railing against the 5:1 syndrome for years... That was never my intent but I sort of overestimated people's ability to think beyond the letter of the guidelines :)

It's why I removed some example code (while I was still with Macromedia and had access to the source of the document). I found people just copying the example code without understanding it and then running into problems (and blaming the example instead of their lack of understanding).

At a conference several years ago, I suggested to one CFer that it would take him a few years to get good at OO - and he was incensed, accusing me of calling him stupid. I started doing OO 17 years ago and I'm still learning and still honing my OO design skills. It's a long road but a lot of people seem to think there's a shortcut, a set of rules they can learn and just churn out code without having to think.

It can get a bit frustrating at times :)


Thanks for you thought Sean, I'll be interested in any comments people have.

The DAO/Gateway approach is simple to understand and as such I have found that once people get something working, they just stick with it without looking at other patterns/languages or the drawback of this approach, thinking that is _the_ way to write the data layer.


I always found it serious overkill and tended to delete the gateways when using the wizard to generate code.

It's nice to hear that others also think the same. When I first saw it been promoted by Macromedia I thought that perhaps I didn't have the depth of knowledge to understand the why of why they were doing it that way.

In the end I saw it as more work than it was worth and simply ignored it.

@Sean,

I took Hal Helms OO test and failed miserably. I've been "trying" to understand OO for over 10 years, but to be perfectly honest I start getting lost pretty early on into the detailed stuff, especially when folks start quoting the big brains who invented all of it. I wish I had the time to really read "design patterns explained" and one day I will, hopefully that will help.


I came to CF from a smalltalk background, DAOs and Gateways never felt right to me and fortunately I've mostly been in a position to avoid using them. Once I find something that works for me I tend to stick with it and I find FuseBox 5.5 and Transfer gives you MVC and easy db interaction and helps stop things getting so complicated you think your brain will explode.


I think the key to this issue lies in ColdFusion's incredibly expensive object creation penalty. As you know, when you create arrays of objects it very quickly begins to cause a performance issue. I will check out the thread but I have always maintained that separation in part because I liked that my DAO dealt in objects while the Gateway in queries (since I think returning queries is still kind of a hack). I am truly hoping that CF9 will begin to resolve this issue which is the source of endless frustration to me (especially when trying to pass items back to Flex and take advantage of the auto type translation).

Fwiw though, I never do 5:1 and I wonder if that isn't oversimplifying the issue (I can't even recall what the 5 would be honestly). The people doing straight 5:1 probably wouldn't be writing better OO without a Gateway. Despite the fact that I authored the code generator that often seems to perpetuate the problem a bit, much more thought goes into the objects and services I create than the 1 table:1 object (and n CFCs).


I never liked that approach and am glad, as @cody noted, it is being discussed.

I built a code generator that spits out CRUD for every table in my database. It is dynamic enough to allow custom queries or simple selects. Lately I've gone to using a controller to access them but that's as far as I'll go.


5:1 = bean + dao + gateway + manager + controller for every table in the DB behind the app. Seen that over and over - very unpleasant.

FWIW, I keep my single object methods and my aggregate query methods segregated by name: getObjByCriteria(criteria) for single objects, findObjsByCriteria(criteria) for aggregate queries. Both in my ConceptDataGateway (since one gateway object usually manages persistence of a group of related entities).


I agree with Brian that separating the components based on return type (object vs query) can be a handy reminder. Hopefully with CF9+Hibernate we'll be able to combine the 2 into a single DAO and only work with objects, but I have my doubts...

As for the 5:1 problem, it's not as bad as long as your components are built around a set of related entities and not just 5 components for every table.


@Tony, well, that "handy reminder" was what I had in mind when I wrote the guidelines in 2003 but it was only intended to get people started - it wasn't meant to be followed slavishly. I had hoped that once people got a bit of OO under their belt in CF, that's start to question the guidelines (and I expected to be in a position to be able to keep updating the guidelines!).


"since I think returning queries is still kind of a hack"

Could one explain why this is frowned upon in CFML?


@Salomoko, Brian thinks you should be able to return arrays of objects, like you would with Hibernate in Java.

CF's object creation is not (currently) fast enough to make that practical - 2,000 records in a query is fine, 2,000 objects in an array is "too slow".

I take the position that query in CFML is already an abstraction and the language has a number of constructs that operate natively on queries. There are aggregate operations that are *harder* on arrays of objects than on native queries. Consider the built-in tags that take a query as an attribute - you cannot pass arrays of objects to those.

So, whilst I'd *like* to see array of object be fast enough to use it for large recordsets, I think a lot else has to change in the language to make that worthwhile.


@Sean @Salomoko - yes, I want to return arrays of objects in part because all of my CF work recently has interfaced with Flex and returning queries doesn't take advantage of the Object to VO type translation. So what happens is I end up converting the queries to typed structures but they aren't deep (as in I leave most of the composed elements out) whereby I still need to retrieve the full object whenever it is accessed. This all seems like a bit of a hack to me to get around a performance issue.


"I take the position that query in CFML is already an abstraction and the language has a number of constructs that operate natively on queries."

@Sean, I *definitely* agree, I do not see a problem with returning a query object in itself. I think that's a perk of the language most languages don't have to offer... I also believe languages that don't natively support query beans (if you will) have to make up the lack of support with arrays...

I say leverage CFML for what it is, rather than trying to mimic other languages DSLs...

idunno :-\


@Brian, yeah, the Flex integration thing is a bit of a pain - I hope Adobe address that. We (at Broadchoice) went with Groovy / BlazeDS / Spring / Hibernate for the back end to our AIR app and we get great performance. Then we built a CFML front end reusing the exact same Groovy-based model (services / entities etc).


i never understood why people in the cf community adopted the 5:1 pattern. maybe the got all object crazy once cf could support objects, maybe they "thought" they were java programmers (their not), maybe they were just being too smart for their own good or maybe they were just being retarded.

rails activerecord is the simpliest, most elegant and easy way to interact with a database. everything is contained in one class for you and it make switching between database platforms pretty painless.

i've been saying for years that adobe, and now the cf advisory counsel, needs to come up with a solution for the object creation penalty. i know it's not the function or purpose of the advisory counsel, but their influence and backing would be extremely beneficial.


@Tony, re: CFML Advisory Committee. We can help drive the language specification but not the vendor implementations (in terms of performance). Market forces will dictate that sort of thing. Adobe are very aware of comparisons between Java / ColdFusion / Railo / OpenBD in terms of object creation speed tho'...


You know the funny thing is I used to feel like less of a CF developer around folks using 5:1. I outgrew that but it still seemed like you couldn't join the "secret society" until you were a 5:1'er. ;-)


I never quite understood why a query that returned a large number of rows should go in a different object than a query that returned a single row, thus all of my hand-coded DAOs have the bulk query functions built into them, and I never hand-code a DAO.

However, what I do use occasionally is a "Report" or "Search" object, which I can inject ordering and filtering information into, and call a function on it to return results. This is usually separate from my DAO, since it often does Joins, subqueries and unions with other tables/information sources. I haven't really seen any documentation for this pattern, but I've found it to be very useful for generating reports and helping build user interfaces for data-mining. I never quite understood the reasoning for the Gateway object, but I suspect it was similar to my Report object.


@sean, you said "I sort of overestimated people's ability to think beyond the letter of the guidelines".

I have written a few blog posts about what I'm about to say, but this is one of the reasons I have been known to rail against the OO community in general. Yes OO is a valuable tool. No, I don't believe that most people think outside of the box. When someone with a reputation like you, Sean, says something about OO, most of the rest of the OO "sheep" (in our little community) follow what you said.

Let me pose some deep questions: are the base OO principles that we follow today the end of the story? Will we continue to find better ways to do OO as time goes on? Will we eventually develop/find some other fundamental programming paradigm that makes OO look like pencil and paper?

I don't know the answer to any of these questions, but I think it's wise for the geniuses among us to continue to push the envelope, so to speak.


"are the base OO principles that we follow today the end of the story?"

Knowledge and best practices are always evolving so that's a a bit of a silly question.

"Will we continue to find better ways to do OO as time goes on?"

Of course! I've said early and often that I started doing OO in 1992 - yes, 17 years ago! - and I'm still learning, still improving and still adapting to changes in thinking about "what's best".

"Will we eventually develop/find some other fundamental programming paradigm that makes OO look like pencil and paper?"

I don't know. In some ways OO is a radical departure from previous thinking but in many ways it's just plain common sense - procedural programming was so far removed from "how the world works" that it's amazing we ever got any systems built!

You also need to remember that COBOL was standardized as an OO language before C++ was standardized (much to the chagrin of some of us on the C++ Standards Committee). Some OO languages date back over 40 years now (but have never been standardized). Functional programming was much vaunted in the 80's as the "next wave" but it never became mainstream (although it still has a very solid following these days, e.g., Haskell). Declarative programming was another style that was very popular in the 90's but, again, never became mainstream (e.g., Prolog).

The worst thing any programmer can do is assume technology is static and that they will eventually master it. Languages evolve. Technology evolves. Thinking evolves.


@tony

ColdSpring certainly does not help the issue. A quick review of the reference PDF that comes with CS and you are already headed down the path of 5:1. Those CF developers looking to expand their OO knowledge and do so by embracing such a framework are inevitably going to spend more time focused on adhering to the implementation "guidelines" set forth in the docs, and less time considering the ramifications.

We lept on Coldspring for that reason, and the fact that we were tightly integrating with a Java-service layer which (surprise!) uses Hibernate. Suddenly, any argument against arrays-of-objects falls to the wayside.

Personally, I'm encouraged by this announcement, and plan to dig deeper.


@Shawn, just to be clear: the ColdSpring *docs* are what you're complaining about here, right?

ColdSpring itself has no bearing on the 5:1 problem (and, in fact, you'll have less work to do with ColdSpring if you have fewer services and data gateways).

Again, the problem here is people slavishly follow "simple examples" and applying them to their own code without understand the principles.

People really need to read more OO literature *outside* the CF world...


@Sean,

I totally agree with all that you said (in response to my comment). Obviously, some of my questions I posed were rhetorical...however, I honestly believe that some of the "sheep" I mentioned earlier don't ever think about questions like this. You do, obviously. And I do, and many others do.

But the sad thing (to me) is that most of the OO crowd (in my opinion) just reads books and follows whatever trend is hot at the moment. But this isn't unique to OO. The same thing happens in all walks of life, from the clothes we buy to the politics we believe in.


@ Sean

Correct, *just* the documentation. What's funny is that on one page, there is a diagram that contains an explosion of DAOs and Gateways.

Of course, CS itself isn't locked down to that model, and a new ref. guide certainly might do it wonders for the new-to-CS developer.

You can add my vote to the "read more OO literature" motion.


About the object creation penalty - I would think that use of frameworks which persist DAOs and services would mitigate some of that. Are there other strategies to minimize the hit? Other than using fewer CFCs?


@Jeff, yes, DAO/Gateway CFCs should be singletons and therefore cached. That has nothing to do with the issue tho'...

Returning an array of CFCs (instead of a recordset query) is the expensive part.


BTW, it's probably worth mentioning that Railo is about 3-4 times faster than CF8 at creating objects but even so, I'm not sure I'd want to create an array of 2,000 objects, even on Railo...


Post Your Comments
Name:
Email Address:
Comments
*** Please note that all comments require moderation so it may be some time before your comment posts to this blog! ***
Remember My Information:
 



Hosting provided by