I did some recreational programming over Christmas and the blog I wrote about it is now guesting in Jeff Barr’s space for your amusement; try the software at IsItOnAWS.com. What I didn’t do there was relay the lessons I picked up along the way; one or two are around AWS, but most follow from this being my first nontrivial expedition into the land of NodeJS. So (acknowledging that only 0.8% of my profession aren’t already Nodesters), here they are. Spoiler: I don’t like Node very much.
Lesson: Lambda has historically been used for behind-the-scenes work. But with the recent arrival of new API Gateway and Certificate Manager goodies, it’s become pretty easy to convince a function to serve HTTP requests pointed at your own web-space. Will this be a popular idiom? Beats me.
Lesson: I can now work with Node’s everything-is-a-callback worldview, but still, at the end of the day I think it’s wrong. What I want to do is fetch data, then process data, then write data, and if a damn computer language can’t give me a sequential abstraction when I want to do sequential things, well screw it.
Yeah, I acknowledge the kozmick performance gains Node achieves, even when living in a single-threaded environment, by pushing developers into callback-or-die territory, but you know, there are things like pre-emptive multitasking and thread pools that should let the system interleave IO and compute for performance without making me worry my pretty little head over it.
Having said that, async/waterfall is a straightforward way to remediate the damage.
Lesson: Constructing a zip was pretty easy with jszip. Except for, despite the fact that a zip is a bunch of bytes, jszip insisted on emitting a Node Stream. But it seems that NPM generally contains correctives for its misfeatures, in this case raw-body.
Lesson: Node’s HTTP-fetch function is kind of dumb and clumsy. Every language should have a one-liner that says “Here’s a URL, gimme back an object with the content-type and the response body’s bytes, or let me know if you can’t.” Of the languages I’ve used in recent years, only Go and Ruby do.
Lesson: Upon publishing this, I will receive much pitying feedback along the lines of “Well of course you could have done it in a one-liner using TheNewHotness.js.” And also pointing out many other better ways to have done this using things my Internet search skills were insufficiently advanced to discover. Draw your own conclusion.
Lesson: The IPv6 address-literal syntax is stupidly human-hostile.
Lesson: NPM has at least one of everything you can possibly imagine.
Lesson: NPM dependencies are a fulminating cancerous mess. This little Lambda that runs when the JSON updates needs fifteen freaking megabytes in its node_module directory, and the zip is like 2.5M. For the little function that actually handles the IsItOnAWS requests, I consciously tried to keep the dependencies down, but I still ended up needing async, ipaddr.js lodash, and sprintf-js for another 2½ meg. Feaugh. What’s a “lodash”, anyhow?
Lesson: The Lambda and S3 APIs are minimal, sensible, and well-integrated into Node’s resistence-is-futile you-will-learn-to-love-callbacks paradigm.
Lesson: The best Node code is Non Fancy Node.
Lesson: The tape unit-test harness Just Worked for me out of the box, had a nearly-zero learning curve, and was minimally intrusive. I’m a fan.