Friday, June 6, 2008

Javascript Basics: Five functions you should write and use all the time

If you're new to Javascript, you've either already found out or will very shortly that there are some tasks that you need to do all the time. It can get pretty tedious having to remember what the code is for those tasks, or even worse, knowing what the code is, but still having to type it out each time you want to use it.

In this article, I'm going to walk through the first of five functions I use frequently when writing Javascript code that will make not only make writing code easier because the code is more concise, but also because in a lot of cases it's easier to understand. Certainly this series won’t cover all of the shortcut functions you may want to write, but if you're new to Javascript this should get you going so that soon you can write your own. So let's get started:


1. $() or id()


If you've written Javascript for more than 15 minutes, you've probably used the “document.getElementById” function. If you've written Javascript for more than 30 minutes, you've probably made the mistake of capitalizing the last "d" and had a Javascript error thrown. Hopefuly the error message from the browser made it obvious what was wrong, but in some browsers deciphering the error message can be an art in itself. Because it is easy to misspell and requires typing out 24 characters to accomplish one of the most basic and frequent tasks in Javascript, it doesn’t take long to get frustrated with the “document.getElementById” function.

If you've ever used the popular jQuery library, you know you can get a reference to an HTML element by writing:


var referenceToElement = $("elementID");


The folks who wrote jQuery felt your pain in writing out "document.getElementById" each time, and made a shortcut function whose name was just the dollar sign. Because the dollar sign is a valid character for use in a Javascript function name but it's not a character that is often used, they chose to create a function that was only one character long to effectively act as an alias for the "document.getElementById" function.

This was such a great idea, we’ve copied it for ourselves at APT and included it in our own Javascript library by writing the following function: (Note: If you use jQuery already, there’s no need to write this function yourself since you already have it!)


$ = function(id) {
// If "id" is a string, return the value of "document.getElementById",
// otherwise, just return whatever was passed in.
return (typeof id == "string") ? document.getElementById(id) : id;
}


Armed with this code, we can now replace all instances of "document.getElementById" with the much shorter "$".

Another side benefit of using this function that hasn’t been mentioned yet is that every time we get a reference to an element, we've reduced the size of our code by over 93% (well, not exactly, but you get the idea). If you add the space saved across a large Javascript file by making this replacement, the result is usually pretty significant.

You'll also notice from our implementation, that when we call our “$’ function, we’re not just directly calling the “document.getElementById” function. Instead we built a little bit of extra functionality into our “$” function.

Notice that if you pass in an object that is not a string, our function won't throw an error, it will just pass back the same object that was passed in. This can be useful in functions where you want your code to be flexible for whoever is using it so that they can pass in either a string that is the ID of an HTML element or a reference to the HTML element itself. At the top of your code you can pass that object through our “$” function, and rest assured that what is returned is a reference to a HTML element.


function myCoolFunction(eitherAnIdOrAnElementReference) {
var definitelyAnElementReference = $(eitherAnIdOrAnElementReference);
// Do something to that element...
}


As a final point, some people don't like using the dollar sign as the function name. You can feel free to name this function whatever you want. For instance, you could name it "id" instead. I prefer using "$" because I can imagine writing code where I name a variable "id" and accidentally overwrite the function I created, which could then lead to all sorts of funky errors. If I use "$", the chances of that happening are greatly reduced.

Alright, so one down. I'll post the next two functions tomorrow which are related to showing and hiding HTML elements.

Wednesday, May 21, 2008

VBScript Syntax Checking


This post describes how to use VBScript to check the syntax of a given block of VBScript code.


The Motivation:


At APT, one software suite we use to run automated GUI tests of our web-based software is Mercury QuickTest Professional. QuickTest runs tests written in VBScript that click through a prescribed path in our software to make sure we don't throw any errors.

Rather than store hundreds of static .vbs files containing the definition of tests, we store our test definitions in a SQL database and dynamically generate the corresponding .vbs files on demand. We do this for a few reasons:

  1. It makes test maintenance easier (you maintain only the structure of the test, not the code's syntax)
  2. It enables users who are unfamiliar with VBS to author and maintain tests
  3. By introducing separation between the test's definition and execution, we can change how we execute our test without changing our test's definition (for example, migrating test execution to another platform such as Selenium, which can execute different languages)


The Problem:


One of the challenges of dynamically generating code is making sure that what you generate is syntactically valid. Making the assumption that your generated code will be perfect is generally a bad idea, because:

  • Your code-generation code may contain errors
  • As you modify your test definition model, the code-generation code can fall out of sync, resulting in invalid generated code
  • You'll likely want to support user-entered "custom" sections of code, which you can't assume will be syntactically valid


The Solution:


After we generate the VBS code for the requested test, we check its syntax prior to executing it by calling the function defined below:





Public Function checkVBSSyntax(vbsCode)
    ' Save any pre-existing error so we can revert to it
    oldErr = Err
    Err.Number = 0

    On Error Resume Next
    ' Execute the vbs code to see if it throws an error
    ExecuteGlobal vbsCode
    hasError = Err.Number <> 0

    On Error Goto 0

    ' Revert to the pre-existing error
    Err = oldErr

    checkVBSSyntax = (Not hasError)
End Function




What we're doing here is simply executing the questionable code in the global scope to see if it throws an error. If it throws an error, we assert that it must be due to a syntax error.

A couple of notes:


  • This function assumes that the questionable code contains only Function and Sub definitions; that is, no code exists outside of a Function or Sub declaration. If it does contain code outside of a Function or Sub declaration, that code will actually be executed (not just checked for its syntax). If you have such code, wrap it in a Public Sub main() ... End Sub statement.

  • This has the side effect of defining all the Functions / Subs in your questionable code in global scope; that is, after calling this function, you'll be able to call any functions defined in your questionable code, as if you included it as a function library. As a result, you'll want to be careful that Function / Sub names in the questionable code don't collide with Function / Sub names in your syntax checking code.


Friday, May 2, 2008

Fault-Tolerant ColdFusion Error Reporting


ColdFusion’s default reporting mechanism for uncaught errors is to dump the error information to the console. This has several disadvantages, two of them being that the console would have to be monitored and whoever is monitoring it is limited to the dumped information. To address this issue, ColdFusion Administrator has a setting for a Site-wide Error Handler. This is a custom template to execute when an error is encountered, and allows for sophisticated post-processing of the error.

At APT, we take advantage of this feature and have a very robust Site-Wide Error Handler. Among other things, it retrieves additional information about the user and setup, retrieves information about the product’s state, diagnoses the error, logs the error to a database, and sends an e-mail to relevant engineering and delivery team members. But there is a catch: if an error is encountered within the Site-wide Error Handler it stops processing and dumps that error to the console. Should this happen, we are right back where we started.

The solution is simple: make sure your Site-wide Error Handler never fails. However, if you have a complicated template, this is easier said than done. In this situation, we must make the Site-wide Error Handler fault-tolerant.

How do we achieve fault-tolerance? The foundation is liberal use of try-catch blocks within your Site-wide Error Handler. While it may at first appear sloppy and clutter up the code, it is critical for isolating the effects of errors, making sure the maximum amount of processing takes place, and ensuring the most information possible makes it back to you.

Look at this simple example template:


<cftry>
    Retrieve user information
    <cfcatch> Handle exception </cfcatch>
</cftry>
<cftry>
    Retrieve information about the product’s state
    <cfcatch> Handle exception </cfcatch>
</cftry>
<cftry>
    Send an e-mail with error and additional
     retrieved information

    <cfcatch> Handle exception </cfcatch>
</cftry>



If retrieving user information fails, we will still be sent an e-mail containing the error information and information about the product’s state. This is exactly the isolation we are going for. Subcomponents within in the try-catch blocks can be wrapped in their own try-catch blocks as well, creating an even more granular and fault-tolerant template.

When errors with your Site-wide Error Hander are caught, be sure you attempt to report information on them instead of letting them get swallowed up silently. In the above example, the information about the error encountered while retrieving user information should be included in the final e-mail sent. This feedback is critical in debugging and improving the Site-wide Error Handler—you will be glad you have it. However, be sure to wrap this reporting in its own try-catch in case there is an error with reporting the error. The overall theme is: the more paranoid the better!

By treating your Site-wide Error Handler as a series of granular tasks contained within try-catch blocks, the effect of failures will be limited while the maximum amount of error information safely makes its way back to you. This will be speed up the time it takes to identify, diagnose, and fix bugs and thus improve the quality of your software. <cftry> and <cfcatch> tags are essentially free, but engineering time is not.

Wednesday, April 30, 2008

What is "An APT Developer?"

Before we get into why we are all here, we'd like to start by saying, "Welcome"! We hope you get as much out of reading these materials as we have by putting them together!

So, "What is 'An Apt Developer'?" you ask. Quite simply, it is a brain dump of all things software happening at Applied Predictive Technologies or APT for short ("An Apt Developer" - clever, isn't it?). APT is a small, growing software company located in Arlington, Virginia that provides its customers with cutting edge business analytics delivered through everyone's favorite medium - the internet! Read more about us here: http://www.predictivetechnologies.com.

Delivering an intuitive, yet rich set of analytic tools, driven by volumes of performance data, via the web has forced us to overcome numerous engineering challenges. Certainly a large number of these are themed around integrating the many technologies we use (Java, ColdFusion, SQL Server, .Net, AJAX, CSS, XHTML, etc.), though not all are technical in nature. As we have grown, we have also learned much about QA, testing, and product management processes. We hope this blog will reflect on much of what we have learned and serve as a way to give back to the broad software community that has already helped us in many ways. Enjoy!