Saturday, May 12, 2012

ColdFusion From an Outsider's Perspective

After changing my primary development language to PHP over a year ago, I've been able to get a new perspective on ColdFusion. One thing I've noticed is that people in the community spend less time focusing on new language enhancements and instead spend more time trying to make the language easier to work with. While this is a good thing, there are two pain-points that seem to come up over and over again that simply aren't issues in most other languages:
  • Case sensitivity
  • Struct key order
Would it really be so bad if ColdFusion was case sensitive? It would make converting ColdFusion objects to JSON or XML a lot more straightforward. "But Tony, I want to be able to define a function named getName but then be able to call it using gEtNaMe()". There should be no place for inconsistency in code. I honestly don't see any benefits to it not being case sensitive. Besides, with the addition of Hibernate, parts of the language are starting to become case sensitive already.

Would it really be so bad if structs maintained their correct key order? I see people building relatively complex solutions trying to solve this problem, often times having to dip into Java to accomplish the task. Wouldn't it be better if the native data type just worked the way you wanted it to? "But Tony, that's not how a HashMap works." Says who? Object keys stay ordered in JavaScript and associative array keys stay ordered in PHP. ColdFusion should work the same way.

In my opinion, making these changes adds a lot more value to the language than some of the other recent enhancements, such as WebSockets or REST.

Wednesday, September 21, 2011

Encode HTML Characters in JavaScript using jQuery

Here's a quick post on how to encode and decode HTML characters in JavaScript using jQuery. I didn't come up with the solution, but I thought it was pretty clever.
function htmlEncode(value){
    return $('<div/>').text(value).html();
}

function htmlDecode(value){
    return $('<div/>').html(value).text();
}
Courtesy of http://stackoverflow.com/questions/1219860/javascript-jquery-html-encoding

Wednesday, August 10, 2011

jQuery Naming Conventions: Don't Prefix Variables With $

When working with jQuery, I hate it when developers prefix their variables with dollar signs. For example, var $buttons = $('.button');. In my opinion the dollar sign really hurts the readability of the code.

Some developers claim that adding the dollar sign is a good naming convention because it shows that the value represents a jQuery object. If that's the case, then everybody should start using Hungarian notation all of the time. Gross.

The one exception I might make is for var $this = $(this);, although even then I would rather prefer something like var me = $(this);.

Long story short, don't prefix your variables with a dollar sign. Besides, it's not like you're working with PHP or anything.

Monday, June 6, 2011

ColdMVC Updates 1.3.7

Here's a quick post describing some small but relatively cool updates to ColdMVC in version 1.3.7: http://bit.ly/ColdMVC-Updates-1_3_7

Monday, May 30, 2011

ColdMVC Documentation Updates

I recently added some more documentation for ColdMVC:

* An overview of models in ColdMVC: http://www.coldmvc.com/guide/models

* Query operators in ColdMVC: http://www.coldmvc.com/guide/operators

* Building complex queries in ColdMVC: http://www.coldmvc.com/guide/queries

* Getters and setters in ColdMVC: http://www.coldmvc.com/guide/getters-and-setters

* Specify required params for an action: http://www.coldmvc.com/annotations/params

* Specify allowed request methods for an action: http://www.coldmvc.com/annotations/methods

Thursday, April 28, 2011

Advanced INI Parsing in ColdFusion

At work, I've been using the Zend Framework for PHP a lot. One of the best features in my opinion is how you're able to manage your configuration settings between different environments within a project.

I've always been a fan of using INI files for storing configuration settings, but the Zend_Config_Ini class that Zend Framework comes with takes INI files to a whole new level by adding section inheritance and nested properties.

After a couple hours, I was able to take the same powerful functionality that Zend Framework provides and port it to ColdFusion, mainly for the purpose of adding it to my ColdMVC framework.

Why do I think this is cool? Let's look at a sample INI file that you might see on a project:


; Settings for the production environment
[production]
autoReload = false
development = false
reminderService.sendReminders = true
facebook.api.username = prod@mycompany.com
facebook.api.password = 90ujlc890$f

; Settings for the staging environment
[staging : production]
reminderService.sendReminders = false
facebook.api.username = staging@mycompany.com
facebook.api.password = 879kjasdf!

; Basic settings for the development environment.
; Each developer should create their own environment that extends this one.
[development : staging]
development = true
autoReload = true

; Settings for Tony's development environment
[development-tony : development]
emailService.options.forceTo = [ "tony@mycompany.com", "tony@gmail.com" ]
facebook.api.username = tony@mycompany.com
facebook.api.password = w1nn1ng

; Settings for Ryan's development environment
[development-ryan : development]
emailService.options.forceTo = ryan@mycompany.com
facebook.api.username = ryan@mycompany.com
facebook.api.password = govikes

; Settings for Joe's development environment
[development-joe : development]
emailService.options.forceTo = joe@mycompany.com
facebook.api.username = joe@mycompany.com
facebook.api.password = welcome


Pretty straightforward settings file. Each environment has its own section, but now it comes with a twist.

See the colons in the section names? That's inheritance in action. If you look at the development-tony environment, you'll see that it extends the development environment, which extends the staging environment, which extends the production environment.

Also, notice the periods in the property names. Those are nested properties, which will be automatically converted to ColdFusion structs at runtime.

So how does this work? Pretty simple:


var ini = new Ini("/path/to/config.ini");
var config = ini.getSection("development-tnelson");


If I were to now dump the config variable that was returned, I'd see the following output:



Pretty sweet if you ask me.

You can find all of the code on GitHub at https://github.com/tonynelson19/ini/, which also includes 26 green unit tests.

Also, I've included the new INI parser in the latest version of ColdMVC, which you should definitely check out if you haven't yet.

Tuesday, April 19, 2011

ColdMVC Quick Start Tutorial

I recently wrote a Quick Start tutorial for ColdMVC, my convention-based MVC framework for ColdFusion 9. Check it out and let me know what you think.

http://www.coldmvc.com/quickstart

Sunday, February 27, 2011

Code Formatting and New Lines

Last week I had a healthy debate with some co-workers about code formatting, which to a lot of developers can be a pretty religious subject. While you could argue that coding style should be a personal preference, I believe it's more important to use consistent coding practices when working in a team environment.

One formatting style we discussed was the use of new lines in code blocks. Here are three common formatting styles for the same code:

Style 1

if (true) {
console.log('yay!');
} else {
console.log('boo!');
}


Style 2

if (true) {
console.log('yay!');
}
else {
console.log('boo!');
}


Style 3

if (true)
{
console.log('yay!');
}
else
{
console.log('boo!');
}


When I first starting coding, I preferred Style 3, since it provides more visual separation. Currently I prefer Style 2, although it's not even a formatting option at http://jsbeautifier.org/, which makes me question my choice a little. Douglas Crockford seems to prefer Style 1, so maybe I should consider making the switch.

Which do you prefer?

Monday, February 7, 2011

Don't Mix Tags and Script in the Same Component

Every now and then, I'll see some code in an open source ColdFusion project that mixes tag syntax and script syntax in the same component. Personally, I find it really annoying when people jump in and out of cfscript blocks. If the component isn't written entirely in script, then don't use any script - stick with tags.

Some people think that since writing in script is cleaner, it's cleaner to write part of the function in script than write it using tags. However, if you're declaring your component and functions in tags, switching to script inside the function actually decreases your code readability in my opinion. Take the following hypothetical example, which is sadly all-too-common in certain open source projects:


<cffunction name="setFoo" access="public" output="false" returntype="void">
<cfargument name="foo" required="true" type="string" />

<cfscript>
variables.foo = arguments.foo;
</cfscript>


</cffunction>

<cffunction name="getFoo" access="public" output="false" returntype="string">

<cfscript>
return variables.foo;
</cfscript>

</cffunction>


I find this style of coding ridiculous.

Tuesday, January 11, 2011

Amazon Order Arrival Date



I expected better from you, Amazon...

Fail.

Saturday, January 8, 2011

Using Markdown in ColdFusion

Markdown is "a text-to-HTML conversion tool for web writers. Markdown allows you to write using an easy-to-read, easy-to-write plain text format, then convert it to structurally valid XHTML (or HTML)."

Here's a quick post describing how you can use Markdown in ColdFusion.

First, download MarkdownJ, a Java port of the Markdown conversion utility originally written in Perl. Here's a direct link to the download site: http://code.google.com/p/markdownj/.

Next, either put the markdownj.jar file in the ColdFusion classpath or download JavaLoader. I prefer using JavaLoader, so that's what my example will show.

Finally, some code:


<cfset paths = [ expandPath("markdownj-1.0.2b4-0.3.0.jar") ] />

<cfset javaLoader = new javaloader.JavaLoader(paths, true) />

<cfset markdownProcessor = javaLoader.create("com.petebevin.markdown.MarkdownProcessor").init() />

<cfset html = markdownProcessor.markdown("This is a *simple* example") />

<cfoutput>
#html#
</cfoutput>


The above code will produce the following HTML output:


<p>This is a <em>simple</em> example</p>


OK. So if that's the simple example, what about a more complex example?


# This is an h1

## This is an h2

This is a normal paragraph. Lorem ipsum dolor sit amet,
consectetur adipisicing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua.

* This is a unordered list. Hanging indents allow
you to wrap a list item onto multiple lines
* List item 2
* List item 3

---
These are horizontal rules
***

This is how to *italicize* something. This is _another way_ to italicize something.

This is how to **bold** something. This is __another way__ to bold something.

1. This is an ordered list
2. List item 2
3. List item 3

This is [an example](http://example.com/ "Title") inline link.

[This link](http://example.net/) has no title attribute.

> This is a block quote. Lorem ipsum dolor sit amet,
> consectetur adipisicing elit, sed do eiusmod tempor
> incididunt ut labore et dolore magna aliqua.

This is a code block.
To produce a code block in Markdown, simply
indent every line of the block by at least
4 spaces or 1 tab



And that's the basics of Markdown. Here's a full set of syntax rules: http://daringfireball.net/projects/markdown/syntax. Pretty sweet if you ask me.

Tuesday, December 21, 2010

My Mini Library

Tuesday, November 16, 2010

Link Dump (11-16-2010)

Facebook's New Real-time Messaging System: HBase to Store 135+ Billion Messages a Month
"Keeping with their small teams doing amazing things approach, 20 new infrastructures services are being released by 15 engineers in one year." Also, very interesting that Facebook chose HBase over their own Cassandra.

Instant Previews: Under the hood
Google uses base64 encoded data URIs to display the instant preview images rather than static images to reduce the number of web requests. "...even though base64 encoding adds about 33% to the size of the image, our tests showed that gzip-compressed data URIs are comparable in size to the original JPEGs."

10 Random CSS Tricks You Might Want to Know About
Target IE6 and IE7 without conditional comments: add a * before the property for IE7 and below, add a _ before the property for IE6 and below.

Yet Another Flavour of GORM: MongoDB
Very cool to see Grails support MongoDB, although it would be cooler if Hibernate had native support for more NoSQL databases.

Why Products Suck (And How To Make Them Suck Less)
"People only complain about things that matter to them; better to have complaints than disinterest. And not all complaints are equal: complaints that you don’t support feature X are far better than complaints about how feature Y sucks."

Monday, November 15, 2010

ColdMVC Plugins and Cells in Rails

I haven't posted in awhile because I haven't felt like I've had anything good to write about, but I've been reading Pragmatic Thinking and Learning: Refactor Your Wetware and one trick to getting over a writer's block is to just write for the sake of writing. So that's what I'm going to attempt to do in the coming weeks.

Lately I've been continuing to work on ColdMVC, my convention-based framework for ColdFusion inspired by Ruby on Rails and Grails. I've mainly been working on updating the plugin architecture for ColdMVC, with a focus on keeping things modular. I've also split out all of the plugins to their own repositories on GitHub to try to make things easier to manage. Right now they all follow a "ColdMVC-{Plugin}" naming convention and can be found here.

I'm also trying to get an official ColdMVC website up with some documentation and links to all the various plugins, but haven't quite got around to it yet.

On a final note, I've found a couple really good blog posts talking about cells in Ruby on Rails.



I quickly threw together a cells plugin for ColdMVC. I'm not sure how I feel about it yet, but at the very least it's an interesting concept.

Monday, August 23, 2010

Creating a LESS CSS Plugin for ColdMVC

One of the coolest things I've seen in awhile is LESS CSS, which "extends CSS with variables, mixins, operations, and nested rules". Barney Boisvert has blogged about using LESS with ColdFusion already, but I wanted to show an even simpler integration using my ColdMVC framework with a little help from around the web.

Assuming you already have ColdMVC up and running, your next steps will be to download JavaLoader and the LESS jar file. Next, we'll create a new ColdFusion project called ColdCSS, which contains the LESS jar file and a single component, ColdCSS.cfc.



Next, open your application's /config/plugins.cfm template and register the ColdCSS plugin. The path to your plugin might be different, but here's what it looks like if the ColdCSS project is in the same directory as your application.


<cfset add("coldcss", "../../coldcss/") />


Here's the content of the new component, ColdCSS.cfc:


/**
* @accessors true
* @singleton
*/
component {

property pluginManager;

/**
* @events applicationStart
*/
public void function generateFiles() {

var jars = [ getDirectoryFromPath(getCurrentTemplatePath()) & "lesscss-engine-1.0.22.jar" ];
var javaLoader = new javaloader.JavaLoader(jars, true);
var lessEngine = javaLoader.create("com.asual.lesscss.LessEngine").init();
var directories = pluginManager.getPluginPaths();
var i = "";

arrayAppend(directories, expandPath("/public/css/"));

for (var directory in directories) {

var files = directoryList(directory, true, "query", "*.less");

for (i = 1; i <= files.recordCount; i++) {

var source = files.directory[i] & "/" & files.name[i];
var destination = files.directory[i] & "/" & replaceNoCase(files.name[i], ".less", ".css");
var content = fileRead(source);

fileWrite(destination, lessEngine.compile(content));

}

}

}

}


Without going over the component line by line, here's how it works. When your application starts, ColdMVC will execute ColdCSS.generateFiles(), which will scan your application and all other registered plugins and find any files ending with a .less file extension, compile them to CSS using the LESS engine, and write them back to disk in the same folder as the original .less file, all in less than 50 lines of code.

Monday, August 16, 2010

Thoughts on Property Getters/Setters in ColdFusion

In ColdFusion 9, you can have ColdFusion automatically generate getters and setters for your properties by adding @accessors true to the component metadata. For example, the following two code snippets are practically identical.


component {
public string function getFirstName() {
return variables.firstName;
}

public void function setFirstName(required string firstName) {
variables.firstName = arguments.firstName;
}
}



/**
* @accessors true
*/
component {
property firstName;
}


Nice. That's a lot less code. Now what happens if you have a business rule where you always need the first name to be capitalized. I know it's not the best real world example, but it's straightforward. Simple enough, just override the generated getter by defining your own getFirstName method.


/**
* @accessors true
*/
component {
property firstName;

public string function getFirstName() {
return ucase(variables.firstName);
}
}


Done. While that works and is the correct way of overriding the getter, it doesn't quite feel cohesive enough to me since the getter isn't visually tied directly to the property. I think it would be better if we were able to define the getters and setters as part of the property, similar to how other languages do it.


/**
* @accessors true
*/
component {

property firstName {
get: function() {
return ucase(variables.firstName);
}
}

}


Obviously this is just hypothetical syntax, but I think it reads a lot better.

Wednesday, June 16, 2010

ColdFusion 9 Bug #82955

Awhile ago I submitted a bug for ColdFusion 9. Here's the description from the bug tracker: Error when calling a function with an implicit struct argument containing a complex value inside a loop. It's a little hard to explain exactly what's going on in words, but here's some sample code that can reproduce the error.

<!--- To test, remove the comments from around each scenario --->

<!--- create a simple array of users --->
<cfset users = [] />
<cfset users[1] = { name = "Tony" } />
<cfset users[2] = { name = "Joe" } />

<cfoutput>
<!---
Scenario 1: Pass in the user. This should work. <br />
<cfloop array="#users#" index="user">
#sayHelloSimple(user)# <br />
</cfloop>
--->

<!---
Scenario 2: Pass in a struct containing the user. This should work. <br />
<cfloop array="#users#" index="user">
<cfset parameters = { user = user } />
#sayHelloComplex(parameters)# <br />
</cfloop>
--->

<!---
Scenario 3: Pass in an implicit struct containing the user. This should work, but doesn't. <br />
<cfloop array="#users#" index="user">
#sayHelloComplex({ user = user })# <br />
</cfloop>
--->

<!---
Scenario 4: Same as Scenario 4, but wrapped inside a try/catch. This should print "fail". <br />
<cfloop array="#users#" index="user">
<cftry>
#sayHelloComplex({ user = user })# <br />
<cfcatch type="any">
fail <br />
</cfcatch>
</cftry>
</cfloop>
--->

<!---
Scenario 5: Pass in a single implicit struct containing the user without looping. This should work. <br />
#sayHelloComplex({ user = users[1] })# <br />
--->

<!---
Scenario 6: Pass in an implicit struct containing the user inside an include. This should work. <br />
<cfloop array="#users#" index="user">
<cfinclude template="user.cfm" />
</cfloop>
--->

<!---
content of user.cfm
<cfoutput>
#sayHelloComplex({ user = user })# <br />
</cfoutput>
--->

</cfoutput>

<cffunction name="sayHelloSimple" returntype="string">
<cfargument name="user" type="any" />

<cfreturn "Hello, #arguments.user.name#" />

</cffunction>

<cffunction name="sayHelloComplex" returntype="string">
<cfargument name="collection" type="any" />

<cfreturn "Hello, #arguments.collection.user.name#" />

</cffunction>


I should note that the complex value doesn't need to be a struct, but it can be an object as well. If you've got a free second, do me a favor and vote it up! http://cfbugs.adobe.com/cfbugreport/flexbugui/cfbugtracker/main.html#bugId=82955.

Also, ColdMVC is now on RIAForge, so check that out too if you haven't yet: http://coldmvc.riaforge.org/.

Saturday, April 24, 2010

GORM vs ColdMVC ORM

One of the more interesting session's at cf.Objective() was Matt Woodward's presentation CFML on Grails. In the presentation, Matt showed how he was able to create a CFML plugin for Grails in order to integrate ColdFusion and Grails.

While the code worked, it seemed a little sketchy at times trying to get the two languages to play nice together cohesively. Even so, Matt achieved his goal of integrating the languages, so he gets props for that.

In his presentation, Matt said one of the biggest advantages of using Grails is being able to leverage Grails Object Relational Mapping (GORM), which is essentially a user-friendly abstraction layer on top of Hibernate.

While Matt took the approach of integrating ColdFusion into Grails in order to use GORM, I took the opposite approach by trying to recreate GORM in ColdFusion inside my ColdMVC framework. Not everything from GORM has been ported over yet, but here's a set of examples for comparison's sake. The top line in each pair is Grails, while the second line is ColdMVC.


def count = Book.count()
var count = _Book.count();

def count = Book.countByTitle("The Shining")
var count = _Book.countByTitle("The Shining");

def count = Book.countByTitleAndAuthor("The Sum of All Fears", "Tom Clancy")
var count = _Book.countByTitleAndAuthor("The Sum of All Fears", "Tom Clancy");

def book = Book.find("from Book as b where b.author=:author",[author:'Dan Brown'])
var book = _Book.find("from Book as b where b.author=:author",{author='Dan Brown'});

def book = Book.findAll("from Book as b where b.author=? order by b.releaseDate",['Dan Brown'],[max:10, offset:5])
var book = _Book.findAll("from Book as b where b.author=? order by b.releaseDate",['Dan Brown'],{max=10, offset=5});

def book = Book.findByTitle("The Shining")
var book = _Book.findByTitle("The Shining");

def books = Book.findAllByTitleLike("%Hobbit%")
var books = _Book.findAllByTitleLike("Hobbit");

def books = Book.findAllByTitle("The Shining", [max:10, sort:"title", order:"desc", offset:100])
var books = _Book.findAllByTitle("The Shining", {max=10, sort="title", order="desc", offset=100});

def book = Book.findWhere(title:"The Shining", author:"Stephen King")
var book = _Book.findWhere({title="The Shining", author="Stephen King"});

def books = Book.findAllWhere(author:"Stephen King")
var books = _Book.findAllWhere({author="Stephen King"});

def book = Book.get(1)
var book = _Book.get(1);

def books = Book.getAll(2,1,3)
var books = _Book.getAll(2,1,3);

def books = Book.getAll([1,2,3])
var books = _Book.getAll([1,2,3]);

def books = Book.list()
var books = _Book.list();

def books = Book.list(max:10, offset:100, sort:"title", order:"desc")
var books = _Book.list({max=10, offset=100, sort="title", order="desc"});


As you can see, aside from a couple small syntax differences, they're almost identical.

Wednesday, April 21, 2010

ColdMVC: Event Listeners

ColdMVC provides your application with several interception points throughout the lifecyle of a request. This is possible thanks to centralized event dispatching from ColdMVC’s EventDispatcher component. In a typical ColdMVC request, the following events will be dispatched:

• requestStart
• actionStart
• preAction
• pre:{controller}Controller
• pre:{controller}Controller.{action}
• action
• post:{controller}Controller:{action}
• post:{controller}Controller
• postAction
• actionEnd
• requestEnd

Any controller within the application can listen for these events by applying metadata to the desired listener method. The events metadata is a comma-separated list of regular expressions, providing quite a bit of flexibility in intercepting. As an example, if you wanted a SecurityController to verify a user is logged in at the beginning of each request, you could have the following code:

component {

/**
* @events requestStart
*/
function verifyLoggedIn() {
if (!session.isLoggedIn) {
redirect({controller="security", action="logout"});
}
}

}

Furthermore, ColdMVC will implicitly invoke certain methods on your request’s controller if they are defined. Before the request’s action is invoked, ColdMVC will invoke the controller’s pre and pre{Action} methods if they exist. Next, ColdMVC will invoke the action for the request, followed by the post{Action} and post methods if they exist. For example, if the current requst is /product/list, ColdMVC will invoke ProductController.pre(), ProductController.preList(), ProductController.list(), ProductController.postList(), and finally ProductController.post().

Tuesday, April 20, 2010

ColdMVC: Plugins

Plugins are custom functions that are available to your views and layouts that help keep your presentation layer clean. Plugins are defined using a simple .cfm file that maps a plugin name to a method on either a helper or a bean defined within ColdSpring.

When you first create an application using ColdMVC, you'll already have access to a standard set of plugins, defined inside /coldmvc/config/plugins.cfm. The most prominent plugin is the linkTo() method that builds URLs for your views.

When ColdMVC loads, it will load any plugins that are found inside your application's /app/config/plugins.cfm, then any plugins inside /coldmvc/config/plugins.cfm. If you would like to override one of ColdMVC's plugins, simply define your own plugin with the same name as the ColdMVC plugin.

While your views and layouts still have access to all of your application's helpers, it is recommended to use plugins rather than the helpers. Even though they will generate the exact same HTML, #linkTo({controller="post", action="list"})# reads a lot better than #$.link.to({controller="post", action="list"})#.