What I did to Mach II

There has been a lot of interest in the steps I took to optimize my client's website. The main interest was in what I did to Mach II in order to speed it up, especially as Mach II is rather optimized to start with. The answer is to cheat.

If you look at the Mach II code you'll see that it's rather complex. It's also 1000% legal. Every component is documented as is every cfcomponent and cffunction tag. Output="False" is used everywhere needed, access is always defined, every cffunction tag has a returntype and every cfargument tag has both a type and a required when needed. It is this attention to detail and legality that gives Mach II and every other CFC based framework it's unexpected overhead.

Let's start with the cffunction tag. The returntype attribute performs a data validation on the information being returned from the function. Any validation operation has a certain amount of overhead and when the validation is done against a component reference then the overhead becomes more noticable. In addition, I find the returntype to almost be an insult. If I wrote the function then I should have a relative clue as to what it is returning. If the returntype is only being used for documentation rather than for actual validation, then that information can be put in the hint.

But wait! I'm not saying to remove the returntype. It is actually rather important to the operation of a function. What it does beyond data validation is tell ColdFusion IF the function is returning anything. For this reason I always have a returntype defined but its value will either be any or void. Any basically tells ColdFusion that the function is returning something but that it should not worry about validating it. Void tells ColdFusion that the function will not return anything at all. If a cfreturn tag is used within the function then an error is thrown.

Original cffunction tag
<cffunction name="getDefaultInvoker" access="public" returntype="MachII.framework.ListenerInvoker" output="false" hint="Returns an instance of the default invoker (EventInvoker) for this Listener.">


Modified cffunction tag
<cffunction name="getDefaultInvoker" access="public" returntype="any" output="false" hint="(MachII.framework.ListenerInvoker) Returns an instance of the default invoker (EventInvoker) for this Listener.">

The removal of the returntype alone causes a noticable speed increase for components that are heavily used. If we take the same idea of removing data validation and apply it to cfargument tags then we'll see even more of an improvement. There are actually 2 different types of data validation going on in a cfargument tag. The first is the same data type validation as defined above and this is defined by the type attribute. The second is a check for existance and is defined by the required attribute. The total removal of both of these attributes increases the savings we get from the removal of the returntype. I do one additional thing, though. I add a hint attribute to the tag, which will tell me what data type was expected and if it was required. This is for documentation purposes only, but does help when debugging.

Original cfargument tags
<cfargument name="eventName" type="string" required="true" />
<cfargument name="eventHandler" type="MachII.framework.EventHandler" required="true" />
      

Modified cfargument tags
<cfargument name="eventName" hint="(required - string) what the data should be" />
<cfargument name="eventHandler" hint="required - component) MachII.framework.EventHandler being passed in" />

The removal of the type and/or required attributes from the cfargument tags is not without consequences. There are times where a function needs to be sure of the data being passed in. I judge these on a case by case basis, but when it comes to Mach II I didn't even bother. Mach II is so solid in its construction that every function is very exact in what gets passed to and from it.

As a final warning, remember that Mach II is a closed system that has been heavily tested and is only modified by a select few. No one is supposed to be touching the core code other than those select few. Because of this strict control, I felt very confident in my alterations and they worked flawlessly. In the end thats all that matters to a client...has the job been done.

I don't hate Mach II

I was doing a remote presentation last night on "Object Orienter Programming for ColdFusion Developers" and it eventually moved over to the topic of optimizing ColdFusion Components. While I was showing what I do for speed, I relayed a story about a client of mine who is using Mach II. I was brought in to speed up the clients site which was timing out on a regular basis.

After a review, I found some places that could be optimized and one major place was the Mach II code. I rebuilt most of it and the time savings was immense. Of course, in order to make it faster I had to cheat and break many of the accepted 'rules' of OOP and CFCs. Not something that I suggest anyone doing without a full understanding of the how and why of it (which I'll talk about another time).

After telling the story and showing what I did, someone assumed that I did not like Mach II and asked what Framework I used. I quickly corrected his conclusion and told him not only do I have nothing against Mach II, but it's a really well thought out and solid framework. I don't use it because I don't use any of the public frameworks. I'm obsessed with optimizing my code for speed and performance and really optimal code doesn't go hand in hand with frameworks. On the other hand, I stressed that using a framework is a MUST in almost all situations and that people should not go my route unless they really know what they're doing and have very strict control over who has access to their code.

Bottom line is that unless your a paranoid, obsessive, hermit programmer, use a framework!

StructKeyExists vs. IsDefined when checking 2+ scopes

There has been a movement away from using the IsDefined() function to using the StructKeyExists() function. The reasoning is that when IsDefined() is used to find an unscoped variable, it follows a specific order of scope evaluation that goes through over half a dozen scopes (9 actually) in order until it finds the variable or fails. StructKeyExists() on the other hand requires a scope and limits the search to that scope.

Note: There is a thought in the community that StructKeyExists() is more efficient than searching for a scoped variable using IsDefined(). I can't comment on this as the difference is probably tiny.

Note: I say over half a dozen rather than 9 as some of the scopes 'exist' but are empty unless specifically used (cffile, url, form, client) or only exist in certain places like the arguments or the 'unnamed local scope' in a UDF.

Now all of this is fine and good, but what happens when a variable may exist in one of two scopes, such as Url or Form? In such a case, most people move back to an unscoped IsDefined() search. I suggest instead to simply use two StructKeyExists() functions and trust in ColdFusion's short circuited boolean evaluation to keep things efficient. All you have to do is make sure you check the scope where you expect the variable to occur most often first.

For example, this CFIF is expecting an email passed to it from an URL or Form. The URL is the most common way in which the email will be sent so I check the URL scope first.

If the email variable is passed on the url, then the second StructKeyExists() will never be processed and the end result is a single function use. In the worst case all you are doing is running 2 functions against 2 (probably small) variable scopes rather than running through half a dozen, at least one of which (CGI) is rather large.

Of course the use of 2 functions may be less cost effective and I await the word of someone like Sean who knows the inside of ColdFusion better than I.

Those who a simple explanation of short circuited boolean evaluation can read this Fusion Authority article from 2000 which details it rather simply: ColdFusion with Style

BlogCFC was created by Raymond Camden. This blog is running version 5.9. Contact Blog Owner
House of Fusion | ColdFusion Jobs @ House of Fusion | Fusion Authority