Wednesday, August 4, 2010

Kool-Aid - now available in ORM flavor!

A few years ago I had the opportunity to play a part in the great ColdFusion OOP debate.  Apparently it still rages on in the form of OO Architecture, and most recently ColdFusion ORM.  So today, while learning CF ORM, I came upon the issue of a lookup table.  You know the sort, one that contains n values that populate a dropdown control.  To create a simple example, lets use a Developer class with a many-to-one relationship of beer preference.  The ERD would look like this:


So the question is, if I wanted to populate a dropdown control, what do we do?  I knew what made sense in my mind but I want to make an attempt embrace CF ORM, so again today I decided to use a lifeline and reach out.  The answer I received was CF ORM 'logic' (air quotes added by the writer ;) ) would say we create a Beer class and use entityLoad('Beer') to create an array of all possible instances of beer, then loop over that array of objects and call getID() and getName() on each instance to populate the dropdown.  Before you say, "But we can lazy load them", sure we can.  But we need each and every class to get all of the beer varieties.  Knowing the CF community's affinity towards a multitude of fine microbrews this list could get pretty long.  I guess a factory reusing object instances could help here but its a dropdown, and this becomes architecture for the sake of architecture (but see how your mind started to wander there - heh).

My logic dictated that I should create a gateway and write a line of SQL, instantiate the gateway as a singleton and we can even cache the query. This means we create one object, do one database read, and sit there and listen for requests.  To that end I created a SelectorGateway class, created a method to select all beer varieties from the selector table, ordered them by name and returned them to the caller as a query.  The singleton was instantiated with the datasource passed in from this.ormsettings.datasource for maintainability.

What I am attempting to illustrate via this simple example is the continued 'architecture for the sake of architecture' mindset that exists within our community.  Keep in mind to always use the best tool for the job, and if something just doesn't make sense to you, it probably doesn't make sense period!  Also, following an agile development philosophy make smart architectural decisions, but don't plan for 10 steps down the road when 99% of the time those steps will never be necessary, but your client still has to pay for them.

All this being said, there may be a better way to perform the above.  I'd love to hear other suggestions!

5 comments:

  1. Maybe I'm crazy, but aren't you -way- overthinking this? If I were building a form to allow me to edit the user and needed all the beer, it would simple be:

    allBeers = entityLoad("beer", {}, "name asc")

    That's it. That's not 'architecture', it's just a simple entity load.

    ReplyDelete
  2. Or, if you really only wanted a query, you could still use ORM:

    ormExecuteQuery("select id, name from beers order by name")

    ReplyDelete
  3. @Ray, wouldn't that still create 60 objects for the purpose of getting the 60 beer variety names? I could just be missing something!

    @Scott - Doh!

    ReplyDelete
  4. If all you want is a query you can just use the following

    var allBeers = entityLoad("beer", {}, "name asc")
    return entityToQuery( allBeers );

    ReplyDelete
  5. I've yet to dabble with the ORM solutions myself, so if I were to go about this I would choose the gateway solution. Lately, I've made it a habit to create proxy CFCs to wrap around the gateway CFCs so I can keep all AJAX-related functions in one place. The proxy CFC is where I actually access the singleton that's cached within the Application scope, and it's worked great for me so far. Should I ever decide to implement ORM, however, I'd go with Dan's approach.

    ReplyDelete