When I started the Opa project five years ago, my goal was to clean up the mess and build a clean technology for writing web applications.
At the time, Web 2.0 applications based on AJAX were increasingly popular and most technology stacks were growing in complexity, surpassing 5 technologies: A web server, a programming language for the server, another for the client, a database and at least one framework. Not counting an ORM layer, caching mechanism, etc., etc. There was room for improvement!
The design was based on two principles:
- There should be a single, unique language for writing web applications.
- There should be a single, clean, runtime on the servers.
This month, two new technologies launched that rely on this first principle. And both chose JavaScript as the single language:
- Yahoo's Mojito framework features dynamic code migration, with the ability to shift computation at runtime from the client to the server for mobile devices, in order to reduce the amount of data transferred to the device.
- Another framework, Meteor, automates the communication between the server and the client part of the web application.
Both use Node.js, the increasingly popular “application server” for JavaScript.
We are really happy to witness this move that makes web application development easier. Since 2008, we have learned a lot by using a single programming language for writing web applications. Especially when growing from prototypes to real-world applications. It turns out that one of the most needed features was the ability to automatically determine where the code should run, on the client or on the server. We named that feature the Opa “slicer”.
You can classically enforce a given side using “client” and “server” directives:
// Client-side
client function client_function(value) { ... }
// Server-side
server function server_function(value) { ... }Most of the time, you want to omit the hint and let Opa guess. Imagine you have a DOM element of id "counter", and a database named "mydb":
// Will be on server side:
function db_update(value) {
/mydb/counter <- value
}
// Will be on client-side:
function dom_update(value) {
#counter = value
}Even better! Both calls (and the automated communication) can be written with a single function:
function update(value) {
/mydb/counter <- value;
#counter = value
}And even with a single LOC:
// Just write _what_ you want to do, without worrying about _how_ to do that
function init() {
#counter = /mydb/counter
}As you may imagine, automatic code repartition is a very complex problem that requires deep code analysis to make it work. In Opa, we tackle this problem by relying on an advanced static typing system. And let's be honest, the type system of Opa is the feature we are most proud of.
Every function in the Opa code gets a type (which is usually inferred). When the developer writes:
function foo(s) {
String.length(s);
}
function bar(x, y) {
foo(x) + y;
}The Opa compiler infers:
int function foo(string s) {
String.length(s);
}
int function bar(string x, int y) {
foo(x) + y;
}Similarly, the slicer infers wether a given function may run on the client, the server, both. Over the years, we developed and refined the approach to make it usable past the prototypes. We introduced hints to quickly precise if the client-server should be asynchronous, or synchronous. Wether, the function may, or may not be, callable. And use the rich typing information to make it work.
The compiler may warn you that:
File "errorslicer.opa", line 6, characters 17-19, (6:17-6:19 | 73-75)
A‚ 'malicious' is tagged as 'client' but it uses 'protected' values:
to prevent you from doing evil things. If you're curious, the sample
code is here.
Opa has also built advanced support for MongoDb. And again, we make use of the rich typing information to make things simpler for the developer while automatically ensuring that the code is well written. You can
read this post by Adam on this subject.
Opa has become a mature technology and now brings together incredibly clean and concise code, but also security and high-quality to web applications. The feedback we received hinted that Opa's biggest drawback is that it relies on its own application server.
Opa already and naturally uses JavaScript, as the Opa compiler translates the client-side Opa code to JavaScript. The popularity of the Node.js platform and the good set of tools and technologies now available, convinced us that we should also support Node.js as a new server backend. After all, we already know how to translate from Opa to JavaScript!
We have the feeling Opa could become the killer framework for writing Node.js applications. Do you also think that would be great?