cf.Objective() 2008 and the Future of ColdFusion

Well the conference has ended and I'm back in Raleigh trying to get back into the groove of work again. ;-) Overall the whole event was excellent, as expected.

I learned a lot at the conference sessions, but also as usual, I think I learned even more sitting at the bar talking for hours with heavy hitters like Chris Scott, Max Porges, Joe Rinehart, Peter Bell, Sean Corfield, Mark Mandel and many others. Some of these guys are just way too smart, but I wouldn't want it any other way.

I feel like my presentations went pretty well and that I'm finally comfortable with public speaking, which is good. I also had a chance to look at the new Swiz Flex framework that Chris created, and it looks really damn good. Hopefully we can move to Swiz from Cairngorm on our current Flex project during a future refactoring, since it is so much easier to deal with.

From talking to other folks in the community, it seems like CF is at something of a crossroads. One thing that kept coming up over and over again was how CF really starts to lose its glamor once you start using it as a back end for Flex. The benefits of CF really shine at the Controller and View layers, but for pure SOA architectures, we really have to jump through a lot of hoops to get true integration with Flex. This is mainly due to the limitations of CFC creation. The autotranslation of CFCs to ActionScript classes looks really sweet...until you have to send 1000 objects across the wire to Flex.

In fact, the dichotomy between the majority of people using CF (the "5 tag crowd", meaning people who just use cfif, cfoutput, cfloop, cfquery, and cfset) and the people who are really pushing the OO envelope became really apparent at the CF9 brainstorm session. Some people were asking for more features, but the core group of "thought leaders" in the CF world are proposing some far more radical changes.

The most compelling to me is the idea of dropping development on CFCs and allowing us to write server-side ActionScript, as well as dropping CFML as it is now and switching to a fully XML compliant markup like MXML. This would allow us to leverage tools like FlexBuilder, which quite frankly are a joy to work in. ActionScript is strongly typed, so this would be a big change, but it has dynamic elements as well such as the ObjectProxy class. And CFML is already nearly XML compliant, so switching over to that kind of synatx would be relatively simple.

Basically, I love all the great and easy features that CF gives us (obviously), but am really starting to hate the verbose syntax needed for CFC development, as well as the lack of proper IDE and tooling support. The built-in services are the reason why I don't "just switch to Java" for the Model. What I want is to be able to leverage all the great stuff CF provides, but do it in a more productive way.

It seems to me that CF9 would be a perfect chance for Adobe to make a clean break and really revolutionize how people use CF, as well as drawing in many new developers who are put off by the current way CFCs are built. There are a large number of odd language idiosyncrasies (arrays passed by value, arrays starting at 1, ListAppend returning the value while ArrayAppend does not, the list goes on) that have built up over the last 8 versions. I'll be blunt and say I think it's time to finally start again.

There is also a massive pool (millions) of people programming in ActionScript and JavaScript, and having a server-side language providing all the great things that CF does would be an extremely compelling draw. I think a bold change could trigger a huge influx of developers.

I realize that a large number of existing CF developers would probably not embrace this, at least not initially. I would argue that for them, they can keep on using CF8 and keep on doing what they are comfortable with. Adobe could offer patches and updates that would port the new AS/MXML features to the old CFML syntax (since the new stuff would be running on Java as well). The question would be whether alienating some of these folks is outweighed by the benefits of such a change and the influx of existing AS/JS developers it would trigger. Being able to use the same language on the client and the server, using a killer IDE, and leveraging a huge array of easy-to-use services would be a ridiculously compelling platform.

I still love CF and I'm only saying this as frank and honest suggestions. Using FlexBuilder really brings home the power of a great IDE. Looking at things like Groovy (with its Spring and Hibernate stack) shows just how easy working in Java has become, and what a difference it makes to really be able to do full-blown OO development instead of worrying about how many CFC instances we're creating.

All that said, I know that the odds are probably close to zero that such a change would actually be made. Still, one never knows. Adobe was listening to us at the conference and I'd like to hope that all options are on the table as they go forward. The fact that they let us talk directly to them and listen to our crazy ideas is one of the things that makes the CF team great. I just want to see CF continue to grow and shine, and as you can probably tell by now, I think a radical idea like this could really shake things up and push ColdFusion to even greater heights.



Returning Typed Structs vs. CFCs to Flex

An awesome little Flex and CF performance gem popped up on the Transfer list last night. Some of us had been discussing how we return data to Flex from ColdFusion. As I've mentioned before on the blog, I use AOP to translate queries and other data into CFC Value Objects for automatic translation into ActionScript classes. I actually thought this was the only way to get the automatic type conversion.

Well Jon Messer piped up with an alternative technique, and Sean Corfield quickly confirmed that it was an "official" option and not just an undocumented hack! You can actually return an array of structures to Flex. You specify all of the properties as structure keys, but then add a key for "__type__", which specifies the CFC type that you want Flex to "see" the structure as! Full details in, where else, the docs: http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=UseFlexDataService_05.html

End result? For large sets of data, this will definitely be faster than returning arrays of CFC instances. I had never even heard of this option so thanks Jon!

Creating A Metadata-Aware ColdSpring Advice

I've been working with Flex a lot recently. One of the first things that I did was create some ColdSpring AOP Advices that would take data coming back from my service layer and convert it into Value Objects so that they can be automatically converted into ActionScript Value Objects on the Flex side. This seemed to work pretty well and did exactly what I needed it to.

However, in the quest for creating something more generic and reusable, I decided to build an Advice that I could feed an XML file. This file would define how I want the data returned by the various services to be converted into Value Objects. This was needed because the way a product query is converted is different than, say, how a shopping cart CFC is converted. Basically, I wanted to define what Value Object Converter to use for a given service, what actual Value Object components to use, and even be able to define different converters for different methods within a service in case it wouldn't work to define one converter for all of the methods in the service.

I got all this to work and it was nice. However, at this point I realized that this idea could apply far beyond my single case of setting up Value Object converters. I could define any data to associate with a specific ColdSpring-managed bean, or any methods within those beans. What I've really got now is a generic Advice that can be detect and use any metadata I want to associate with a bean or a method!

To start with my Value Object converter example, I would attach my Advice to my Remote Proxy in the ColdSpring configuration:

<bean id="remoteProductService" class="coldspring.aop.framework.RemoteFactoryBean" lazy-init="false">
      <property name="interceptorNames">
         <list>
            <value>VOConverterAdvisor</value>
         </list>
      </property>
      <property name="target">
         <ref bean="productService" />
      </property>
      <property name="serviceName">
         <value>RemoteProductService</value>
      </property>
      <property name="relativePath">
         <value>/presentation/flexbookstore/remote/</value>
      </property>
      <property name="remoteMethodNames">
         <value>*</value>
      </property>
      <property name="beanFactoryName">
         <value>BeanFactory</value>
      </property>
   </bean>
   
   <bean id="VOConverterAdvice" class="presentation.common.components.VOConverterAdvice">
      <property name="metadataConfig">
         <value>/myproject/config/advicemetadata.xml</value>
      </property>
   </bean>
   <bean id="VOConverterAdvisor" class="coldspring.aop.support.NamedMethodPointcutAdvisor">
      <property name="advice">
         <ref bean="VOConverterAdvice" />
      </property>
      <property name="mappedNames">
         <value>*</value>
      </property>
   </bean>

Probably looks familiar to people who have used ColdSpring's AOP capabilities (and if you haven't, don't worry, it looks worse than it is). However, notice that I am passing a property called "metadataConfig" to my Advice. This is where the magic happens.

My VOConverterAdvice extends a component called AbstractMetadataAwareAdvice. This component reads in the metadata file specified by the path, processes it, caches it, and has it available for use by the VOConverterAdvice any time it handles an incoming method call.

The advicemetadata.xml file is very simple:

metadata>
   <target name="ProductService"
         vo="presentation.common.components.ProductVO" />

</metadata>

Now my generic VOConverterAdvice knows that when a method is invoked on my ProductService, I want the converter to create ProductVO value objects from the returned data.

OK, you might think that doesn't look particularly mind blowing. But I can also do this:

metadata>
   <target name="CartService"
         converter="CartVOConverter"
         cartVO="presentation.common.components.CartVO">

      <method name="getCart"
            productVO="presentation.common.components.ProductVO" />

   </target>
</metadata>

So when the CartService is called, the Advice now has a bunch of useful information at its disposal. It knows that I'm using a custom converter named "CartVOConverter". It knows the path to the CartVO value object that I want to use. Further, when I call getCart() on CartService, not only is all of the previous data available, but it also gets a path to a ProductVO.

So I can define some global data to associate with the entire service, as well as any specific data to associate with one or more methods. The data in the method will override any data defined for the whole service. This is extremely useful because it opens up a huge amount of capability to your Advices by giving them information that they otherwise would never be able to know.

This can be applied to any data you wish you could feed to your Advices. Consider:

metadata>
   <target name="CartService"
         converter="CartVOConverter"
         logVariables="foo,bar,blah"
         cartVO="presentation.common.components.CartVO">

      <method name="getCart"
            logVariables="zoo,goo,blah"
            productVO="presentation.common.components.ProductVO" />

   </target>
   <target name="ProductService"
         logVariables="foo,bar,blah"
         vo="presentation.common.components.ProductVO" />

</metadata>

I can tell a Logging Advice what variables I want logged, but at the overall service level or for specific methods. Hopefully you can see where this is going. My Advices have become vastly more intelligent because they have much more information to use when they run.

Again, all of this is cached, so there should be virtually no performance cost for being able to do this. Big benefit at low cost...I like the sound of that.

Anyway, I'm curious to hear what other ColdSpringers (is that a word?) think about this idea. Obviously, I think this is cool, because I wrote it. Do others see possibilities here? Or possibly, have I missed an easier route to solve the problem? Please let me know!

Learning Flex Part 5: Using ColdSpring AOP to Create Arrays of Value Objects

One of the great things I discovered while working on the Flex version of my Bookstore sample application was another affirmation of the benefits of a good service layer. In this case, it was very easy to take query data coming back from my service layer and convert it into an array of Value Objects that Flex will then translate into ActionScript Value Objects.

By using ColdSpring's AOP capabilities, I was able to create this translation without having to modify my existing service layer objects at all. Further, I was able to do this in a fairly generic way. This technique has its limitations, but I think it will work fine in most situations.

Say I have an existing service layer method that returns a query, like this:

<cffunction name="getFeaturedProducts" access="public" returntype="query" output="false" hint="I return the products marked as 'featured products'.">
   <cfreturn getProductGateway().getByFields(featuredProduct=1) />
</cffunction>

As you can see, this returns a query of featured products, meaning the products I might want featured on the home page because they are on sale or something. In the normal HTML version of the Bookstore, this query would then be rendered into a table in one of the View templates.

In the Flex UI, I want these to be converted into an array of Product Value Objects so that they can be used in a DataGrid or a TileList. To do this, I created a generic AOP Advice called VOConverterAdvice, which looks like this:

<cfcomponent output="false" displayname="VOConverterAdvice" hint="" extends="coldspring.aop.MethodInterceptor">

   <cffunction name="init" returntype="any" output="false" access="public" hint="Constructor">
      <cfreturn this />
   </cffunction>
   
   <!--- PUBLIC METHODS --->
   <cffunction name="invokeMethod" returntype="any" access="public" output="false" hint="">
      <cfargument name="methodInvocation" type="coldspring.aop.MethodInvocation" required="false" hint="" />
      <cfset var local = StructNew() />
      <cfset local.voArray = ArrayNew(1) />
      
      <cfinvoke
         component="#arguments.methodInvocation.getTarget()#"
         method="#arguments.methodInvocation.getMethod().getMethodName()#"
         argumentcollection="#arguments.methodInvocation.getArguments()#"
         returnvariable="local.result" />

      
      <cfset local.rowCounter = 1 />
      <cfloop query="local.result">
         <cfset local.tempData = StructNew() />
         <cfloop list="#local.result.columnList#" index="local.thisColumn">
            <cfset local.tempData[local.thisColumn] = local.result[local.thisColumn][local.rowCounter] />
         </cfloop>
         <cfset ArrayAppend(local.voArray, CreateObject('component', getVOType()).init(argumentCollection=local.tempData)) />
         <cfset local.rowCounter++ />
      </cfloop>
      
      <cfreturn local.voArray />
   </cffunction>
   
   <cffunction name="setVOType" access="public">
      <cfargument name="voType" />
      <cfset variables.voType = arguments.voType />
   </cffunction>
   
   <cffunction name="getVOType">
      <cfreturn variables.voType />
   </cffunction>

</cfcomponent>

What this does is call the underlying service layer method to get the query. Then, for each row in the query, it populates a simple Value Object CFC based on the query column names. In this way, it builds up an array of Value Objects, and then returns that array. The Value Object CFC might look like this:

<cfcomponent displayname="ProductVO" output="false">
   
   <cfproperty name="productID" type="numeric" />
   <cfproperty name="productName" type="string" />
   <cfproperty name="productDescription" type="string" />
   <cfproperty name="productPrice" type="numeric" />
   <cfproperty name="asin" type="string" />
   <cfproperty name="featuredProduct" type="numeric" />

   <cffunction name="init" access="public" returntype="presentation.common.components.ProductVO" output="false">
      <cfargument name="productID" type="numeric" required="false" />
      <cfargument name="productName" type="string" required="false" />
      <cfargument name="productDescription" type="string" required="false" />
      <cfargument name="productPrice" type="numeric" required="false" />
      <cfargument name="asin" type="string" required="false" />
      <cfargument name="featuredProduct" type="numeric" required="false" />
      
      <cfset this['productID'] = arguments.productID />
      <cfset this['productName'] = arguments.productName />
      <cfset this['productDescription'] = arguments.productDescription />
      <cfset this['productPrice'] = arguments.productPrice />
      <cfset this['asin'] = arguments.asin />
      <cfset this['featuredProduct'] = arguments.featuredProduct />
      
      <cfreturn this />
   </cffunction>
</cfcomponent>

The ColdSpring XML to create this Remote Proxy and apply this VOConverterAdvice looks like this:

<bean id="remoteProductService" class="coldspring.aop.framework.RemoteFactoryBean" lazy-init="false">
   <property name="interceptorNames">
      <list>
         <value>ProductVOConverterAdvisor</value>
      </list>
   </property>
   <property name="target">
      <ref bean="productService" />
   </property>
   <property name="serviceName">
      <value>RemoteProductService</value>
   </property>
   <property name="relativePath">
      <value>/presentation/flexbookstore/remote/</value>
   </property>
   <property name="remoteMethodNames">
      <value>*</value>
   </property>
   <property name="beanFactoryName">
      <value>BeanFactory</value>
   </property>
</bean>

<bean id="ProductVOConverterAdvisor" class="coldspring.aop.support.NamedMethodPointcutAdvisor">
   <property name="advice">
      <ref bean="ProductVOConverterAdvice" />
   </property>
   <property name="mappedNames">
      <value>*</value>
   </property>
</bean>

<bean id="ProductVOConverterAdvice" class="presentation.common.components.VOConverterAdvice">
   <property name="VOType">
      <value>ProductVO</value>
   </property>
</bean>

So Flex calls getFeaturedProducts() on the RemoteProductService. ColdSpring automatically generates this Remote Proxy for me. It then applies the VOConverterAdvice, which gets the query results from the underlying ProductService, converts that query into an array of ProductVO CFCs, and returns that array to Flex. Flex then automatically converts that into an array of ProductVO ActionScript classes, which I can then use however I want to in my Flex application.

It's a bit verbose, but it only has to be done once and now all of the methods in my ProductService that return product queries can now return arrays of Product Value Objects to Flex. And again, the big win here is that I'm able to do this without having to change anything in my existing ProductService.

I do wish there was a way that I could have the Remote Proxy tell the VOConverterAdvice which kind of Value Object I want to translate instead of having to explicitly define it, but there isn't (that I am aware of). This kind of goes back to my old idea of being able to pass additional metadata to Advices, but that's another discussion. Since you can supply ColdSpring with your own XML or XML Document Object instead of an XML file name, one workaround might be to build up the XML dynamically, but I haven't tried it yet. But this is a digression. However it is done, the great thing about all this is that my existing service layer is able to feed data to my Flex application with no changes!

That about sums it up for my approach to leveraging ColdSpring to help me feed data to my Flex applications. If anyone has any comments or advice (no pun intended) on this, or has a different way to approaching the problem, I'd love to hear about it in the comments.

Learning Flex Part 4: Cairngorm Events != Flex Events

One thing I struggled with while learning about Cairngorm is the Cairngorm Event model. In short, Cairngorm Events are quite different from standard Flex Events in the way they are handled.

This may be obvious to seasoned users of Cairngorm, but this took me a while to wrap my head around. Cairngorm Events map to Commands via a Cairngorm Controller. They are (as I understand them) meant to update the ModelLocator and get data from the server (via Delegates and Responders). They don't "bubble" up the Flex container hierarchy, and they don't get announced to the rest of the Flex application.

My first instinct was to try and decouple my Views from Cairngorm by having them only announce Flex events. These events would bubble up the container hierarchy and be handled at the top level of the application. From there, corresponding Cairngorm Events would be dispatched. This way, I could still have non-Cairngrom event listeners respond to the bubbling events, and my Views would be decoupled from the Cairngorm framework, which sounded like a good idea.

However, with more experimentation and thought, I've realized this approach adds complexity and doesn't offer much in the way of benefits. It requires a separate layer of event mappings so that the Flex events can be translated into Cairngorm events. And in most cases, your Views are tied to Cairngorm anyway. For example, a Shopping Cart panel is directly tied to the ModelLocator to keep track of what is in the cart. You can't easily reuse this Cart component in a non-Cairngorm app without changing it. The same thing probably applies to most of the Views. So in retrospect, in most cases I believe it is fine for your Views to just go ahead and dispatch Cairngorm events and avoid all the overhead of trying to make them framework independent.

Now, I can see that for certain kinds of components, this would not apply. If you truly have a reusable component, say a custom Select Box for picking States or something, this would benefit from being totally decoupled from Cairngorm. You can have it dispatch a custom Flex event that the parent container would then handle by dispatching a Cairngorm Event. So it appears that one must consider the purpose of the View component in question and decide whether it is application-specific or application-independent. The answer would seem to dictate whether it is appropriate to announce Cairngrom Events vs. Flex Events.

I'm interested to hear from anyone more deeply familiar with Flex and Cairngorm. Is my thinking on the right track on this? Please fire away in the comments and let me know your thoughts. Thanks!

More Entries

BlogCFC was created by Raymond Camden. This blog is running version 5.9. Contact Blog Owner