Wednesday 5 March 2014

CFML is dying. Let's drop it off at Dignitas

G'day:
Yes. It's another "CFML is dying" article. We haven't had one for a while. Note that this is not "ColdFusion is dying", this is CFML in general.

TBH: the headline is slightly tongue-in-cheek, and designed to garner outraged click-throughs whilst the Daily Mail readers amongst us search for the "Comment on this article" button so they can display their mouth-froth to everyone.

This article actually isn't about CFML. And that's the point.

I had a meeting with some fellas from the CFML community a coupla months back, and during that meeting an idea was tabled which we'd all independently been thinking about prior to sitting down. I thought this was cool because it added validation to a few ideas I'd had... finding out some of my peers also had the same thoughts. My mind has been stewing over this since, so I've asked if it's OK if I share the idea in this article, so as to get the conversation in the community going. I hasten to add that the content of this article is all my own thoughts on various things we discussed, however I cannot necessarily claim that all the ideas were originally my own.

So here goes... I think it's time for Railo to put CFML into maintenance mode.

In the 1990s and probably early 2000s, CFML (under the guidance of Allaire, Macromedia and Adobe) was a technical leader in its field. The field of dynamic tag-based language designed to facilitate the automation of HTML page generation. And I mean the archetypal CFM "template" notion, where a web site is basically made out of a bunch of HTML files with CFM file extensions, with mark-up being generated dynamically with CFML tags.

Since then the notion of web sites and web applications has changed, grown and become far more important and complex pieces of software. And along with the increasing complexity, CFML has grown in breadth and complexity to facilitate the ever-changing requirements. However, TBH, I don't think the language has really kept apace with where other languages are going. It dwelt too long in the "tags make it easy" mantra, which has always been a load of bullshit anyhow, and was also too focused on adding bells and whistles rather than building a strong language. CFMX 6.x's foray into OO was half-arsed, and almost all features since then have been what ought to have been add-on bundles, not core to the language. Macromedia and Adobe were just going for the shiny shiny to attract the cheque books of the easily-impressed goggle-eyed IT Managers. And as a result, CFML is a bit of a mess.

Railo came along and is doing a good job of trying to drag CFML into this decade, and I am impressed with their approach and their work. I used to be very sceptical of them, basically thinking they were simply delivering a cheap knock-off of ColdFusion: RyanAir compared to British Airways, if you like. However over the last year or so I have realised they're actually far better at their jobs than the Adobe crew are (for whatever reason. I'm looking at the end result, not how they get there and what constraints are placed upon people), and indeed the future of CFML lies with Railo, not Adobe.

But.

I think this is not a good use of Railo's time any more. CFML is dead. CFML is a pariah amongst its peers because of all this emphasis on tags for everything, which results in what looks like playschool code. Because CFML has this reputation of a pretend language for web monkeys, it's never gonna get any decent uptake from new developers, it's never going to be taken seriously again, and it will wither and die off. Well basically as a career-prospect, it will just be "maintenance mode". Adobe killed CFML by focusing on tag-based code, and the CFML developers in the community have killed it by perpetuating this approach to coding.

So here's my / our idea... retire CFML.

CFML has a lot of really good functionality. The ease of which one can hit a DB and get a recordset back is fantastic. Making a call to a directory server? Easy. Hell, even reading files is an easy pleasure. What it does is great. How it goes about it is rubbish.

Another great asset Railo has (and Adobe do too, but I don't care about ColdFusion for the purposes of this article) is that CFML is a dynamic JVM language. This is the current cool (well: one of the current cools... some new supposed coolness comes out every day, it seems). Everyone's decided Java itself is a bit of a behemoth, but the way the JVM works is pretty cool. And obviously now we have a lot of languages out there which - dynamically - compile down to Java byte code.

Right. So the functionality of CFML is great, and the platform is great. The language is not. Ditch the language.

I think Railo should create their own JVM-based language, reusing a lot of their existing work for CFML, but making a good language. One that seems modern, and that people might want to use.

Here's some ideas of what they could do...

Files

I propose three different file types: .rclass and .rscript and .rview (all the labels I'm giving stuff is just proof-of-concept and because I need to give labels to things to discuss them: I made up those file extensions just now as I needed to type something). .rclass would be the equivalent of a CFC. But let's just call 'em classes, OK? That's what they are. .rscript would be the equivalent of a CFM file now one might use where a CFC isn't appropriate (that said, this requirement might be moot). And an .rview file is what it suggests: a view.

Views

The significant thing here is that an .rview is the only file that will compile tag-based code. Other than that, the language will be entirely script-based. I'll get to that.

Tags will be treated as a DSL rather than really part of the language itself: basically tags for adding flow-control logic to the view. Any actual data-processing logic will be in the .rclass or .rscript files.

Tags


Tags will be written in code as name-spaced custom tags, eg:

<rv:loop index="i" from="1" to="10>
    <!--- repeated content here --->
</rv:loop>

<rv:if myVar EQ "someValue">
    <!--- conditional code --->
<rv:elseif otherCondition>
    <!--- other conditional code --->
<rv:else>
    <!--- fallback code --->
</rv:if>

Note: there is no attempt to make that XML-compliant as that notion is a thing of the past and was always a dumb idea anyhow.

Now... CFML taggers will recoil in horror at this one. Almost all tags will be dropped from the DSL. Here's an assessment of the fate of CFML tags:



CFML tag Valid
cfabort Yes
cfswitch / cfcase / cfdefaultcase Yes
cfdump Yes
cfflush Yes
cfif / cfelse / cfelseif Yes
cfimport Yes
cfinclude Yes
cfloop / cfbreak / cfcontinue Yes
cfscript Yes
cfset / cfparam Yes
cftry / cfthrow / cfcatch / cfrethrow / cffinally Maybe
cfexit Maybe
cfimage Maybe
cftimer / cftrace Maybe
cfwebsocket Maybe
cfajaximport / cfajaxproxy / cfapplet / cfcalendar / cfchart / cfchartdata / cfchartseries / cfclient / cfclientsettings / cfcol / cfdiv / cfform / cfformgroup / cfformitem / cffileupload / cfgrid / cfgridcolumn / cfgridrow / cfgridupdate / cfinput / cflayout / cflayoutarea / cfmap / cfmapitem / cfmediaplayer / cfmenu / cfmenuitem / cfmessagebox / cfpod / cfpresentation / cfpresentationslide / cfpresenter / cfreport / cfreportparam / cfselect / cfslider / cfsprydataset / cftable / cftextarea / cftooltip / cftree / cftreeitem / cfwindow / cfhtmlhead / cflocation / cfprogressbar No
cfapplication / cfargument / cfcomponent / cffunction / cfinterface / cfinvoke / cfinvokeargument / cfassociate / cferror / cfobject / cfoutput / cflock / cfprocessingdirective / cfproperty / cfreturn / cfsetting / cfsilent / cfthread / cflog / cfwddx / cfxml No
cfcache / cfobjectcache / cfsavecontent No
cfcollection / cfindex / cfsearch No
cfcontent / cfcookie / cfheader No
cfdbinfo / cfinsert / cfprocparam / cfprocresult / cfquery / cfqueryparam / cfstoredproc / cftransaction / cfupdate No
cfdirectory / cfexecute / cffile / cfprint / cfregistry / cfsharepoint / cfspreadsheet / cfschedule / cfzip / cfzipparam No
cfdocument / cfdocumentitem / cfdocumentsection / cfhtmltopdf / cfhtmltopdfitem / cfpdf / cfpdfform / cfpdfformparam / cfpdfparam / cfpdfsubform No
cfexchangecalendar / cfexchangeconnection / cfexchangecontact / cfexchangeconversation / cfexchangefilter / cfexchangefolder / cfexchangemail / cfexchangetask / cfimap / cfimapfilter / cfmail / cfmailparam / cfmailpart / cfpop / cffeed / cfftp / cfhttp / cfhttpparam / cfldap No
cflogin / cfloginuser / cflogout / cfNTauthenticate / cfoauth No

(some of those groupings are a bit arbitrary, I know).

So basically we keep the flow-control and debugging tags, but axe all the rest. They are all inappropriate for a view.

There are some tags worth mentioning separately:

<cfquery>

Sorry... it doesn't belong in a view. Gone. I don't care that it's "nice" to have one's SQL within tags; there are better ways of doing it.

<cfoutput>

This will be implicit in views, so not needed.

<cftry> etc

I suspect it is not appropriate to have exception handling in a view: the controller should be handling this? But I've put it as "maybe".

Now I hasten to add that I am not suggesting any of that functionality is ditched from the language (OK, some of it should be... all the UI stuff for example); I'm just saying it won't be implemented as tags. Instead of <cfexecute> one will use execute() or something like that. But it doesn't belong in a view, so it won't be represented as a tag.

Language

OK, so it's all script. But there'll be changes here too.

Functions

Built-in functions will also go out the window. All of them. Everything will be a method on a class. Some methods will be static, eg:

myResult = Query.execute(sql)

Query here is the class, not an object. myResult will be an object.

There might be scope for UDFs as functions though, or perhaps they are added as methods on a scope or something. I haven't thought about that.

Queries

These'll go too. The result set from a DB call will be an array of structs.

<cfquery> is gone

Queries will be executed much as they are now in Railo / ColdFusion 11 with queryExecute(). I would say that the sql argument can either be a string of SQL (as per now), or a reference to a .rscript (or maybe an .rview to facilitate using tags for flow control, but the file extension would need a better name if so) file within which one can have one's SQL / HQL. Having inline SQL in a CFM file as it currently is implemented is convenient, but I think it's actually a pretty grim practice. Just as one ought to minimise how much inline JS and CSS one has in one's files (and markup in a CFC etc), I really feel the same way about SQL.

Perhaps instead of representing SQL statements as strings, something like JOOQ could be used? I'm not used it, but it came up in search results when seeing what existing languages did to better represent SQL statements than just in strings.

Arrays

It pains me to say it ("Why do ColdFusion arrays start at 1 instead of 0?"), but arrays will be zero-based. It's dumb that that is how modern languages do it, but it's a point of contention and best to follow the herd with this one.

That said: see the comments below, starting with Sean's one, and continuing with my follow-up, and his to mine. The question is... should the actual numeric value of the index be important? Most array looping would be done with an iteration method (like .each()), and generally one just needs to leverage the ordering of an array, not necessarily the numeric value that implements the ordering between one array element and the next. I think perhaps this desire to know the array index comes from a history of using indexed for loops to loop of the index values of the array to then access the elements. That's quite old school. Food for thought.

Data-types in general

Adobe position CFML as "typeless" which is a bullshit idea and has lead to all sorts of stupidity in ColdFusion. For example this:

<cfset aNumber = 1>

Results in aNumber being set as a string. I have no problem with the idea that a numeric value can be automatically converted to a string if it needs to be, but it should be initially set as being numeric, and stay that way until such time as it gets instructed to be otherwise.

The language ought to be considered "loosely-typed". Railo handles this much better: in the example above, Railo will correctly set aNumber to be numeric.

Because CFML data needs to interact with strongly-typed languages, I'd like to have more control over this. I'd like to be able to do this:

<cfset Double aNumber = 1>

Where this will set aNumber to be a Double (as opposed to an Integer, which might be the best fit from the look of the original value). This will not set aNumber's type in stone, if an operation is done to it which would make it a string or an integer, all good. But at least we can control it.

Null

It will be implemented properly, and with full support.

Booleans

"Yes" and "No" will play no part in boolean values.

Literals

Literals (eg: "G'day world", {key=value} etc) should be objects. So this should be possible:

shouty = "G'day World".ucase()

Semi-colons

Not needed.

Classes

Should be able to extend (or be extended by) other JVM-language classes.

Custom Tags

Custom tags have been neglected in CFML I think, however they should be the absolute bread and butter of implementing dynamic views. There could be an argument that view shouldn't even have flow control tags; this should all be done with custom tags. I don't know much about the CFC-based implementation of custom tags in Railo, but it sounds like how it should most likely be done. The important thing here is that custom tags ought to return to the forefront of the language.

Closure-functions / callbacks / etc

(And by that I mean stuff like each() / map() / reduce() etc). These will be a heavy focus in the language.And function expressions, IIFEs and all that magic will be promoted. If there's any other functional-programming-esque notions the language can leverage (so being a functional / OO hybrid), it'd be good to hear about them. Sean... am looking at you when I say this.

Another kinda similar which I might get away with describing under the "functional programming" banner is the concept of generators, which are functions which run to a point (when they encounter a yield statement), then return to the calling code. The next time the function is called it doesn't start afresh, it resumes at the next statement after the yield. This can be leveraged to some quite interesting ends. I thought I had written an article in which I mention these as a suggestion for CFML, but I cannot find it at the mo'.

Async programming

A while ago Luis suggested adding async capability to "slow" operations like file process, DB processing and the like. He details it in this thread on the Railo Google Group: "Add closure support to blocking operations to allow them to be non-blocking operations". My position on this in the context of CFML was that it was too focused and a broader / more general approach would be better: "Threads, callbacks, closure and a pub". I stand by that for CFML, but if we're creating a new language, perhaps async optionality could be added to functionality as matter of course. For example a Query.execute() call would run by default synchronously, but if success / error handlers are passed in, then it'll be run asynchronously instead.

Event-driven programming

I love event-driven programing in JavaScript: listening for events, firing custom events, basically the Observer Pattern strikes a chord with me. I write about this in "Native event framework for ColdFusion 11 ?" I like the idea of a process completing and going "hey, anyone who's interested... I've done some work and here's the result", and any other code which has registered a listener will have their event handler fire, with the result being passed to it. Nice.

ORM

ORM will be promoted as being the preferred way of DB interaction, and the implementation will be revamped to have as little ceremony, but as much stability as possible.


REST

A good implementation of REST. I am not suggesting Railo's implementation of REST is not good, but my own exposure to REST in CFML is in ColdFusion, and it's a bit of a ball-ache to develop with.

Server

I don't want to get into too much detail as to the server implementation as it's not something I have expertise in, but there's a coupla significant elements to consider.

MVC

Some manner of convention-based MVC framework should be embedded in the server (not the language), to encourage decent programming practices.

Package Manager

Like NPM or Ruby Gems etc. And as someone else has pointed out... the current package admin thing in Railo is nothing like the requirement here.

Extending the language

One should be able to extend the language by dropping new classes into a directory structure which when simply exposes them as native functionality to the developer.

Equally one should be able to override built-in functionality (eg: to fix a bug in isValid(), one can drop in a replacement of isValid() somewhere, and that replacement will be used.

CLI / REPL

The server should offer a built-in CLI / REPL capability.

That's about it at the moment. What do you think?

--
Adam