Yawn, Blue Dragon Goes Open Source

The ColdFusion community is aflutter with news that Blue Dragon has gone open source. Many other voices have chimed in on this. But I feel like I have something different to say.

Regardless of the any business gains that Blue Dragon gets from doing this, I don’t think the community will get a tremendous benefit from this.

You see, there is this stream of logic that goes something like this:

  • ColdFusion has a small market share, and it is shrinking
  • ASP.NET, PHP, and Ruby (on Rails) have much more of the market
  • PHP and Ruby (on Rails) are Open Source and free.
  • ASP.NET is zero cost on top of something else we forget you have to pay for
  • ColdFusion would gain market share if it was open source.
  • By “open source” we actually mean “free.”

I think this line of reasoning comes from people that base their request for opening up ColdFusion on what they think the rest of the web development world wants. They think it is all about cost. There are reasons that other people prefer PHP or Ruby (on Rails) or ASP.Net. Not all of those reasons have to do with ColdFusion’s cost.

  • Some people just have to do many small CRUD apps. For just this specific subset of CRUD apps, Ruby on Rails is a better solution than a default install of ColdFusion.
  • Some people want to build around one or several of the many open source applications written in PHP. Why use ColdFusion when you just have to write a few extra PHP pages.
  • Some people have to work with proprietary Microsoft technology. With the exception of Exchange, ColdFusion isn’t as good as ASP.Net for that.
  • Alright – some people don’t like proprietary solutions of any kind. At least we know they’re not using ASP.Net.

I think the ways in which ColdFusion can build inroads around these solution-needs are:

  • More community support around the existing scaffolding solutions for ColdFusion
  • More open source solutions written IN ColdFusion
  • More Adobe support around proprietary interfaces that draw people away from ColdFusion.
  • Acceptance of the fact that just because some people won’t buy proprietary solutions doesn’t mean they shouldn’t exist.

Notice “open source ColdFusion” wasn’t on that list. I don’t think it ever will be.

I don’t know which of the reasons holds the biggest opportunity for ColdFusion to gain market share. You’d need to do surveys and ask current and defecting customers a whole bunch of questions. That sounds like a job for the marketing department of Adobe. Hmmm. Didn’t Adobe add tags for getting information about database’s schema a little easier? Didn’t they fund RIAForge? Didn’t they add code for calling .NET assemblies and the CFExchange tags?

I think Adobe has already decided which customers they are going to go after. Right or wrong, they’ve stuck with selling their current solution, and tailoring it to get those three groups. I think what happens to Blue Dragon, ColdFusion, and market share will do a good job of sorting out who’s right here. I’m betting on Adobe.

Oh, why did I write “Ruby (on Rails)” everywhere? I get annoyed when people fail to understand the distinction between the language and the framework. That being said, I think that Ruby on Rails is the right thing to call the ColdFusion competitor, as it is the entire solution that attracts web developers to it, not just the language. As a further aside, I think the total solution that ColdFusion provides is the special sauce of ColdFusion, not just the language.

ExportReports.com

I’m pleased to announce that I’ve teamed up with Mark Phillips and the guys at Vertabase to publicly release ExportReports.com.

What is ExportReports.com, you ask?

ExportsReports.com is a site that enables users of the 37signals product Basecamp to export copies of their projects to a PDF file. Before ExportReports, a Basecamp user could request a backup of their site, and receive an XML dump of their project. Now, through our site, a user can ask for PDF exports at will. It’s perfect for either ongoing status reports, or an end of project knowledge dump to a client.

We do charge a small fee, but for the first month, we are running at reduced rates.

Technology

ExportReports was written with Adobe ColdFusion, and uses the Basecamp API’s provided by 37signals. Three factors led to us choosing ColdFusion:

  1. We needed to consume webservices, and ColdFusion makes this really easy.
  2. We needed to work with PDF’s and ColdFusion pretty much rocks the PDF.
  3. Let’s face it, I think ColdFusion rocks.

So, wish me luck on this commercial endeavor. If you’re a Basecamp user, I hope you like it. If not, become one, it’s a fantastic product. Then use ExportReports.com.

About Time – An Air and SQLite Application

I few days ago I came across this post at Signal vs. Noise. The first item is about a clock that tells you the approximate time – for example 11:59 is “Nearly Twelve”, 12:30 is Half Past Twelve, etc. etc. The idea is, “Do you really need to know it is 12:53?” This clock gives you the amount of precision that you actually need when dealing with time.

I thought it was kinda cool, but I would never buy one. However when I thought about it, I realized it would make a good AIR application.

After thinking about I decided to do it because:

  • It’s a simple thing to write
  • It could use a database
  • I have a Air and SQLite presentation to prepare

All of these things added up to me writing the thing in about a day. Here’s what I did:

  • Filled a SQLite database with times and descriptions
    • 1 = Just After
    • 15 = Exactly Quarter Past
    • 59 = Nearly (Next hour)
  • Used HTML, JavaScript, and an Image to build the UI
  • Got rid of the default Chrome
  • Used Air Methods to query the database.
  • Placed taskbar items that allow you to:
    • Close
    • Force app Always on Top

The amazing thing to me was how easy it was to do. The actual app worked relatively quickly, most of my time was spent getting the details like icons, and text placement correct.


Download About Time

So if you want to know about what time it is, download your copy of About Time.

Disclaimer: This totally is “an Air app that didn’t really need to be”. I get that. I figured someone else might like it, or at least want to look at the source.

Posting Form to Itself

I’m working on someone else’s code base, and found that they were posting forms to themselves. However they had hard coded the form template names into the code for the form. Like the following:


action=“index.cfm”
method=“post”>

This is a bit of a pet peeve of mine because it tends to make the code very un-portable. What happens if you rename the file “dosomethingelse.cfm.” Now you have to go back and change the file name and the reference.

It was a quick proof of concept application, so I don’t fault the author. But they just aren’t lazy enough.

I prefer doing it this way:


action=“#cgi.script_name#”
method=“post”>

It’s highly cut and paste-able, and you never have to worry when you rename your templates. If you aren’t using cfform, you can still do it, just wrap the form element in a .

Now, I imagine that I will get a comment that says something about not trusting cgi variables. It works with every flavor of IIS and Apache that I have ever worked with. Anybody see any gotcha’s doing that.

Using ColdFusion and SVN to Create Release Notes

I was talking last week about using XML to act as an intermediate step in building your documentation (Automating Documentation and Automating Documentation Part 2). It dawned on me that I could also share my technique for building release notes.

I use Subversion. I’ve gotten positively anal about commenting when I make changes. So if you were to take the history of my SVN commits, they make pretty decent release notes. The trick is to grab them and automatically turn them into documentation.

SVN makes this pretty easy. It takes one command to grab all of the changes. It takes one switch to make the change export as XML. Once that is done, manipulating the content in ColdFusion is a breeze. I do it using <cfexecute> and svn.exe, below is my code:

<cfset svn.wc = “[path to svn working copy]”
/>

<cfset svn.exe = “[path to svn executable]”
/>

<!— -v = verbose –xml outputs it as xml —>

<cfset svn.arg = “log #svn.wc# -v –xml”
/>

<!— get contents of SVN history —>

<cfexecute name=“#svn.exe#”

arguments=“#svn.arg#”

timeout=“30”

variable=“changes”
/>

<cfset changes = XMLParse(changes) />

<cfoutput>

<cfloop
index=“i”
from=“1”

to=“#arrayLen(changes.log.logEntry)#”>

<!— lxml = LoopLocalXML (shorted for display) —>

<cfset lXML = changes.log.logEntry[i] />

<dl>

<dt>#lXML.XmlAttributes.revision#</st>

<dd>

<ul>

<li>#lXML.author.XMLText#</li>

<li>#lXML.date.XMLText#</li>

<li>#ParagraphFormat(lXML.msg.XMLText)#</li>

</ul>

<p>Files Effected</p>

<ul>

<cfloop
index=“j”
from=“1”

to=“#arraylen(lXML.paths.path)#”>

<!— lPaths = LoopLocalpaths —>

<cfset lPaths = lXML.paths.path[j] />

<li>

#lPaths.xmltext#

(#lPaths.xmlattributes.action#)

</li>

</cfloop>

</ul>

</dd>

</dl>

</cfloop>

</cfoutput>

In my build process, I use <cfsavecontent> and <cffile> to write the content to a file, and then use ANT to call the CFML page that creates the release notes – voila, release notes are now part of every build, with no extra work on my part.

Shortcut Key for Commit in Subclipse

This had been driving me nuts for a little while. Maybe I can save someone else the hassle too.

To set a shortcut key for Subclipse commit:

  • Go to Windows → Preferences
  • Go to General → Keys
  • Check the box “Include unbound Commands”
  • Then in the “type filter text” box, type commit
  • Then assign it to whatever key combination you want

If you go through this, and commit and other SVN methods don’t show up.

  • Go to Help → Software updates → Find and Install
  • Choose “Search for updates of currently installed features.”
  • Go through the choices and update Subclipse.

ColdFusion and ODBC Agent

This sent a co-worker down a wrong path yesterday, so I thought I would blog it in case it tripped anyone else up.

There was a problem with one of our SQL servers yesterday. (It was down a long time during a routine patch and reboot due to extra stuff in a Microsoft Tuesday patch.) In trying to troubleshoot the issue, one of the administrators saw errors in the event logs coming from the ColdFusion ODBC Agent.

We are using default driver for Microsoft SQL Server in the drop down on the Data Sources page. Therefore, we were using JDBC driver and weren’t impacted by the ODBC error. The error message was a red herring. It took focus away from the real problem, namely that the database server hadn’t come back online yet.

Going further, as far as I can tell all of the defaults on that page are JDBC drivers, with the exceptions of “ODBC Socket” and “Microsoft Access”. According to this Damon’s comment on this blog post, the “Microsoft Access with Unicode” doesn’t even need the ODBC driver. So I would say, unless you are doing coding against Access databases, or a known ODBC only product, you probably don’t need to install the ODBC services; especially since you can always install them if you need them.

I’d be interested to know if anyone violently disagrees, or if this has been said authoritatively somewhere, and I just not up on my Google-Fu.

Automating Documentation Part 2

This is a follow up to the post Automating Documentation. Jim Priest wanted to see example code, and I’m happy to oblige.

For this example, I am sharing the code for documenting “steps” in Squidhead. Steps are operations that do one thing, like generate stored procs, or ant scripts, or email developers. They are powered by cfm templates in a specific folder. Once there they can be referenced through in the project’s config file. The documentation for them is included in the download for Squidhead, and can be viewed online (Squdihead – Steps).

So after the jump, here is the code for creating this documentation.

So first thing I do is setup a few parameters.

<cfset stepsXMLfile = “#expandPath(‘.’)#/stepsXML.xml”
/>
<cfset
outputfile=“w:inetpubwwwrootsquidhead2docssteps.cfm”
/>

<cfdirectory
action=“list”
recurse=“false”
directory=“#expandPath(‘../../steps’)#”
name=“steps”
type=“file”
/>

Then I conditionally build the file in case I deleted it.

<h2>Building XML</h2>
<cfif

not
FileExists(stepsXMLfile)>

<p>Transforming Steps to XML.</p>

<cfxml
variable=“XMLOutput”>
<steps>
<cfoutput
query=“steps”>
<#ListFirst(name, ‘.’)#>
<documentation />
<requires />
</#ListFirst(name, ‘.’)#>
</cfoutput
</steps>
</cfxml>

<p>Writing to Disk.</p>

<cffile
action=“write”
file=“#stepsXMLfile#”
output=“#XMLOutput#”>


<cfelse>

<p>Already Built.</p>

</cfif>

Then I go through and check to see if each file has a documentation node:

<h2>Checking XML</h2>

<cffile
action=“read”
file=“#stepsXMLfile#”
variable=“rawFile”
/>
<cfset
stepsXML = XMLParse(rawfile) />
<cfset
changed = FALSE
/>

<cfoutput>
<cfloop

query=“steps”>
<cfset stepName = ListFirst(name, ‘.’)/>

<cfif
not
structKeyExists(stepsXML.steps, stepName)>

<p>Adding #stepName#</p>
<cfset changed = TRUE
/>

<cfset stepsXML.steps[stepName] = XmlElemNew(stepsXML,stepName) />
<cfset stepsXML.steps[stepName][‘documentation’] = XmlElemNew(stepsXML,“documentation”) />
<cfset stepsXML.steps[stepName][‘requires’] = XmlElemNew(stepsXML,“requires”) />

</cfif>

</cfloop>

</cfoutput>

<cfif changed>
    <cffile
action=“write”
file=“#stepsXMLfile#”
output=“#stepsXML#”
/>
</cfif>

Next I go through and mark any documentation that is not filled in as a problem and through a 500 error. This will cause ANT to stop running.

<cfset incomplete = FALSE
/>
<cfset
stepArray = StructKeyArray(stepsXML[‘steps’]) />

<h2>Checking Documentation</h2>

<cfoutput>
<cfloop

index=“i”
from=“1”
to=“#ArrayLen(stepArray)#”>

<cfif
StructKeyExists(stepsXML[‘steps’][stepArray[i]], “documentation”) AND

len(stepsXML[‘steps’][stepArray[i]][‘documentation’][‘XMLText’]) lt
1>


<p>Documentation for step #stepArray[i]# is not filled in. </p>


<cfset incomplete = TRUE
/>


</cfif>


</cfloop>
</cfoutput>

<cfif incomplete>

<cfheader
statuscode=“500”
/>

</cfif>

I finish by writing the XML back out to disk as HTML. I’m sure this can be done through XSLT, but I don’t bother.

<h2>Building HTML Reference.</h2>

<cfsaveContent
variable=“stepReference”>

<h2>Step Reference</h2>

<cfinclude
template=“stepsDocs.cfm”
/>
<cfset
stepArray = StructKeyArray(stepsXML[‘steps’]) />
<cfset

ArraySort(stepArray,‘textNoCase’ )>

<h2>Step Details</h2>

<cfoutput>
<dl>

<cfloop
index=“i”
from=“1”
to=“#ArrayLen(stepArray)#”>

<dt>#stepArray[i]#</dt>
<dd>#stepXML[‘steps’][stepArray[i]][‘documentation’][‘XMLText’]#</dd>
<cfif
len(stepXML[‘steps’][stepArray[i]][‘documentation’][‘XMLText’]) gt
0>

<dd
class=“requires”>Requires: #stepXML[‘steps’][stepArray[i]][‘requires’][‘XMLText’]#</dd>

</cfif>


</cfloop>

</cfoutput>

</dl>

</cfsavecontent>

<cffile
action=“write”
file=“#outputfile#”
output=“#stepReference#”
/>

Then to call through ANT, I just add this line to a task in my ANT build file:

<get
src=“${project.url}/tools/stepDocumenter/”
dest=“${project.logPath}/tools/stepDocumenter.html”
/>

I then include these dynamic steps in a static document that includes some background on what steps are and what not.


Automating Documentation

One of the things that I’ve been doing lately is writing reference documentation for my projects. Squidhead has an extensive set of configuration options, and an internal project has a custom XML format. I thought I would share the method I’ve come up with to make it much easier for me to do.

The problem with this type of documentation is that is really easy to do once and then not keep up to date. When coming up with a solution, it had to be repeatable and additive. You could just read in all that information and recreate dynamically from scratch, but that means you can’t manually alter the documentation. I was looking for something that would basically just remind/force me to document new options or files. With that in mind here is what I do:

  • Assume that I am documenting a set of configuration files
  • Create an XML file where each file to be documented is a node
  • Do a directory list of the files to be documented
  • Grab the name of each file
  • Check to see if a node currently exists in the XML for each file.
  • If not I add a node named after the file
  • Create blank sub nodes for “documentation,” “notes,” or “required” or whatever

When that pass is done:

  • I scan the XML
  • I check for blank sub nodes.
  • If any exit I throw an error

I then add this process to my ANT build for the project. Now every time I go to build the project, the documentation gets scanned, added to if needed, and I am prevented from moving forward until I document new changes.

This turned documentation for me from an incomplete mess of a task that takes two hours or so every few weeks to 5 minute maintenance step every time I build.