ColdSpring: An Answer to a Problem You May Not Know You Have

Over the last two years or so I’ve been working hard to really “get” object-oriented programming as it applies to ColdFusion development. Like a lot of ColdFusion developers that have been around a while, when I started trying to create applications using CFCs, I essentially had CFCs that were collections of UDFs. Before long, after talking with other developers that understood OO principles, I started making my CFCs more “object’y” as I learned more about those principles.

Along the way I naturally heard about various frameworks related to ColdFusion (Fusebox, Model-Glue, Mach-II, ColdSpring etc etc) but never gave them more than a passing glance as I was trying to cram a bunch of new concepts into my brain as it was and I just didn’t have the mental bandwidth to take on frameworks at the same time (however that has since changed and I’ve had a chance to work with Mach-II and Model-Glue). Eventually I got to the point where my applications used numerous objects and some of those objects required the services of other objects to do their jobs. That’s the point that I really began struggling with the effort involved in writing a good OO application. It took lots of lines of code to create an object, configure it simply to pass it into another object.  Sound familiar? Maybe you’re at that point with your ColdFusion OO trek. If so, read on and I’ll introduce you to ColdSpring, a free dependency-injection framework (whoa there, stay with me, don’t let the buzzwords turn you off) that will make your life much easier.

What is ColdSpring?

The simplest way to describe what ColdSpring does for us (for dependency injection at least) is to think of it as an centralized place where we can go to retrieve fully-configured, ready-to-use objects within our code. We ask the ColdSpring object for a particular “bean” (every object in ColdSpring is referred to as a bean…don’t get that confused with a bean in the Gateway/DAO/bean design pattern) and ColdSpring creates the object, runs the init methods with any arguments and hands it back to us ready to use.  If one of the arguments happens to be another object, ColdSpring creates that object, inserts it into the init function automatically. Sounds great right? Trust me, it gets better.

There are two main benefits of using ColdSpring this way.

  1. The configuration for a specific “bean” is confined to one place (the coldspring.xml file) so if something changes with the object, you don’t have to go searching all over your code base to update all the places where you’ve manually created the object.
  2. Object creation and configuration is the same every time meaning that you don’t have to remember all the configuration parameters every place in your code where you need to use that object.

There’s a third, less obvious advantage to using ColdSpring to manage your objects.  When you define an object in ColdSpring, you can elect to tell ColdSpring to make it a singleton (meaning that only one instance of this object will ever exist in your entire application). Any time after application init that you ask for that object, ColdSpring will hand you the copy of it that already exists, eliminating the time required to create and configure a new instance.

This benefit comes with a bit of a caution however. You should never create any objects as singletons that store session-specific data (such as a Product, User, etc). DAOs, Gateways, Config objects and the like are prime candidates for singleton status because, while they have attributes within them that they need to do their jobs, they simply move data around as requested, never storing that actual data within themselves.

How ColdSpring makes life easier

Using ColdSpring increases modularity within our code base. Essentially, each CFC should be as “dumb” to the world outside itself as possible.  Code within a CFC should not reach out to shared scopes to pull values (eg Application, Session, Server scopes, etc). It should not be responsible for knowing the dot-notated path to a particular object that it needs to use to do its work. This is sometimes referred to as the “Law of Demeter” or “Principle of Least Knowledge”. Essentially, this principle states that an object should be provided everything it needs (called dependencies) to do its job and should not have to have knowledge of anything outside itself and the objects that are given to it in order to perform its work.

For example, consider a DAO component that requires a datasource to run its queries. If you hard code #application.dsn# into the datasource attribute of every <cfquery> tag and someone comes along and decides that a more verbose variable name (say application.datasource) is preferable, you have to manually update every  <cfquery> tag in your application.

However, if you’ve created a private variables.datasource property inside your DAO component and included a <cfargument> in your init function that takes the name of a datasource which is then stored in your private property, your <cfquery> tags have no need to know that, outside your DAO component,  you’ve changed the name of the variable storing that string. This is, admittedly, a simple example, but the same holds true whether it’s a simple value or another object that is required to be passed in so your component can do its job.

ColdSpring makes adhering to this principle much easier than if you were doing all the dependency creation by hand before passing it into the object.  By specifying in your datasource as a default property when you create the ColdSpring object, you can reuse that in all your objects.  Consider the following example to create the ColdSpring object:

<!--- Create ColdSpring defaultProperties ---><cfscript>	defaultProperties = structNew();	defaultProperties.dsn = "myHighPoweredDatasource";	defaultProperties.mailServer = "mail.mydomain.com";</cfscript>

When you create the ColdSpring object and pass in the “defaultProperties” structure, you can then reference these values in your object creation.  For example:

<bean id="CustomerDAO"         class="model.customers.CustomerDAO" singleton="true">	<constructor-arg name="datasource">		<value>${dsn}</value>	</constructor-arg></bean>

The code above tells ColdSpring to create an object named CustomerDAO using the component located at model.customers.CustomerDAO. Once it’s created ColdSpring will run the init method (ColdFusion’s constructor method) and pass in the value of the default property “dsn” as an argument named datasource.  What this is accomplishing is effectively removing any link between your DAO component and the application.dsn variable.  Your component doesn’t know (and frankly doesn’t care) that there’s a value stored in the application scope—you’ve explicitly given the DAO object all it needs to do its job.

Notice if you will the last attribute on the <bean….> line above. See that? Setting singleton=”true” means that there will only ever be one CustomerDAO object created in your application—a big plus if you’re constantly getting and putting customer records to/from the database through this object.

Constructor args to ColdSpring bean definitions need not be simple values. Consider the following bean configuration entry from that same example:

<bean id="CustomerGateway" 	class="model.customers.CustomerGateway" singleton="true">	<constructor-arg name="datasource">		<value>${dsn}</value>	</constructor-arg>	<constructor-arg name="dao">		<ref bean="CustomerDAO" />	</constructor-arg></bean>

Our CustomerGateway object needs a datasource and a DAO object to be able to do its job. Here we’re creating a CustomerGateway object much the same way tha
t we created the DAO.  The first constructor argument is the same datasource that we used in the DAO (hey, they need to talk to the same database right?). However, notice the content of the second <constructor-arg>. Here we’re not passing in a simple variable using the <value> tag.  We’re telling ColdSpring that it should pass the “bean” named “CustomerDAO” that we previously created to the init function of the CustomerGateway as an argument named DAO.

So, that’s a little different than passing in a simple string, right. Not according to ColdSpring.  The beauty of this is, Coldspring will create and configure the CustomerDAO “bean” first and then pass that fully-configured, ready-to-use (don’t forget singleton) object into the CustomerGateway bean (even if in your XML config file you have the DAO config AFTER the Gateway config).

If you were doing this by hand, you’d have to manually create the DAO object, run the init function passing in the DSN. Then manually create the Gateway object, run the init function and pass in the DSN and the DAO object you just created….every time you needed a Gateway object. That’s a fair amount of work right?  ColdSpring does this all for you with a few simple lines on XML configuration and you can get on to more important parts of building the application.

But what about….

Aha Grasshopper, I can see that you’ve realized something.  We’re continually having to manually type ${dsn} (and other string variables you need to give to your objects). That’s a lot of work right? Patience, Grasshopper, next time we’ll talk about two tools that the brilliant developers of ColdSpring gave us to solve that very (redundant) issue—the MapFactoryBean and the ListFactoryBean.  Until then…..

**Special thanks to my good friend Dan Wilson for his insight into object-oriented principles, ColdSpring and a bunch of other cool stuff.

Leave a Comment