As promised, here are my slides and code from today's presentation.
The slides can be found at: http://slidesix.com/view/TDD-Demystified
The code is at: http://github.com/bittersweetryan/Katas
Thanks for visiting!
Thursday, October 21, 2010
Wednesday, October 20, 2010
I'll be Presenting on "TDD Demystified" at the Online ColdFusion User Group This Week!
If you are interested in TDD but don't quite know how or where to get started join Jon Dowdle (http://jdowdle.com/wp/) and myself at the Online ColdFusion User Group this Thursday 10/21/2010.
I'll be covering Unit Testing basics, Test Driven Development basics, and to finish John and I both be doing a live coding demonstration solving a simple TDD Kata problem. I hope to see you there!
http://www.meetup.com/coldfusionmeetup/calendar/15165569/
I'll be covering Unit Testing basics, Test Driven Development basics, and to finish John and I both be doing a live coding demonstration solving a simple TDD Kata problem. I hope to see you there!
http://www.meetup.com/coldfusionmeetup/calendar/15165569/
Wednesday, September 1, 2010
Using Mock Objects to Test Functions With Named Arguments in MXUnit
Today I was writing some code that dynamically called a method setter on an object. While all of the dump output looked like what I was expecting my MXUnit tests kept failing and I couldn't figure out why. Then I realized that I was using a cfinvoke statement to call the setter and that always uses named parameters to set the argument values. As soon as I added the argument names to my tests I got my happy little green bar.
For example, this is my component that calls a setter dynamically using cfinvoke:
Here is the first test I wrote:
As a side note you might notice that my tests are written in script format while my CUT is written in tag format. This is because my production environment at work is CF8 but I use CF9 locally and write my tests in script to practice my CF9 skills
The above test produced this result:
Here is my new test using named arguments:
The above test gives me the happy little green bar:
For example, this is my component that calls a setter dynamically using cfinvoke:
<cfcomponent> <cffunction name="SetDynamicProperty" access="public" output="false" returntype="void" hint="I set a value on a object dynamically"> <cfargument name="theValue" type="any" /> <cfargument name="theProperty" type="string" /> <cfargument name="theObject" type="any" /> <cfinvoke component="#arguments.theObject#" method="Set#arguments.theProperty#"> <cfinvokeargument name="#arguments.theProperty#" value="#arguments.theValue#"> </cfinvoke> </cffunction> </cfcomponent>
Here is the first test I wrote:
As a side note you might notice that my tests are written in script format while my CUT is written in tag format. This is because my production environment at work is CF8 but I use CF9 locally and write my tests in script to practice my CF9 skills
component extends="mxunit.framework.TestCase" { function testSetDynamicProperty_should_call_SetFirstName(){ var NamedArguments = new NamedArguments(); var MockTestObject = mock(); //create the mock behavior MockTestObject.SetFirstName('Ryan'); NamedArguments.SetDynamicProperty("Ryan","FirstName",MockTestObject); MockTestObject.verify().SetFirstName('Ryan'); } }
The above test produced this result:
Here is my new test using named arguments:
component extends="mxunit.framework.TestCase" { function testSetDynamicProperty_should_call_SetFirstName(){ var NamedArguments = new NamedArguments(); var MockTestObject = mock(); //create the mock behavior MockTestObject.SetFirstName(firstname='Ryan'); NamedArguments.SetDynamicProperty("Ryan","FirstName",MockTestObject); MockTestObject.verify().SetFirstName(firstname='Ryan'); } }
The above test gives me the happy little green bar:
Labels:
ColdFusion,
MXUnit,
TDD
Tuesday, August 17, 2010
ColdFusion Developer Fantasy Football League!
I just created a Yahoo Fantasy Football league just for you ColdFusion developers out there! Its at http://football.fantasysports.yahoo.com/league/coldfusiongeeks. For bragging rights only, but what great bragging rights they are.
The rosters, rules and scoring are all set to the league defaults. The draft will be an auto-pick draft so you don't need to be there to get your team, just set your draft order and forget about it.
Please shoot me an e-mail or hit me up on twitter @bittersweetryan if you are interested in participating and I'll send you the password.
The rosters, rules and scoring are all set to the league defaults. The draft will be an auto-pick draft so you don't need to be there to get your team, just set your draft order and forget about it.
Please shoot me an e-mail or hit me up on twitter @bittersweetryan if you are interested in participating and I'll send you the password.
Thursday, August 12, 2010
Intro To the CFInterface Tag With A Real World Example
One of the most confusing things I encountered while learning OO concepts was the concept of interfaces. Definitions of interfaces was were abundant but I couldn't find much information on how they were used in an actual application. This post will focus on a real world example of using an interface in an application and hopefully help clarify how they can be used to create more flexible objects. Also, please feel free to leave me a comment and tell me where I'm way off here, I'm always learning and willing to listen to any good constructive criticism.
At a very high level interfaces are types, just like components are types and can be passed around similar to components. The difference between an interface and a component is that an interface has no implementation code (code that actually does something) inside of the function definition. All an interface does is define functions and their signatures. A function's signature is its name plus unique combination of arguments. Lets take a look at an example of an interface that defines a "Document" in a system that I am currently working on.
Pretty simple looking, right? The main thing to note here is that there is no implementation code, the function is just a skeleton. This interface is a contract for any component that implements it saying that the component must have a method called GetDocumentData that returns the type of "any". Its up to the implementing component to actually do stuff within the GetDocumentData function.
For the application I'm currently working on a Document object can represent either a Binary document such as a Word or Excel document or an XML document. Since the handling of binary data is different than the handling of XML data I needed to create seprate components to handle each type of document. Here is the code for the BinaryDocument Component:
You can see that the GetDocumentData function now returns variables.documentData which defaults to an empty Binary object and is set by the SetDocumentData function. The XMLDocument component is very similar, except the document data is stored as a string:
Now this is were interfaces become useful. My system also includes an Attachment component that can represent either a binary or XML document. The Attachment component has a Document property which is set using the SetDocument function. Whats important to see here is that the argument type that the SetDocument function expects is IDocument. This means that any component that implements the IDocument interface can be passed into this function. Since we know that the IDocument interface defines a function called GetDocumentData we can call that function on the Document property to return the data from any type of document. The code for the Attachment object is shown below (I've removed all the other properties from this function to keep things terse):
The following code is shows how all of these components are put together to output different types of data:
This is what the preceding code outputs:
For additional reading on Interfaces check out Sun's Java Tutorials here: http://download.oracle.com/javase/tutorial/java/concepts/interface.html. I'd also suggest you read http://www.artima.com/lejava/articles/designprinciples.html where Erich Gamma talks about why programing using interfaces is preferred over inheritance here .
At a very high level interfaces are types, just like components are types and can be passed around similar to components. The difference between an interface and a component is that an interface has no implementation code (code that actually does something) inside of the function definition. All an interface does is define functions and their signatures. A function's signature is its name plus unique combination of arguments. Lets take a look at an example of an interface that defines a "Document" in a system that I am currently working on.
interface hint="I represent either a binary or xml document" { public any function GetDocumentData() hint="I send back document data" output="false"; }
Pretty simple looking, right? The main thing to note here is that there is no implementation code, the function is just a skeleton. This interface is a contract for any component that implements it saying that the component must have a method called GetDocumentData that returns the type of "any". Its up to the implementing component to actually do stuff within the GetDocumentData function.
For the application I'm currently working on a Document object can represent either a Binary document such as a Word or Excel document or an XML document. Since the handling of binary data is different than the handling of XML data I needed to create seprate components to handle each type of document. Here is the code for the BinaryDocument Component:
component displayname="BinaryDocument" implements="IDocument" hint="I represent a binary document (word, excel, etc)" output="false" { variables.documentData = ToBinary(''); public void function SetDocumentData(binary documentData){ variables.documentData = arguments.documentData; } public any function GetDocumentData() hint="I send back document data" output=false { return variables.documentData; } }
You can see that the GetDocumentData function now returns variables.documentData which defaults to an empty Binary object and is set by the SetDocumentData function. The XMLDocument component is very similar, except the document data is stored as a string:
component displayname="XMLDocument" implements="IDocument" hint="I represent a XML document (word, excel, etc)" output="false" { variables.documentData = ""; public void function SetDocumentData(string documentData){ variables.documentData = arguments.documentData; } public any function GetDocumentData() hint="I send back document data" output=false { return IsXml(variables.documentData)?XMLParse(variables.documentData):false; } }
Now this is were interfaces become useful. My system also includes an Attachment component that can represent either a binary or XML document. The Attachment component has a Document property which is set using the SetDocument function. Whats important to see here is that the argument type that the SetDocument function expects is IDocument. This means that any component that implements the IDocument interface can be passed into this function. Since we know that the IDocument interface defines a function called GetDocumentData we can call that function on the Document property to return the data from any type of document. The code for the Attachment object is shown below (I've removed all the other properties from this function to keep things terse):
component displayname="Attachment" hint="I represent an attachment" output="false" { property name="variables.Document" type="IDocument" setter="true"; public IDocument function getDocument() { return Document; } public void function SetDocument( required IDocument Document ) { variables.Document = arguments.Document; } public any function GetDocumentData() description="I return a documents data as defined by the Document object." output="false" { return variables.Document.GetDocumentData(); } }
The following code is shows how all of these components are put together to output different types of data:
//create a new binary document BinaryDocument = new BinaryDocument(); BinaryDocument.SetDocumentData(toBinary('')); //create a new XML document XMLDocument = new XMLDocument(); XMLDocument.SetDocumentData('XML is it your friend or foe?'); Attachment = new Attachment(); Attachment.setDocument(XMLDocument); WriteDump(Attachment.GetDocumentData()); Attachment.setDocument(BinaryDocument); WriteDump(Attachment.GetDocumentData());
This is what the preceding code outputs:
For additional reading on Interfaces check out Sun's Java Tutorials here: http://download.oracle.com/javase/tutorial/java/concepts/interface.html. I'd also suggest you read http://www.artima.com/lejava/articles/designprinciples.html where Erich Gamma talks about why programing using interfaces is preferred over inheritance here .
Thursday, August 5, 2010
My MXUnit TDD Perspective in CFBuilder (or CFEclipse for that matter)
First things first, if you are not doing Test Driven Development yet you should at least give it a try. Sparing all the technical aspects of why its good, its just a fun way to code.
In order for you to understand why I have my perspective setup this way for TDD a quick explanation of what TDD is in order. The basic principal of Test Driven Development is to write unit tests before you write your implementation code. For instance, if I wanted to write a function in an Account object to test if a username existed I'd start by writing a test called something like "TestIsUsernameUnique" in a CFC Called TestAccount.cfc. Once that test is written it is run and should fail since the IsUsernameUnique method has not been implemented yet. This is an important step in TDD, if that test passes there is certainly something wrong with the test itself. Once you have seen the test fail the implementation code (the actual IsUsernameUnique function) is written and the test is run, and re-run until the test passes.
One great way to learn TDD is to watch TDD Kata's. These are screencasts of people doing live test driven development. I've always learned best by example so watching TDD Kata's has been invaluable to my learning of TDD.
Now that I've gotten that out of the way lets talk about how I have my development environment setup for Test Driven Development. When I'm doing TDD there are 4 things that are important to me: 1 - my UML diagram, 2 - the Test code, 3 - the implementation code, and 4 - my MXUnit view. Additionally I like to have my outline and console views handy so I can get a quick glance of what functions are in in the code I've written.
The first step in creating my TDD perspective is to minimize the navigator view and get rid of every other view. This might be a good place to point out that you can always reset your CFBuilder or CFEClipse perspective back to its default state by going to Window -> Reset Perspective. The following image shows what my default ColdFusion perspective looks like before I clean up the screen:
This is what my perspective looks like after I clean up my screen:
Now that I have a blank canvas lets get my workspace setup for Test Driven Development. Assuming that you have the MXUnit eclipse plugin installed, open it by either clicking on the MXUnit icon on the top toolbar, or by going to Window -> Show View -> Other -> MXUnit -> MXUnit. By default this should open on the right side of the screen as shown:
This isn't the ideal location for TDD so I'll move it to the bottom of my screen by dragging the tab towards the bottom of the screen until the outline fills the width of the eclipse screen and dropping it there as shown here:
This is useful when using TDD for a few reasons. First you get more real estate to read the "Tag Context" of the MXUnit view so you can see exactly why your tests are failing. Second, as you'll soon see I need all the horizontal real estate as I can get for my code.
Once I have my MXUnit view anchored on the bottom of my screen I'll also do the same process to add the Outline and Console views next to my MXUnit view on the bottom. I add these tabs because I like to be able to see what functions are available in the file I am working on to make sure that the function names in my test code and in my implementation code are the same. I also like to see what MXUnit is doing behind the scenes in the console.
Now for the important part, the code. If you haven't already created your implementation and test cfc's, use the Navigator (which was minimized so you'll need to click on the Navigator icon on the left of the screen to see it) to create them. Now you should now have two code editor tabs open in your editor, one for your implementation code and one for your test code. The next step is to get both of these files to display right next to each other. Personally I like my test code to be on the right and my implementation code to be on the left, but the order really doesn't matter. To do this grab the tab for either your test code or your implementation code and drag it towards the left side of the screen until the outline fills half of your editor area and drop it there. The final workspace should look something like this:
Now you can see your test code, test results, and implementation code all on the same screen and are ready to become a TDD ninja.
One last step is to save this perspective so it's readily available for your TDD development. Go to Window -> Save Perspective As and enter a name for it.
In order for you to understand why I have my perspective setup this way for TDD a quick explanation of what TDD is in order. The basic principal of Test Driven Development is to write unit tests before you write your implementation code. For instance, if I wanted to write a function in an Account object to test if a username existed I'd start by writing a test called something like "TestIsUsernameUnique" in a CFC Called TestAccount.cfc. Once that test is written it is run and should fail since the IsUsernameUnique method has not been implemented yet. This is an important step in TDD, if that test passes there is certainly something wrong with the test itself. Once you have seen the test fail the implementation code (the actual IsUsernameUnique function) is written and the test is run, and re-run until the test passes.
One great way to learn TDD is to watch TDD Kata's. These are screencasts of people doing live test driven development. I've always learned best by example so watching TDD Kata's has been invaluable to my learning of TDD.
Now that I've gotten that out of the way lets talk about how I have my development environment setup for Test Driven Development. When I'm doing TDD there are 4 things that are important to me: 1 - my UML diagram, 2 - the Test code, 3 - the implementation code, and 4 - my MXUnit view. Additionally I like to have my outline and console views handy so I can get a quick glance of what functions are in in the code I've written.
The first step in creating my TDD perspective is to minimize the navigator view and get rid of every other view. This might be a good place to point out that you can always reset your CFBuilder or CFEClipse perspective back to its default state by going to Window -> Reset Perspective. The following image shows what my default ColdFusion perspective looks like before I clean up the screen:
This is what my perspective looks like after I clean up my screen:
Now that I have a blank canvas lets get my workspace setup for Test Driven Development. Assuming that you have the MXUnit eclipse plugin installed, open it by either clicking on the MXUnit icon on the top toolbar, or by going to Window -> Show View -> Other -> MXUnit -> MXUnit. By default this should open on the right side of the screen as shown:
This isn't the ideal location for TDD so I'll move it to the bottom of my screen by dragging the tab towards the bottom of the screen until the outline fills the width of the eclipse screen and dropping it there as shown here:
This is useful when using TDD for a few reasons. First you get more real estate to read the "Tag Context" of the MXUnit view so you can see exactly why your tests are failing. Second, as you'll soon see I need all the horizontal real estate as I can get for my code.
Once I have my MXUnit view anchored on the bottom of my screen I'll also do the same process to add the Outline and Console views next to my MXUnit view on the bottom. I add these tabs because I like to be able to see what functions are available in the file I am working on to make sure that the function names in my test code and in my implementation code are the same. I also like to see what MXUnit is doing behind the scenes in the console.
Now for the important part, the code. If you haven't already created your implementation and test cfc's, use the Navigator (which was minimized so you'll need to click on the Navigator icon on the left of the screen to see it) to create them. Now you should now have two code editor tabs open in your editor, one for your implementation code and one for your test code. The next step is to get both of these files to display right next to each other. Personally I like my test code to be on the right and my implementation code to be on the left, but the order really doesn't matter. To do this grab the tab for either your test code or your implementation code and drag it towards the left side of the screen until the outline fills half of your editor area and drop it there. The final workspace should look something like this:
Now you can see your test code, test results, and implementation code all on the same screen and are ready to become a TDD ninja.
One last step is to save this perspective so it's readily available for your TDD development. Go to Window -> Save Perspective As and enter a name for it.
Friday, May 7, 2010
Three Helpful ColdFusion Buider Tips
Here are a few quick tips to help increase your productivity using ColdFusion Builder.
1) Use Ctrl + Click Shortcuts
When creating an object, using a cfinclude statement, or calling a function mouse over the object, template, or function call and hold down Ctrl key to activate a hyperlink for that definition. While holding down the ctrl key left click the hyperlink to open the file in a new editor tab. This comes in really handy when tracking down a problem.
Creating a Component:
Using a cfinclude:
Calling a function:
2) Start your development server from CFBuilder
Assuming that you've added your development server to the Servers View in Builder, always use the Server View to start your ColdFusion server instance. This will bind the console view to your server instance and allow the server to display valuable information in the console. Here is a quick example of the binding in action.
Note: This will only work if you do not have the option "Use Windows Service to start/stop the server" selected in your server definition.
Lets start by throwing an error when the local ColdFusion server was running BEFORE ColdFusion Builder was started:
Now lets go back into builder and take a look at the console view:
Nothing is there but a generic server is available message. Now I will go into my servers view and restart my ColdFusion server and rethrow the error. Now the console view gives us some valuable information about the error that just occurred:
This gets even more helpful as your errors get more complex because the console view will show you the entire java stack trace.
3) Use the SQL Editor (This is not the same as the RDS Query Viewer)
The SQL Editor is a very different animal than the RDS Query Viewer. The SQL Editor can be opened by clicking Ctrl + Alt + S or by right clicking in the code editor and selecting SQL Editor. The SQL Editor in CFBuilder will allow you to edit your query, preview your results, and insert the SQL code back into your template. The biggest difference between the SQL Editor and the RDS Query View is that the SQL Editor will provide you with SQL Code insite!
1) Use Ctrl + Click Shortcuts
When creating an object, using a cfinclude statement, or calling a function mouse over the object, template, or function call and hold down Ctrl key to activate a hyperlink for that definition. While holding down the ctrl key left click the hyperlink to open the file in a new editor tab. This comes in really handy when tracking down a problem.
Creating a Component:
Using a cfinclude:
Calling a function:
2) Start your development server from CFBuilder
Assuming that you've added your development server to the Servers View in Builder, always use the Server View to start your ColdFusion server instance. This will bind the console view to your server instance and allow the server to display valuable information in the console. Here is a quick example of the binding in action.
Note: This will only work if you do not have the option "Use Windows Service to start/stop the server" selected in your server definition.
Lets start by throwing an error when the local ColdFusion server was running BEFORE ColdFusion Builder was started:
Now lets go back into builder and take a look at the console view:
Nothing is there but a generic server is available message. Now I will go into my servers view and restart my ColdFusion server and rethrow the error. Now the console view gives us some valuable information about the error that just occurred:
This gets even more helpful as your errors get more complex because the console view will show you the entire java stack trace.
3) Use the SQL Editor (This is not the same as the RDS Query Viewer)
The SQL Editor is a very different animal than the RDS Query Viewer. The SQL Editor can be opened by clicking Ctrl + Alt + S or by right clicking in the code editor and selecting SQL Editor. The SQL Editor in CFBuilder will allow you to edit your query, preview your results, and insert the SQL code back into your template. The biggest difference between the SQL Editor and the RDS Query View is that the SQL Editor will provide you with SQL Code insite!
Labels:
ColdFusion Builder
Friday, April 30, 2010
My Favorite Things In ColdFusion Builder
After I read Sam Farmer's "5 Things I Love About ColdFusion Builder" article I started to think about why I love ColdFusion Builder so much. To put it in perspective exactly how much I love it, I told my CTO I'd be willing to have them take money out of my paycheck to purchase it if my company wouldn't outright buy it for me. FYI they did end up purchasing it for me. With that out of the way here is why I love ColdFusion Builder:
Debugging Perspective
This has to be one of the most helpful tools for me in Builder. I love the fact that we can now do line debugging and view variables in real time. Most (but not all) of the time it sure beats the old cfdump cfabort method of debugging. My only gripe about the line debugger is that it tends to run a bit slow. The documentation states that using the "Step Over" command over the "Step Into" command will improve performance, however, this isn't very helpful when debugging a complex OO project.
Ctrl+Click Shortcuts
When I first read about the ctrl+click I had no idea how much I'd use it. For those of you who don't know about it, when you create an object or include a file you can hover over the object definition or the file location and hit ctrl-click to open that file or object in the editor.
Servers View and the Console View
I use these features hand in hand most of the time. As long as your ColdFusion server is started using Builder, the console is very helpful when debugging, is most cases you get the full stack trace of the problem.. I also love the fact that I can open up my administrator and server monitor right in the Builder interface instead of having to switch to my web browser.
CFC Method Insite
Even though our ColdFusion staff is small I still have have to frequently consume objects written by other people. Because of method insite I don't need to know the method names or arguments of the public interface of an object before implementing it. All I need to know where the CFC lives and CFBuilder will tell me what I need to know when referring to that object.
While I this is definitely one of my favorite things about ColdFusion builder, it is also one that provides me much frustration. For starters it doesn't work when you pass in an object as an argument to a function. Second it seems somewhat hit or miss for me when inside a cfscript tag. I haven't been able to track down exactly where and why it fails but I think it has something to do with error parser.
Extensions
Last but certainly not least is the support for custom extensions written in ColdFusion! What a brilliant idea, allow the community to enhance your product by extending it with the language we all know and love. I can't wait to see what extensions the community is going to come up with. I'll definately be keeping my eye on Ray Camden's ColdFusion Builder contest.
Debugging Perspective
This has to be one of the most helpful tools for me in Builder. I love the fact that we can now do line debugging and view variables in real time. Most (but not all) of the time it sure beats the old cfdump cfabort method of debugging. My only gripe about the line debugger is that it tends to run a bit slow. The documentation states that using the "Step Over" command over the "Step Into" command will improve performance, however, this isn't very helpful when debugging a complex OO project.
Ctrl+Click Shortcuts
When I first read about the ctrl+click I had no idea how much I'd use it. For those of you who don't know about it, when you create an object or include a file you can hover over the object definition or the file location and hit ctrl-click to open that file or object in the editor.
Servers View and the Console View
I use these features hand in hand most of the time. As long as your ColdFusion server is started using Builder, the console is very helpful when debugging, is most cases you get the full stack trace of the problem.. I also love the fact that I can open up my administrator and server monitor right in the Builder interface instead of having to switch to my web browser.
CFC Method Insite
Even though our ColdFusion staff is small I still have have to frequently consume objects written by other people. Because of method insite I don't need to know the method names or arguments of the public interface of an object before implementing it. All I need to know where the CFC lives and CFBuilder will tell me what I need to know when referring to that object.
While I this is definitely one of my favorite things about ColdFusion builder, it is also one that provides me much frustration. For starters it doesn't work when you pass in an object as an argument to a function. Second it seems somewhat hit or miss for me when inside a cfscript tag. I haven't been able to track down exactly where and why it fails but I think it has something to do with error parser.
Extensions
Last but certainly not least is the support for custom extensions written in ColdFusion! What a brilliant idea, allow the community to enhance your product by extending it with the language we all know and love. I can't wait to see what extensions the community is going to come up with. I'll definately be keeping my eye on Ray Camden's ColdFusion Builder contest.
Labels:
ColdFusion,
ColdFusion Builder
Sunday, March 21, 2010
A better alternate to the exec() function in sql server 2005 to run a dynamic SQL statement.
When creating a dynamic SQL statement in SQL Server 2000 and up avoid using the exec() function. There is a system stored procedure that works better called sp_executesql(). Here is a link to Microsoft's documentation: (SQL 2005) http://msdn.microsoft.com/en-us/library/ms188001(SQL.90).aspx (SQL 2000)
http://msdn.microsoft.com/en-us/library/aa933299%28SQL.80%29.aspx
http://msdn.microsoft.com/en-us/library/aa933299%28SQL.80%29.aspx
Wednesday, March 17, 2010
ColdFusion cfswitch bug not completely fixed...
I remember a bug in ColdFusion where a long cfswitch statement would throw an error. This was thought to be fixed, however it still does exist when using switch and case statements inside of a cfscript tag.
I have a large controller (2500 lines or so) file that makes a lot of object calls within my switch statements and when using switch and case statements within cfscript I would get a "Invalid method Code length" error. Once I converted the switch statements to markup everything worked fine...
<cfscript> switch(fuse) { case "login": { ArrayAppend(IncludeArray,"DisplayFiles\dsp_Login.cfm"); break; } case "logout": { include("ActionFiles\act_logout.cfm"); relocate("index.cfm?fuse=login&message=You have been successfully logged out."); break; }
I have a large controller (2500 lines or so) file that makes a lot of object calls within my switch statements and when using switch and case statements within cfscript I would get a "Invalid method Code length" error. Once I converted the switch statements to markup everything worked fine...
<cfswitch expression="#fuse#"> <cfcase value= "login"> <cfscript> ArrayAppend(IncludeArray,"DisplayFiles\dsp_Login.cfm"); </cfscript> </cfcase> <cfcase value= "logout"> <cfscript> include("ActionFiles\act_logout.cfm"); relocate("index.cfm?fuse=login&message=You have been successfully logged out."); </cfscript> </cfcase>
Labels:
ColdFusion
Optimized ColdFusion Record Paging and Sorting using SQL Server 2005
While working on a large application with lots of data I began to think about optimizing my record paging. I began working on an old school approach of using temporary tables and stored procedures to do my record paging when I decided to hit up google to find a better approach. The simple search of "ColdFusion record paging" didn't bring up anything of use to me but then I searched "SQL Server 2005 record paging" and found something I could use. In SQL 2005 a new function called row_number() was added which makes record paging much easier and much more efficient.
Using record_count my query looked something like this:
Here is what my final code looks like:
Here's the proof that the optimized paging query works much, much faster (click on the images for a full sized version that will show you the execution times better):
Using record_count my query looked something like this:
SELECT * FROM ( SELECT row_number() over(order by S.name) as rowNum ,S.siteId ,S.code ,S.name ,S.roleBitMask ,R.description as regionDescription ,R.regionId FROM Site S INNER JOIN Region R ON R.regionID = S.regionId WHERE S.deleted = 0 ) AS List WHERE rowNum between 1 and 25This query worked great, however it was leaving out one very important piece of information: the record count. I did not want to make another call to the db to get the record count so a few minutes of research brought me to this solution:
WITH List AS ( SELECT row_number() over(order by S.name) as rowNum ,S.siteId ,S.code ,S.name ,S.roleBitMask ,R.description as regionDescription ,R.regionId FROM Site S INNER JOIN Region R ON R.regionID = S.regionId WHERE S.deleted = 0 ), ListRecordCount AS ( SELECT * FROM List ,(SELECT MAX(rowNum) AS recordCount FROM List) AS recordCount ) SELECT * FROM ListRecordCount WHERE rowNum between 1 and 25Now I'm only pulling 25 rows from the database at a time, and I'm getting a record count! All that is left is to use ColdFusion to pass in my start and end rows and to pass in different order by clauses as well.
Here is what my final code looks like:
<cfquery name="local.GetSiteListQuery" datasource="#variables.datasource#"> WITH List AS ( SELECT row_number() over(ORDER BY <cfif arguments.SiteListView.GetSortBy() neq ""> #arguments.SiteListView.GetSortBy()# <cfelse> S.name </cfif> #arguments.SiteListView.GetSortOrder()#) as rowNum ,S.siteId ,S.code ,S.name ,S.roleBitMask ,R.description as regionDescription ,R.regionId FROM Site S INNER JOIN Region R ON R.regionID = S.regionId <cfif arguments.SiteListView..GetSiteView().GetRegionId() neq 0> AND R.regionId = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.SiteListView.GetSiteView().GetRegionId()#"> </cfif> WHERE S.deleted = 0 <cfif arguments.SiteListView..GetSiteView().GetCode() neq ""> AND S.code = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.SiteListView.GetSiteView().GetCode()#"> </cfif> <cfif arguments.SiteListView..GetSiteView().GetSiteId() neq 0> AND S.siteId <> <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.SiteListView..GetSiteView().GetSiteId()#"> </cfif> <cfif arguments.SiteListView.GetStartRow() neq 0> AND S.siteId > <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.SiteListView.GetStartRow()#"> </cfif> ), ListRecordCount AS ( SELECT * FROM List, (SELECT MAX(rowNum) AS recordCount FROM List) AS recordCount ) SELECT * FROM ListRecordCount WHERE rowNum BETWEEN <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.SiteListView.GetStartRow()#"> AND <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.SiteListView.GetStartRow() + variables.recordsPage#"> </cfquery>
Here's the proof that the optimized paging query works much, much faster (click on the images for a full sized version that will show you the execution times better):
Tuesday, March 16, 2010
Be careful when using try/catch inside of a cftransaction tag.
While doing development on a somewhat large project for managing weatherization jobs I found a funny little thing about using the cftransaction tag outside of a try/catch statement. Take the chunk of code below for example:
Now I had incorrectly assumed that if my UpdateLocationCode function would throw an error that the transaction would be rolled back automatically. It turns out that since that error is caught and normal processing continues after the catch tag that this transaction commits just fine.
<cftransaction> <cfscript> try { variables.LocationCodeDataDelegate.UpdateLocationCode(arguments.LocationCodeView.GetLocationCode()); arguments.Event.AddMessage("Location code updated successfully."); arguments.Event.SetError(false); } catch(any ex) { arguments.Event.SetError(true); arguments.Event.AddMessage("There was an error updating the location code.<br><br>#ex.message# The error occured on or around line #ex.TagContext[1].line# on file #ex.TagContext[1].template#<br>#ex.detail#",true); } </cfscript> </cftransaction>
Now I had incorrectly assumed that if my UpdateLocationCode function would throw an error that the transaction would be rolled back automatically. It turns out that since that error is caught and normal processing continues after the catch tag that this transaction commits just fine.
The fix for this problem is a simple one. In my Event object I have a boolean property called Error that is defaulted to true, only when the code inside my try block completes is it set to false. All I need to do is check my Event object for an error condition right before my tag and rollback the transaction if the error condition is true as shown below:
<cftransaction> <cfscript> try { variables.LocationCodeDataDelegate.UpdateLocationCode(arguments.LocationCodeView.GetLocationCode()); arguments.Event.AddMessage("Location code updated successfully."); arguments.Event.SetError(false); } catch(any ex) { arguments.Event.SetError(true); arguments.Event.AddMessage("There was an error getting the location code.<br><br>#ex.message# The error occured on or around line #ex.TagContext[1].line# on file #ex.TagContext[1].template#<br>#ex.detail#",true); } </cfscript> <cfif arguments.Event.GetError()> <cftransaction action="rollback" /> </cfif> </cftransaction>
Labels:
ColdFusion,
Error Handling
Thursday, March 11, 2010
Better CF documentation
If you don't like the adobe live doc's or using the PDF documentation this site will be your new best friend: http://coldfusiondocs.com/app/. I don't remember exactly where I found this, but I immediately bookmarked and have been using it daily since.
Another very nice about this site is that it includes both the Adobe CFML and Railo documentation in separate tabs!
Another very nice about this site is that it includes both the Adobe CFML and Railo documentation in separate tabs!
Saturday, February 20, 2010
How To: Install ColdFusion on IIS 7 in Windows and Vista. (No more 500 errors!)
After much head scratching I finally got ColdFusion working on my Windows 7 computer. I've also done this process on windows Vista so I know it works for both Operating Systems. If you install IIS 7 with its default options on 7/Vista and run the ColdFusion 8 or ColdFusion 9 installer you will get a funny little 500 server error when the installer tries to run the post-installation scripts on your server.
The solution is very simple, all you have to do is enable CGI and ISAPI in IIS! The following instructions apply to Windows 7 however they are very similar in Vista.
The solution is very simple, all you have to do is enable CGI and ISAPI in IIS! The following instructions apply to Windows 7 however they are very similar in Vista.
- Open Control Panel -> Programs
- Select "Turn Windows features on or off"
- If "Internet Information Services" is not already selected make sure you select it.
- Expand the "Internet Information Services" Node
- Expand the "World Wide Web Services" Node
- Expand the "Application Development Features" Node
- Check "CGI", "ISAPI Extentions", and "ISAPI Filters"
- Hit "OK"
- If you have the ColdFusion post-installation screen still open in your browser "refresh" it.
- If you don't still have the screen open re-install ColdFusion and this time the post-installation script should run just fine.
ColdFusion 9 Still a Macromedia product?
I know its not but look at this error I received today on my local machine ruining ColdFusion 9. As I was waiting for ColdFusion to start I grew impatient and tried to pull up a template while the server was still starting and got this error message:
Friday, February 19, 2010
Local Websever + Port 80 + Skype = Fail!
On my local development environment I run both IIS or Apache depending on weather I'm doing ColdFusion or PHP development. I run both of those servers on port 80 and use manual scripts to start them. I recently installed Skype on my development box and afterwards none of my local servers were starting properly!
I ran a netstat - ab and found that Skype was listening on port 80! Looking at the Tools -> Options -> Advanced -> Connection setting in Skype I found a little checkbox that says: "Use port 80 and 443 as alternatives for incoming connections." I unchecked this box and my webservers started again!
I ran a netstat - ab and found that Skype was listening on port 80! Looking at the Tools -> Options -> Advanced -> Connection setting in Skype I found a little checkbox that says: "Use port 80 and 443 as alternatives for incoming connections." I unchecked this box and my webservers started again!
Thursday, February 11, 2010
ColdFusion CFInvoke Eliminates The Need For Evaluate() When Dynamically Executing User Defined Functions
This came in very handy for me today.
ColdFusion CFInvoke Eliminates The Need For Evaluate() When Dynamically Executing User Defined Functions
ColdFusion CFInvoke Eliminates The Need For Evaluate() When Dynamically Executing User Defined Functions
Monday, February 8, 2010
We are looking to hire a new ColdFusion developer and I'm looking for some fresh ideas on interview questions.
We are looking to bring on a new Junior or Intermediate ColdFusion developer to help code a few large projects we have coming up. I've conducted about 8 ColdFusion interviews and have a standard set of questions that I usually ask but I'd like some feedback from the community.
What are some questions you guys typically ask CF candidates? What kinds of things are you looking for in a prospect?
What are some questions you guys typically ask CF candidates? What kinds of things are you looking for in a prospect?
Labels:
ColdFusion
Subscribe to:
Posts (Atom)