Monday, August 31, 2015

Book Review: JavaScript: The Good Parts

From the perspective of a book on a programming language that is frequently quoted with reverence by developers that regularly use that programming language, it could be argued that Java Script: The Good Parts is to JavaScript developers as Effective Java is to Java developers. The subtitle of Douglas Crockford's JavaScript: The Good Parts is "Unearthing the Excellence in JavaScript." I finally purchased and read JavaScript: The Good Parts (O'Reilly/Yahoo! Press, 2008) and this is my review of that book. This is more than a review, however, in that it also provides me a forum to highlight some of observations from that book that most interested me.

JavaScript: The Good Parts is a relatively short book with ten chapters and five appendices spanning fewer than 150 pages. It's impressive how much content can be squeezed into 150 pages and is a reminder that the best writing (in prose and in code) is often that which can say more in fewer words. I was able to read all of the chapters and the two appendices that interested me the most during a flight that took a little more than an hour (although my reading started as soon as I was seated on the airplane). There is one caveat to this: although some of JavaScript: The Good Parts is a very quick read for anyone with basic familiarity with JavaScript, other portions required me to re-read them or even tell myself, "I better come back to that later and read it again." This is another way in which this book reminds me of Effective Java.

Preface

The first page of the Preface is the core content of that section and it provides an overview of what a reader of JavaScript: The Good Parts should expect. The Preface describes JavaScript as "a surprisingly powerful language" which has some "unconventionality" that "presents some challenges," but is also a "small language" that is "easily mastered." One category of developer to which this book is targeted is "programmers who have been working with JavaScript at a novice level and are now ready for a more sophisticated relationship with the language." That sounds like me!

Crockford uses the Preface to describe what JavaScript: The Good Parts covers. He states, "My goal here is to help you learn to think in JavaScript." He also points out that JavaScript: The Good Parts "is not a book for beginners," "is not a reference book," "is not exhaustive about the language and its quirks," "is not a book for dummies," and "is dense."

Chapter 1: Good Parts

In the initial chapter of JavaScript: The Good Parts, Crockford points out that programming languages have "good parts and bad parts" and that "JavaScript is a language with more than its share of bad parts." He points out that these deficiencies are largely due to the short amount of time in which JavaScript was created and articulates, "JavaScript's popularity is almost completely independent of its qualities as a programming language." Crockford has found that a developer can write better programs in any language by only using the good parts of that language as much as possible. This seems to be particularly true with JavaScript. Crockford provides a high-level description of JavaScript's good parts:

"JavaScript has some extradordinarily good parts. In JavaScript, there is a beautiful, elegant, highly expressive language that is buried under a steaming pile of of good intentions and blunders."

In the section "Analyzing JavaScript," Crockford surveys the "very good ideas" that JavaScript is built upon along with the "few very bad" ideas that JavaScript is built upon. This first chapter is only 4 pages and the overview of these good and bad ideas is contained in a couple of pages. However, the remaining chapters of the book provide more details on the good parts and the first two appendices provide more details on the bad parts.

I agree with Crockford's assertion that a significant portion of the negativity and even hostility toward JavaScript is probably more appropriately aimed at the DOM. JavaScript has probably been accused of being non-standard and browser-specific millions of times when it is really the browser's DOM implementation that is non-standard and browser-specific.

I cannot finish my review of the first chapter of JavaScript: The Good Parts without quoting one more astute quote: "[Given JavaScript's] many errors and sharp edges, ... 'Why Should I Use JavaScript?' There are two answers. The first is that you don't have a choice. ... JavaScript is the only language found in all browsers. ... The other answer is that, despite its deficiencies, JavaScript is really good."

Chapter 2: Grammar

The second chapter of JavaScript: The Good Parts provides 15 pages of introduction to the "grammar of the good parts of JavaScript, presenting a quick overview of how the language is structured." For someone who has used JavaScript previously, much of this chapter may not be particularly insightful, though just seeing the parts of the language that Crockford feels are "good" is useful. The section on "Statements" points out early some "unconventional" aspects of JavaScript: code blocks delineated by curly braces do not limit scope to those blocks and variables should be defined at the beginning of a function rather than at first use.

Chapter 3: Objects

The 6 pages of Chapter 3 introduce JavaScript Objects. Significant aspects of JavaScript objects (key/value pair nature, prototype object association, pass-by-reference, objection inspection with typeof and hasOwnProperty, and reducing an object's "global footprint") are covered succinctly.

Chapter 4: Functions

Chapter 4 of JavaScript: The Good Parts begins with the statements, "The best thing about JavaScript is its implementation of functions. It got almost everything right. But, as you should expect with JavaScript, it didn't get everything right." This chapter is longer (20 pages) than the ones before it, reinforcing that Crockford believes functions are one of the really good parts of JavaScript. Despite its being lengthier than the preceding chapters, Chapter 4 seems to me to also be more dense (particularly than Chapters 2 and 3).

Chapter 4's coverage of JavaScript functions point out one of the differences in JavaScript I needed to come to terms with to feel more confident with the language: "Functions in JavaScript are objects." The section on function invocation briefly describes the four patterns of invocation in JavaScript (method invocation, function invocation, constructor invocation and apply invocation) and explains how this is initialized differently depending on the particular pattern of invocation used. JavaScript's different meaning of this depending on context has been one of the more difficult aspects of working with JavaScript after coming from a Java background, but this explanation is the clearest and most easy to remember that I have read.

The fourth chapter covers exception handling, method cascading, and type augmentation. The section on "Augmenting Types" presents multiple examples of adding "significant improvements to the expressiveness of the language" by "augmenting the basic types" via addition of methods to appropriate prototypes.

The sections on "Recursion," "Closure," and "Module" are where things got a bit dense for me and I needed to read several portions of these sections more than once to more fully appreciate the points being made. I believe I still have a ways to go to understand these concepts completely, but I also believe that understanding them well and implementing the module concept presented here is the key to happiness in large-scale JavaScript development.

The "Curry" section of Chapter 4 states that JavaScript lacks a curry method, but explains how to address that by associating a curry method with Function. The "Memoization" section demonstrates how to use memoization in JavaScript so that "functions can use objects to remember the results of previous operations, making it possible to avoid unnecessary work."

Chapter 5: Inheritance

JavaScript: The Good Parts's fifth chapter begins by briefly explaining the two "useful services" that inheritance provides in "classical languages (such as Java)": code reuse and type system. It is explained that JavaScript is dynamically typed and therefore gains a single advantage from inheritance: code reuse. Crockford states that "JavaScript provides a much richer set of code reuse patterns" than the "classical pattern."

The "Pseudoclassical" section of Chapter 5 begins with the assertion that "JavaScript is conflicted about its prototypal nature." There is in-depth discussion about the dangeris and drawbacks of using the constructor invocation pattern. The most "serious hazard" occurs when a developer forgets to use new when calling the constructor function. Crockford warns that in such cases, this is associated with the global object rather than the (likely) intended new object. The author states that convention is to use uppercase for the first letter of the "constructor function" objects" to indicate this risk, but he advises that the better course is to not use new or the constructor invocation pattern at all.

This discussion in the "Pseudoclassical" section of Chapter 5 provides more detail on issues Crockford raised with the "constructor invocation pattern" in Chapter 4. These two sections forced me to acknowledge that while I've liked using the constructor invocation pattern in JavaScript, it's only because "the pseudoclassical form can provide comfort to developers who are unfamiliar with JavaScript." Crockford warns that its use "hides the true nature of the language."

Chapter 5 introduces object specifiers and dives into coverage of JavaScript's prototypal implementation and differential inheritance. The "Functional" section of this fifth chapter illustrates how to use a functional approach to reuse and states that this functional approach "requires less effort than the pseudoclassical pattern and gives us better encapsulation and information hiding and access to super methods." The fifth chapter concludes with discussion and code example of composing objects "out of sets of parts."

Chapter 6: Arrays

The 6-page sixth chapter of JavaScript: The Good Parts introduces the concept of an array and mentions a couple of its benefits, but laments, "Unfortunately, JavaScript does not have anything like this kind of array." The author describes what JavaScript offers as "an object that has some array-like characteristics." He points out that this array-like object is "significantly slower than a real array, but it can be more convenient to use."

Chapter 6 discusses JavaScript's "unconventional" length property for JavaScript "arrays" and introduces syntax for accessing elements, push, and delete. Crockford points out that "JavaScript does not have a good mechanism for distinguishing between arrays and objects" and he provides two brief implementations of is_array functions (the second relies on toString() not being overridden).

The sixth chapter wraps up with discussion regarding adding methods to JavaScript's Array. Specific code examples include a function thar initializes the delements of a JavaScript array and a function that initializes the elements of a matrix (array of arrays).

Chapter 7: Regular Expressions

The nearly 23 pages of JavaScript: The Good Parts's seventh chapter focus on applying regular expressions in JavaScript. For those who have used other implementations of regular expressions (particularly Perl's or implementations based on Perl's), this will be fairly familiar.

Crockford points out several motivations for keeping regular expressions simple, but a JavaScript-specific motivation for simpler regular expressions that he cites has to do with lack of portability between different JavaScript language processors' regular expression support.

Chapter 7 introduces two forms of creating regular expressions in JavaScript: literals (/ syntax) and RegExp constructor. The chapter also introduces other JavaScript syntax for working with various regular expression concepts in JavaScript.

Chapter 8: Methods

The 15+ pages of Chapter 8 of JavaScript: The Good Parts feel like an API reference and reminds of me books such as Java in a Nutshell. These pages summarize the "small set of standard methods that are available on the standard types" in JavaScript. The chapter lists the method signature, brief method description, and examples of using that method for standard methods defined on Array, Function, Number, Object, RegExp, and String. Although these are nice summary descriptions and example usages, this chapter may be the least useful chapter of the book given that these APIs are documented online in sites such as the Mozilla Developer Network's JavaScript Reference.

Chapter 9: Style

JavaScript: The Good Parts's most (pleasantly) surprising chapter for me may be Chapter 9. When I was browsing the table of contents and saw "Style," I thought this chapter would be another bland spelling out of what to do and not do stylistically in code. I'm tired of these stylistic discussions. The chapter is fewer than 4 pages, so I did not expect much.

It turns out that the ninth chapter has some important observations in its just over three pages on style. I like that Crockford takes the reasons for style concerns with any programming language and emphasizes that they are particularly important in JavaScript.

My favorite part of Chapter 9 is when Crockford explains his style used in the book for JavaScript code. Some of it is the bland matter-of-taste stuff like number of spaces for indentation, but some of it is motivated by an understanding of JavaScript nuances and limitations. For example, Crockford states, "I always use the K&R style putting the { at the end of a line instead of the front, because it avoids a horrible design blunder in JavaScript's return statement." Similarly, he points out that he declares variables at the beginning of a function and prefers line comments over block comments because of other nuances of JavaScript. He (and my review) covers these more in the appendices.

This second-to-last chapter offers some poignant advice regarding coding style and large-scale JavaScript applications:

"Quality was not a motivating concern in the design, implementation, or standarization of JavaScript. That puts a greater burden on the users of the language to resist the language's weaknesses. JavaScript provides support for large programs, but it also provides forms and idioms that work against large programs.

Chapter 10: Beautiful Features

JavaScript's bad features are the focus of Appendix A ("Awful Parts" that "are not easily avoided") and Appendix B ("problematic features" that "are easily avoided"), but Crockford focuses Chapter 10 on what he considers JavaScript's "beautiful features." Because this is the theme of the book, this chapter only needs a bit over 2 pages to highlight Crockford's concept of "Simplified JavaScript": taking the "best of the Good Parts" of JavaScript, removing the features of the language with very little or even negative value, and adding a few new features (such as block scoping, perhaps the thing I miss most in JavaScript).

Appendix A: Awful Parts

Appendix A highlights the "problematic features of JavaScript that are not easily avoided" in just over 7 pages. Crockford warns, "You must be aware of these things and be prepared to cope."

The body of the appendix opens with an assertion that's difficult to argue with: "The worst of all of JavaScript's bad features is its dependence on global variables." I also like that Crockford points out that while many programming languages "have global variables," the problem with JavaScript is that it "requires them."

Appendix A also highlights why JavaScript's handling of reserved words, lack of block scope, 16-bit unicode support, typeof limitations, parseInt without explicit radix, confusion of + for adding or concatenating, "phony" arrays, and a few other features are problematic and how to avoid or reduce their use.

Perhaps the most interesting discussion for me in Appendix A is the explanation of why JavaScript may somtimes insert semicolons and, instead of fixing things, will make things worse (mask more significant code issues).

Appendix B: Bad Parts

The six pages of Appendix B "present some of the problematic features of JavaScript that are easily avoided." The chapter details why JavaScript features such as ==, with, continue, falling through switch, statements without blocks, bitwise operators, typed wrappers (and new Object and new Array), and void should be avoided.

Appendix C: JSLint

Appendix C provides 10 pages focused on JSLint, described as "a JavaScript syntax checker and verifier." About JSLint, Crockford states, "JSLint defines a professional subset of JavaScript ... related to the style recommendations from Chapter 9. JavaScript is a sloppy language, but inside it there is an elegant, better language. JSLint helps you to program in that better language and to avoid most of the slop."

Appendix C details how JSLint helps JavaScript developers identify global variables and functions, identify potentially misspelled members (used only once because misspelled but JavaScript itself won't report), identify missing or extraneous semicolons, identify potential issues of automatic semicolon insertion due to improper line breaking, and identify block statements missing opening and closing curly braces. Other items flagged by JSLint include fall-though switch statements, use of with, assignment operator used in a conditional expression, potential JavaScript type coercion with == and !=, eval, void, bitwise operators, potentially non-portable regular expressions, and constructor functions.

The chapter also demonstrates how to specify to JSLint the "subset of JavaScript that is acceptable." In other words, one can choose to not have certain conditions flagged by JSLint. I find it interesting that JSLint provides some HTML validation in addition to checking for well-formed JSON.

I have found that static code analysis tools for Java not only help improve existing Java code, but help me write better Java code in the future as I learn what is considered wrong or bad form, why it is wrong or frowned upon, and how to avoid it. The same is true for JSLint's effect on JavaScript; a person learning JavaScript can benefit from learning what JSLint flags to know the bad/ugly parts of JavaScript to avoid..

Appendix D: Syntax Diagrams

The fourth appendix consists solely of syntax diagrams that graphically indicate how various JavaScript constructs are syntactically constructed. The diagrams are of the portions of JavaScript highlighted in JavaScript: The Good Parts. Appendix D is a reference guide similar to Chapter 8 and, like Chapter 8, is probably the least valuable of the book's appendices because it is information that is readily available online.

Appendix E: JSON

The final ten pages of the book are in Appendix E and are dedicated to JavaScript Object Notation (JSON). The appendix describes JSON as "based on JavaScript's object literal notation, one of JavaScript's best parts." This introduction explains that JSON is a text-based format that is a subset of JavaScript but can also be used as a language-independent data transfer format. Most of the material in this appendix was obviously a lot newer to people in 2008 when this book was published than it is today because today many developers who don't even know JavaScript very well are aware of JSON.

Appendix F describes the syntax rules of JSON in approximately a single page because "JSON's design goals were to be minimal portable, textual, and a subset of JavaScript."

The section of Appendix F on "Using JSON Securely" looks at the risks of using JavaScript's eval to turn JSON into a useful JavaScript data structure and recommends use of JSON.parse instead. There is also interesting discussion on security implications of assigning an HTML text fragment sent by the server to an HTML element's innerHTML property. What makes this interesting is Crockford's pointing out that this security issue has nothing to do with Ajax, XMLHttpRequest, or JSON, but is rather due to the core JavaScript design flaw of featuring a global object. Crockford takes one more shot at this "feature": "This danger is a direct consequence of JavaScript's global object, which is far and away the worse part of JavaScript's many bad parts. ... These dangers have been in the browser since the inception of JavaScript, and will remain until JavaScript is replaced. Be careful."

The last 5 1/2 pages of Appendex F feature a code listing for a JSON parser written in JavaScript.

General Observations

  • JavaScript: The Good Parts deserves the praise and reverence heaped upon it; it is a great book and I cannot think of a JavaScript book that I've read that has done as much for my understanding of this unconventional language as JavaScript: The Good Parts.
  • Many technology books rave about the covered language, framework, or library and either don't acknowledge the deficiencies and downsides of the covered item or quickly explain them away as insignificant or inconsequential. JavaScript: The Good Parts is more effective because it doesn't do this. Instead, Crockford's writing makes it obvious that there are many aspects of JavaScript he likes and finds expressive, but that he also recognizes its downsides. His book is an attempt to teach how to mostly use only good parts of JavaScript and mostly avoid use of the bad parts of JavaScript.
  • Because Crockford takes time to explain JavaScript's unconventional features and distinguish between cases where the unconventional approach is "good" and cases where unconventional approach is "bad," readers of the book have a better opportunity to appreciate JavaScript's positives rather than mostly seeing its negatives.
  • JavaScript: The Good Parts reinforces the idea that trying to treat JavaScript like Java (or any other classically-object-oriented language) is a mistake. It explains why this approach often leads to frustration with JavaScript.
  • JavaScript: The Good Parts is a highly-readable and generally approachable book. The (English) language of the book is clear and well-written. The conciseness is impressive, especially considering that some of the book's most important points are made multiple times in different contexts and the entire book has fewer than 150 main pages.
    • Although JavaScript: The Good Parts is written in a very readable form, some portions of it are more difficult to read because the content is more difficult. This is particularly true in some of the sections in Chapter 4 on functions. Some of these sections required multiple readings for me, but they are also the sections that bring the most insight when understood.
    • One reason that JavaScript: The Good Parts can be as concise as it is has to do with it providing so little introduction. Those who have never coded before or have no JavaScript coding experience, will likely be better off reading a more introductory book or online resource first.
  • Several useful JavaScript code snippets are provided in JavaScript: The Good Parts to illustrate good and bad parts of JavaScript. Along the way, several pieces of code are provided that are generic and reusable and worth highlighting here:
    • Chapter 3 (page 22) provides 6 lines of code for associating a "create method" with the Object function that "creates a new object that uses an old object for its protype."
    • Chapter 4 (pages 32-33) provides 4 lines of code for making a named method available to all functions. A slightly revised version of this is presented one page later with the addition of a "defensive technique" to ensure that a newly defined method does not override one that another library is already using.
    • Chapter 4 (page 33) provides 3 lines of code for adding an integer to Number.prototype that "extracts just the integer part of a number."
    • Chapter 4 (page 33) provides 3 lines of code for adding trim method to String.prototype that "removes spaces from the ends of a string."
    • Chapter 4 (page 44) provides 8 lines of code for adding a curry method to Function.
    • Chapter 4 (page 45) provides 11 lines of code that implement a geeneralized funtion for generation of memoized functions.
    • Chapter 5 (page 54) provides 7 line of code that implement a superior method that "takes a method name and returns a function that invokes that method."
    • Chapter 6 (page 61) provides two brief implementations of is_array functions for determining if a given JavaScript item is an array.
    • Chapter 6 (page 63) provides an implementation of a dim method on arrays that initializes all elements of an array.
    • Chapter 6 (pages 63-64) provides an implementation of a matrix method on Array that initializes all elements of arrays nested within array.
    • Appendix F (pages 140-145) provides an implementation of a "simple, recursive decent [JSON] parser" to generate a JavaScript data structure from JSON text.
  • A book such as JavaScript: The Good Parts is necessarily opinionated (same applies to the excellent Effective Java). I like it in this case because it's not one-sided, rose-colored glasses opinions, but rather expresses opinions of both JavaScript's good and bad parts. Not all opinions are created equal. In this case, author Douglas Crockford brings great credibility to back his opinions. His involvement with JSLint and JSON alone speak volumes for his experience with and knowledge of JavaScript. Opinionated books written by inexperienced individuals are not likely to be very valuable, but an opinionated book by an experienced developer is often among the most valuable of technical books.

Conclusion

JavaScript: The Good Parts is one of those relatively rare technical books that is very hyped and lives up to that hype. It helps the reader to understand how to use the best parts of JavaScript and avoid or reduce exposure to the bad parts of JavaScript. In the process of doing this, it does help the reader to do exactly what the author is trying to accomplish: to think in JavaScript. JavaScript: The Good Parts condenses significant low-level details and important high-level language design discussion into fewer than 150 pages.

No comments: