Here are the screencast and the write up on the talk I gave today at One-Shot London NodeConf. As usual I diverge a bit from the initial narrative and I forgot to mention a couple of topics I wanted to highlight, but I have had a horrible week and considering that, this has turned out pretty well!
It was great to meet so many interesting people at the conference and seeing old friends again! Also now I'm quite excited to hack with a few things. Damn (or yay!).
A little more than a year ago I started working at an agency in London as a creative technologist. It was fun to be trying out all the new things and building cool experiences with them. So whatever new APIs were out there, we would come up with some idea to use them. Sometimes that would be because the client wanted to be "first" in using that browser functionality so theirs would be the first website that did X and that would drive a ton of traffic to them, and other times we just wanted to do some cool experiment for our own website so we would master that technology and also attract traffic and get new clients--that's how it works in advertising.
I had been toying with node.js on and off for a while already, but this was when I started to actually believe that I could just use JS for everything... even build scripts!
The worst habits
But I had the worst habits after a life of many other programming languages, and although I wasn't consciously aware of them, I knew that something didn't feel quite right. But what? It was hard to say when everyone else in your environment was OK with whatever solution you came up with as long as it worked well enough and you delivered on time.
This was also part of why I joined Mozilla--I was feeling super guilty that we were building things that were not using standards and they would break in the future, or even worse, set bad precedents and habits. I didn't want to contribute to a web where the cool experiences only worked on one browser, but I wanted to contribute to make the web more powerful and expressive.
My buddy Jen
A couple of months later, I was in Mountain View for my onboarding week. I was disoriented and jetlagged, but also very excited and scared! And more people on from my future team were in Mountain View for that week. One of them, Jen, sent me a message pretty much just as I checked in into the hotel: "hey, ready for dinner?"
I hadn't even met her or spoken to her during the interviews, so I wasn't even sure how did she look like in real life. I washed my face and told to myself in the mirror that it was 6pm, NOT 2 AM as my body was trying to protest, and that everything was OK. And went downstairs to meet her.
She was waiting in the parking lot. I had only seen a tiny picture of her with shorter hair in her (very prolific) github profile, but honestly, who waits alone in the parking lot of a hotel in Mountain View at 6pm on a Sunday? We said "hi" and she said: "it's my birthday today, and I want to have a nice dinner". Would I oppose such thing? No!
Jen's a philosopher, therefore she philosophises
We walked to Castro street, spending some time admiring the peculiarities of the business on either side of El Camino Real. You might have a chiropractice, a massage parlour, a beauty salon, and a gun seller, all side by side. It was all very amusing. Then we went into a Moroccan restaurant, and we had to prove our age by showing our respective passports, which was amusing again.
So we started talking about the food first... how it didn't taste like anything Moroccan I had had before, and whether the Moroccan food I had had either in London or Paris could be considered authentic, or more authentic than this--based on closeness to the "source". But you can only analyse food so much, so we switched to other topics and at the end of dinner she was telling me how she was going to build a distributed blog system but she would do it into a module so she could then reuse it for other things because it would be generic enough and... with the wine and the jetlag I was really finding it hard to follow.
She continued discussing and elaborating on these ideas during the week. She was hacking on a module that would be called meatspace. And she excitedly told me: "to empty it you would just call the flush method!". Not being a native English speaker, I didn't understand what 'meatspace' meant initially, so the whole naming seemed disgusting to me. Flushing meat drown the drain to empty the stored messages! GROSS.
My first task to get acquainted with the Mozilla process was to port or rewrite one of my existing Android apps to the web. WebRTC support was coming up soon in Firefox, so I opted to build something similar to Nerdstalgia. And I built something, and then I had Jen code review it. I didn't know it initially, but she had been appointed my "Moz buddy", to guide me around and introduce me to the usual processes.
She would keep mentioning this notion of "making things into modules" but I still didn't quite get it. I regularly extracted my code into libraries, right? So why all this insistence on modules?
Intrigued (or sparkled) by her insistence, I started extracting modules out of rtcamera. The first one was the Animated_GIF library, and then gumHelper. This was quite providential because a while later she was exploring this idea of a distributed multiuser chat that could use your webcam to capture your facial expression, and because we had these libraries handy, adding them to the stack was very easy. You might, or might not, have heard of a thing called Meatspace Chat
Frida is one of Jen's cats. This is Frida after seeing comma-first JS, according to Potch.
Something that really helped me "get the node way" were her comments on how to pass parameters, and callbacks. This was one of the reasons why I felt my node.js code didn't feel 'right', and that's because I was using my own adhoc style which was the result of having programmed in many languages but not being profficient in node.js - so I wasn't using their idioms, and my code felt weird when using other people's code--even system modules such as fs.
She insisted a lot on using a standard "callback signature" -- the function(err, result) style which honestly drove me a bit nuts at the beginning. But if you're using the same style throughout the code you can exchange node modules or even send the callback to another function, and it's easier than if you have different signatures on each library.
Another of her lessons was that if you were trapped in callback hell, maybe you were doing it conceptually wrong. Maybe you should be simplifying your code so you do calls in a different way. I am not totally sure of what I like most yet--promises or just plain callbacks, but I see her point, and oftentimes I would bring a Promises library to my project, then after refactoring the code so it would be suitable for promises I find that I don't really need them at all.
Likewise for user interfaces--most of the time we agonise over how pretty something has to look but the fact is that the site might not provide any value to a user and so they leave. We should focus on the experience first, and then maybe we can make the things prettier.
Another important lesson: it's totally OK to use other people's modules! Believe it or not, my initial node code almost didn't use anyone's modules, and if I used external code that was because I downloaded the code and copied it to the src folder AND loaded it with a local require path. npm? What was that thing?
Funny fact: I was watching RealtimeConf's live stream because Jen was doing a talk on all the experiments she had been working on and was going to present Meatspace chat for the first time, and so I stayed for a while. And then I learnt a nice lesson not from her directly but from Max Ogden on his RealtimeConf talk: you don't need to care about the code style in a node module, as long as it works. If it doesn't, either you replace that module with another one, or you fix it. And again, if you're using the same signature, this is easier to accomplish--you're just replacing "boxes".
Having tests is incredibly useful for this. Jen often writes the module tests first and then the module code itself--so she defines the API that way and sees if it feels natural and intuitive.
At this point there's no UI code yet, just tests that make sure the logic works. If you can run the same test input data through two different modules you can make sure they do what they are supposed to do, and can also compare their performance or whatever nit is that makes you want to switch modules. This again is way easier if your function signatures are "standard node.js style".
I heard about this one actually the same week I started in Mozilla. But I was unable to appreciate its awesomeness--I was just used to applying Google Closure compiler to my concatenated code and calling it a day. I either concatenated the code with a nice
cat *.js > all.js
or maybe I built Python scripts that would read certain code files and join them together before either invoking a local version of the closure compiler (which was Java), or would send the uncompressed code to the Google Closure service to hopefully get it back, if there weren't any errors.
But I quickly forgot about it. About some time later, I was looking into building a somewhat complex thing for my JSConf.EU project, and somehow Jen reminded me about it.
This project was a fun one, because I was using everything on it: server side node with Express.js serving the slides, which were advanced according to the music player with virtual Web Audio based instruments that was running on the browser, plus I had Socket.io sending data to and from a hardware MIDI device through OSC. So there were lots of data to pass back and forth and lots of modules to orchestrate, and including script tags in the browser wasn't going to work well if I wanted to stay sane. So all the front-end code was launched using Browserify.
Another favourite anecdote in this project is that I in fact extracted several modules out of it, with tests and all, that I then reused in other projects. So I was taking advantage of my own work later on, and I like to think that when this happens, more people might find it useful too.
Finally--and this is not a thing that only Jen taught me-- one of the reasons why we like node a lot in Mozilla is because it makes it so much easier to write code that works everywhere. And with that I mean different platforms. As long as node can run in that system, the code can run.
This is very important because most of the times developers assume that everyone else is running the same system they are developing on, and in rich countries this often means the assumption that people use Macs, but that's not the case everywhere, and certainly not in poorer countries. They use Windows or Linux, and setting up a toolchain to have a working make tool with which to run Makefile is either harder or not for the faint of mind.
So in this context, distributing build scripts written for node.js is way more democratic and helps us get our code to more people than if we used Make or Bash scripts.
And here comes one of my favourite stories--when one of the meatspacers sent me a PR to improve the build system of one of the libraries I had extracted and make it use node.js with uglify instead of the bash script I was using. That simple gesture enabled all the Windows developers to contribute to my module!
- node modularity is awesome, but it takes time to 'get it'. It's OK to not to get things at the first try.
- If you can find a mentor, it will help you 'get it' faster.
- Otherwise maybe hang on the proper channels (irc, user groups, blogs, confs), study other people's code and BE A SPONGE (a nodesponge?)
- Don't be afraid to experiment but also use the safety harness: tests!
- And don't be afraid to publish your code - maybe someone else will find it useful OR give you advice to improve it!