Many tools makers realized that this is not the way to go and started working on unifying some of those aspects in more comprehensive solutions for the Web (Google Web Toolkit is one result of such efforts). In a world where dynamic programming and Agile development are king, two modern incarnations of the comprehensive Web solution concept are Node.js and Opa. Both feature an event-driven model that makes them a good fit for writing "real-time" web applications. Let's take a closer look at those two technologies and compare / contrast their offerings.
Opa and the Node.js: What's the Difference?
Opa is a platform for developing Web applications. It is both a programming language and a runtime engine that tightly integrates all the required features. It uses a similar asynchronous model to that of Node.js, but it uses a completely new statically typed, compiled, functional language, designed specifically for the Web. Its development began in 2007 and is sponsored by a startup called MLstate.
Same features, same use cases -- so are Node.js and Opa really similar? Not quite! There are more than a few differences and this article will focus on them.
Opa vs. Node.js: The Web Chat Benchmark
To illustrate and compare those two languages we will use the example that is slowly becoming a standard benchmark for Web frameworks/languages: a Web chat. It is a good benchmark, as it involves extensive client/server communication.
Below we present screenshots of chats developed, respectively, in Node.js (by Ryan Dahl, the author of Node.js himself) and in Opa (by Frederic Ye, an Opa developer). The Node.js chat app is a typical example showcasing the language, while the Opa chat app was written specifically for comparison. We encourage you to click on the images to play with the live application and to browse their sources. Both applications are equivalent feature-wise.
Opa vs. Node.js: Productivity
Developer productivity is a very important consideration when choosing one's tools. If you can develop fast, it means you can innovate. You can quickly create prototypes, and you can quickly react to changing market and user needs.
There are many pitfalls of using SLOCs (Software Lines of Code) as a metric to compare productivity, but they are a good rough estimate and can give an impression of the effort required to develop something. Instead of presenting raw numbers, below we show a bird's-eye view on the source code of the two projects, after removing comments and new lines (for Node.js sources we included only client.js and server.js, as the remaining files can be considered to belong to the standard library). The Opa project is on the left, and Node.js is on the right.
While not definitive, this example suggests that Opa is much more concise. This can be probably explained due to its more high-level nature than that of Node.js. For instance, Opa's distribution model is providing primitives of distributed sessions that make it very easy to set-up asynchronous communications between clients or client and server. A minimal chat in Opa even fits on one screen.
Opa vs. Node.js: Building UIs
Both Node.js and Opa use (X)HTML and CSS for building user interfaces. Of course, in both cases, it's possible to build libraries and abstractions on top of that layer but neither language enforces that and both allow direct, full control over the markup.
Node.js does not have any special support for HTML, and the markdown is simply built as a string with string concatenation (as here). There are several problems with this approach. To begin with, developers cannot perform a validation of the correctness of the markdown; unclosed tags, typos and the like will have to be noticed and corrected when testing the application. But possibly even more importantly, this poses a very serious security threat. Since HTML is treated as a string, it takes very careful development not to allow the possibility of XSS injection to slip in (where the attacker can inject and execute client-side script in the app).
On the other hand, in Opa HTML is a data type (interestingly enough it's not a primitive type but is developed as part of the standard library of the language), with special support in the syntax that allows developers to write it easily (as here). While on the face of it, it may look only slightly better esthetically, the implications are far-reaching. Essentially all the aforementioned problems are solved: ill-formed markdown will be rejected by the compiler and the language offers built-in protection against XSS injections by properly escaping any values inserted in the constructed HTML.
Below we show equivalent snippets (taken from Node.js' chat) in both languages.
Opa vs. Node.js: Server-/Client-side Separation and Communication
Since both Node.js and Opa are meant for both client- and server-side coding, it's interesting to see how they both address the issue of communication between the client and the server.
Node.js provides a very explicit approach. The server and client separation is enforced at the source code level, as some files will be included in the Web page served to the users and others will be interpreted by Node on the server. Hence, the chat example contains the aptly named server.js and client.js files.
For the communication one directly uses the Ajax primitives of jQuery.
In Opa, there is no explicit separation between the client and the server part of the code. One just writes the application code, and then the Opa compiler figures out which part of the code should be sent to the client and which should be executed on the server. Of course, the developer can influence those decisions by prefixing functions with client or server directives, or one of the safety directives, such as protected (meaning the function is security sensitive and should not be trusted to the client). As a result, moving code between the client and the server is as easy as adding/changing a few directives. That's why Opa's chat consists of just one file: main.opa (in this example, for clarity, all the functions were explicitly annotated).
Since Opa provides this location transparency, its communication is also on a higher level of abstraction. All one does is use simple function calls and Opa's compiler, depending on the location of the caller and the callee, and implements those as either local function calls or remote (Ajax/Comet) procedure calls.
Here is a snippet of the Node.js chat and its rough equivalent in Opa.