CFLOCK Further Explained!

In a comment on my recent post explaining CFLOCK (http://www.horwith.com/index.cfm/2008/4/28/cflock-explained), Duncan asked an excellent question: "why has the (cflock) Scope attribute not been deprecated?". He also pointed out that I made the statement in that blog entry that "we won't discuss scope locks since their use has not been recommended since ColdFusion 5". Addressing Duncan's question isn't as straight forward as I'd like because I have to make some assumptions and draw on personal experience, and even then the answer can be somewhat confusing... so in order to do so I felt I had to post my response in the form of a blog entry.

First, to address the question as to why the "scope" attribute hasn't been deprecated (Duncan pointed out that in CF8 they even added a scope - you can now specify "request" as a valid value). The truth is, I'm not sure why it hasn't been deprecated because, if you read the available CF 8 documentation on locking http://livedocs.adobe.com/coldfusion/8/sharedVars_01.html#1159066, it appears to be absolutely no different to a named lock - you're just using the name of a scope and specifying it via a different attribute. One possible difference is that in the case of session scope locking, it's reasonable to assume that the tag is "smart" enough to limit the lock to THAT USER'S session scope (and not effect other users' sessions). You could still achieve the same result by doing something like name="session#session.sessionid#", though. One of the things I dislike most about ColdFusion is the fact that, being a commercial product owned and controlled by a company, not enough of the details of its inner workings are explained. If someone on the CF Server team would like to clarify the difference between how CFLOCK works internally depending on whether it's named or has a scope specified, it'd be greatly appreciated.

I promised a confusing response, and that didn't seem too confusing, did it? If you took the advice I just gave and read everything in the documentation about locking variables however, then you are probably extremely confused at this point. The reason being: the documentation is in direct conflict with my statement that you don't need to lock scopes and that it's not a recommended practice. So what's the truth?

It is true that ColdFusion is thread safe - this means threads will not try to modify the same variable simultaneously. However, Adobe does not guarantee the order in which the server, which is a multi-threaded engine handling a lot of simultaneous requests (among other things), will execute those threads. In other words, while trying to read and write to the same variable with 5 simultaneous threads won't crash the server, there's no guarantee in what order those threads will execute. This can cause inconsistent/inaccurate data. Basically, take my prior discussion about race conditions and apply the same principals to server threads in an environment where extreme load is causing VERY frequent simultaneous writes/reads to the same variable. Another environment where this may be an issue is in the case of a very slow server where processing isn't measured in milliseconds. The only way Adobe will guarantee data integrity is if you lock. Now, I have some thoughts on this.

First, I'll state for the record that I've never seensuch extreme load on CFMX servers that unlocked scope access caused incorrect results... this includes one environment in which the load was so great that CF had to be all-together abandoned (yes, that's A LOT of load). I'll also say that, in an application that follows what I'd call "ColdFusion Software Architecture Best Practices"), there is a very unlikely chance of data becoming corrupt in any of the ways described in the documentation. So maybe if you write really poor code you should play it safe and use a lot of CFLOCKing (remember though, CFLOCK will slow down your app). I also think it's worth noting that in the two environments I describe where the problem is more likely to arise (that of a server under massive load and that of an extremely slow server) there is a better answer. A server under THAT much load probably means (hopefully means is more like it) that you can afford to buy more (or better) servers. In the case of a server that is taking a really long time to process threads/requests - I'd say you've got bigger problems to worry about. Either way, based on my past experience, I wouldn't use scope locking.

Hopefully, that helps to clear things up. Again, I would love for an engineer from the CF Server Team to chime in on this one.

Still Looking For a Few Good Men (or Women) in New York

Nearly four months ago I blogged about needing to hire CF developers (http://www.horwith.com/index.cfm/2008/3/19/hiring-loads-of-developers-in-new-york). We made some good PM and developer hires... and now I need to make some more!

There are three different candidate profiles I'm looking for:
  • Senior Developer - you can work independently, are a strong developer, and can lead a project/team and mentor others... I'd expect you have 5+ years of experience but it's possibly you could have less experience and still be at this level
  • Mid-Level Developer - you can work independently and handle constant change in projects, as you'll be doing a lot of maintenance when you're not on new projects... I'd expect you have 2+ years of experience
  • Intern/Apprentice - this individual will be working directly with and for me pretty much exclusively - programming, documenting, researching, and doing business stuff for me (attending meetings, etc.). This candidate doesn't need any CF experience (some is great, though) but has some IT experience, ideally some programming experience, and is a fast learner who's interested in learning.

Anyone interested should email me at shorwith at nylontechnology dot com for more details or send me a resume/cover letter at that address.

Four things you should know in advance:

  1. These are full-time positions
  2. I'm not open to remote/telecommuters at this time
  3. These positions are in my office, located in downtown New York - you've got to be able to come in for an interview, but I'm open to relocation if you need it
  4. If you're a head hunter/staff augmentation company, don't email me without attaching a resume(s) and don't waste my time if the candidates don't match any of the profiles described above

We're a fast growing company that's been around for a long time (in web years, anyway) and these are good opportunities to work on some exciting projects with some good developers... I hope to hear from some good candidates soon.

Apologies if my server just bombarded you with email

Just a quick note - I noticed something really wrong in how my mail server was configured (one of my security settings was reset when I upgraded the mail software about 7 months ago) so I had about 7 months worth of undelivered mail in my CF Server undeliverable folder. Rath than killing it, I decided to push it out... better late than never, I suppose. I apologize to anyone who's inbox was attacked ;)

Why Can't I Run More Than One Server Instance at the Same Time?

Many developers, myself included, like to set-up their local development environment to run ColdFusion on top of a local J2EE Application Server. There are a lot of reasons to do this: you can run multiple instances (and play with J2EE settings per instance), run different versions of CF side by side, and deploy other J2EE apps (like LCDS or BlazeDS) to name a few.

I was recently setting-up a new development machine in this manner: installing databases, IDEs, application servers, etc. After running through the whole set-up, which is something I can do in my sleep having done it so many times over the years, I was surprised to find that this time, for some reason I couldn't start any instances on the machine. Slight correction - whenever an instance was already running I couldn't start any other instances... that's important to note. This was a first for me.

Whenever this happens you should immediately suspect your jvm.config file, as it's shared by all your instances when they start. If something in that file locks a resource (usually a port) then the other instances won't be able to start. You should also, if you aren't already doing so, immediately try starting your instances from a console window so that you can see what's going on when the instance tries to start. The culprit, as it turns out, is the ColdFusion 8 debugger.

In order to use the interactive/step debugger that ships with CF 8, you need to set up and use the Eclipse/CFEclipse debugging environment, but not before first configuring your server for debugging. The instructions are in the CF Documentation - online at http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=usingdebugger_4.html. If you read the instructions in the documentation you'll note that in a J2EE (multi-server) environment, in addition to enabling/configuring debugging in the CF Administrator, you also need to add a few extra arguments to your jvm.config file. The arguments look like: -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address= - where matches the port number in the CF Admin debugger page. The default port is 5005. Not so coincidentally, the errors I was seeing in the console window were all alluding to the fact that port 5005 is already in use.

So, if you want to use the interactive debugger in a multi-server environment, be sure to have each J2EE server instance start-up using a different config file (use a "-config" flag at the command line or in the service definition) and in each config file specify a unique debugger port: making sure, of course, that each instance running ColdFusion also specifies the same unique port in it's CF Admin debugger page. On Windows you can see what ports are currently in use by opening a command prompt and typing: netstat -an |find /i "listening". If you have instances not running CF, they can all start with the same jvm config file... provided that it doesn't contain the parameters for CF debugging. I haven't tested this, because my other instances didn't need debugging, but I hazard to guess you can use pretty much any port not already in use as a debugger port. The documentation doesn't mention any of this... at least not anywhere that I could find.

I was really surprised that nobody has blogged about this issue, but I searched a bit and didn't see anything. I keep getting the odd feeling that there must be something I'm missing... but until I find it, I'm going to call this one a bug (in the documentation, at least). Hopefully, this entry helps someone out there who's banging their head against the wall...

Addressing A Comment About Array Syntax

In the comments to my last post (http://www.horwith.com/index.cfm/2008/7/2/frequently-under-implemented-cf-functions#comments) Ben Nadel made a few comments that require a lengthy enough response that I had to post a blog entry in response to clarify my position. Let me begin by first thanking Ben for "forcing" the issue - that's a very good thing. Now, to address his comments/concerns.

First, to address my comment that "I would also, probably 99% of the time, not hire a candidate who did it on a code test" - referring to dynamically naming a variable inside if quotes on the left hand side of an equals statement in a set. Yup, I definitely stand by that statement. "Yes", Ben, for using a "documented feature of the language" and "No", it's not at all "silly" nor should you "pretend you didn't read that". I stated quite deliberately that I wouldn't be likely to hire someone who did that on a code test. After 13 years of doing code reviews, peer evaluations, and troubleshooting other people's code believe me - I know what's easy to read and maintain and what isn't. I'd never fire a developer for doing it, but in the code you submit for a code test that's part of a job interview, you're supposed to be submitting a sample of the best work you can do. Though I do first need to determine if you can technically fulfill the role you're applying for, after that the first thing I care about is whether or not your code will be easy to read and maintain... and that type of code is not. I'm expecting a great example of your work in an interview. If it helps to put things into perspective, I'd also be unlikely to hire someone who did a "SELECT * FROM" in a query they submitted as part of an interview code test, too. If you want more examples I've got a ton of them... there are plenty of things that you REALLY don't want to submit to me (or anyone else) when you're interviewing for a job (how about CFINSERT or CFPDATE tags to name a few more?)

Now, to get to the "meat" of Ben's comment that needs addressing - the statement that array notation "seems to be a bug and violates the general rule about struct notation". Wow - I'm not sure where to start. First of all, it's not at all a bug, it's quite deliberate and it works exactly as it should 99% of the time (I keep using that number - "perhaps I do not know what it means"... or I'm just generalizing). The example given (http://www.bennadel.com/index.cfm?dax=blog:224.view) is a specific example of a bug in how the caller scope works within custom tags (the first comment to the post, made by Ray Camden, even states that very fact). While I'm still on the subject of things I don't ever want to see from applicants (or in ANYONE else's code in general) - you should not pass a string that "paths" a variable in the request scope to a tag and then set it in the caller scope. While I do agree that what Ben stumbled on in that experiment is a bug in the server behavior, it's also only able to be replicated if you do something completely wrong in your code to begin with. The caller scope is supposed to be a pointer to the "variables" scope of the page that called it... you shouldn't be trying to force it to do something other than that to begin with. From an architecture point of view, encapsulated code is supposed to be data-in and data-out... the last thing you should ever do is try and "force" encapsulated code to set a variable in a specific scope - that violates so many best practices that I don't know where to begin.

Getting back to the behavior Ben discovered and describes in the blog post he referenced, array notation per-se, work exactly as it should everywhere that I can think of, and under "proper use" that includes the attributes scope. Also, I see know evidence that it has "clearly been overloaded in an undocumented way" any where but in the example he showed... and if you use the caller scope as intended (to write to the variables scope of the caller page) you'll find that it works just fine as well. Array notation is not a bug, so please don't call it such and please try to use it (at very least, I don't think it's fair to tell people they shouldn't use it). If nothing else, you'll be glad you did when moving to other environments (so many of which support array notation for accessing object properties and associative array keys).

For the record, this wasn't an attempt to pick on Ben or to flat-out reject what he had to say (I suppose I owe you a coffee after this one, Ben)... the world needs guys like Ben to try and hunt down obscure behavior. The simple fact that his commentary prompted me to write this post is a testament to the value of his input. It's ALWAYS important to see/hear both sides of any argument - no matter how much people may religiously oppose or support your opinion. It also happens that in this case I also happen to be very confident that I am able to show that the arguments aren't that relevant. There also isn't necessarily a "right or wrong" answer in this case, but hopefully folks have gotten some food for thought from it all.

Frequently Under-Implemented Functions

There are a select few CFML functions that are often times not used despite the fact that they are the most elegant solution to a problem. Why some are overlooked and others are not, I don't know. Nic Tunney recently blogged his thoughts on the 6 top underused functions in CF (http://www.nictunney.com/index.cfm?mode=entry&entry=E1E350D7-FF61-56C5-E94CA390F9B3D0F0) and it makes for a good read, especially if you're just starting out with CF. There are also some interesting additions to the list in the comments on that post. I thought I'd add two more to Nic's list (I mentioned them in a comment on his blog but wanted to explain further here).

The first overlooked function I'd add is setVariable(). This function does just what it sounds like - it creates a variable and assigns it a value. Yeah, there are loads of other ways to do this... why is setVariable() different? The name of the variable is dynamic - VERY dynamic. I say "VERY dynamic" because setting variables with dynamic names is a very common task, and more often than not simple array notation is all you need (ex: variables[myVarName] = 'foo';). In the case of setVariable() the first argument is the name of the variable - this string can be built as dynamically as need-be (the second argument is the new variable's value). This flexibility is not needed too often but is extremely useful when you begin dynamically setting values that are nested very deep inside complex variables. Specifically, I've found it to be the only elegant solution for dynamically changing values of values nested deep within an XML DOM when you can't easily determine how to create the alternative array notation needed to access the value (you don't always know the child position of every node in the path from the root node to the value you're setting).

The other often times overlooked function I wanted to mention is structAppend(). If I had a dollar for every time I saw code that loops over structure A and create a key in structure B with the same name and value, I'd have a fat wad o' cash. One of the cardinal rules of performance tuning/troubleshooting that I teach in my custom architecture classes is to suspect loops - i.e. "never loop when you don't need to, and always be extra-careful about the code you place inside the body of your loops because it's going to be repeated. In the case of developers not using structAppend(), we're talking about looping when you don't need to. Here's what the 'bad' code and the 'good' code look like side by side:
<cfscript>
   // BAD CODE for looping over the URL scope and 'copying' it's members into the form scope
   for (i in url){
      form[i] = url[i];
   }
   
   // GOOD CODE for looping over the URL scope and 'copying' it's members into the form scope
   structAppend(form, url, true);
</cfscript>
Anyone have any additional 'hidden gems' besides those mentioned here and on Nic's blog?

GAIA - Finally, A Flash Framework I Like!

I recently heard about GAIA - a new framework for creating Flash applications and thought I'd check it out. I haven't had time to use it extensively at all yet, but so far I'm very impressed with what I've seen - it's small and lightweight, and doesn't appear to try and do too much for you (unlike some of the other frameworks out there). It also has a very simple API and an easy to use panel in the flash authoring environment. My biggest complaint so far is that there's no Flex Builder version of the panel. GAIA creates a scaffolding driven rapid development environment and allows you to make use of the timeline or pure AS for navigation tweening.

Whether you decide to use GAIA in production or not, one thing is for sure: it certainly makes the process of creating Flash prototypes for clients as quick and painless as possible. If you build RIAs, I strongly suggest visiting the GAIA website at http://www.gaiaflashframework.com/ and taking a look for yourself.

Adobe Adding CMS Capabilities to ColdFusion?

I'm not saying (nor do I know) that Adobe will or will not ever integrate Content Management System features into the ColdFusion product. It is something that wouldn't suprise me to see at some point. Let me explain why.

First, there is (was) Spectra - the Allaire CMS written entirely in ColdFusion. At the time it was an impressive example of what you can do with CF, but it had serious architectural and performance issues and, ultimately, failed as a product. There clearly is a market (otherwise Spectra never would have existed, companies like Paperthin wouldn't be alive and well, and there wouldn't be so many CF based CMS offerings available) and the first priority of the CF Product Team when deciding what new features to add to the product has always been, in my experience, features that can be monetized. In other words, the features that Adobe thinks will help sell more licenses or that their biggest spenders (paying customers) want get high priority. CMS capabilities could be on this list.

The second reason to think it could happen is to look at LiveCycle ES. About 2 weeks ago, Adobe announced that they are adding Content Management capabilities to LiveCycle ES by integrating the open source Alfresco CMS (http://www.alfresco.com/). Clearly, someone at the company not only still believes there's a CMS market out there that Adobe should go after, but this recent announcement describes a CMS in which you have CMS functionality delivering content that takes advantage of the best in data visualization, user experience, and document management by leveraging Flex 3 and Acrobat. If I were a large enterprise company (or making purchasing decisions for one) I'd want to "run out and get me some". The Adobe Press Release, by the way, is online at http://www.adobe.com/aboutadobe/pressroom/pressreleases/200806/061708AdobeLiveCycleES.html.

Getting back to the topic at hand - "why would I say that there's a chance Adobe could integrate CMS functionality into CF?" - there's a third reason, which these first two offer evidence to support. When Allaire (just prior to the Macromedia acquisition) first publicly announced and showed the Java-based CFML server that would become CFMX (they showed this in the keynote at DevCon 2000 in Washington, DC) they cited a few reasons for the server rewrite. One of the primary reasons cited in that keynote for the move to Java, if my memory serves correct, was the abundance of open source code available that they could take advantage of. Hmmm... sound familiar? If not, go back a paragraph and re-read what I said about LiveCycle ES having an integrated Alfresco CMS. I can't think of any technical or legal reason that Adobe couldn't also just integrate Alfresco with CF - so adding CMS functionality to CF isn't really such a daunting task for the engineering team, is it? The idea that CF would be made better because the CF Engineering team can take advantage of the Java Community has, so far, held-up very well. So many of the CF features are really open source Java exposed in a nice friendly way (log4J, JAAS, etc.) and CFUnited this year included a sneak peak of CF with integrated Hibernate ORM functionality.

I don't want to say anything more about the topic of Open Source Java being dropped into CF, as I do plan to write extensively about the future of CF, as I see it, in the very near future. I was thinking about the new CMS functionality in LCES and it got me thinking... and I just thought I would share. By the way, with regards to whether or not integrating CMS functionality into CF would be a good thing or not, I'm on the fence. There's definitely a large part of me that really detests the idea, but in all honesty I couldn't blame them... it probably would help sell a lot more servers. It would, unfortunately, most likely put a lot of CF developers out of a job, too. What do you think?

Lack of Snipex Security - Bug Mark Drew About It

If Mark's anything like me, he tends to getting to things quicker when more and more people bug him about it. If you haven't taken a look at Snipex yet, you should (http://snipex.riaforge.org/). It's a CFC and tiny database schema that allows you to set-up a central repository of CFEclipse snippets. It's a great idea... but unfortunately there's no way to secure it. The CFEclipse plug-in doesn't support challenge/response authentication. Even if you want to put together a quick security hack to secure your company snipex server by requiring a URL variable that only you and your internal employees know about, you're out of luck... the plug-in doesn't appear to support that either.

I already spoke with Mark about the issue recently at CFUnited and he was 100% on-board with the idea that it should be able to run in a secure manner, and I've already created a ticket in the CFEclipse Wiki... but like I said, bugging people makes them do stuff. So if you know Mark, bug him for me!

BTW - I really only blogged about this to make people aware of the fact that if you use a snipex server, you can't easily secure it in it's current state so be careful how/where you deploy it if you need to. Don't give Mark a hard time. We're buddies and I'm sure he'll get to it when he can... AND he's taken on one of the most thankless but important jobs available in the CF Community. Keep up the good work, Mark!

A CF 8 Race Condition to Avoid

I recently stumbled across a scenario in which what appears to be the most flexible way to write some code ends-up introducing a somewhat nasty race condition that breaks your ColdFusion 8 application. In Application.cfc you can specify application settings such as session behavior and the application name - in CF 8 you can also specify application specific custom tag paths.

It's not uncommon for a company to have a template or template files that they use when creating new applications - these "skeleton files" often contain common or "generic starting point" code that you then build upon. We have a core CFC code base that requires a mapping to use easily across every application... so I thought it made an awful lot of sense to have something like the following in our "skeleton" Application.cfc file for defining each application:
<cfscript>
   // change per app
   this.name = '[your_app_name_here]';
   this.sessionManagement = true;
   this.sessionTimeOut = createTimeSpan(0,0,20,0);
   // change per app (add paths)
   this.customTagPaths = '';
   this.customTagPaths = listAppend(this.customTagPaths, expandPath('path-to-our-code-library'));
</cfscript>

Note that each application can set their custom tag path to whatever they want, and the code in the skeleton file will always append the path to our core code base to the custom tag path. Makes a lot of sense, except for one small problem: this code exists outside all of the server event handler methods, so it runs on every request. For the brief period of time between when a request runs the line of code that initializes the custom tag path and the line of code that appends the core library path to the custom tag path, any code that executes for any user that requires the path to the core code library to be in the tag path will fail.

The CFCs in the core library, as you'd imagine, are used in several server event handler methods including the onApplicationStart() and onSessionStart() methods - so the core library must be added to the custom tag path in this script block outside the event handler methods. If you don't believe me, try hitting an app. that appends to the tag path in this manner with some load. If you have long-running code blocks that rely on the mapping you will, of course, find it much easier to see the errors get generated.

So the moral of the story is, if you want to be safe, do not append to the custom tag path in your Application.cfc files - like the infommercial says, just "set it and forget it".

More Entries

This site is hosted by HostMySite and runs off of BlogCFC - thanks, Ray.