By Peter Bell

Retrieving Beans with Rich Getters in Flex

Let's say you have a business object which has rich getters (where the properties of the bean do not correspond directly to the columns in the database table). What is the best way of architecting your model to return the calculated values for both your Flex and HTML applications? Here are some thoughts . . . (Thanks to Jeff Tapper for his excellent intro to Flex which got me thinking about this topic)

Let's take a simple case. You have a User with FirstName, LastName and DateofBirth columns in tbl_User but want to display User.FullName and User.Age which are calculated based on the columns. What are the best approaches to take? (Please note, as with most examples, this is kind of trivial. Imagine that we're really talking about very rich getters where you have products with complex calculations to determine price for a given user at a given time of day - the general case problem isn't just comprised of single line concatenations and calculations.)

Let Flex take the Load
One solution would just be to pass a user cfc or a struct with FirstName, LastName and DateofBirth and let Flex do the heavy lifting. For some use cases this is fine, but you don't usually want to put model logic into your Flex view as you'd have to replicate the functionality if you wanted to add another front end (HTML, web service, etc.).

Let the Database do the Work
ATt the other extreme you could let database views do the heavy lifting. This is actually a good solution for a certain class of problems - especially if you'd like to use multiple scripting languages and effectively make the database the model, but there are also downsides. Changing databases will be painful if all of your business logic is in the DB, but more importantly there are some classes of calculations that a database can't perform. What happens if the price for a product depends on a web service call to get additional third party information? I personally feel that for anything more than simple applications, letting the database become the model is painting yourself into an architectural corner and if you ever need to add one feature to a "getter" that your database doesn't support you're going to have a huge pile of refactoring to do. Also, the IDE tools for writing SQL views aren't as rich as those for scripting or other programming languages and the language constructs are more limited.

Put it on the Gateway
Another approach would be to ask the (table data) Gateway to return the appropriate properties. Looking at the summary of the pattern, that might seem OK, but if you actually read Fowlers book, you'll find that the intent of the Gateway pattern is really just to return a recordset. It is ideal for simple use cases where there is a 1:1 mapping between the db columns and your business object's public properties but the intent of the gateway was never to perform transformations on recordsets. Of course, you *could* do this, but gateways aren't really set up for doing a good job of this so I don't think it is the optimal approach.

Stick it in the Service
For all of your business object method calls the business object service classes act as an interface - an API - to your business object functionality, so they are definitely a candidate for including the transformation required to turn your dumb recordsets into smartly calculated collections of value objects or arrays of structs.

There is no question that they are going to be involved in the process as whenever someone wants to "get" a list of users, it's the UserService (or if you prefer you might call it UserManager) that's going to return it (unless you're using a single class with class and instance methods as a lot of Ruby and Smalltalk developers do which is another pattern but I prefer the separation of concerns of class vs. instance methods in a Service and Bean respectively). The question though is how you want to handle the transformations. For me, the no brainer solution is to have a getFullName() and getAge() method in the User bean (in the general case a get%PropertyName%() method for each richly calculated property in the %BusnessObjectName% bean). That is the default OO approach and follows the principle of least surprise for experienced developers. It is also the default pattern for a reason - it works really well.

So, we can put the calculations into the business object, but how do we orchestrate that to get back a struct or value object containing the all of the properties required? Well, the general rule is that if you're asking an object for more than a couple of things, you should be telling it to do something instead. Rather than having a service method that asks business object for each of the properties in its gettable property name list (in this example "FullName,Age"), you want to have some kind of asVO() or asStruct() method on the bean that returns either the explicitly requested property name list or the default gettable property name list for the bean as a Value Object or Struct respectively. What would this look like? Imagine a service method on the UserService called getTransformedUserByID(UserID:numeric) which provides you with a struct or value object (I'll use a struct for now and explain why in a moment) for the user requested. What would it look like?

<cffunction name="getTransformedUserByID" output="false" hint="I take a user ID and return a struct contaning the appropriate property name values for it - whether simple or calculated.">
   <cfargument name="UserID" type="numeric" required="true">
   <cfargument name="PropertyNameList" type="string" required="false" default="">
   <cfscript>
      var Recordset = "";
      If (Len(PropertyNameList) LT 1)
      {PropertyNameList = variables.PropertyNameList;};
      Recordset = UserDAO.getByID(UserID, PropertyNameList);
      User = new(); // Calls "new" method on service which calls DI engine to create and initialize transient       User.loadQuery(Recordset);
   </cfscript>
   <cfreturn User.asStruct(PropertyNameList)>
</cffunction>

Very simply I'm taking a user ID and an optional property name list (hey, user might have 200 properties and you may only need 3 of them - SQL has a "select" statement for a reason :->). I call the UserDAO.getByID method and my DAO returns a recordset, then my service method calls my DI engine to create and initialize a transient user (I have a UserService.new() method which encapsulates my implementation of this). Then I load a query into the user to load it with the FirstName, LastName and DateofBirth (I have a data mapper composed in my DAO that is smart enough to know that if you ask for a calculated property name to query for the unique dependent property names, so if you ask the DAO for FullName and Age it'll query and return firstname, lastname and dateofbirth).

Then I return the User as a struct and it loops through the property name list calling either custom or generic getters to return a struct with the necessary information. I will also work up a version of this which allows you to return an array of structs if your bean contains a recordset with n-records- perhaps a User.collectionofStructs(PropertyNameList: string).

What no Value Objects?!
So, we now have (to me) a really nicely OK way of handling this that works for anything from HTML to web services to Flex, that encapsulates the custom getters or setters in the business object and yet that is performant even in ColdFusion by only having to instantiate a single bean to represent and encapsulate an entire recordset of 0..n records.

The only real question left is why I'd return a struct not a value object. In truth, I may not. I could easily enough write something that'd return asValueObject() and ascollectionofValueObjects(). I'm not really sold on value objects in ColdFusion. To me, a value object is a typed struct (each key has a type). That really isn't something I have a use case for, but I haven't played with Flex yet. If it makes AS all warm and fuzzy to remoteobject to a collection of VO's, then I'll add that. otherwise I'll save the instantiation time and just use an array of structs. (Why do I like beans and dislike VO's? Because beans sing for their supper by offering support for custom getters and setters providing an obvious place to put custom getter and setter logic. In fact I even compose validation and DAO within my beans but that is a whole different conversation. VO's do nothing for me right now but take up clock cycles. Based on YAGNI I'll add them when they promise to make my life a little easier)

Comments
In summary, youre saying have a UserService cfc containing a getTransformedUserByID() method. The UserSevice calls the User bean to get the raw data and does the postprocessing. Correct? This is similar to what Matt Woodward showed yesterday at his <a href="http://cfunited.com/go/topics#topic-1342">OOP Back to Front</a> preseo. Good stuff Peter as always.
# Posted By Jim Collins | 7/1/07 1:02 PM
Hi Jim,

The big distinction here is that the service layer does NOT do the processing on the bean - that'd be procedural style coding. Instead the servcie layer asks the bean to process itself which to me is a much more OO approach. It also means that the same custom getters can be used by the DAO when providing a single bean to interact with.

To be fair I missed Matts preso, so I'm not sure what he was advocating, but to me it is really important that the processing is done by the bean itself - not by a smart service layer operating on a dumb bean.
# Posted By Peter Bell | 7/1/07 8:30 PM
(test - it seems moderation is turned on, because nothing's showing up)
# Posted By Joe Rinehart | 7/19/07 8:56 PM
No moderation - never was. Go for your life with the comments!
# Posted By Peter Bell | 7/20/07 6:09 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.005.