Uglify!
I’ve just moved ShareJS from using the google closure compiler to uglify.
Aside from compiling way faster and being written in javascript, uglify compresses sharejs better than closure! (Only ~1% better, but I’ll take it).
I needed to fiddle with the sourcecode of uglify, and I was amazed at how legible it was. They’ve made very different design decisions from sharejs:
- There’s no unit tests
- Its straight javascript
- Most of the code is in giant functions in a 2000 line long file
But reading it is still extremely pleasant. They make heavy use of the visitor pattern, and once you grok how that works the rest of it is fine.
If you’ve got a few hours free, its worth a look: https://github.com/mishoo/UglifyJS/blob/master/lib/process.js
Google’s new browser language
Google’s working on a new browser based language that they’re going to be announcing soon. I wonder if it’ll be any good…
They’ve accidentally put an internal only document about it up online: http://markmail.org/message/uro3jtoitlmq6x7t . I bet heads rolled about that.
A few notes:
- Types will be optional
- It’ll compile down to javascript anyway
- It sounds like they might want to write a nodejs competitor, designed for googley scale using it.
I love this quote - so microsoft!
The clean break strategy, in isolation, would leave us in an undesirable situation if it were to fail—Javascript evolution would have slowed down or evolved in undesirable ways without our support
BrowserChannel’s secrets
After struggling against socket.io’s many bugs, I’ve been reading through google’s opensourced BrowserChannel code. For those who don’t know, browserchannel is the bidirectional AJAX library google wrote for Google Chat in GMail.
The library does long polling for server->client messages and POSTs for client->server messages. ShareJS over BrowserChannel will be horribly inefficient because every time you press a key, the browser will issue a whole HTTP header. If I want to make browserchannel work for me, I should be able to wrap it in a shared API which uses websockets whenever they’re available and working. To be honest, I’m a little surprised google still doesn’t use websockets in gmail and plus when they can. Maybe they’re waiting for websockets to settle down a bit.
So, I’ve been reading through the browserchannel client code, which is pretty bulletproof these days. There’s some great little gems hiding in there. Today I found out they do a little AJAX using HTTP image objects. The image is loaded by making a new image object, then setting src= . Of course, it doesn’t matter what the actual content of the image is - its never added to the DOM. This is used in two contexts:
- To tell the server that the client has disconnected, browserchannel makes an image object which points at http://example.com/channel?SID=randomsessionid&TYPE=TERMINATE.
- In case of network trouble the client creates an object to load an image hosted at google.com. If the image doesn’t load, the client knows your internet connection is down.
I’m finding it a really weird experience to deal with googley javascript. The style of the code is completely different from what idiomatic node.js / coffeescript usually looks like. Instead, its all OO. It uses enums everywhere. All the functions and parameters have their types specified. There’s almost no nested functions - its all really flat. I’m rewriting it in coffeescript as I go, and I’m making huge structural changes to do so. Its quite fun :)
New version of ShareJS
I”ve pushed a new version of sharejs tonight, now with type-specific API support.
Previously, you could write this:
sharejs.open('hello', 'text', function(doc, error) {
// Insert some text
doc.submitOp([{i:"Hi there!\n", p:0}]);
// Print the document's contents
console.log(doc.snapshot);
// Parse incoming operations
doc.on('remoteop', function(op) { ... });
});
… and now you can do this:
sharejs.open('hello', 'text', function(doc, error) {
// Insert some text
doc.insert("Hi there!\n", 0);
// Print the document's contents
console.log(doc.getText());
// Parse incoming operations
doc.on('insert', function(text, pos) { ... });
doc.on('delete', function(text, pos) { ... });
});
Voila!
That doesn’t look like much, but it means that you’re insulated from the specifics of how ops are constructed. … And so is the editor; so now swapping between text implementations is just a matter of asking for a different type. By magic, sharejs’s ace editor component now supports editing TP2 documents as well.
I’m planning on using the same system to make editing JSON documents less awful. (Jeremy’s idea.) At the moment, you’ve got to construct ops by hand, and the op format is uuugly. We should now be able to just add a few functions in the right place and JSON documents will be magically endowed with sane editing capacity.
On languages and thought
There’s an interesting effect involving programming languages, where each language seems to encourage a particular kind of thinking in its users.
Its different from the Sapir–Whorf hypothesis (that languages shape thought). Instead, it seems to be that certain philosophies give rise to certain programming languages. - Or, the best way to write a program changes depending on what language you’re using.
The classic dichotomies are between dynamically typed and statically typed languages, but there’s waaay more subtlety in the programming philosophies than types.
The thing I find most interesting about the different schools of thought is how I change my patterns of thinking to accomodate the language I’m programming in rather than the other way around.
A simple example: Suppose I want to model a banana which can be eaten. In Java, I’d use:
class Banana {
void eat() {
}
}
Banana b = new Banana();
b.eat();
Whereas in javascript, I’d start with:
b = {eat: function(){}}
b.eat();
Where’s the banana class? Well, since b is the only banana I’m not going to bother making a class. This is the first, perhaps most obvious philosophical distinction in languages: What to do in the presence of an incomplete spec. The old guard school of thought is to first make the spec as complete as possible, and program your code so that it will be as robust as possible to spec changes. In essence, optimise such that you have to rewrite as little code as possible if/when the spec changes. A better java banana implementation looks like this:
interface Banana {
void eat();
}
class BananaImpl implements Banana {
void eat() {
}
}
class BananaFactory {
Banana create() {
return new BananaImpl();
}
}
BananaFactory fact = new BananaFactory();
Banana b = fact.create();
b.eat();
Why write all this code for such a simple problem? Why write all this code when there’s only one banana implementation? … And the banana implementation doesn’t have any parameters? Good java programmers will tell you its so that in the future, if there are ever more banana implementations created, you only have to change the factory. Furthermore, if the banana implementation gets a parameterised constructor, the banana factory will allow the programmer to change the smallest possible amount of code. If bananas need more methods, the interface can be changed and this will force all banana implementations to be updated. Finally, this is arguably easier to test, because you could dependancy inject a different BananaFactory which creates mocked out bananas. More code = more resiliance to change.
That all sounds rather consistant. What have you to say, javascript programmers?
Well, goes the alternate philosophy: You are optimising to change the smallest possible amount of code if the spec changes. The other way you can change the smallest amount of code is if you write the smallest possible amount of code. When the spec changes, just throw your code out if its no good. You will probably end up writing less code in total (since many of your ‘what if’ scenarios will never come to pass). Less code = less bugs.
The reality is, you can write code using any language, using any set of philosophies. Its just that by doing so you tend to go against the grain of the language. A great example of the java way of thinking written in javascript is the ace editor. Google’s closure compiler is a tool to help with stuff like that - it gives you a canonical set of tools for modelling classes, scopes, etc and adds decorators for strong typing. Most of the google engineers I’ve talked to about this stuff (who program in JS) support the java style of thinking. Apparently its easier to write a big project like that when you have a lot of people working on it.
I haven’t seen much java code written in the agile style, though its probably more common than I think. Mockito is a good example. I suspect the agile style tends to work better with a small number of developers, because you will need to rewrite large swathes of code from time to time, and that’ll bother fewer people when you’re in a small team. The more code you have, the more elbow room developers have when they’re working on a project together.
Another big difference is the attitude to testing. All developers that I talk to accept that testing is important, but most of the java projects I’ve worked on have a much more relaxed attitude to testing than, say, ruby developers. I saw a talk from a ruby conference where a ruby developer wore a wristband to remind him to write his tests first, and when he ever wrote code before tests, he would swap wrists. You’d never hear of a java developer doing that - most java developers I know think of testing in the same way I think about breakfast: I’ve heard its important and I have felt better when I’ve eaten it, but I’ve managed many many mornings without it.
You can see how these feelings come about. The java compiler will find + catch heaps more bugs than the runtime environments of dynamic languages. Still not all, but.. most. Enough that debugging isn’t as big a deal. When it comes to debugging, the debuggers of static languages are a million times better than that of dynamic languages anyway. So, people programming JS or ruby have to spend proportionally way more time debugging. Untested code will have heaps more bugs-per-line, and so testing moves from a nice-to-have into a necessary part of development.
Again, there’s code out there which bucks the trend. Webdriver is a java library thats obsessed with testing. And I’m sure there’s plenty of webpages out there with JS that has never been unit tested.
For a point of comparison, Wave in a box (java) has 1 line of testing code for 5 lines of code. ShareJS is 1:1.
I find myself sometimes arguing this out with other developers I respect - the static language camp says that you can’t be productive in dynamic languges because of all the time you have to spend debugging. The dynamic camp says that its fine, you just have to write lots of unit tests (your testing code can often be much longer than your actual code.). And besides wiggles finger you static guys should be writing tests anyway. And so the argument goes.
Are you more productive with dynamic languages using TDD, or with a static language with a cavalier attitude to testing? Tests will slow you down. Tests make refactoring more reliable (you can test your new code!), but changing interfaces becomes really expensive (you have to rewrite all those tests!). But also, dynamic languages also happen to be much more expressive - you don’t need as much code to say the same thing.
Here’s how you set a timer in Java (GWT):
Timer t = new Timer() {
public void run() {
Window.alert("Nifty, eh?");
}
};
// Schedule the timer to run once in 5 seconds.
t.schedule(5000);
Vs coffeescript:
window.setInterval (-> window.alert 'Niftier.'), 5000
I would love to see some data on productivity. You would need: - A problem which has been solved in a similar way in many languages - Programmers with similar skill - Stats on how long it took them to code the thing up.
Though there’d still be a difference in implementation; if my brain is on the java gear I’ll design a different program to when I’m thinking with ruby.
Maybe thats the most interesting part in all this; that its often better to go with the grain of a language / environment than to go with the philosophy you prefer. Good programmers have opinions, but can program in any style. But I suspect that after awhile, a philosophy is used so much on a day-to-day basis that you stop imagining programming in a different way.
Finally, where does a language like scala fits in? Scala’s syntax is very similar to that of ruby and coffeescript (it also borrows from haskell). But its strongly typed and compiles to the JVM! Is canonical scala more like ruby or more like java?
Teaching = fun.
Gave a talk to year 5/6 kids today (from a gifted + talented program).
It turns out, most of them love minecraft. (I think thats awesome.)
We spent a bunch of time talking about the theory behind AI, and how you write computer programs. I got some really great questions, including: “If you use a computer to write a computer program, how was the first computer program written?”, “Couldn’t you just get an AI to read lots of books and figure out what good and evil are?” … and stuff like that.
Teaching kids = great fun.
(Source: plus.google.com)