comment

My Approach to Test Driven Development Part 1 - Application Structure and Apache

2008 August 27
No Comments
As I delve deeper into Test Driven Development (TDD), I have refined my development setup in order to feel confident that my tests are relevant and that they provide immediate feedback about the status of my working code. The two most important goals that I have tried to accomplish with my revisions are to follow the credo of never committing broken code and to isolate and reset the database to ensure the integrity of test data. The following examples are not solely related to TDD, but represent an accumulation of development "best practices" gathered from many sources. I'm going to admit straight up that I am not a TDD purist. I almost always write model components before tests. But I always test before running code on the client side. One of the biggest selling points about unit testing and for me is that I can debug faster should a problem arise and I can do it repeatedly and confidently. Working this way makes me feel somewhat pragmatic. I'm willing to spend a known amount of time setting up and running tests so that I can avoid spending an unknown amount of time debugging. First up, my application directory structure and Apache virtual host settings.

read more...

School's Out...Forever!

2008 August 20
No Comments
Today, I wrote the final exam for the final course I need for my BComm. It was fitting that I wrote it at my home town University in Windsor, Ontario. I live in BC now, but circumstance brought me to Windsor this week, so I made arrangements to write my exam in town. Before the exam, I had that "full circle" feeling walking around the campus I had not set foot on for nearly 20 years. For a little history, I started university in September 1985 and left school in February 1989 to pursue personal interests (of the rock and roll variety). After many joe jobs and many bands, I made the decision to return to school in 1998 as a distance education student. Now ten years later, I've completed the requisites for my degree. It's been a long strange trip and now that it's over I just have to crank up the Alice Cooper...

Jon Messer Writes! Check out Amcom Technology Blog's Newest Author

2008 June 18
No Comments
Amcom Technology is chock full of serious Coldfusion and Flex talent. Not the least of which is Jon Messer who has long contributed to the many of the popular CF lists. Jon is starting a new series on building an object oriented application with multiple MVC clients including Flex. The first installment introduces the series and describes modeling business objects. If you are interested in OO application design for Coldfusion, I highly recommend this series as a reference.

Dynamic Configuration with Environment Config And a Coldspring Config Factory

2008 June 16
No Comments
When developing web application, it is very likely that at some point you will need to create dynamic configuration for your application in terms of development, staging and production environments. I recently discovered the excellent Environment Config project by Rolando Lopez. Rolando has created a very interesting package with lots of robust features for configuring your application dynamically. There are portions of the package that I must admit, I'm not using (yet). What follows is my current setup for integrating the environment config with a custom factory.

read more...

Model Glue Event Security Using Broadcasts and Results

2008 June 05
No Comments
When building web applications, you will inevitably need to provide secure pages or an entire area of your application for users and administrators. For my most recent Model Glue project I wanted to define a common approach to securing all access to the admin area with the exception of login pages. After several failed attempts at universal security, I decided that securing events is best achieved through explicit broadcasts and results, with a minimal amount of logic handled within the controller. Here's a simple example. Let's presume that the default event for my admin sub-application is "admin.home", here is my event listener declaration. <event-handler name="admin.home">
<broadcasts>
<message name="loginRequired" />
</broadcasts>
<results>
<result name="noValidLogin" do="login.go" redirect="true" />
<result do="layout" />
</results>
<views>
<include name="content" template="home.cfm" />
</views>
</event-handler>
The loginRequired has a listener defined by the following. <controller name="SecurityController" type="admin.controller.SecurityController">
<message-listener message="loginRequired" function="verifyLogin" />
</controller>
Finally, in my SecurityController, the verifyLogin method looks like this. <cffunction name="verifyLogin" access="public" returnType="void" output="false">
<cfargument name="event" type="any">
<cfif not getSecurityService().adminLoggedIn()>
<cfset arguments.event.addresult("noValidLogin")>
</cfif>
</cffunction>
In a previous application I chose to use event.forward() within my controller to redirect the request to the login event. Although this works, it is, in my opinion, better to use addResult and have Model Glue handle the redirection. Although the xml is more verbose, I really like that the intent of each event is clearly defined. Which provides a nice roadmap for any other developers that may take over the project.

Transfer ORM Event Model Examples - BeforeCreate and BeforeUpdate

2008 May 21
No Comments
The topic of how one might track created and modified dates came up on the transfer list today and Brian Kotek mentioned how he uses the transfer event model to track changes when creating or updating Transfer objects. I thought it might be interesting to see just how easy it would be to implement his approach. The transfer event model is an implementation of the Observer/Observable pattern in which one object registers itself to listen for events from another object. When an event occurs on the observable object, the observer (a.k.a listener, or subscriber) is notified. The transfer event model currently supports seven events, each of which require the observer to implement a specific "listener" method. Here's how I decided to implement Brian's approach.

CAVEAT LECTOR I rushed this post out without thinking through the implementation. This is an incorrect and possibly dangerous way to use the transfer event model. Please see Bob Silverberg's post on this topic.

I define a configure() method within all of my transfer decorators. Configure() is invoked when a transfer object is instantiated. This makes it a perfect candidate to add additional behaviour by registering the Transfer object to listen for specific events. In this example I'll setup the transfer object to listen for the BeforeCreate and BeforeUpdate events. <cffunction name="configure" access="public" output="false" returntype="void">
<!--- register for transfer events --->
<cfset getTransfer().addBeforeCreateObserver(this)>
<cfset getTransfer().addBeforeUpdateObserver(this)>
</cffunction>
Once registered for these events, the Transfer object must implement the following methods. <cffunction name="actionBeforeCreateTransferEvent" access="public" returntype="void" output="false" hint="I set the created date before I am persisted for the first time.">
<cfargument name="event" hint="The event object" type="transfer.com.events.TransferEvent" required="Yes">
<cfset setCreatedDate(now())>
</cffunction>

<cffunction name="actionBeforeUpdateTransferEvent" access="public" returntype="void" output="false" hint="I set the created date before I am persisted for the first time.">
<cfargument name="event" hint="The event object" type="transfer.com.events.TransferEvent" required="Yes">
<cfset setModifiedDate(now())>
</cffunction>
Assuming that we have two properties on our Transfer object for CreatedDate and ModifiedDate, setting those values is now nicely de-coupled from a service or controller layers. Which is one of the reasons I really like using transfer decorators. Additionally, if you are in the habit of creating these properties on all your business objects, you could place these methods in a base decorator and call super.configure() within the configure() method of your transfer decorator.

Use Ant to Maintain Custom Framework Builds

2008 May 18
No Comments
I'm pretty new to Ant, so I'm thankful that a lot of other developers have examples and sample build files that I can use as a guide to learning Ant. After writing a few small build files, I wanted to tackle something a little more ambitious. I like to keep all the frameworks that I use up to date from their respective repositories, and, when deploying a new site or project, I will typically include the framework dependencies as a minimal include at the project root. This requires a bit of work, exporting and stripping out documentation, examples and tests from my local checkout of the framework files. As a learning objective, I decided to write an ant build file to maintain my own "nightly build" of each framework customized to carry only the core files.

read more...

cf.Objective() 2008 Reflections

2008 May 05
No Comments
I really picked a winner for my first Coldfusion conference. Unfortunately, I wasn't able to attend every session that I wanted, so I guess I'll have to come back next year! It's really hard to pick a favorite, but the Agile, Coldspring and Coldbox workshops all stand out. Over and above the excellent content and presenters, I got to meet and hang out with some really great folks. I'd start name dropping y'all, but you know who you are... The evening meals had a lot of variety. First there was the fabulous Brazilian churrascaria steakhouse Fogo de Chao, then two classics White Castle and Mickey's Diner, and finally the wonderful Sakura topping it off. Big thanks to Jared, Steven and the entire steering committee for putting on a great conference!

Transfer ORM Quickstart

2008 April 25
No Comments
Transfer ORM is, as the name implies, an object relational mapper for Coldfusion. Transfer has a myriad of advanced features which can be intimidating for newcomers. Fortunately, Transfer can be installed and used very easily without learning some of the more advanced features. What follows are instructions you can use to install, configure and use transfer in a few simple steps.

Installation

UPDATE: Transfer 1.0 is now available. The last official release of transfer is 0.6.3. This version is now quite old and it is recommended that you use the bleeding edge release (BER) from subversion. If you have any misgivings about using the BER, rest assured that many production systems are running the transfer BER. It's stable. To install the transfer BER, point your subversion client to http://svn.riaforge.org/transfer and checkout or export the source from /trunk/transfer. You can either set a mapping for "/transfer" in the cf administrator, or drop the source transfer folder in your web root.

Configuration

To use transfer in an application you'll need to setup two configuration files. One for the datasource that transfer will use and another to describe the objects that transfer maps from your relational database. These files are typically named Datasource.xml and Transfer.xml, but you can use any name you like and/or append a .cfm extension to prevent the files from being visible in a web browser. Datasource.xml The transfer datasource.xml config specifies the values for the following: - a datasource name that currently exists in the cf administrator - a username (if required - leave blank otherwise) - a password (if required - leave blank otherwise) <?xml version="1.0" encoding="UTF-8"?>
<datasource xsi:noNamespaceSchemaLocation="../xsd/datasource.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<name>dsn_name</name>
<username></username>
<password></password>
</datasource>
Transfer.xml The transfer.xml file is used to define the properties and relationships of transfer objects that are mapped to the relational tables in your database. Objects can have onetomany, manytoone, or manytomany relationships. The following xml is the object definitions from the tBlog sample app. <?xml version="1.0" encoding="UTF-8"?>
<transfer xsi:noNamespaceSchemaLocation="../xsd/transfer.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<InvalidTagDefinitions>
<package name="user">
<!-- User details -->
<InvalidTag name="User" table="tbl_User">
<id name="IDUser" type="numeric"/>
<property name="Name" type="string" column="user_Name"/>
<property name="Email" type="string" column="user_Email"/>
</object>
</package>
<package name="system">
<!-- Different categories for Blog Posts -->
<InvalidTag name="Category" table="tbl_Category">
<id name="IDCategory" type="numeric"/>
<property name="Name" type="string" column="category_Name"/>
<property name="OrderIndex" type="numeric" column="category_OrderIndex"/>
</object>
</package>
<package name="post">
<!-- A Blog Post, with a Decorator of type com.Post -->
<InvalidTag name="Post" table="tbl_Post" decorator="tblog.com.Post">
<id name="IDPost" type="numeric"/>
<property name="Title" type="string" column="post_Title"/>
<property name="Body" type="string" column="post_Body"/>
<property name="DateTime" type="date" column="post_DateTime"/>
<!-- Link between a Post and the User it who wrote it -->
<manytoone name="User">
<link to="user.User" column="lnkIDUser"/>
</manytoone>
<!--
Link between a post and it's array of Comments
-->

<onetomany name="Comment">
<link to="post.Comment" column="lnkIDPost"/>
<collection type="array">
<order property="DateTime" order="asc"/>
</collection>
</onetomany>
<manytomany name="Category" table="lnk_PostCategory">
<link to="post.Post" column="lnkIDPost"/>
<link to="system.Category" column="lnkIDCategory"/>
<collection type="array">
<order property="OrderIndex" order="asc"/>
</collection>
</manytomany>
</object>
<!-- A comment for a blog post -->
<InvalidTag name="Comment" table="tbl_Comment">
<id name="IDComment" type="numeric"/>
<property name="Name" type="string" column="comment_Name"/>
<property name="Value" type="string" column="comment_Value"/>
<property name="DateTime" type="date" column="comment_DateTime"/>
</object>
</package>
</objectDefinitions>
</transfer>

Integration

Using Transfer with Coldspring <bean id="transferFactory" class="transfer.TransferFactory">
<constructor-arg name="datasourcePath"><value>/config/transfer/Datasource.xml</value></constructor-arg>
<constructor-arg name="configPath"><value>/config/transfer/Transfer.xml</value></constructor-arg>
<constructor-arg name="definitionPath"><value>/path/to/definitions</value></constructor-arg>
</bean>

<bean id="datasource" factory-bean="transferFactory" factory-method="getDatasource" />

<bean id="transfer" factory-bean="transferFactory" factory-method="getTransfer" />
Using transfer as an application scope "singleton". <cfset transferConfig = StructNew() />
<cfset transferConfig["datasourcePath"] = "/config/transfer/Datasource.xml" />
<cfset transferConfig["configPath"] = "/config/transfer/Transfer.xml" />
<cfset transferConfig["definitionPath"] = "/path/to/definitions" />
<cfset application.transferFactory = CreateObject("component","transfer.TransferFactory").init(argumentCollection=transferConfig) />
<cfset application.transfer = application.transferFactory.getTransfer() />

Usage

To grasp the full breadth of the transfer API, you really need to review the Transfer docs. I'll cover the four methods you will likely work with the most in the beginning. They are, get(), new(), save() and delete(). Using the tBlog object definitions above, to retrieve a post object use: <cfset application.transfer.get("post.Post",1) /> To have transfer return a new instance: <cfset post application.transfer.new("post.Post") /> To modify and save a new post: <!--- create a new post --->
<cfset post = application.transfer.new("post.Post") />
<!--- retrieve category with id 1 --->
<cfset category = application.transfer.get("system.Category",1) />
<!--- set properties (not shown) --->
<!--- set category for post --->
<cfset post.setCategory(category) />
<!--- save the post --->
<cfset application.transfer.save(post) />
A small, but significant, benefit of using Transfer ORM, is that when you save an new object the object's state reflects it's new persisted state. So you can find out the new id by simply calling. <cfset newid = post.getID() /> Lastly, transfer delete() method works like save(), you pass the transfer object to the method. <cfset application.transfer.delete(post) />

Much, much, more

This quick start is intended to help impatient types (like myself) get a taste for how simple it is to start using Transfer ORM. As you become comfortable with the Transfer API, you will definitely want to explore features like Transfer Object Decorators, the Transfer Event Model and Transfer Query Language (TQL). Mark Mandel has put a great deal of effort to into Transfer since it turned POSS. If you are not comfortable using the bleeding edge source code from subversion, keep an eye out for a 1.0 Release Candidate.

My cf.Objective() Schedule - Focus on Frameworks and Automation

2008 April 17
No Comments
I've finally decided to stick with a theme for my first CF conference. The goal is to increase my frameworks acumen and better my development methodology. So with that in mind, here's my cf.objective() schedule. Let's hope it sticks.