Viewing by month: December 2005

Dec 29 2005

Sample DAOFactory CFC

After my last post on Factory vs. Abstract Factory, I received an e-mail asking me how I'd implement a basic DAO factory. This is a basic template I use for most of my simple factories, customized to act as a DAO factory.

Its init() method takes a bean representing datasource information, and its create() method tries to create DAOs via a CFSwitch block.

The default action is to blindly create a DAO based on the name passed to create(), handing (a reference to) the datasource bean to the DAO's init() method. You'd probably want to try/catch this to get a meaningful error message when you're two or three API layers up an ask for a DAO you haven't yet created (I do this all the time!).

By adding a custom case to the switch, you can handle "special" creation cases. In this example, I've added a custom case to create a ContactDAO that's composed with an AddressDAO.

<cfcomponent displayname="DAOFactory" output="false">

<cffunction name="init" access="public" returntype="DAOFactory">
   <cfargument name="datasource" type="ModelGlue.Bean.CommonBeans.Datasource">
   <cfset variables._datasource = arguments.datasource />
   <cfreturn this />
</cffunction>

<cffunction name="getDatasource" access="private" returntype="ModelGlue.Bean.CommonBeans.Datasource">
   <cfreturn variables._datasource />
</cffunction>

<cffunction name="create" access="public" returntype="any">
   <cfargument name="name" type="string" required="true">
   
   <cfset var result = "" />
   <cfset var temp = structNew() />
   
   <cfswitch expression="#arguments.name#">
      <!--- Put "custom" DAOs in their own cases. --->
      <cfcase value="contact">
         <cfset temp.addressDAO = create("address") />
         <cfset result = createObject("component", "ContactDAO").init(getDatasource(), temp.addressDAO) />
      </cfcase>   
      <!--- By default, just try to create something by name --->
      <cfdefaultcase>
         <cfset result = createObject("component", arguments.name & "DAO").init(getDatasource()) />
      </cfdefaultcase>
   </cfswitch>

   <cfreturn result />
</cffunction>

</cfcomponent>

5 comments - Posted by Joe Rinehart at 9:27 AM - Categories: ColdFusion MX

Dec 29 2005

Abstract Factory vs. Factory Method

After dicussion on the lists, Sean Corfield has posted a quick explanation of the difference between these two patterns (they're not the same!) over at his blog. He was asked if Abstract Factory is overkill in ColdFusion, and answered that "we [ColdFusion developers] would find more applications for the factory method design pattern in our world - abstract factories are pretty complex beasts."

I agree, but I do have an application that has a pretty clear illustration of Abstract Factory for those who want to wrap their skull around it.

First, let's look at Factory Method in a nutshell: when you use it, you defer instantiation of an object to a factory. In simplest terms, this means that instead of writing CreateObject(), you call a method on your factory that in turn calls CreateObject() and handles other logic around instantiation.

Factory seems simple, and maybe more complicated than necessary, until you hit a complicated instantiation sequence. For example, If you have a Contact that has-a address, the ContactDAO may have-an AddressDAO. Each of these needs a DatasourceBean to keep going.

Without a Factory, I'd constantly have this in my code:

<cfset ds = createObject("component", "Datasource").init() />
<cfset ds.setDSN("foo") />
<cfset addressDAO = createObject("component", "AddressDAO").init(ds) />
<cfset contactDAO = createObject("component", "ContactDAO").init(addressDAO) />

Whew, that's a lot of stuff to remember to do each time I need to persist a contact. If something changes, and this is scattered all over the place, I'm up the creek.

By moving this code into a factory, I replace it with something like this:

<cfset addressDAO = daoFactory.create("Address") />
or
<cfset addressDAO = daoFactory.createAddress() />

H'ok. That's simple factory. Sean did say that abstract factory can be a complex beast. I don't think it's all that complex in terms of implementation, but the reasons behind it are where your brain needs to get away from procedural thinking.

Let's say that our application now needs to support multiple database implementations. Thinking ahead, we put our AddressDAO, ContactDAO and the DAOFactory CFC in a directory named /data/mysql, because we've built them for MySQL. However, we now need to support Oracle. To do this, we make a copy of /data/mysql and name it /data/oracle.

Now, we have to figure out which DAOFactory to use: /data/mssql/DAOFactory.cfc or /data/oracle/DAOFactory.cfc. Hey, wait, that's cool! We've made the choice of the database platform nothing but a configuration variable! There's a lot of ways to handle this, but using an IoC container like ColdSpring would be ideal (see: What is Inversion of Control?).

There's something else here, however, that we've also done. It's not as concrete...more, well "abstract." We've taken the idea of what the MySQL DAOFactory does and abstracted it, declaring (in our minds, or on paper) that the Oracle DAOFactory must act the same way and "look" the same to the outside world. In other words, they implement the same interface.

We have two factory (MySQL and Oracle DAO Factories) that serve to create DAOs from two different families. However, both factories and the DAOs themselves act the same as their counterparts built for the other platforms.

And that's about the only practical, application-level use for the Abstract Factory method I've come up with in ColdFusion.

6 comments - Posted by Joe Rinehart at 7:12 AM - Categories: ColdFusion MX

Dec 21 2005

What is Inversion of Control?!?

IoC is "all the rage" right now in the Java circle, and some of us are really getting into its applications inside of ColdFusion via the ColdSpring framework. However, it's got a pretty steep learning curve! At the moment, it seems like you either know about IoC, how it helps, and think ColdSpring is a Godsend, or you're just kind of wondering what all the hubbub is about.

Inversion of Control serves to "resolve dependencies" for the various components in your application. In plainer English, it automatically gets all of your ducks in a row.

A (simple) real world example

I do a lot of work that relies on servers providing a network-based service, such as LDAP. However, when I'm not connected to certain networks, I can't get to those servers. In order to help me develop remotely, I often write two different CFCs:

RealClient.cfc - The "real" client for the service

FakeClient.cfc - A "fake" client that doesn't actually use the service, but pretends to and returns hard-coded test data

Hard-coded Instantiation

I've got a Gateway that needs to use this service as part of its datasource. Without an IoC container, like ColdSpring, when I need to switch the between the RealClient and FakeClient, I'm stuck editing this gateway, changing this:

createObject("component", "tld.domain.RealClient").init(stuff)

To this:

createObject("component", "tld.domain.FakeClient").init(stuff)

Moving to a Factory

Hard-coding the instantiation isn't very elegant. So, for a first revision, we'll decide that since FakeClient and RealClient implement the same interface, I can use a factory and ask it for the appropriate client based on a configuration setting. That means I'm still stuck changing code:

serviceFactory.create("fake")

or

serviceFactory.create("real")

I've made one good move: recognizing that there's an interface, and that I can delegate instantiation to something else, like a factory. However, I'm still stuck changing code for something that isn't a concern of the code, and is really just a configuration issue.

Wouldn't it be nice if there was something that'd read a configuration file, and then return the correct client based on the configuration file?

ColdSpring IoC!

By moving what changes (real vs. fake client) into an XML file used by ColdSpring, I can then store multiple "configurations" of my application in multiple XML files, never editing code. It's pretty straightforward, in this case I'd have the following in my ColdSpring XML file:

<bean id="ServiceClient" class="tld.domain.RealClient" />

or

<bean id="ServiceClient" class="tld.domain.FakeClient" />

My application code then needs to never do anything but the following:

ColdSpring.getBean("ServiceClient")

It never knows which service client is really being used, because they both implement the same interface. My code now never has to change!

Coming Soon

I'll be writing a post sometime soon that shows more advanced things ColdSpring can do, such as resolving dependencies between components it creates, the architectural/design benefits of using IoC, and the basics of Aspect-Oriented Programming.

15 comments - Posted by Joe Rinehart at 9:26 AM - Categories: ColdFusion MX

Dec 20 2005

AM Agg: Ajax - enough to-do lists, ok?

Ajax (n) - An old technology, billed as new again, that's really caught on in a market segment primarily interested in reinventing the to-do list in every flashier ways. See Agave, 37signals, voo2do.com, rememberTheMilk, tudu, ackertodo, Orbeon, tudu (again, but different), and last, cheapest, and fastest to boot: the notepad and pencil my Dad carries in his pocket.

Maybe there's some internal, private development going on with Ajax (I've done a fair amount, all ColdFusion + Model-Glue), but for public-facing applications, I have to think that if Ajax is going to be a serious development tool, it'd be used for more than Ajax developers keeping track of the list of cross-browser Ajax tweaks they need to fix in their Ajax to-do list "Betas"

In other news:

Ray Updated Canvas Wiki

Ray Camden, WACK co-author and creator of all kinds of great, free, CF software, has updated his Wiki tool, named "Canvas," with some of his own code and a mix of updates from the likes of Rob Brooks-Bilson, Doug Hughes, and Sean Corfield.

Writing UTF-8 Files from ColdFusion

Dan at Pengoworks blogs a solution for writing UTF-8 files from ColdFusion that properly include the BOM (Byte Order Mark). This byt me in the arse a while back, too, so it's nice to have it wrapped into a UDF.

New Richard Stallman Interview

Richard Stallman, "father" of the open software movement, gives a new interview over at Znet. Largely same stuff he usually says, covering freedoms "0 through 3": freedom to run the software as you wish, freedom to study and change the source code as you wish, freedom to copy and distribute the software as you wish, and freedom to create and distribute modified versions as you wish. I think it works great for libraries, and not so great when you need to make a living as a consultant.

Moby in Space

Moby's booked a $200,000 ticket with Richard Branson's "Virgin Galatic" space tourism company, scheduling a flight somewhere around 2010. Also rumored to have booked a flight is Dave Navarro.

2 comments - Posted by Joe Rinehart at 7:39 AM - Categories: The AM Agg

Dec 19 2005

CFUnited-06 Speakers: Corfield, Helms, Camden...and me!

Last year I taught a full day pre-conference class, but I'm shifting to the main schedule this year, giving two talks: one on MVC, and another on some basic best practices.

Reading the speakers / topic list at http://cfunited.com/topics.cfm, I quickly wanted to figure out how to clone myself, because there's no way I'm going to be able to attend all of the sessions I'd like to see.

There's definitely a lot of "tried and true" CF speakers on the list, but I'm excited to see some other "new blood" I'm friends with showing up to talk, including Simeon Bateman and Adam Lehman.

2 comments - Posted by Joe Rinehart at 8:52 AM - Categories: ColdFusion MX | Conferences and Speaking Engagements

Dec 19 2005

AM Agg: Firefox Victory.

Firefox is in Forbes. Apple is growing. GMail goes mobile. There's some Factories vs. ColdSpring vs. Service Locator posts on CFCDev everyone should be reading - I'll blog some thoughts and quotes later today.

Firefox: Victory

I touched on this last week, but it's fascinating that IE7's use of the Firefox RSS icon was actually picked up by forbes, and made the top Google News headlines.

Apple: 42% Increase in Laptops Projected

The Topology Research Instituting projects that Apple will ship 42% more laptops in 2006, thanks to popularity of the iPod and new, lightweight chasis.

_ Framework

Looks like we have another presentation/control tier framework in ColdFusion, called "Underscore." Based off of Fusebox, it uses an Application.cfc that extends a base framework CFC, and then uses natural naming of pages instead of the "circuit-to-fuse" naming convention. I'll check it out and blog more later.

MAX Interview: Jared and Tim

In a Fusion Authority video interview, Jared Rypka-Hauer interviews Tim Buntel, the Senior Product Manager for ColdFusion.

Ruby without Rails

IBM has an interesting article that focuses on helping transition Java developers to Rails, focusing on syntax and semantic differences.

Gmail goes Mobile

GMail is now available on your cell phone. It optimizes its layout to your phone, and it lets you "reply by call" to contacts whose phone numbers are in your address book. Heck, I may have to fix my cell phone, which has been out of commission since just after CFUnited05.

1 comments - Posted by Joe Rinehart at 8:28 AM - Categories: The AM Agg

Dec 16 2005

ColdSpring vs. Anemic Domains: DAO is Good!

Scott Barnes has an interesting post over in his blog that got me thinking this morning; in his post, he discusses the validity of the DAO, DG, and Bean/VO combination many of us are using in our applications. I'm a fan of this setup; I've talked about it, written about it, and taught classes on it. I think it's a good way to begin moving from script-based, procedural ColdFusion towards a more OO paradigm.

I'm with Scott, however, in thinking that it has its issues. My beef with it isn't the same as his; mine is that I feel it leads to what's known as an "anemic" domain model.

What's an anemic domain model? Typically, it's where you've used "Design Patterns" to move nearly all of the actual logic out of your model and into services. With an amenic domain model, you're beginning to move away from the point of OO programming (combining data and logic), and more to a place where you're writing procedural scripts in your services that act on VOs or Beans. A very good article on the "Anemic Domain Model" anti-pattern is available on Martin Fowler's site.

Probably one of the most "factored out" pieces of domain behavior is persistance. Now, I'm not for scrapping the DAO pattern, I just think we've gone way away from why it exists (separate persistence behavior from the objects they persist) and made it almost an odd mantra. Using tools like ColdSpring, there's no reason I can think of why one as to why your domain entities shouldn't have a save() method. By using an IoC container (ColdSpring!), you can wire your domain entities to their DAOs via xml. Then, by asking your BeanFactory for the entity, you receive an entity, prebuilt with its own persistence.

What would this look like? Well, with anemia, we'd typically have something like this:

<!--- set up a datasource --->
<cfset datasource = createObject("com.clearsoftware.contactmanager.data.DatasourceBean").init() />
<cfset datasource.setDSN("myDatasource") />

<!--- create and populate a contact --->
<cfset myContact = createObject("com.clearsoftware.contactmanager.contact").init() />
<cfset myContact.setFirstname("Santa") />
<cfset myContact.setLastname("Claus") />

<!--- persist the contact --->
<cfset daoFactory = createObject("com.clearsoftware.contactmanager.data.DAOFactory").init(datasource) />
<cfset contactDao = daoFactory.create("ContactDAO") />
<cfset daoFactory.create(myContact) />

That's not much code, but it requires a large amount of knowledge from the developer's side. They have to understand the Contact's API, the concept of the DAO Factory, and the API of the DAO factory. That can be quite intimidating.

By using ColdSpring, we can "wire together" a domain model with some meat on its bones at runtime. By using XML like the following, we can defer all of this object instantiation and configuration to a configuration file, letting the ColdSpring BeanFactory take care of the grunt work, so that our code is only concerned with what we want to achieve (adding Santa to our Contact Manager database).

<beans>
<bean id="Contact" class="com.clearsoftware.contactmanager.Contact" singleton="false">
<constructor-arg name="DAO">
<ref bean="ContactDAO" />
</constructor-arg>
</bean>

<bean id="ContactDAO" class="com.clearsoftware.contactmanager.data.ContactDAO">
<constructor-arg name="Datasource">
<ref bean="Datasource" />
</constructor-arg>
</bean>

<bean id="Datasource" class="com.clearsoftware.contactmanager.data.DatasourceBean">
<property name="DatasourceName">
<value>ContactManager</value>
</property>
</bean>
</beans>

Ok - we've told ColdSpring that we have a Contact entity, and when we ask for it, it needs to init() it with a ContactDAO entity, and that, in turn, that ContactDAO should be init()'d with a Datasource entity. We can add a save() method to the Contact entity that in turn calls the ContactDAO it's been composed with.

That turns our earlier code into this:

<cfset beanFactory = createObject("component","coldspring.beans.DefaultXmlBeanFactory").init() />
<cfset contact = beanFactory.createBean("Contact") />
<cfset contact.setFirstname("Santa") />
<cfset contact.setLastname("Claus") />
<cfset contact.save() />

Yeah, that's it. We've added some behavior back to our domain model, but we've done it in a way that avoids the problems of actually coding the behavior into our domain objects.

ColdSpring Framework

Scott Barnes' Post on DAO

10 comments - Posted by Joe Rinehart at 8:34 AM - Categories: ColdFusion MX