Working with a new client can be exciting, challenging and sometimes will call into question your sanity for your chosen profession as a developer. Most often times this happens over the course of your career, rarely will it happen all within the same week. This was that kind of week for me. It all started out with a simple idea to use some JQuery and AJAX love on some old form and display pages in a client’s application to show some simple ways to freshen up the UI and consolidate code. This is also where the trouble began as well. Long story short I was making AJAX calls to some ColdFusion CFCs to return data to display information on a page.

$.ajax({
     type:'get'
     ,url: '/com/some.cfc'
     ,data:{method:'someMethod', ReturnFormat:'json', passToken: someValue}
     ,dataType: 'json'
     ,success: function(){
          my success logic here;
     }
     ,error: function(){
          my error logic here;
     }
});

The AJAX call properly requested the format returned to be a JSON Object and looking at Fiddler confirmed this to be true.

{
     "COLUMNS":["COLUMN1","COLUMN2","COLUMN3","COLUMN4"]
     ,"DATA":["VALUE1","VALUE2","VALUE3","VALUE4"]
}

On my local machine everything worked perfectly, as well as in the Testing and Staging environments. Production was a different story, the code failed. A quick inspection of Fiddler reveals the presence of a JavaScript cookie being injected into the response header coming back from the method of the ColdFusion CFC for the requested data. 

<SCRIPT>
    document.cookie = "IV_JCT=%2Fsomevalue";
</SCRIPT>
{
     "COLUMNS":["COLUMN1","COLUMN2","COLUMN3","COLUMN4"]
     ,"DATA":["VALUE1","VALUE2","VALUE3","VALUE4"]
}

As we all know this is not good because any extra data appended to a JSON Object before or after the object renders the response useless to the AJAX call. Unbeknownst to myself, the client is using Tivoli in their single sign on implementation in the production environment. Quick glance over the Tivoli documentation let me know the client has implemented the use of Junction Cookies to maintain state of which client connections belong to which requests for each application. Documentation further goes on to say that the JavaScript cookie will be injected into all response headers with a document type of text/html.

Solution to the problem? Two lines of code added to the top of the CFC to change the response type to something other the the default text/html response.

<cfcomponent>
     <cfset response = getPageContext().getResponse()/>
     <cfset response.setContentType("application/json")/>

	<cffunction name="getSome" access="remote" output="true" returntype="any">
		<cfargument name="SomeValue"/>
		
		my method logic here
		
		<cfreturn rtnValue/>
	</cffunction>
</cfcomponent>

Thanks to Ray Camden I was able to implement a solution to the problem by changing the document content type returned from the CFC method to “application/json” to have the Tivoli servers just pass the response back unmolested.

This is a post in direct response to a recent blog post series from the Developers over at Dave Ramsey. They have recently decided to switch from ColdFusion as their development platform after twelve [12] years to Ruby On Rails with a Java services layer. I must say with them being one of the largest ColdFusion development shops in Nashville, I sat up and took notice. I was eager to read each post to gain knowledge of the who/ what/ where/ when & why’s of what was evaluated and the motivations as to why the change was needed. I was expecting some hardcore information, graphs of performance, lots of side by side analysis of features, pros & cons. But alas, all I got was a marketing fluff piece and whining about how hard it is to find senior level ColdFusion developers.

Please feel free to hop over and read each of the posts yourselves: Part1Part2Part3 and come to your own conclusions.

This post had a totally different direction in the first draft. I had planned on picking apart each one of their posts point by point with counter points of my own about ColdFusion. I had planned on taking on the role of Defender of ColdFusion and how dare they choose Ruby. My frustration with the postings is there was not enough information given on the process of evaluation and the postings felt like an underhanded pimp slap to the face of the developers in the ColdFusion community. The main highlights that stood out to me while reading the postings where:

  • Want to use OOP paradigm
  • The company wants a free/ nearly free solution by going open source
  • We can’t find ColdFusion Developers that meet our standards

Wanting to use the OOP paradigm is to me a style choice or personal coding preference, not a business requirements necessity. ColdFusion had clearly been running for them flawlessly for 12 years and scaled very well during the major growth spurts. No, ColdFusion is not an OO language at heart, even though developers in the community have made attempts to have it mimic OO. That is not how ColdFusion was originally built to run. ColdFusion’s learning curve is lower for a reason; it removes having to learn the whole process of OO and just lets you create applications without all of the headaches.

It’s really hard to argue with upper management when the mandate comes down to cut costs. When they look over the costs of development and start eyeballing the costs of maintaining a ColdFusion server verses some Open Source  Solution, free always wins. I feel it is the responsibility of the development team [leader] to know how to defend against this type of attack. What you gain from cutting the cost of having a ColdFusion server is eaten up with the increases in man hours with respect to development time. The ratio is rarely a 1:1 and I would venture to say it is closer to 1:5 in that for every $1 you saved on cutting costs of ColdFusion license(s) out of budget, you add $5 to the budget in development costs.

The last point is the underhanded pimp slap I referred to earlier.

 To top it all off, there aren’t a lot of senior developers jumping at the chance to learn ColdFusion as their language of choice these days, making it harder to fill our current openings.

This was a very misleading and undeserved statement that sent my blood blooding. First it feeds into the “ColdFusion is a dead language” negativity bandwagon, and second it insults the community of senior level ColdFusion developers in your own backyard of Nashville, TN. The reality of why it is so difficult for your company to find senior level developers is due to the culture of your company. I am not in any way saying you do not have a right to run your business the way you choose, but please live with the rest of us in reality. You are limiting yourself to a much smaller talent pool by your own choices of how you choose to do business. The salary you offer for a senior level developer is WELL below market rate and is the first thing that turns candidates away. Even with a bonus structure in place, a bonus is never a guarantee for income. To expect a senior level developer to take on average a $20k cut in pay to come work for you is highly counter-productive. The second factor, your company is a faith based business that mandates employees participate in a weekly company-wide devotional. If the low salary didn’t scare a candidate, this mandate surely does. You have no idea how many quality senior level developers regularly take a pass on your company after learning these factors. Yes when I was approached by a recruiter about a contact-to-hire position for your company and learned these factors, I too took a pass on your company. There have been several open and candid discussions about working with your company and the interview process among the Nashville ColdFusion community and these factors are repeated time and time again.

In the end, I came away disappointed reading the posts. I expected to gain some insight into a competing technology and some nuggets of information I could further research. What I got was no solid information from the evaluation process and a little more dirt kicked in my face from one of the more respected ColdFusion Development shops in Nashville as they marched off into the Open Source Sunset.

Working with a client that wanted to implement bread crumb navigation on application along with some other navigational menus. I hadn’t had much experience with bread crumbs, actually I have no experience with it at all, so I did the ‘search Google’ thing looking for code examples. There were several that looked promising like this one JavaScript location script that would grab the url from the href and then pull the title of the page from out of the title tag of the page. Got it working except for one thing I over looked before I started down this path. All of the pages on the site are hard coded in the title tag to display the name of the company and the trade mark symbol. So this does me absolutely no good considering all the bread crumbs would appear “Some Company Name ™”.

Like seriously… who does this anymore? I thought we were all on the dynamically name your title tags band wagon now a days. Guess someone missed the memo. After slamming my head into the desk multiple times, I decided to use JQuery’s magical goodness and all would be right with the world. I used JQuery to intercept any anchor tags throughout the application if clicked. The code below intercepts any <a href> hyper link on the site, prevents the default behavior of the <a href> tag and allows me to grab the URL and the text of the link to store in a session variable. Then upon loading of any sub pages be low my main level of navigation pages I can then parse the session variable and construct a nice and neat bread crumb trail.

JQuery code added to bottom of application pages via a cfinclude – footer.cfm

<code>

<script>
$.ajax({
type:’post’,
datatype:’json’,
url:’/main.cfc?method=getCrumb&currentPage=’ + currentPage + ‘&returnformat=json’,
success: function(data){
var pData = $.parseJSON(data);

if (!$.isEmptyObject(pData)) {

var pTitle = Array();
var pURL = Array();
pTitle = pData.PAGETITLE.split(“|”);
pURL = pData.PAGEURL.split(“|”);

$.each(pTitle, function(i, a){
liEle = $(document.createElement(‘li’));
liEle.attr({‘class’ : ‘breadcrumbs’});
aEle = $(document.createElement(‘a’));
aEle.attr({‘href':pURL[i],’id’ : ‘anchorCrumb’,’class’ : ‘breadcrumbs’}).text(pTitle[i]);
//This is the added click event handler function
aEle.click(function(event){
event.preventDefault();
var linktext = $(this).text();
var linkURL = $(this).attr(“href”);

$.ajax({
type:’post’,
datatype:’json’,
url:’/main.cfc?method=setCrumb&pageTitle=’+linktext+’&pageURL=’+linkURL+’&returnformat=json’,
success: function(data){
$(location).attr(‘href’,linkURL);
}
});
});
aEle.appendTo(liEle.appendTo(‘#crumbList’));
});
}
}
});

/*
Intercept any links on the page and use the information to
build the breadcrumb trail manually in the SESSION.crumbBox
then pass the user on to the target page.
*/
$(‘a’).click(function (event) {
event.preventDefault();
var linktext = $(this).text()
var linkURL = $(this).attr(“href”);

$.ajax({
type:’post’,
datatype:’json’,
url:’/main.cfc?method=setCrumb&pageTitle=’+linktext+’&pageURL=’+linkURL+’&returnformat=json’,
success: function(data){
//After the AJax call is successful, proceed to the URL that was clicked.
$(location).attr(‘href’,linkURL);
}
});

}

});
</script>

</code>

This is the cfc that manipulates the session variable.

<code>

<cfcomponent>

<cffunction name=”init” access=”remote”>
<cfreturn this>
</cffunction>

<cffunction name=”setCrumb” access=”remote” returntype=”any”>
<cfargument name=”pageTitle” default=”No Title For Page Found”/>
<cfargument name=”pageURL” default=”/index.cfm”/>
<cfargument name=”resetFlag” default=”0″/>

<cfif len(ARGUMENTS.pageTitle) GT 30>
<cfset ARGUMENTS.pageTitle = left(ARGUMENTS.pageTitle, 30)&’ …’/>
</cfif>

<cfif ListFindNoCase(application.topmenulist.pageURL, ARGUMENTS.pageURL,”|”)>
<cfset SESSION.crumbBox.pageTitle = ”/>
<cfset SESSION.crumbBox.pageURL = ”/>
<cfset SESSION.crumbBox.pageTitle = ListAppend(SESSION.crumbBox.pageTitle, ARGUMENTS.pageTitle,”|”)/>
<cfset SESSION.crumbBox.pageURL = ListAppend(SESSION.crumbBox.pageURL, ARGUMENTS.pageURL,”|”)/>
</cfif>

<cfif NOT ListFindNoCase(SESSION.crumbBox.pageURL,ARGUMENTS.pageURL,”|”)>
<cfset SESSION.crumbBox.pageTitle = ListAppend(SESSION.crumbBox.pageTitle, ARGUMENTS.pageTitle,”|”)/>
<cfset SESSION.crumbBox.pageURL = ListAppend(SESSION.crumbBox.pageURL, ARGUMENTS.pageURL,”|”)/>
<cfelse>
<cfset tmpLen = ListLen(SESSION.crumbBox.pageURL,”|”)/>
<cfset tmpPos = ListFindNoCase(SESSION.crumbBox.pageURL,ARGUMENTS.pageURL,”|”)+1/>
<cfloop from=”#tmpLen#” to=”#tmpPos#” step=”-1″ index=”fx”>
<cfset SESSION.crumbBox.pageTitle = ListDeleteAt(SESSION.crumbBox.pageTitle, fx,”|”)/>
<cfset SESSION.crumbBox.pageURL = ListDeleteAt(SESSION.crumbBox.pageURL, fx,”|”)/>
</cfloop>
</cfif>

<cfif ListLen(SESSION.crumbBox.pageURL,”|”) GT 5>
<cfset SESSION.crumbBox.pageTitle = ListDeleteAt(SESSION.crumbBox.pageTitle, 1,”|”)/>
<cfset SESSION.crumbBox.pageURL = ListDeleteAt(SESSION.crumbBox.pageURL, 1,”|”)/>
</cfif>

<cfreturn SESSION.crumbBox/>
</cffunction>

<cffunction name=”getCrumb” access=”remote” returntype=”any”>
<cfargument name=”currentPage”/>

<cfif ListFindNoCase(application.topmenulist.pageURL, ARGUMENTS.currentPage,”|”)>
<cfset SESSION.crumbBox.pageTitle = ”/>
<cfset SESSION.crumbBox.pageURL = ”/>
<cfset SESSION.crumbBox.pageTitle = ListAppend(SESSION.crumbBox.pageTitle, ListGetAt(application.topmenulist.pageTitle,ListFindNoCase(application.topmenulist.pageURL,ARGUMENTS.currentPage,”|”),”|”),”|”)/>
<cfset SESSION.crumbBox.pageURL = ListAppend(SESSION.crumbBox.pageURL, ARGUMENTS.currentPage,”|”)/>
</cfif>

<cfreturn SESSION.crumbBox/>
</cffunction>
</cfcomponent>

</code>

And there you have it ColdFusion with a little JQuery loving to solve a headache of a problem.

So I am currently working with a client that I have spent the better part of six months and change rewriting a ColdFusion application that serves as a knowledge base and software update portal. We launch the new code base into production and work through 99.9% of the bugs. But now it’s killing off that .10% of the bugs that has me bent out of shape. The errors coming back are a bit strange and don’t follow the logic path that is expected. There have been several times that I have seen ColdFusion throw one error about one thing, but that error is not the real error, it’s a silent database error that gets glossed over like it never happened.

Anyway in my research in uncover what the true issues is, I decided to use the ColdFusion AdminAPI to get back more then just the standard stack trace of pages and debug information. So after looking at a few blog entries and the Adobe documentation I come up with:

<cfscript>
        cfAdminObj = createObject(“component”,”cfide.adminapi.administrator”).login(“thepassword”);
        cfDebugObj = createObject(“component”,”cfide.adminapi.debugging”);
        qEvents = cfDebugObj.getDebugRecordset();
</cfscript>
Which runs all fine and dandy on my local development machine. But when I take it to production, it bombs on the cfDebugObj.getDebugRecordset(); line. After banging my head on the desk and checking the production server, I find out that my local CF is at version 9.0 and the production box is at 9.0.1. I then quickly check the code on my laptop which is ver 10 and it bombs there as well. Long story short after a few email exchanges with Ray Camden [Thanks Ray!] my worst fear comes true. I have found my very first verified ColdFusion bug ever. Now the wait till the fix makes it way into a hotfix update ensues.

Dear Prospective Recruiter Looking To Represent Me;

Thank you for considering me for your client’s needs at this time for an experienced ColdFusion Developer. I am happy to know that you were able to find my resume easily on one of the few job boards I tend to post my resume. [Dice.com & Monster.com] I appreciate you using the contact information I made available to get in touch with me to inform me of your client’s current needs. It lets me know that the Internet is doing it’s job helping me to stay employed and my career stable.

Please allow me to take this time now to explain to you what I do not appreciate. I do not appreciate the fact that you did not take the time to read my resume that was posted. The reason I know you didn’t read it is because you have contacted me about a .Net position with your client, or a SQL DBA position available or even better an Inside Sales position with a new marketing company. None of these positions are mentioned in my resume, nor am I even qualified in the lest to fill these positions.  Next I don’t appreciate the way you have called my phone multiple times with in a few hours on a work day. One call with a voice mail will do, maybe an email along with the call but no more. You see just like you are at work, so am I. Maybe I am in a meeting, maybe I am in the middle of trying to solve a complex bug in code, maybe just maybe I am trying very hard to conceal the fact that I am looking for a new position from my current employer. In any case, if I am interested I will call you back so there is no need to call me several times in the same day. Next I really don’t appreciate getting multiple calls from the same recruiting firm from different recruiters offering me the same position. It makes it look like your firm is highly disorganized or worst, highly cut throat between the staff. In either case I wouldn’t allow you to be my representative because I feel you wouldn’t have my best interest at heart. Lastly I really don’t appreciate you calling me and you have an extremely heavy accent. This is directed at you Mr & Ms Recruiter from India. Here’s the deal, if I can’t understand you enough to comprehend what the position is, how can I trust you will be able to communicate to the client what benefit I will be to the company? Even more so, how can I trust that your communication skills won’t be the barrier that causes me not to get the job because the hiring manager decided you are to difficult to understand?

So in closing lets review. Read the resume of the candidate you are contacting and know what career path they follow. One phone call with accompanying email and/or voicemail in a 24 hour period is enough. Work with your fellow recruiters or at the very least give the impression that you are well organized. Lastly, if you have an accent get some speech lessons. If you follow these simple but important pointers I can assure you candidates will be more willing to work with you and your clients will get their much needed resources. Which in turns means more money in your pocket at the end of the day.

Sincerely,

Highly Irritated ColdFusion Developer

I can honestly say that in the beginning I had absolutely no idea of where this ColdFusion thing was going to take me. At the time it was just a tool to help me make a couple of pages to manage the two C-Class IP Licenses my employer owned and the couple hundred mom and pop websites we hosted. Now 10 plus years later it has become a way of life, my passion and my career. I am far from a ‘Fan Boy’ but I have been loyal to the language. However I must admit I have started to become curious about the other languages out there and their way of doing things.  I have been playing around in my spare time and I am starting to form the opinion that languages are just syntax, the important thing is knowing logic and critical thinking process. Learning a new language is really about knowing what you wish to accomplish, and then learning that language’s syntax to accomplish it.

I can see this is going to be an interesting ride as I learn more about the ways of the other languages.