Wednesday, December 5, 2012

Using JSLint To Improve Google Spreadsheet JavaScript Code Quality

 Spreadsheet programming generally has earned a bad reputation in many quarters due to several factors including:
  • Distribution of poor quality and untested/under-tested applications.
  • Poor, or even absent, documentation
  • Code is not under version control.  
  • Absent or ineffective error trapping and exception handling.
End-users and managers become understandably suspicious of "buggy macros" and may go so far as to ban Excel "macros" entirely from their departments.  Excel VBA, like JavaScript, is frequently used by hobbyists and end-users who generate code by recording a "macro" followed by cut-and-paste either from the macro-generated code, from internet searches, or by peeking into somebody else's code and copying parts of it.  JavaScript browser programming has been similarly plagued by these types of approaches and both it and Excel VBA alike have been unfairly blamed as programming languages for the resulting poor-quality applications.  Use of version control, testing and documentation can help to mitigate these outcomes.  By the way, recording macros in Excel is a great way to learn about the object libraries and the object methods and properties but a recorded macro is not an application.  We should strive to deliver "applications" and not "macros"!  VBA, like JavaScript, has more than its share of "bad parts" but, as the old saying goes, "A bad workman always blames his tools".

JavaScript is blessed with an additional tool of great utility when it comes to delivering better quality JavaScript: This tool is called JSLint.  It was developed by Douglas Crockford, the author of the acclaimed JavaScript: The Good Parts book, discoverer/creator of JSON and someone who has done more than most to rehabilitate JavaScript's reputation. 

I have mentioned and recommended his book in earlier blog entries but none of the JavaScript code given hitherto has been subjected to the JSLint test.  So just as the last entry ushered in the GitHub era, so this one now welcomes the JSLint era.  All code from now on will be JSLint-compliant.

So what is JSLint?  The best place to find out is to check out the Read the instructions link on the JSLint web site.  As the first line in the linked web page says, "JSLint is a JavaScript program that looks for problems in JavaScript programs. It is a code quality tool.".

To demonstrate JSLint, I have taken just one JavaScript function from an earlier blog entry as an example, a function called "listSheets" from the Using the Google App Scripting API - Part 1 entry.

Here is a screenshot of this function after all the comments have been removed:
 There is nothing particularly interesting in this code, it is just a JavaScript function that successively displays message boxes  containing the names of sheets in the active spreadsheet.  The code looks ok, the semi-colons have been added, all the variables are declared, and the indentation looks about right.

What does JSLint make of this code when it is pasted into the Source textbox?  Actually, this code snippet generates a surprising number of JSLint errors and warnings.

Here is the same fully JSLint-compliant version of this JavaScript function:



All the default settings in JSLint were used for this example.

The function is the same as before in terms of what it does but to get from the original to the JSLint-compliant version, the following changes were required:
  1. Add /*global SpreadsheetApp: false, Browser: false */
  2. Add ‘use strict’;
  3. Remove space between function name “listSheets” and the empty parentheses.
  4. Indentation for all lines within the function body is re-set from 3 to four spaces.
  5. Use a single var pattern and move variable declarations out of the for loop to the top of the function.
  6. Replace the increment ++ with += in the for loop.
  7. Remove the spaces immediately after the opening parenthesis and before the closing parenthesis in the if statement.

    • The "'use strict';" was added to ECMAScript version 5 and recognized by Google App Script.  Its use was recommended in an earlier blog entry.   It can be placed outside the function at the top of the script or within a function, when placed within the function, it only applies to that function's code.
    • JSLint is quick to pounce on any indentation discrepancies.
    • The first step is required so that JSLint does not regard these Google App Script objects like "SpreadsheetApp" as undeclared global variables.  In the JSLint documentation, it states "Some globals can be predefined for you.", the first line in the JSLint version predefines the global Google Apps Scripting objects  SpreadsheetApp and Browser in order that JSLint will ignore them.  The "false" means that assignment to this variable is not allowed .
    • using three rather than the default four spaces for indentation.
    • The single var pattern is expected by JSLint and is widely used so, from now on, I'll use that too.  It also makes sense because JavaScript does not have block scoping so declaring the count variable in the for loop does not limit its scope as it would in a language like Perl that does have block scope.
    • JSLint's rejection of the increment (++) operator may be surprising but Crockford has pointed out that it can lead to problems so I'll drop it and the decrement operator in future.
    This code example is very small but I think JSLint is a great tool that goes a long way to rectifying some of JavaScript's rough edges.  Douglas Crockford knows a lot more about JavaScript than I do, so I'm graterful for his advice as expressed by JSLint.  He warns that it will "hurt you feelings" but I am happy to be corrected/warned/advised.  After working on a larger code example that I'll discuss in a future entry, I was really convinced of its benefit because it really helped me.
    I use Perl a lot and in that language we have perlcritic (Perl::Critic) and perltidy (Perl::Tidy) tools.  These are highly configurable and when everyone in the team used agreed configurations, we were then able to write Perl code in a standardized and readable format.  No mean feat in Perl!  JSLint can do the same and more for JavaScript code and if someone complains about the coding conventions you are using, you can let them know that it is JSLint-compliant.

    The two code versions used here have been posted to GitHub link






    3 comments:

    1. This comment has been removed by a blog administrator.

      ReplyDelete
    2. This comment has been removed by the author.

      ReplyDelete
    3. I can't get on-board JSLint when it disallows the for statement and ++/-- as well as multiple var's defined on one line delimited by commas. All three patterns are sensible and should be allowed. JSLint is retrograde.

      ReplyDelete