Tuesday, August 10, 2010

I @#$%&* JavaScript!

I am by no means an expert web developer or particularly familiar with JavaScript, which might influence my distaste for it. My experience is mostly from making small changes in moderately complex existing applications.

JavaScript was originally intended as a small domain-specific glue-language to ad some client-side behavior to otherwise largely server-side web applications: do some client-side input validation, dynamically modify the page based on user input, etc. But with the growing popularity of AJAX style web-applications, much of the JavaScript client-side code has grown into monstrosities - mostly because of a lack of inherent support for modularity and encapsulation.

One of the most important properties a language environment should support in order to scale to large projects is a way to divide an conquer. There should be a way for one programmer to build upon the work of others without having to understand the implementation details of these building blocks which might be called libraries, modules, packages, interfaces, objects, widgets, components, etc. depending on the on the language. This should also include the ability to debug in the context and level of abstraction in which the code is being written.

For example, if an error occurs as the result of an API call, the error should be reported in terms of the API and the parameters passed through it and not just by a location in somebody elses low-level library code, where supposedly something has gone wrong, most likely because I make a mistake in an API call.

My experience with complex JavaScript libraries and frameworks (in particular the Closure library) is that the benefits one would expect to gain from using high-level libraries and components is greatly reduced, by having to debug and understand so much of the provided low-level code - just because the language system does not provide the necessary isolation. If the inclination is to write everything from scratch, so that at least I understand the code which I have to debug in my application, then the language environment has failed from a scaling point of view.

In this case, the blame not only lies with JavaScript as a language but as much with the ecosystem it lives in. De facto, JavaScript runs in a set of target environment, which are typically the most popular browsers (IE, Firefox, safari, chrome, etc.). The debugging support of these browsers is still severely lacking - even though things have gotten a lot better with things like the firebug extension to Firefox or JavaScript console built into Webkit. Part of the problem also comes from the fact that the typical JavaScript application is never self-contained but interacts with and depends on the DOM representation of a page in the browser and depends heavily on the quirks with which this particular browser renders the page and interprets the CSS attributes. The trickiest part of using a 3rd party JavaScript UI widget is often getting the right kind of CSS definitions loaded in the right order in the page where the JavaScript code is being executed.

Since rich AJAX style web applications are compelling and powerful to use, there will have to be a way out of this mess. JavaScript and its browser based ecosystem will either need to grow the features needed to support large scale software development, a higher-level language abstraction will be layered over it to make it more productive to programmers or a whole new web programming model will be created.

For an example of the second approach, GWT is an interesting step in the right direction. GWT is a compiler based approach, where an AJAX web application is written in Java and then compiled into JavaScript as the target for execution in the browser - relegating JavaScript to a kind of assembly or virtual machine language. The app can be partially debugged naively in Java. However because of browser quirks, much debugging is still required on the browser, where the abstraction breaks down again as it did for high-level languages before the existence of source-level debuggers: write code in a high-level language and debug the generated machine instructions.

Another advantage of this high-level compiled language approach is that the execution engine in the browsers is now only used by code generated by compilers and could be more easily optimized or even replaced by something new altogether simply by close collaboration between whoever builds the compilers and the JavaScript engines in the various leading browser platforms.

However there is another unfortunate issue with the GWT approach: while it can be scaled up pretty well to very complex AJAX web applications, it cannot be scaled down as easily to the simple tasks JavaScript was originally designed to do. This would leave a world where for simple things one would still use hand-written JavaScript and for complex applications a compiled AJAX framework like GWT. With an obvious discontinuity when a once simple application grows into a complex one and unfortunately, this is a pretty common case in real life.

Among the languages I commonly use, Python has the best properties of scalability from a software development point of view. It seems to be easily approachable by novice programmers and is now commonly used to teach a gentle introduction to programming for non-technical users. It is sufficiently high-level and low on framework-overhead to do simple things simply and easily and yet has just enough rigor and structure to scale to some pretty amazingly large-scale projects. It is an embeddable language and while it's standard distribution is quite a bit bigger than JavaScript, it would not be impossible to embed into a browser a library to manipulate the DOM. In fact some efforts to do that seem to exists. While Python was nowhere near as mature and proven in 1995 as it is today, one is left to wonder what would be the state of web programming, if Netscape had chosen to embed Python into its browser instead of JavaScript...