Sunday, December 13, 2009

ColdFusion shared scopes and race conditions

In a recent Google Group thread discussing the Singleton design pattern, Phillip Senn asked whether the application scope needs to be locked in onApplicationStart. Ray Camden answered with the following:
You don't need to lock if you let them run "normally." If you run the methods manually (many people will add a call to onApplicationStart inside their onRequestStart if a URL param exist) then you may need a lock. Of course, you only need a lock if you actually care about a race condition. 99% of the code I see in application startup just initializes a set of variables.
Ray's comment about not needing to lock when onApplicationStart is invoked implicitly during the application start event is completely correct. However, things get a little more complicated when you directly invoke the same method. Not only does it create race conditions, but the race conditions it creates are often not easily solved by cflock.

Let me explain with a story. Once upon a time a CF coder wrote some application initialization code that looked like this:
application.settings = {};
application.settings.title = "My application";
application.settings.foo = 42;
application.settings.bar = 60;
application.settings.baz = false;
To allow these settings to be reloaded, the coder added the following to onRequestStart:
<cfif StructKeyExists(url,"init") and url.init eq "abracadabra">
<cfset onApplicationStart() />
</cfif>
This worked fine in development and testing and so was deployed to production.

The application was successful and its usage grew. The original coder moved on to other projects and the maintenance was handed off to a new coder. Many months later the new coder noticed something. Occasionally, when the maintainer used the init=abracadabra parameter to reset the application variables, he would see errors pop up in the error log at the same time. The errors looked something like this:
Element BAR is undefined in APPLICATION.SETTINGS
The source of the error was not isolated to a single place in the code; it occurred in many different places in the application. The element also changed: sometimes it was BAR, other times it was BAZ or FOO or TITLE. The only thing in common to all the errors was APPLICATION.SETTINGS.

The coder couldn't see any pattern to the errors and so wrote it off as an anomaly; either an obscure bug in ColdFusion or some server misconfiguration. The errors continued but not frequently enough for end-users to really notice and complain about it.

Some time later, a project to add enhancements was approved for the application and another coder was brought in to assist the maintainer. The new coder is a bit of a "guru" and knew something about race conditions. When the code guru saw the strange errors he quickly identified the source of the problem: the initialization code contained a race condition.

By initializing the application.settings variable with an empty structure, there was a short period of time when the structure did not contain the title, foo, bar, or baz members. This is not a problem during the application start event because the event occurs before any normal request processing, but it is a problem if the same code invoked directly. If any other request thread tries to access one of those members after the re-init has created the structure but before it has assigned a value to that member, an error will occur.

So how did the guru fix the race condition? The naïve approach would be to simply put a cflock around the call:

<cfif StructKeyExists(url,"init") and url.init eq "abracadabra">
<cflock scope="application" type="exclusive" timeout="60">
<cfset onApplicationStart() />
</cflock>
</cfif>

However, to making this work would also require a read lock around every single access to the application.settings structure! A painful approach to say the least.

The guru knew a better way. He made some simple changes to the initialization code:

var settings = {};

settings.title = "My application";
settings.foo = 42;
settings.bar = 60;
settings.baz = false;

application.settings = settings;

Voila! By initializing the settings structure in a local variable and only assigning it to the application scope after it is fully initialized, the original race condition disappeared. No locking required!

The fix was deployed and the no trace of the error was ever found again.

Some time later, another coder noticed that he was seeing a similar problem in his application, except his errors were in the session scope and they occurred much more frequently.

The CF guru rolled his eyes. "Here we go again," he thought to himself...


Sunday, October 11, 2009

Model-Glue: Event result handlers

One feature of Model-Glue that seems to frequently trip newcomers is the <result> tag. I tend to call these result handlers, to distinguish them from results issued by controller methods.

A result handler is used in a event handler to specify which event(s) should be processed after the current event. A named result handler is fired only when a controller issues a result of the same name during the event, while an unnamed or default event handler is "always" fired and does not require an explicit result from a controller (except under certain situations that I will explain in this post).

However, a Model-Glue result handler has two quite distinct behaviours depending on the value of the redirect attribute:

  • When redirect="true", processing of the current event is stopped and the event queue is discarded. The framework then issues a to the target event. By default the event state is preserved and is available in the target event, but this can be overridden by adding preserveState="false".
  • When redirect="false" or is unset, the target event is added to the event queue. Because an event handler may have more than one <result> tag, an event handler may add more than event to the queue. After all matching <result> tags have been processed, the framework invokes the handler for the next event in the queue.
The basics of the <result> tag is explained in the Section 5 of the Model-Glue Quickstart.

A Model-Glue newcomer is likely to first think of <result> as a kind of GOTO statement and may not realize that multiple events can get queued by an event handler. In a recent post to the Model-Glue mailing list, a developer wondered why the following event handler did not work as expected when an error result was issued:

<event-handler name="signup">
<broadcasts>
<message name="doSignupForm" />
</broadcasts>
<results>
<result do="page.index" />
<result name="error" do="signupform" />
</results>
</event-handler>

What was happening of course is that both "page.index" and "signupform" were being added to the event queue. In this case the developer was seeing the view rendered by page.index, but the final rendering would depend on how the two target event handlers were written.

There are two solutions to this. One solution suggested by another member of the mailing list is to have the controller method issue a success result when there is no error:

<event-handler name="signup">
<broadcasts>
<message name="doSignupForm" />
</broadcasts>
<results>
<result name="success" do="page.index" />
<result name="error" do="signupform" />
</results>
</event-handler>



Another solution is to use redirect="true" to imbue the error result with the expected GOTO-like behaviour:

<event-handler name="signup">
<broadcasts>
<message name="doSignupForm" />
</broadcasts>
<results>
<result do="page.index" />
<result name="error" do="signupform" redirect="true" />
</results>
</event-handler>

One interesting feature of redirect result handlers that I've discovered is that they fire immediately upon a controller method issuing them. This means that any controllers that are waiting to process the current or subsequent message broadcasts in the current event will not be executed.

For example, let's say you wanted to use a message broadcast to log successful signups. One approach would be to add a second broadcast to your signup event:

<event-handler name="signup">
<broadcasts>
<message name="doSignupForm" />
<message name="log"> <argument name="message" value="Signup success" /> </message>
/broadcasts>
<results>
<result do="page.index" />
<result name="error" do="signupform" redirect="true" />
</results>
</event-handler>

If the error result uses redirect="true", this will work as intended because an error result would interrupt the event processing so that the log message would not be broadcast. If the redirect="true" is removed, the log message would be broadcast even on error results.

To get the correct behavior for a non-redirect result you must put the log broadcast in the target event. You may need to define an intermediate event for this. Here is an example:

<event-handler name="signup">
<broadcasts>
<message name="doSignupForm" />
</broadcasts>
<results>
<result name="success" do="signupSuccess" />
<result name="error" do="signupform" />
</results>
</event-handler>

<event-handler name="signupSuccess" access="private">
<broadcasts>
<message name="log">
<argument name="message" value="Signup success" />
</message>
</broadcasts>
<results>
<result do="page.index" />
</results>
</event-handler>
In this case I had to use a named result handler for success so that it would not be fired on error. I also declared the target event handler as private: this is to prevent anyone from triggering the event externally.

For the signupSuccess event handler I would make one more change. If a user signs up successfully and then triggers a browser reload, I do not want to process the signup event again. To prevent this, I could change the final result handler to a redirect:

<event-handler name="signupSuccess" access="private">
<broadcasts>
<message name="log">
<argument name="message" value="Signup success" />
</message>
</broadcasts>
<results>
<result do="page.index" redirect="true" />
</results>
</event-handler>
With this change, a user who successfully signs up would end up at index.cfm?event=page.index instead of index.cfm?event=signup. A browser reload at that point would simply reload the main application page instead of repeating the signup processsing.

Sunday, August 30, 2009

Challenging Ourselves with Progressive Enhancement

Introduction


Most Web coding these days is a jumbled mess of HTML, CSS, and JavaScript. I was starting to believe that this was simply an ugly truth I had to live with, but then I learned about progressive enhancement. Progressive enhancement (PE for short) is a Web design strategy that uses web technologies in a layered fashion to separate the jumble and provide universal access to basic content and functionality while also providing an enhanced experience for those with more capable browsers and bandwidth.

Following PE requires some discipline. I and many other long-time Web developers have gotten used to using presentation markup, inline styling and scripting because we started at a time when there was no other way to provide a suitable user experience. However, browser technologies have matured to the point where the developers are now usually holding back the technology rather than the other way around.

With this in mind, I wanted to come up with a few simple rules for guiding Web developers towards this new approach. My idea is to offer a series of challenges, where each challenge involves implementing some common Web development task while being restricted to a set of rules to steer the developer away from obsolete techniques and towards PE. My intent is to offer a way to gently introduce the practice of PE to Web developers (including myself).

The Challenge


The Progressive Enhancement Challenge consists of four rules and three levels. The rules enforce separation of the layers while the levels enforce the progressive construction of those layers.

The Rules

  1. All markup must be well-formed.
  2. Transitional or other pure presentation markup must not be used.
  3. Inline styles or scripting must not be used.
  4. All links to external stylesheets and client scripts must be within the document head.

The Levels


Each level must maintain all the levels below it, so levels must be constructed in order and higher levels must not break lower levels.

Level 1: Function

The application must provide all required functionality even when client scripting and/or CSS is disabled or not available.

Level 2: Presentation

The application's presentation should be enhanced with appropriate styling.

Level 3: Interaction

The application's client-side behavior should be enhanced with appropriate scripting.

Conclusion


If you're not familiar with current Web technologies, some of the rules may seem impossible. For instance, Rule #3 prohibits the use of HTML event attributes such as onload or onclick. The Progressive Enhancement alternative to event attribute is to use unobtrusive JavaScript techniques such as jQuery event handler functions. Likewise, most other popular techniques prohibited by the rules have better alternatives that are well support in all the major modern browsers.

The goal of this challenge is to push us to become better Web developers. As such, it is merely a means to an end, and not an end unto itself. While I'd like to see this create a little friendly competition between developers, the last thing I want is for people to take this too seriously. If you try to use progressive enhancement for real work and find yourself in a situation where sticking to these rules is proving too difficult, don't sweat it; your page won't crumble to dust if you break a rule here or there. And please, please don't create or put any badge graphics on your Web pages claiming they are Progressively Enhanced!

Stay tuned for some PE challenge exercises coming to this blog Real Soon Now(tm)!

Tuesday, August 18, 2009

Adobe ColdFusion: A new beginning, or the beginning of the end?

For my very first blog post I thought I'd start with some big thinking ... very big thinking.

Along with many other ColdFusion coders, I was excited about the recently released Gartner report on Adobe ColdFusion. The overall positive outlook by Gartner on the ColdFusion technology platform provided a welcome relief from naysayers dominating the CF blogosphere during the previous few months. Many of those naysayers seemed to be former CF coders that had left the platform years ago and were unaware of how the platform has evolved under Adobe's stewardship.

However, a closer read of the report reveals that the authors believe the "uptick" that ColdFusion is currently experiencing will be short-lived. While they see the value of the current ColdFusion platform in making it easy to build enterprise Web applications, they also see this value diminish over time as other factors become more important to organizations. Organizations looking to reduce the complexity of their technology landscape will steer towards broader platforms such as Java EE and Microsoft .NET. Organizations looking to reduce the cost of their technology landscape will steer towards Open Source platforms such as PHP and Ruby.

As much as I love coding in ColdFusion, I agree with this general assessment. Adobe has put a lot of work into the enterprise integration features of ColdFusion, and yet these features have not attracted the attention of many CF coders. For instance, XForms is a great open technology for separating a form's function from its presentation, yet ColdFusion XML forms (powered under the hood by XForms) is all but dead. The ColdFusion event gateway interface is an elegant way to perform asynchronous communication with everything from Google Talk to JMS brokers, but CF coders seem to be more interested in the cfthread tag. Many CF coders are interested in Flex for developing richer front-ends, but only a fraction of those seem to know what BlazeDS is or why they should care about it.

It looks to me that even though the ColdFusion platform has evolved a lot over the years, ColdFusion coders haven't changed much at all. The applications they build now may have richer interfaces using Flash and Ajax, but they are the essentially the same kind of applications they built before: Web front-ends to SQL databases. These are the types of applications that ColdFusion coders are most comfortable with; yet they are also the types of applications that any Web development platform can do, and therefore have the biggest risk of getting dumped in the context of larger technology strategies within organizations.

This is a great time to be a ColdFusion developer. It is also a very dangerous time to be comfortable with being a ColdFusion developer.

Fortunately I'm already uncomfortable as a ColdFusion developer. This is not because I am worried about the state of the platform; rather it is because uncomfortable with what I see as the status quo of ColdFusion application development. Some of it has to do with technology, but a lot of it has to do with process.

I see a lot of ideas and tools that have a lot of potential for improving outcomes in the delivery of ColdFusion-based business solutions. Here is a partial list of ideas that have captured my attention of late:
  1. Agile development practices such as Scrum to provide quality and value to clients more quickly and more frequently.
  2. Agile requirement practices such as User Stories to improve collaboration between developers and clients in finding features that offer real business value.
  3. Agile QA practices such as Test-Driven Development and Behavior-Driven Development to spread the cost of QA throughout the development process instead of leaving it to the end (where it almost always gets short-changed at the expense of the client).
  4. Testing frameworks such as MXUnit, Selenium, and Tellurium in conjunction with the above for a streamlined testing process instead of the usual hit-and-miss affair.
  5. Build automation tools such as Ant and Maven for stress-free deployment of Web applications, and Continuous Integration tools such as CruiseControl to manage quality levels during the project.
  6. Using alternate programming languages for back-end functionality in ColdFusion applications, from standard Java to the interesting dynamic language Groovy to the much more exotic language Scala.
  7. Using Progressive Enhancement and Unobtrusive JavaScript with Ajax libraries like jQuery for better collaboration between back-end coders and user experience builders to create rich and robust HTML front-ends.
  8. Techniques for refactoring application code to design patterns and refactoring databases for improving the long-term maintainability of applications.
  9. Designing service interfaces for ColdFusion back-ends that can be simultaneously exposed through traditional HTML front-ends, Ajax front-ends, Flash remoting and Web Services.
  10. Improving the cacheability of Web interfaces by proper use of HTTP features and implementation of REST concepts to improve performance and scalability.
I think 10 items is a good place to end my brain dump for today.

As you can see, I'm not short on ideas for moving beyond "comfortable" ColdFusion development. The real trick is going to be in identifying ideas that I have a real chance at actualizing, and then making it happen. It won't be easy: with the only person asking me to do this being myself, I'll have to be harder on myself than usual to build and maintain momentum.

If and when I start on any of this I'll post it here.