Can ColdFusion Handle Enterprise Applications?

There are a few common reasons given whenever a company says they don't want to use ColdFusion or a developer says "Oh, ColdFusion isn't a REAL programming language". One of these claims is that ColdFusion can't handle large scale enterprise applications. The majority of ColdFusion developers, especially the fanboys, immediately take offense and dive into a passionate discourse on the merits of ColdFusion, blah, blah, blah. I've done my fare share of CF-Evangelism over the years, and I do still believe that the merits of the platform make it a great solution a lot of the time... but I'm much more technology-agnostic these days than I was in my youth, and as I fall in love with other languages because of their merits, I find myself reflecting and sometimes re-evaluating my feelings about ColdFusion. In this entry I'd like to share my thoughts about CF: the good and bad, some advice for developers and companies, and some stories about recent real-world experiences I've had.

The Good
There are some things that make ColdFusion a terrific platform. Deployment is a breeze compared to most other programming languages. CFML is not a perfect language, but it is a simple language that makes most programming tasks easy to tackle. This tends to make rapid development easier to accomplish and lends itself particularly well to iterative, agile development practices and all that comes with it (like refactoring). This, coupled with the server error reporting and a few programming language constructs, also means that debugging ColdFusion applications is relatively painless and quick compared to other languages. Speaking directly to the questions of performance and scalability, it is possible to write applications that perform very well and scale exceptionally well with ColdFusion. For example, we (at Nylon Technology) recently successfully developed and deployed a large scale content management system across multiple servers and server instances. This CMS manages gigabytes of content (tens of thousands of pages) and has a lot of remarkable features (workflows, a robust permissions based security API, etc.).

The Bad
There are a few negatives about ColdFusion that should not be ignored. ColdFusion and CFML's ease of use means that you don't have to be a rocket scientist to use it. As I said, this is a strength, but it is also a weakness. There are far too many poorly developed CF applications "in the wild" and far too many "ColdFusion Developers" aren't good "Software Developers". I'm not saying all developers should have a degree in computer science, but more CF Developers should have a better understanding of the ramifications of the code they write, the limitations of the environment they're writing software in, and how to design ("architect") and develop applications that are not just modular, but easy to read, maintain, and extend. Sub-par programmers and poorly written applications will give any programming language a bad reputation. Coupled with the relatively small pool of available talent, it's no wonder some companies want to shy away from ColdFusion, is it?
So let's assume that good developers do create a well-written Enterprise ColdFusion application and have tweaked the hardware and JVM so that they know those won't factor-in as negatives - will it scale and perform well? The three second answer is "maybe... it might and it might not".
The Adobe ColdFusion Application Server is a commercial product and, as such, is a "black box". You write your code and save it somewhere that CF can see, and it "does it's magic" and spits out the results. If you don't like the results, you can change your code and try again, but you can't change what's inside that black box (i.e. the server internals). The most you can do is optimize the Application Server (CF and J2EE) and runtime (JVM) but not the way the server actually works with your code. This is obviously a problem if it turns out that some built-in ColdFusion function or tag is what's killing performance.
Though our client is happy with the CMS I mentioned earlier, along the way we did encounter several (performance related) stumbling blocks that were not the fault of the hardware or software architecture, but ColdFusion itself. One of the things that the CMS does is work with Objects (CFCs) a lot - and constructing/populating thousands of objects comes at a price. The CMS has a caching architecture that in simple terms boils down to storing CFC instances in a structure, using the ID of the content as the key name. We found that as the number of objects in memory grew, performance crept to a complete stand still - the server eventually died, as more and more threads timed out waiting for the threads that were accessing the structure keys to complete their job. Turns out that not caching the instances was the fix - but why? Because of a bug in ColdFusion that as far as I know, was first reported by David Sheldon on his blog at http://cfdumped.blogspot.com/2006/09/bad-hash-function-causes-problems-with.html. Maybe this bug doesn't affect the majority of applications, but for applications that need to store a large number of values in a complex data type, structures are not an option. One of the few fundamental data types in CF is broken - that's a big deal. I believe this issue was addressed in a CFMX 8.01 hotfix this year, but I haven't confirmed... and I personally think it's unacceptable for that bug to be made public knowledge and not be fixed for 2+ years.
We recently had another performance related issue with the application. The unique IDs of search results from a SQL statement are stored in a string and that string of IDs persisted and used for pagination. This is necessary because re-running the query isn't an option and storing the entire recordset would use far too much memory. So, the approach is right... but performance is abysmal (to the point that internal server errors are thrown) when lists get large - sometimes they're as large as 150,000+ (remember, this is an enterprise application and we need to work with huge volumes of data). The code that kept crashing looked something like this:
<cfscript>
for(j = 1;j lte listLen(daList);j++){
test = listGetAt(daList,j);
}
</cfscript>
OK, so you're thinking, "Remove the listLen() call from the loop condition" - right? We did, and it got a little better but would still time out sometimes and would be very slow other times. That code looks like:
<cfscript>
tmpVal2 = listLen(daList);
for(j = 1;j lte tmpval2;j++){
test = listGetAt(daList,j);
}
</cfscript>
Turns out that listGetAt() is just a horribly inefficient beast. Temporarily replacing the list with an array and then accessing indeces in the array worked like a charm and made an exponential difference to performance:
<cfscript>
tmpVal3 = listToArray(daList);
tmpVal2 = arrayLen(tmpVal3);
for(j = 1;j lte tmpval2;j++){
test = tmpVal3[j];
}
</cfscript>

The example of listLen() brings up a good question - is there something wrong with that code or is it fair to say that ColdFusion is to blame? Rather than answering directly, I'll describe how I view the roles and responsibilities of CFML and the (ColdFusion) server, as well as my own complaints/disappointments with each. We'll start with the language - CFML. The CFML programming language is not the problem - in fact I think it's a good language (note that by "CFML" I mean "CFML and CFSCRIPT"). When I first heard about the CFML advisory panel, though skeptical, I did think it was a good idea - I still do. However, what I believe we truly need is a real language specification - one that states how the built-in tags and functions are to be implemented. Of course, since Adobe owns the server, though they've put together an advisory board, they have not published the language as a public specification. I would be pleasantly surprised if they did. There are several good examples of how a language specification is implemented and of the benefits that come from a public spec. One example is ANSI SQL - if a vendor says they support it, you are assured that your SQL will work. Another good example is ANSI Common LISP - the specification states exactly what (and in many cases how) vendors must implement the language. If you write your applications in Common LISP, you know exactly what to expect from implementation to implementation. Unlike CFML, for which a public specification could easily be made, the ColdFusion Server is a product owned by an entity and it wouldn't be fair (or make sense) to publish a standard defining how to write the server. Perhaps there is a solution, though. At a high level, the server is responsible for serving two primary functions: it is a compiler and it is a runtime platform. Perhaps it does not make sense to have an open standard that states how the runtime must work internally (beyond a specification for the side effects and behavior of the CFML language constructs), but a specification for how the server works as a compiler, if expressed at the language construct level and as part of a CFML specification, is plausible. For example, in my first list code snippet I pointed out that the listLen() in the for loop condition (for(j = 1;j lte listLen(daList);j++)) was causing a serious performance problem because it's evaluating on every pass... but there's no reason that the server, when compiling that CFML, couldn't have introspected the contents of the loop and determined that it was safe to compile it as byte code that evaluates a number (instead of the actual expression) on each pass. "Compiler Optimization" is something I've learned a lot about in my continuing education and experimentation with LISP - and it's something that the Adobe Engineering team should be focused on. I'm not saying they aren't (I really don't know) - I know they do focus on making the internal server code faster (the actual tags/functions) and the compilation process faster, but I do not know if they look at ways to optimize the actual results of the compilation process (rather than the code those results executes). A language specification that defines the compiler behavior for some, if not all, of the language would be a huge benefit to all.

The bottom line is that in the Enterprise, ColdFusion absolutely can perform and scale very well - but that no matter how great the hardware, how tweaked the VM and servers, and no matter how well written and well architected the code base, a very resource intensive application may perform poorly for no reason other than what can only be nicely described as "quirks in the server".

Comments
I really like the post, and I agree with what you're saying, but I did have two minor issues I thought I'd mention:

" no reason that the server, when compiling that CFML, couldn't have introspected the contents of the loop and determined that it was safe to compile..."

It's not safe to compile, for example:

daList = "1,2,3,4,5";
for(i = 1; i lte listlen(daList); i++){
writeOutput(listlen(daList));
daList = listDeleteAt(daList, 1);
}

will produce the output "543", it only iterated, and should have only iterated, 3 times.

The compiler could try to check for cases like these, but it's hard to do in a dynamic language.

Also, CF doesn't have a List type, so if I'm not mistaking, anytime you call ListGetAt, you're parsing that string which is at best an O(n) operation. In most languages (and I imagine cf as well) an array look up would be O(1).

As your dataset grows larger, the ListGetAt call is going to be slower, but the array lookup should be the same.
# Posted By Joe Zack | 1/6/10 3:55 PM
Thanks for providing an objective POV of ColdFusion. I have used it for over 10 years now and really like it, but I also understand the merits of Java and .NET as well as scripting languages (PHP, Ruby, etc.) besides CF. It seems often times CF developers can fall into one of two camps: 1. CF Can do everything - There is no nail this hammer cannot pound, even if the nail is actually a screw :-).

2. If only CF could... - This group always wants to add or take something away from the language to make it more like something else. For instance, If CF just did X it could be more like (Java, C#, PHP, etc.)

I have spent time in both those camps at different points in my career. But ultimately long as CF Developers remember that CF is just a tool (albeit a good one for most tasks) and keep religion out of it, then things would be better. But I'm sure you could say this about any programming language and/or platform.
# Posted By James White | 1/6/10 4:05 PM
Joe,
You are correct about the performance factor because of how CF handles lists, but there's no specification that says "list functions treat strings like lists" and, to be honest, it shouldn't. When you operate on a value with a function, CF should cast it to the appropriate data type. I'd imagine it already does that in other places - we can treat arguments scope like an array or struct, and we can do the same thing with parsed XML DOMs. The bottom line is that having so many "list" functions in the language implies a data type, and that's a very misleading implication which also has serious consequences.
Regarding the "smart compiler" topic - that's what I am saying. The server should look at the code in the loop, determine that nothing in that loop has side effects (i.e. nothing in the loop can affect the value of the loop condition), and replace the condition with an actual value. That's what optimized compilers do in other languages - why not in CF? If nothing else, Adobe should publish documentation that clearly states exactly how the built-in functionality works as well as best practices. For example - they've always warned developers that if you know you're going to put more than 'x' indexes in an array, it's faster to resize the array THEN add the values. Adobe should, at the very least, provide additional guidelines regarding the use of other data types.
# Posted By Simon Horwith | 1/6/10 4:45 PM
James,
I completely agree - though I can also relate with the fanaticism at times. I've been called a "CF Fanatic" a "CFScript Fanatic" and a "LISP Fanatic" among other things... and sometimes it is hard not to get pumped-up when you start talking religion about these things... which is fine as long as you keep an open mind and don't make any stupid/costly decisions based on it. CF is a great tool... I do believe that wholeheartedly. I am also 100% sincere when I question the drawbacks of the black box. My job, like most of my readers', is to solve problems. Sometimes, though not too often, the problem IS the black box and when that is the case, Adobe hasn't given me everything I need (or, at least, would like) to solve these problems. This is the one advantage that Open Source Software has - if there's something wrong with it, you can get the code from a repo and figure it out.
# Posted By Simon Horwith | 1/6/10 4:53 PM
Simon,

I think you are correct that one should look at any language and all of its flaws and work around those problems. Since, CFMX is not a lower level language, one should look at possible performance problem first. Sometimes, we think OOP and frameworks is the answer to all problems when it could be the problem. As you stated concerning the performance with CFC's in earlier version of CFMX, one needs not to presume. I try not to be 'religious' about a language, but give the 'facts' and pros/cons about the best tool.
# Posted By Patrick Whittingham | 1/8/10 8:35 AM
if you can, use railo instead of adobe's cf engine in your project. i'm in total agreement with you that having bugs like the ones you described in adobe's cf for that long is completely inexcusable. i have had personal experience with the railo crew and can only say great things about them. in my experience i've seen that the railo crew takes performance and bugs extremely seriously. while railo might not have all the features of cf9, it is on par with cf8 and multitudes faster.
# Posted By tony petruzzi | 1/8/10 9:36 AM
I've tried to move away from using lists and related over the years for anything other than basic parsing purposes. CFML is the only language that I'm aware of that (until recently?) had more native functions for delimited strings than arrays. Also I've run into major memory issues with building nested structs and arrays that have really lowered my confidence in CF.
# Posted By Dan Roberts | 1/8/10 10:19 AM
Simon,

Glad to see a post like this. Completely agree about being agnostic and realizing the limitations. Interestingly I find I am using more calls to java classes/methods now to address various performance issues. I'm not a java developer, so having this has been a big help.

I wonder for your list problem if the java iterator function, which is array based would have worked. I wrote part of my security code in a framework using this (thanks to Ben Nadel for this)

objIterator = SecurityArray.Iterator();
checkSecVal = event.getCurrentEvent() & '|' & roleTask ;
   if (IsDefined("myUser.ROLEPERMISSIONS") ) {
   //first check to see if role allowed if not then check specific role, allow granular check
      if ( ArrayLen(StructFindValue(myUser.ROLEPERMISSIONS, checkSecVal) ) <= 0 ) {
         // User does not have permissions throw error page
         while (objIterator.hasNext() IS 'YES')
         {
         objTest = objIterator.next() ;
         if (objTest['NAMEDASSET'] EQ checkSecVal AND objTest['SECURITY_ROLE_ID'] EQ myUser.PRO_ROLE_ID) {
            // it passed
            break;
             } else {
                rc.checkSecVal = checkSecVal;
               Event.overrideEvent("ehGeneral.dspForbidden");
             }
                     }
                  }
                  // it passed
               }
# Posted By Kevin | 1/12/10 10:57 AM
Kevin,
Yeah - there are several ways I could get around the issue by using other data containers. In CFML, Arrays work... but I could have used something like an ArrayList in Java. I suppose my problem is that these days, every time I have to use Java in order to get around a shortcoming in ColdFusion, it makes me wonder why I'm bothering to use CF.

Speaking of which, due to the number of online and offline responses I've received from this post, I plan to blog more about how I currently view ColdFusion both in technical and business terms. Having been around in the CF world for as long as I have, and having filled every role from 'developer' to 'instructor' to 'CTO' over the past 15 years, I've got a lot to say... and my views have changed significantly. Until recently, I kept the blog focused purely on technical tidbits, but I think it's time to start sharing more of the information I have that's about substance more than syntax.
# Posted By Simon | 1/12/10 1:33 PM
Simon,

Glad to see a post like this. Completely agree about being agnostic and realizing the limitations. Interestingly I find I am using more calls to java classes/methods now to address various performance issues. I'm not a java developer, so having this has been a big help.

I wonder for your list problem if the java iterator function, which is array based would have worked. I wrote part of my security code in a framework using this (thanks to Ben Nadel for this)

objIterator = SecurityArray.Iterator();
checkSecVal = event.getCurrentEvent() & '|' & roleTask ;
if (IsDefined("myUser.ROLEPERMISSIONS") ) {
//first check to see if role allowed if not then check specific role, allow granular check
if ( ArrayLen(StructFindValue(myUser.ROLEPERMISSIONS, checkSecVal) ) <= 0 ) {
// User does not have permissions throw error page
while (objIterator.hasNext() IS 'YES')
{
objTest = objIterator.next() ;
if (objTest['NAMEDASSET'] EQ checkSecVal AND objTest['SECURITY_ROLE_ID'] EQ myUser.PRO_ROLE_ID) {
// it passed
break;
} else {
rc.checkSecVal = checkSecVal;
Event.overrideEvent("ehGeneral.dspForbidden");
}
}
}
// it passed
}
# Posted By puma | 2/2/10 2:25 AM
Thank you for an objective estimation of the ColdFusion. As for me, I like it. It satisfies my needs and plans. Maybe it is not good for diferent enterprise tasks but here we can follow now your advice. A very informative and essential post. Thanks!
Best wishes from Rain http://www.mp3hunting.com
# Posted By Rain | 7/16/10 6:06 AM
we think and frameworks is the answer to all problems when it could be the problem
# Posted By batterie | 7/21/10 3:35 AM
. The server should look at the code in the loop, determine that nothing in that loop has side effects
# Posted By labatterie | 7/21/10 3:36 AM
I am also 100% sincere when I question the drawbacks of the black box
# Posted By Rolex watches | 7/21/10 3:36 AM
I try not to be 'religious' about a language
# Posted By r4 ds | 7/21/10 3:37 AM
HUNW HUH http://www.ghohunag.com/
<a href="http://www.ghohunag.com/">wehhde</a>
[url=http://www.kfunag.com/]weode[/url]
# Posted By sheing | 7/23/10 4:00 AM
I like this article, this article that i learned a lot of knowledge.
# Posted By DVD Ripper | 7/25/10 9:23 PM
Thank you for sharing. it is wonderful super classic.
# Posted By blu-ray ripper | 7/25/10 9:23 PM
's helpful. thank you very much the share. you are very creative.
# Posted By DVD to AVI | 7/25/10 9:25 PM
He is quite a good reading. i'd appreciate it. time to realize his.
# Posted By DVD to iPod | 7/25/10 9:27 PM
It is my pleasure that I have the unique opportunity to comment on this awesome post. It is a very nice message and I have pretty good understanding of the subject.
http://simulationassuranceauto.org
# Posted By simulation assurance auto | 7/25/10 9:59 PM
This site is hosted by HostMySite and runs off of BlogCFC - thanks, Ray.