Some thoughts about JavaScript

Originally published on Mon, 01/06/2014 - 02:08

Out of date

JavaScript has gone through several new versions since I wrote this article. Some of the links are broken and will be fixed soon. Overall, I think that the comments made in the article are still valid. However, I would add some discussion of nodeJS and the current popular UI frameworks, particularly Angular, React and Vue. I would also praise the addition of many of the new features of JavaScript except those related to the abomination of classical object-orientation.

I love JavaScript. It is my second favorite language. Sure, I know about its ugly parts but it has real beauty. And beyond beauty, it has all of the attributes that count: efficiency, momentum, a vibrant infrastructure and community, and a future.

Developers tend to be an opinionated lot. This isn’t necessarily bad but I see a lot of unfounded opinions stated as if they are fact about JavaScript. Often developers are so taxed for time that they must choose development tools and techniques out of expediency or precedent or ignorance. Sadly, these choices become subject to cognitive dissonance and often then misperception and denial. JavaScript elicits strong opinions and hyperbole. For anyone who might be interested, below I am providing a few paragraphs about my own opinions about JavaScript.

Learning to write JavaScript well

It is easy to start writing JavaScript. Or rather, it is easy to start writing sloppy JavaScript. It’s not so easy to learn how to use JavaScript well. You need to read about the structure and features of the language (both the core and the API as implemented in browsers). You need to:

• Explore the resources and documentation at the MDN (Mozilla Developer Network). A good place to start is https://developer.mozilla.org/en-US/docs/Web.

• Watch some videos. I particularly recommend all Douglas Crockford lectures available at http://www.yuiblog.com/crockford.

• Read the right books – there are many really BAD JavaScript books. The book by David Flanagan, JavaScript, The Definitive Guide and Douglas Crockford’s JavaScript: The Good Parts are each an absolute must have. I do not see how anyone can be more than a novice without having the former at close hand and having read the latter at least twice. You may also like Marijn Haverbeke’s Eloquent JavaScript, A Modern Introduction to Programming which can be found online at http://eloquentjavascript.net and JavaScript Garden at http://bonsaiden.github.io/JavaScript-Garden/.

• Read a lot of well-structured code (for example, read and understand the code that implements some popular libraries such as jQuery and underscore.js). • Familiarize yourself with online documentation which exist in abundance often in alternative forms. For example, you may use the official jQuery documentation or an excellent alternative found at http://jqapi.com. • Subscribe or regularly visit some blogs. I recommend http://dailyjs.com/ and http://javascriptweekly.com/.

• Experiment using http://jsfiddle.net. Validate your code using http://www.jslint.com or http://ww.jshint.com.

• Write a lot of code! Share and critique code with others. Explore alternative ways of attacking problems.

Prototypal vs Classical Inheritance

OK, a bit of opinion here: The widespread and long-lived adoption of classical inheritance and object orientation as found in languages such as C++ and Java was a huge mistake in the evolution of software development technology. I intend to write a longer blog post about this sometime in the future but some of the major points of my argument are:

• Classical object orientation bears only superficial and misleading resemblance to the way that concepts are formed in the human mind. Prototypal inheritance is quite a bit closer and certain aspects of automated reasoning as implemented through Description Logic and Feature Logic inference engines is closer still.

• The development of Description Logic technology can be compared to the development of OO technology. Early work in Description Logics placed considerable weight on the maintenance of concept classifications based on “is-a” relationships. More current work emphasizes reasoning about role relationships (such as part-whole, “owns”, etc.) and views classification as important but not an end to itself. Likewise, classical object orientation holds the classification hierarchy as central as opposed to prototypal object orientation which places ideas such as “mix-ins” in their proper place of importance. As a modeling discipline, prototypal object orientation is more powerful, natural, and expressive than classical object orientation.

• Classical object oriented code is static and thereby places far more roadblocks to maintainability and reusability of code in contrast to prototypal object orientation.

• The teaching of classical object orientation tends to close the minds of developers to alternative ways of structuring code. I think that a classical object orientation strongly influences resistance to alternative ideas including functional programming and logic programming. Practitioners of classical object orientation tend to have trouble applying declarative programming technology. This does not seem to be the case with people who are comfortable with prototypal object technology.

The support of prototypal inheritance in JavaScript is one of its brightest features; I think that trying to water down JavaScript by creating classical inheritance within JavaScript is akin to retrofitting a buggy whip to an automobile. I have looked at a number of libraries aimed at doing this and each time come away shocked and appalled that anyone would take it seriously.

Functional Programming

I love using JavaScript as a functional programming language. For a good introduction, I suggest reading Michael Fogus’s book Functional JavaScript. You should be sure to download the errata from http://www.oreilly.com/catalog/errata.csp?isbn=0636920028857. Depending on your background you might find some of the presentation to drag a bit, but overall it is well worth reading. I suggest that you familiarize yourself a bit with Underscore.js if you have not already before reading the book. Also, be aware that the errata contains a list of the book-defined functions that were omitted from the index. The books by Flanagan and by Crockford mentioned above also have discussions of functional programming in JavaScript.

Most of the real beauty of JavaScript emerges from closures and the use of a well-formulated functional style. Asynchronous programming (through, for example, promises) and event-based control become clear, testable, and maintainable.

If there is anything I don’t like about functional programming in JavaScript is that it falls short of the beauty of the declarative style of relational/logic programming in Arity/Prolog.

For example, here is a recursive definition of factorial in JavaScript:

function factorial(num)
{
    // If the number is less than 0, reject it.
    if (num < 0) {
        return -1;
    }
    // If the number is 0, its factorial is 1.
    else if (num == 0) {
        return 1;
    }
    // Otherwise, call this recursive procedure again.
    else {
        return (num * factorial(num - 1));
    }
}

var result = factorial(8);
document.write(result);

// Output: 40320

And here is the same in Arity/Prolog, with better error checking (fails if there is an error):

fact(Num, Fact) :-            % check for an error just once! (unlike above)
      integer(Num),           % must be an integer
      Num >= 0,               % must be non-negative
      fact1(Num, 1, Fact).    % extra arg is an “accumulator”

fact1(0, Fact, Fact) :- !.    % this is the stop case
fact1(Num, Acc, Fact) :-      % this is the recursive rule
      Acc1 is Acc * Num,      % update our accumulator
      dec(Num, Num1),         % decrement for the next recursive call
      fact1(Num1, Acc1, Fact).

:- fact(8, X).
X = 40320

The Arity/Prolog code is much closer to a true declarative definition of the factorial function. Also, Arity/Prolog provides tail recursion optimization – something that is still coming for JavaScript. This means that the compiler can automatically turn fact1/3 which has been recursively defined into a highly efficient iterative form for execution that does not consume more stack or heap as the input Num increases in value. (!)

There is a deep and satisfying beauty in both the JavaScript functional style and the Arity/Prolog logical style of programming.

The factorial example above is pretty trivial. What about more complex code? Well, I do a lot of graph algorithm work, commonly using an initial graph structure as a generator for some larger structure using some form of constraint propagation. Such systems can be very inefficient if not implemented properly. One of my favorite algorithms that is used as a component of constraint inference is a topological sort which creates partial orders from a set of binary dependencies in linear time (or generalizing a bit at some cost, I’ll add in Tarjan’s algorithm for finding strongly connected subcomponents). Having written code for such algorithms in both JavaScript and Arity/Prolog, I find implementing in JavaScript much harder. The Arity/Prolog code is faster to write and debug and is much clearer. Both are efficient and scalable (with a slight edge to Arity/Prolog).

Design Patterns and Algorithms

It is a current fashion to make reference to design patterns, a formalism often attributed to an architect named Christopher Alexander and subsequently adapted to software architecture by the so-called “Gang of Four” in a 1995 book Design Patterns: Elements of Reusable Object-Oriented Software. The central idea is that certain recurring practices, both good and bad, can be characterized and referred to by name.

The study of design patterns is different from the study of algorithms; both have value. These days I hear stories of employment interviews that include quiz questions about design patterns but I do not hear as much about algorithms. This reflects the shallow nature of so much software production. All too often I see complaints about poor scalability of some system, assigning blame to the implementation language or the execution environment when a quick analysis can demonstrate that the underlying algorithms are poor.

I believe that a programmer’s analytic capabilities are very limited without a strong command of a wide variety of algorithms and knowledge about complexity. Now, I like design patterns and I think that programmers should have a solid working knowledge of the two dozen or so of those that are most used in practice. However, I worry that too many programmers have substituted knowledge of design patterns for knowledge about algorithms.

I recommend Addy Osmani’s book Learning JavaScript Design Patterns. Also, an interesting (but slightly odd) resource is the JavaScript Patterns Collection, including code samples, at http://shichuan.github.io/javascript-patterns/. Algorithms are suited to life-long learning and their study is idiosyncratic to each developer. A start might be the list at http://en.wikipedia.org/wiki/Listofalgorithms. Of course, this is very general and incomplete and almost any deeper dive into a particular set of problems will require a literature search.