Converting from Mach II to Fusebox 4

On November 19th, 2004 I converted this site from Mach II 1.0.10 for ColdFusion to Fusebox 4.1 Beta for ColdFusion. A lot of people immediately started asking why a staunch advocate of the Mach II project (and project contributor!) would switch to the other framework. I'll address my reasons (and they are many) at the end of this article (hey, don't just scroll to the bottom!) but first I want to talk about the actual experience of the conversion.

This isn't the first conversion I've gone through with this site. As noted on my blog, I've gone through all these:

Each conversion seems to be getting less and less painful which I attribute to streamlining the code and the URL structure during each conversion rather than any particular aspects of the frameworks involved.

No display fuse changes

Since the site was once a Fusebox 3 site, it should not be too surprising that I did not need to change any display fuse code this time around. When I moved from Fusebox 3 to Mach II, I kept the changes display fuse changes to an absolute minimum - each display fuse became a view in Mach II and I just added a couple of layout views to replace the nested layouts I was already using. Mach II has the notion of content variables (contentkey=) so I planned to use the same machinery in Fusebox 4.1 (contentvariable=).

A couple of my views had started to use the Mach II event object so they contained code like this:

<cfset section = event.getArg("section","0")/>
<cfif event.isArgDefined("archive")> ... </cfif>

I had a choice here to either change the views or to provide an equivalent mechanism. In order to increase 'portability' of my view code between Mach II and Fusebox 4.1, I decided to provide event object compatibility within Fusebox. In the fusebox.init.cfm file, which is automatically executed at the beginning of every request, I added the following code:

<!--- fake attribute lookup for compatibility with mach ii views: --->
<cffunction name="machii_getarg">
<cfargument name="arg" type="string" required="true"/>
<cfargument name="def" type="string" default=""/>
<cfif structKeyExists(attributes,arguments.arg)>
<cfreturn attributes[arguments.arg] />
</cfif>
<cfreturn arguments.def />
</cffunction>
<cffunction name="machii_isargdefined">
<cfargument name="arg" type="string" required="yes"/>
<cfreturn structKeyExists(attributes,arguments.arg) />
</cffunction>
<cfset event = structNew() />
<cfset event.getArg = machii_getarg />
<cfset event.isArgDefined = machii_isargdefined />

Mach II moves all the URL and form scope variables into a single event object; Fusebox moves all the URL and form scope variables into a single attributes struct. These UDFs provide a general level of Mach II compatibility within Fusebox 4.

Circuit definitions

Again, since the site was once a Fusebox 3 site, most of my URLs were already in the form of circuit.fuseaction - which I had preserved when I converted from Fusebox 3 to Mach II. In fact, as I'd added new events to the Mach II version of the site, I'd tended to stick to the circuit.fuseaction style of event name. Of course a few single word event names had also crept in (montana, machiirewrite, php2cf). I created circuit.xml.cfm files for every implicit circuit in the various event names in my mach-ii.xml file (actually my mach-ii-cf.xml file) - a total of fifteen circuits. Some of them were artificial sub-divisions so I just created a sub-directory whose circuit.xml.cfm file that included display fuses from the directory above - one of Fusebox 4's key strengths is being able to define circuits that have a name independent of its directory (and being able to define parent-child circuit relationships).

Mach II's single monolithic mach-ii.xml file becomes a series of small circuit.xml.cfm files. Common event handler code can sometimes be moved to <prefuseaction> / <postfuseaction> within a circuit (see Pros & cons below for more discussion of this).

Private viewing

Mach II requires that you declare every view, Fusebox lets you simply include a view file into a fuseaction. That means that where a Mach II event handler invokes a named view and requires a definition for that view, Fusebox lets you omit the definition part:

<!-- Mach II: -->
<event-handler event="foo.bar">
	<view-page name="foobar"/>
</event-handler>
...
<page-view name="foobar" page="/views/foobar.cfm"/>

becomes:

<!-- Fusebox 4: -->
<fuseaction name="bar"> <!-- in circuit foo -->
	<include template="foobar"/>
</fuseaction>

The location of the view is specified differently in Mach II and Fusebox (this was mostly a non-issue). The other difference is that Fusebox does not require the file extension to be specified (so that, in theory, a Fusebox application's XML files can be used with both ColdFusion and PHP).

Who's listening?

My site only used two Mach II listeners, neither of which really took advantage of the framework.

The email listener was a simple service CFC that had one method - which sent an email. Just remove the extends= attribute from the component and use the <invoke class="mailer" methodcall="..."/> verb (new in Fusebox 4.1).

The bookstore listener had a non-standard method which acted as the constructor and then provided a number of accessor methods used by the bookstore view to display various lists of books and authors. Again, I was able to remove the extends= attribute and simple instantiate the object:

<instantiate object="bookstore" class="bookstore"/>
<invoke object="bookstore" returnvariable="attributes.bookstore" methodcall="parseBookList()"/>

I think I had to add an empty init() method to both CFCs. If I'd had a configure() method (as I should have done) then I could simply have specified constructor="configure" instead. In other words, if I'd followed best practice, this would have been slightly cleaner.

Pros & cons

I guess this is going to be the controversial part. I'm a strong advocate of Mach II and I've also become an advocate of Fusebox. They have a lot of similarities and a lot of differences. Each framework has its own strengths and weaknesses. My site doesn't have much of a model behind it, very little logic, so Mach II doesn't bring much benefit to a site like mine - my site is mostly about simple views. Fusebox lets you include a view file directly in a fuseaction, Mach II requires that you define a view and then render it which means the XML is somewhat redundant.

Comparing the size of the XML files might be unfair but it represents a measure of maintainability. The Mach II version of the site had 425 lines of XML (nearly 16k of data). The Fusebox version of the site has 270 lines of XML (nearly 12k of data). Instead of one monolithic XML file, I have 16 separate files - that is both a pro and a con. One file is easier to manage in some ways but the size is a problem. Sixteen files is more of a maintenance problem overall but each file is easier to work with.

Code reuse: Mach II has no way to refactor event handler code for related groups. Fusebox allows you to group 'events' into circuits and then refactor code using <prefuseaction> and <postfuseaction> to simplify code. Both frameworks provide a variety of plugin points but they don't match - Mach II has pre-/post-view plugin points that have no Fusebox equivalent; Fusebox has a wide variety of plugin points that have no Mach II equivalent.

The areas where Mach II really shines are not highlighted by my site. My site's logic does not need filters or dynamic event queuing.

Why change?

There are several reasons why I changed my site from Mach II to Fusebox 4.1.

I switched my blog to Ray Camden's fine Blog CFC and then built a Fusebox 4.1 front end for it. Now that I've switched the rest of my site from Mach II to Fusebox 4.1, I'll probably build out a Mach II front end for Blog CFC. All of this informs the first point above - my talk comparing frameworks.