Thursday, December 13, 2012

Object-Oriented JavaScript (Part 1) - An Example

Part 2 of this post goes into this topic in detail and gives a Google Apps Script example that should be much more suited to anyone wanting to apply OO JavaScript in Google Spreadsheets (Note added 28-Jan-2013).
 
To be expanded, updated and improved in due course.  The code on GitHub is ok but I would like to elaborate on the whole topic of object-oriented JavaScript.  Meanwhile, if you get a chance, check out Nicholas Zakas' book mentioned below.  I have the 2nd edition and that has a  very good chapter on OO. (Added: 21-Dec-2012).
This entry uses the same example of DNA sequence translation into protein as was described in an earlier entry where VBA was used.  As in that example, the code deals with DNA sequence ambiguity expressed using IUPAC codes (R = A and G mixture).  This is its only novel or interesting feature from a functionality point of view in the example given.
The aims of this entry are to:
  • Demonstrate the Combination Constructor/Prototype Pattern as described in the book "Professional JavaScript For Web Developers" by Nicholas Zakas.
  • Show how the same JavaScript code can be used in 
    1. A simple web page
    2. In a Google spreadsheet
    3. In server-side Node.js

The code is on GitHub

The main file is JavaScript/TranslateDna.js on this GitHub link.

Firstly, there is a HTML test page with some embedded JavaScript to show how the JavaScript "TranslateDna.js" can be used in a web page form, see HTML page link.

To use
  • Copy the HTML to a file named "DNA_Translator.html"
  • Save this in a location recognized by your web server (On my Mac running Apache, I save it to "/Library/WebServer/Documents/".
  • Save the JavaScript file "TranslateDna.js" to the same location.
  • View the web page using the URL http://localhost/DNA_Translator.html
  •  Assuming the web server is is working, you should see a crude form with two inpout textareas and one button, screenshot:
 The dummy input DNA sequence is in the upper textarea and the translated output is in the lower one.  The form is very crude, and the HTML-embedded JavaScript is very simple but it works fine in Safari, Chrome and Firefox, I cannot test IE on my Mac.

The same JavaScript code that the HTML page uses to do the translation can also be called as user-defined functions (UDFs).

To do this:
  • Create a new Google spreadsheet.
  • Paste the code containing the user-defined functions in this GitHub link into the script editor.
  • Add another script file by selecting File->New->Script File in the script editor and paste in the code from this GitHub link.
  • To use call the functionality as UDFs, enter these dummy DNA sequence values in cells A1 and A2:
AAACCCGGGTTT
RAACCCGGGTTT

  • In cell B1, this function call "=getTripletsFromDNA(A1, "|")" produces AAA|CCC|GGG|TTT
  • while "=getTripletsFromDNA(A2 "|")" gives RAA|CCC|GGG|TTT
  • To test the translation of these two dummy sequences enter the formulas "=getAminoAcidsFromDNA(A1,"|")" and "=getAminoAcidsFromDNA(A2,"|")" into cells C1 and C2, respectively. The output from these calls is:
K|P|G|F
ke|P|G|F

See how the R is dealt with in the second call, it results in a double amino acid mixture.

The main point of this blog entry is that Google Apps Script is JavaScript. Functionality can be developed in Google Apps Scripts that can then be used on a web page as well as in a Google spreadsheet. The same code can even be run in Node.js. Therefore learning Google Apps Scripting is well worthwhile and confers immediately transferable skills.

 In the next entry, I will discuss the code in the TranslateDna.js file as part of a broader object-oriented JavaScript theme.

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