ColdFusion 10 recently shipped… congratulations to the Engineers, Product Managers, Evangelists, and testers. Great work. It’s time now to start planning for CF 11. Herein I offer my unsolicited advice… a wish list, if you will.
tl;dr
- I want to code in Groovy
- I want safety by default
- I want a Grails-like framework
- I want Package management (plugins)
- I want GPars or Akka concurrency
- I want a console
Now… let’s dig in. Warning: many words will be sacrificed in the writing of this post. I care about this stuff.
What I love about CF
I started with CF over 10 years ago. During my first programming class (Intro to C), a woman showed me a website she had built using this thing called ColdFusion. It had awesome Dynamic-Drive style JavaScript flyout menus. If you remember back to 2000, you know you HAD TO HAVE flyout menus. That night, I bought the CF 3.1 WACK from half.com. The book and CD arrived a few days later. I’m flipping through the index trying to find the “menus” section. Wait, what? WTF is SQL? What’s a query? Where in the hell are the javascript menus? What an idiot I was.
A week or so later I had built my first data-driven website.
That’s why I love CF. It was a gateway to my next career; it’s been extraordinarily good to me. I’ve met some of the best humans on the planet… in the ColdFusion community. I’ve contributed significantly to open source CF projects. I’ve built apps that have brought value into this world. Thank you, ColdFusion.
For me, CF has never been about “language”, but about features. Historically, it’s made harder things simple… Data access, web services, XML processing, file manipulation, Email, FTP, VFS, PDF creation, etc. More recently we have ORM, ehcache, Websockets, etc. All great stuff.
Community members have given us a slew of frameworks, libraries, applications, etc. to use. We suffer an embarrassment of riches in this regard.
And yet….
We can do better
The Language
CF’s strength has always been in its features, but never in the language itself. To follow along, you will need to separate, in your mind, the features you use from the language with which you use them.
I recently spent @3 months on a project with Groovy and Grails. Groovy was fairly popular a few years back but has lost some mindshare on the JVM in recent years, largely due to the ascendance of Scala and to some degree Clojure. Lots of reasons exist for this, which I won’t get into. Suffice to say, of these 3 languages, Groovy is probably the most natural transition for CF developers. It is a fantastic language, to be sure.
On this project, I am still shocked at how little code I typically had to write, compared with CF code that would’ve done the same thing. But I’m not going to fall into that trap of “see, it’s fewer characters and thus SUPERIOR!”. Instead, I’ll say that the language is simply more joyful. It’s a nebulous thing, open to much finger wagging… I know this. I haven’t quite yet identified for myself why it’s more joyful to me. Probably it’s a mix of Collections functions, collections looping, closures, mixing static and dynamic typing, sane concurrency abstractions, and so forth. Plain old every day stuff like array and map manipulation, object population… bread and butter stuff that pays the bills.
I want to use Groovy in my ColdFusion applications. I want to create CFCs that are, in fact, all Groovy.
In addition, when I need to use CFML, I want the following
- Null-safety operator, and the rest of the Groovy operators
- Death to the var scope
- Death to CFQueryParam
Better operators. Go check out Groovy’s operators, specifically the “Safe Navigation” operator. If you’ve used ORM in ColdFusion, you no doubt have isNull() checks littered throughout your code. It is, without doubt, the absolute worst part about moving from a query to an ORM based persistence model. Nulls have caused me more pain than virtually anything in CF save for the var scope (more on that little bastard momentarily). Groovy solves that problem with the safe navigation operator. In my CF views, I must write this constantly: <cfif not isNull(object.getSomeThing())> #object.getSomeThing()#</cfif>. In Groovy, you’d simply do this: user?.address?.street
Death to the var scope. ColdFusion components are unsafe by default. Don’t believe me? Create a CFC. Add a function. In that function, use cfquery. Store that CFC in the application scope (it’s a DAO after all, so make it a singleton).
If you don’t see a problem with what you’ve just done… that is the problem!. Because what you’ve just done is perfectly sensible. No sane server-side language should allow variables to be in the global scope by default. In a function, the default scope should be local, period. There is no compromise here. Local. Default. Period.
In CF 11, I want the var scope to be unnecessary. Old code that uses “var” won’t break, because it’ll simply become a no-op keyword to be deprecated. It will have no effect. Any variables created in a function will be local scoped. If you wish to create it in the variables scope, you do it intentionally, not accidentally.
Death to cfqueryparam. The hell you say! Hear me out. OK, maybe not the “death”, per se, but how about it being there for when you absolutely, positively need it but otherwise you don’t use it much day to day. Here’s why:
When I do this: <cfquery>select * from foo where id = ‘#form.Uberl33tH4x0rPwninMyA55#’</cfquery>
I am now vulnerable to sql injection. So I must use cfqueryparam to escape it. But why?
I propose that CF should turn variables into bound parameters in queries. It is, after all, a variable. CF knows this. So do what cfqueryparam does and turn it into a bound parameter for me. Again: safety by default. By the way, Groovy does this.
Better Java datatype interoperability. CFMongoDB does some trickery to turn booleans into booleans, and numbers into numbers, before stuffing data into Mongo. It’s because “1” is not 1, and “true” is not true, and when you query against fields containing numbers and booleans in Mongo, you darn well better make sure your numeric data are numeric and your boolean data are boolean; otherwise, you’re be left wondering why collection.find({age : 5}) won’t return anything, even though you know damn well you have a 5 year old in your collection.
The problem is that CF treats numbers and booleans as strings, and consequently when they’re inserted into Mongo as part of a document (think: struct), or used in a query (which is also a document), they’re usually (not always… GRRR) inserted as strings. Thus, you must use javacast or in the case of CFMongoDB, something faster and more clever.
I do not want to worry about this datatype business any more. In a struct, a number is a number, and a boolean is a boolean. No compromise. That’s it. Number. Boolean. Period.
Enough about language. Moving on..
Grails-like functionality
Grails is a web framework, inspired by Rails. It’d be a mistake to say it’s merely a clone, however.
I don’t want to get into whether CF should ship with an “official” framework. I have no skin in that game and want no part of that argument. Instead, I’ll simply put out there what joy Grails has brought me (and what pain). CF has always seemed to me to be an interesting mix of language and framework, so perhaps these things can be brought into CF without the need for a framework.
Dynamic finders. Grails’ dynamic finders are inspired by Rails. Basically, if you have an object User, and it has properties firstName and DateOfBirth, you can query for instances by doing this: User.findByFirstNameAndDateOfBirth()…. for all possible combinations of properties. It’s brilliant.
ORM, in general. Go read the grails docs on establishing many-to-one and one-to-many relationships in a grails domain model. Compare that with the latest code you had to write in a CFC to do the same. Night/Day.
Object population. One feature I’ve come to rely on heavily is Grails bean population via a Map. This is Groovy based but Grails adds some sugar on top. Given a Map (struct), you can create a new object like this: def project = new Project( yourMap ). For all the keys in that struct, it’ll call the corresponding setters from your object. In addition, if you use a “.id” idiom, it’ll also do relationship lookups for you: If your Project has a “region” property which is a Region object, and your map looks thusly: myMap.region.id = 5, then calling new Project( myMap ) will cause grails to go look up the Region object with id “5”. Joy.
Plugins. Most modern web stacks have a plugin system… but not CF. Rails has gems. Node has NPM. Grails has plugins. Basically, the problem it solves is that it makes it much easier to bring other people’s libraries into your application. Want to use Spring Security in Grails? How about this: >grails install-plugin spring-security-core.
That’s it.
Want a pre-built user admin interface? >grails install-plugin-spring-security-ui
I will absolutely admit that my experience with grails plugins has been love-hate. Incompatibilities, missing maven repos, inscrutable class-loading bugs. This is likely the nature of plugin systems in general, and I don’t have a solution. Still, overall, having a solid plugin system is preferable to none at all. This is a no-brainer.
Grails-inspired. I want the CF team to spend a month or two building an application in Grails. Not a blog. Build something meaningful… some kind of internal application. Whatever. Just use it and learn it. Now, take everything that is awesome, and put it into CF. Think of what could be even awesomer, and put that into CF. Then, think about the things that suck, and make sure they don’t end up in CF.
Yes, I know a lot of those things are possible in CF with a bunch of onMissingMethod hackery. That’s not the point. The point is I want it baked into CF.
Concurrency
I created cfconcurrent because concurrency is hard, CFThread is suitable for a small set of use cases (fire-and-forget), and superior solutions have existed for a very, very long time. Still, even java.util.concurrent, which cfconcurrent exposes, is considered by some very smart people to be too low level even today. They believe even better abstractions can exist on top of it. Enter GPars and Akka. GPars is Groovy’s concurrency solution, while Akka is Scala-based but also exposes a Java API. I will do neither of them justice here. Instead, I’ll simply state my wish:
I want CF to include one of these libraries as its official concurrency mechanism
Console
Groovy ships with a “console” and a REPL (read-eval-print-loop). The console is a GUI that you pop up and write code in. The REPL is a command prompt that executes your code. I don’t care so much about the REPL, but the console is gold.
Grails also ships with a console that is based on Groovy’s console. It extends it by providing you access to your grails application – all your objects, models, plugins, etc. It’s brilliant.
On this aforementioned Groovy/Grails project, my workflow changed considerably. Typically, I write a bit of code, along with a test, and ping-pong between code and test. However, because testing is this weird mix of awesome and horrifying in Grails (out of scope for this discussion), I found myself writing a lot more code early on, in the console, and once it worked as I wanted I’d bring it into my app and start testing it. I know, bad TDD’er! Whatever. When integration tests take 10, 20, 30 seconds just to start, this is the kind of thing you do to meet deadlines.
The console makes it so easy to simply play. Because it’s simple text, and your only debugger is println, I found myself keeping things very simple. In addition, you can easily inspect objects with its inspector, which eliminates the need for a proper debugger.
Even now, for every day scripting tasks, I typically use the groovy console.
If you’ve ever used Chrome’s (or Firebug’s) JavaScript console for fiddling with your JS, or even if you’ve used JSFiddle, then you’ll know what I’m talking about and perhaps can understand why it’d be fantastic to have something like this for ColdFusion.
I want a console. I want to open up a CF Console, type code, play, explore, learn.
Conclusio!
Like all of you, I could A) go on and on about all of the above, and B) provide even more things I’d like to see in CF 11 (like LiveCycle’s Reader Extensions for PDF!; or Spring integration, but Kotek shall continue to be the official bearer of that torch).
Know this: it’s OK to emulate! When I was a teacher, we had a saying: “The best teachers beg, borrow, and steal material to help their students learn”. Am I suggesting that CF become a copycat? Of course not. I will however state the obvious: CF has long since lost the “rapid application development” claim to other technologies. If it wants to reclaim it, it must adopt the features / tools / approaches that have caused so many developers to fall in love with platforms like Rails and Grails.
The wish list above includes the things that are most important to me and which I think would provide the greatest value – and Joy -- for the majority of ColdFusion developers.
Thanks for listening.
Make. It. Happen.
--Marc
31 comments:
Marc, great thoughts, a good read, and I hope Adobe listens! It seems like a lot of the trouble we have with CFML stems from the lack of being opinionated. Things like fixing the var scope can't easily happen now because of the lack of decision making when implementing it, and lack of decision making when attempting to fix it.
The package manager is a different kind of beast. There have been a couple trys over the years but nothing that caught on. Railo's admin 3rd party installer is probably the closest. I think the CF community should solve this problem.
For the console, I don't see that happening at all, however, I bet we could make one. Something like firebug, execute your console commands in the context of a session-scoped component running in your application. It could be marginally helpful and very dangerous. Web-based more than anything because that's just how CF runs.
Overall, I like where your thoughts are. The big picture is the same one I'm trying to paint. ColdFusion needs a reboot. There's a lot of great tech behind it, but it's like a movie franchise, when the actors don't look like teenagers anymore, you get a new spiderman. Microsoft knows this, and ASP became ASP.NET, and now ASP.NET MVC. Look at the rise and meh of Rails.
We need big changes.
OK I'll bite, Marc, and ask the obvious question -- why not just switch to Grails? Well, maybe it's not completely up to you vis-a-vis your employer. But if all of a sudden you were free to develop all future apps in Grails, would that solve your problems? Also, in Railo 4 you'll be able to do CFML in the console (Railo will essentially enable CFML to run on the JVM without needing a web server -- just like Groovy. So I don't see why this wouldn't be possible with Adobe CF).
BTW -- this doesn't mean that I don't thing there are some good ideas here for CF -- especially the stuff about 'safety by default' (var scope and cfqueryparam) and java type interoperability.
I couldn't agree more. CF10 is dead. Long live CF 11!
Tony, thanks for commenting! Your question is fair, and I did not address it in my post because the post is about CF, not me. But I'll answer it here:
The straight answer is: I might choose CF, or I might choose Grails, depending on the project.
I enjoy programming in the Groovy language... a LOT. I quite like Grails as well. However, there a a few problems -- some small, some not so -- that might lead me to choose CF for a project.
The testing story in particular is a problem for me. Grails has great testing *tools*, but with integration tests in particular, it's too darn slow. Essentially, it spins up your entire app and then runs your tests. It's infuriating. So the recommended approach seems to be to do less integration testing, and more unit testing, with mocks. But that's not what I want... there are certain things I always want to fully test. Drives me nuts.
The other irritating thing about grails is application reloading. Now, to be clear: Grails has very sweet hot reload so that *typically*, you don't have to restart your application when you make a change. So you get typical "F5" development that we're used to with CF. However, it doesn't always work as advertised, and there are definitely cases where Grails can't hot reload. In addition, if you're using certain plugins (we used BlazeDS), sometimes the plugins can't successfully reload/restart and so you have to restart your app. Not a big deal, but a bit frustrating if you're used to CF. Still.... worlds better than typical Java development! And as I said, you don't have to do it often.
Finally, there are possibly some other cases where I'd choose CF because it had a feature I really needed -- cfdocument, cfpdf, etc -- although I suspect in that case I'd just stand up a CF instance as a service provider but still build the main app in groovy/grails.
As I said in the post, CF has been great to me and I'm still heavily invested in it. I want to see it not wither on the vine, though: I want to see it succeed and thrive. To do so, it's going to need BIG thinking.
10 years ago, CF was the RAD king. It is not any longer, and hasn't been for some time. It becomes increasingly harder to justify the cost of CF when you can develop in other technologies in the same -- and even less -- time. I want CF to be worth the money we spend for it, compared with the free alternatives.
Marc, some great things here. I'm going to pass this URL on to the CF team to make sure they see it. I did have a few small comments:
cfqueryparam: To be fair, don't forget it isn't just for safety, it can also provide performance benefits for the server. We already _do_ escape values like you said, it just isn't 100% full proof. I think it would be good if it was, but I'd argue folks would probably still use cfqp to get the additional performance benefits.
@Nathan: "Things like fixing the var scope can't easily happen now because of the lack of decision making when implementing it, and lack of decision making when attempting to fix it." You know I have to step up for my boys. :) Remember, a decision you don't agree with isn't necessarily one that wasn't made. I'd like to assume that a great deal of thought _was_ put into this, whether or not the outcome is to your liking. :)
@The Console: Do you guys think this would be useful in CF with so much code bound to input (ie, form, url, etc)?
A follow up question In terms of operators, you showed this as an example:
user?.address?.street
Does that work in a conditional? My Groovy is rusty, but would this be valid:
if user?.address?.street {
}
If not, and if this is only useful in output, then wouldn't you still need IFs anyway? I rarely _just_ output something like that by itself. Normally it would be that + a BR tag for example. So if CF supported it, I couldn't just do
#user?.address?.street#
I'd still need a condition to see if it exists because I'd need a
tag at the end to render it properly.
Marc. I see your point. After years I have now a 90% Ruby developer and I really see how CF has been surpassed by Rails type frameworks.
Slow tests have been an issue in Rails too up to when Spork was built. Basically spork keep an application instance always up and refresh only your changes so no need to reload your entire app anytime you want to run some test.
Does Grails world has nothing similar?
Thanks for the detailed response, Marc. I realize that it might've sounded like I'm trying to push you off CF and that couldn't be further from the truth. I want to see CF thrive as well. But as we all know it's also good to learn (and learn FROM) other languages and technologies. I've recently been playing with Grails as well (and liking it) and it's great to get your perspective since you've built some production code with it.
Fyi, cfqp is not required, there are other ways to sanitise the data, such as cfparam, Val, are, etc.
Cfqp also has other uses such as execution plans and performance, you should read up on these if you think it only exists for safety.
Var scoping is no longer required I believe since cf9, unless im confusing it with Railo..
You can already use groovy in CF, Google cfgroovy, hope that makes your day.
While these may all be good ideas I think it all misses the point of why CF was created by Allaire all those years ago and the more it is losing the original purpose with every release as become more of just another oop language and more like java language. After you have turned into your ideal language One would have to ask why even bother to use CF at all, just use java and groovy and get rid the extra application later.
It certainly isn't the non programmer friendly Web development solution it used to be, newbies are finding CF difficult to learn instead of easy, and I bet a lot of them are going to php instead as a result.
@Snake - actually var scoping is still required in CF9 and Railo. The only thing that's different is that there is a built-in local scope. So you can var scope by saying cfset var foo = "bar" or cfset local.foo = "bar". Either way, you still have to explicitly scope your variable when you're in a function. What Marc's talking about is being able to say cfset foo = "bar" inside your function and having that variable just be local to the function. As it is now, when you do that, it's like saying cfset variables.foo = "bar" (not local to the function) which can lead to trouble if you do that within a cfc that's used as a singleton.
Marc: Great post and ideas about the direction of CF. I agree that the language needs to keep evolving and "beg, borrow, steal" and make better is great advice.
ColdFusion 10 does some of the object population you are talking about I believe:
http://www.samfarmer.com/blog/index.cfm/2012/4/30/10-Little-Ones-Automatic-CFC-Init-5
Its a small item in the range of what you are talking about but a good one :)
All, regarding CFQueryParam, I'm sorry I wasn't clearer: I did state that I wanted it turned into a bound parameter (which is what CFQP does), but that apparently got lost in the "escape" stuff. So I've reworded it to be more clear. I do not, in fact, want anything "escaped". I want it turned into a prepared statement, with bound parameters.
@Ray, regarding the safe navigation operator in Groovy: it's just an operator, with no notion of "output context" or any such thing. So: absolutely you could use it in a conditional as you have written.
It's interesting that you rarely just output something. Personally -- particularly with CFUniForm -- I seem to "Just output something" all the darn time!
As for the usefulness of the console: I think that'd be highly dependent on the developer, or perhaps what the developer is currently working on. *Most* of my time in ColdFusion is spent in object-ville, and not so much in HTML-ville. So for me it'd be quite useful. Even so... just about any time I wanted to write some play-around code, learn how to do something, how something works, etc, a console would be fantastic. Ctrl+W to clear, Ctrl+Enter to run, Ctrl+Shift+R to run current selection.... I can practically code and test at the speed of thought in the Groovy console.
@Snake: regarding cfgroovy... you're missing the point my man. I'm not asking for more "bolt on" stuff. I think what Barney's done with cfgroovy is fantastic! But I'm not going to in all my code. Even with CFGroovy, it's still a 2nd class citizen. I'm proposing something far more "revolutionary", as it were. By the way, I'm certainly not the first person to propose this, and remember that there was quite a contingent -- and even a commitment from Adobe at one point -- to make ActionScript another valid language in ColdFusion. Personally I'm glad that idea died as I think Groovy is a superior language.
Regarding "missing the point of why CF was created"... yeah, I was expecting that. I don't think anything I've said detracts from CF's ease of use. In fact, my non-groovy language enhancements are precisely in the direction of "making things easier".
As for it being a "non programmer friendly web development solution"... hooboy. Ok, here goes: I do not care. At all. I need to build real, big, complex applications. My tech stack needs to support that. THAT, and not "cfoutput" and "cfquery", is why people love CF... because you do some pretty darn amazing things with it. For Pete's sake, I'm not suggesting ripping out the 5 tags! As for newbies having a hard time learning it... I can't speak to that. All the young folks who've come into our group have taken to CF really quickly. But I can absolutely tell you that the smart young folks who've had experience with other languages / frameworks can attest to the fact that they have to do a fair bit more work in CF compared with stacks like Ruby and Rails. BUT: what often sells them on CF is exactly what I mentioned at the beginning of my post... the Features! All the stuff that CF simplifies that isn't so simple in other stacks.
I'll also throw this crazy thought out there, at risk of being run out of town by you crazies: I would not be at all upset if Adobe started modularizing their features and selling them as components. You want websockets in your grails app? Here's a jar. You want VFS? Here's a jar. I'd gladly pay for those things (well... for the things that Spring hasn't already made simple :-) )
Touching on query related topics; queries in cfscript are more cumbersome to write and slower performing compared to using tags. CF11 needs a native implementation of queries instead of the object wrapper that we have now. That's the #1 item on my wishlist, it's a pity that CF10 didn't address this :(
I think this is a great blog post Marc! A lot of thought and experience has gone into this, I'll bet.
For the last four years I've been writing polyglot projects with CFML, starting out with Groovy (at Broadchoice, with Ray, Brian and Joe) and then Scala and now extensively with Clojure.
I can see why you like Groovy so much - it has a lot of Java background but with all the noise stripped away and so many just plain ol' useful things in the language itself that make it a great, fun language to use. I enjoyed working with it immensely.
Scala wasn't a great fit: it's a very powerful language but you lose the fast response of edit-reload-test that we're used to with CFML and which you can get with Groovy/Grails (modulo the slowness of integration tests).
Clojure has proved a great fit for a CFML back end. It feels like a dynamic scripting language, you can edit-reload-test easily enough and deploy as source, just like CFML. You can connect a REPL directly into your running application and, if you need to, update the code live while the application is running. With its focus on immutable (high performance) data structures it's "safe by default" and concurrency is brain dead simple to use via a number of built-in language constructs - and the STM (software transactional memory) provided for those occasional times you really need mutable data bring the benefits of a database (transactions, rollback, commit, retry) to your in-memory code. Clojure also has very sensible ways of dealing with null - most operations on null simply return null so you can navigation through multiple levels of data structures and if you hit null somewhere, you just get null back, without having to test it everywhere.
I'd love to see CFML pick up the best parts of several other languages and backward compatibility concerns have definitely held CFML back in a number of areas (especially the local variable nonsense).
At World Singles, we love CFML for View-Controller stuff but we're increasingly using Clojure for the Model for most of the reasons you cover: null-safe navigation, safe by default variables (immutable as well as local), prepared statements for queries - see https://github.com/seancorfield/jsql for the sort of abstraction I mean (based on what we're doing at World Singles).
On the Java interop issue, we find Railo is way better than ACF: in Railo numbers are numbers, booleans are booleans and strings are, well, strings. Consequently passing data into Clojure "just works" as expected, unlike in ACF, and a Railo struct with numbers and booleans etc can be passed straight thru to MongoDB without coercion.
I'm not a fan of ORM (the "Vietnam of Computer Science" - Google it) so we have a fairly simple data mapper (in Clojure) with a generic dynamic Bean.cfc wrapped around results. Instead of the dynamic finder, we pass a struct of what we're looking for or just named arguments: user.findByKeys( firstName = ..., dateOfBirth = ... ) - again see the jsql project. I agree that ORM as implemented in ACF and Railo is pretty horrible when you look at what Grails has.
Part 2:
For plugins, the Railo extension provider system and the online store for extensions makes installation of "plugins" (and frameworks and applications and so on) a simple, one-click affair in the Administrator. It would be great if the community could enhance it to run on ACF as well - it's all CFML so it shouldn't be too hard - and it's easy to write a provider service since that's also just a CFC exposing a web service.
On concurrency, you're right that CFML is way behind the curve (and the variables-scope-by-default issue just makes it worse). GPars, Akka, Clojure all have great stories here.
On the console issue, I also agree. Once you start working with a live console/REPL, your entire workflow changes! You evolve your application, piece by piece, from real, working code, knowing it does what you need. I always have a console open in my IDE and I can execute any piece of code in any file with just a keystroke or I can code directly in the console and copy the result back into unit tests or application files. If I'm not sure how to tackle a problem, I can just brainstorm in the console until the solution starts to appear. As you say, it encourages you to code in small, maintainable pieces.
Railo 4 allows CFML code to be executed from the command-line - no running server needed - which isn't a REPL but I'm hoping to spend some time figuring out how to add REPL-like functionality on top of that at some point (the beauty of open source is that I can do so).
Responding to the unknown commenter above, the CFC-based approach to implementing several tags in "script" is really horrible and, as you observe, leads to cumbersome code and poor performance. Railo offers the CFCs for compatibility but also implemented the syntax discussed in the CFML Advisory Committee (which I blogged about at the time) so you can just write:
query name="foo" datasource="bar" {
writeOutput( "SELECT * FROM USER WHERE ID = " );
queryparam value="#url.id#" type="integer";
}
You can also use the echo() function which is shorter than writeOutput() and serves the same purpose. Note that you need some way to distinguish CFML code from SQL so outputting SQL into the "response" buffer is a natural way to handle it (think of custom tags and generated bodies). And it's also how the mail ... { ... } script tag works, and savecontent ... { ... } and so on.
Again, thanx for putting out a post like this. None of us should be blind to CFML's shortcomings and it's healthy to discuss areas where the language can (and should) improve.
I like this entry a lot cause talk of something that CF really lost on the way. CF was born to make things fast and easy. After more than 12 year I still see example on how is easy to make a sql query from cf as if it should still be a feature to sell .....
I can confirm that writing sql statements in Ruby can be a bit more tricky but developing an application in Rails is 30% respect CF these days. I think CF lost the train on the stack aspects.
Developers does not need new built in features .... they need a stack like rails and grails are. A fast and productive way to use the language.
I know many Ruby and Groovy developers but anyone of them will use Rails or Grails in one or another way.....
This speaks to the heart of many CFers (myself included) I'm sure.
@jedi, I think have CF run in a console without a running webserver is a big deal and I'd sure love to have it.
I've started thinking about a package manager for CF - I think it should come from the community and I think that it has to:
1. Kick ass
2. Be adpoted by the big frameworks and subsequently become a defacto standard (in order to be useful)
Having a console would make a package manager more useful too I think. Imaging being able to run someone's unit tests without spinning up a webserver and making their tests web-accessible. Just:
> cfpm install coldbox
> cfpm run-tests coldbox
or somesuch...
Having a universal package manager might help increase the standards and expectations of open source CFML too (by providing common structures and expectations on testing, etc.)
Anyways, great post. Thanks for sharing :)
Hi Marc: interesting post! One of the better blog posts I've read recently.
Ray's already commented on what I was going to say about CFQUERYPARAM, but your modification to your initial statement is still wide of the mark. One cannot simply take any variable reference out of the SQL string and make it into a parameter: parameters are only for DATA VALUES, whereas a CF variable in the SQL string might contain the numeric value for a TOP or LIMIT statement, a table name, a boolean operator, columns names etc. None of which can be parameterised.
Basically CFQUERYPARAM already works exactly how it should, and does the job well.
Everything else you say is very interesting though, so I don't mean my clarification above to detract from anything you've said.
Your blog post as spurred me into checking out other languages to see what we can lift from them for CF11 too. I'd much rather new versions of CF focus on language constructs rather than bells and whistles like ORM and that sort of stuff.
Oh, and AMEN to the people who observed that CF's approach to CFScript-friendly queries and the like being a dreadful implementation. It's always seemed like a dismissive, work-avoidance band-aid to me, rather than a thoughtful implementation of a real requirement in CF.
--
Adam
I've not read the comments, but, the blog is spot in.
How about allowing a Application.cfc to set the encoding for the entire application? When working with i18n sites it is painful to add to every file that can contain source strings. I understand this can be mitigated by using resource bundles but I want to add it to the wish list anyway.
Thanks.
Doe! The last comment was modified by the commenting system. I was talking about adding a cfprocessingdirective tag to every file that may have origin strings.
Thanks.
Aaron, cfprocessingdirective controls _compilation_ so character set encoding cannot be a _runtime_ setting in Application.cfc.
@Adam, that's a fair point regarding strings in queries. However, I stand by what I said: safety first. There's got to be away around it.
Groovy solves it nicely: if you need dynamic, non-parameterized stuff (like your column list example), then you simply create a regular old String instead of a GString. You pass that string into your Sql object, and it won't get parameterized. You can mix and match strings and gstrings such that for the parts that need parameterized, you get it.
I confess I don't know how this would work in ColdFusion. But I think the goal of safety first in this case supersedes simplicity for rarer cases; consequently, I think it's worth exploring
What I want from ColdFusion are improved widgets and library controls for API such as Chat online reputation management. PHP with Apache has done just that.
Ok, so I'm really late at commenting on this post (in defense, I only just found it) and in general it is a good post with some great ideas but... to my thinking there's absolutely nothing wrong with CFQueryParam and in fact quite a lot right with it. SQL is strongly typed after all and even if you know nothing about optimizing SQL queries, the query optimizer can make use of knowing what the variables are to create some valuable performance improvements. To say nothing of providing some 1st-level protection against trivial kinds of SQL injection (e.g. trapping out an input "4;select * from user" by finding that it's not an INT before it ever hits a query or anywhere else it can do some damage).
I have to ask though, why do you think that writing in-line queries is a good thing? You do know that there's this nifty database invention called Stored Procedures, don't you? (In which case, of course, we use CFProcParam, but same thing, kinda...) Ok, so that's a bit sarcastic but truly, inline queries are such a bad way to go about writing code and yes, you can use ORM and this is a good abstraction and tiers the application the way it should be but it actually hides what you are doing to the database, makes creating an atomic call to, say, a set of transactions across multiple tables to perform an application functional insert or update more difficult and (in my experience anyway) often much more code to write. And it makes you dependent on an extra subsystem (hibernate) which, although good, is still 1 more possible point of failure and layer of debugging to go through.
And SPs have a lot of benefits that aren't advertised on the packaging - especially if you have a library of good, efficient, atomic functions that support them, you have a good naming convention, and you have a half-decent knowledge of SQL and how databases work (tip: it's not that hard!). And if you have the know-how and it's your own DB engine so you have access to e.g. "master" (in SQL Server) then you can do amazing stuff, as long as you're careful.
Post a Comment