"Fancy code is exclusionary"

From "Explicit Code is Inclusive":

And this is the point: fancy code is exclusionary. The cost of changing that code is higher because the pool of developers that can work on it is lower, and the cost of increasing the size of that pool is higher.

This isn't to say that inclusivity is the only criteria we should use to examine code, but it's something we often forget, and it's pretty important. If your team plans to grow, the more programmers out there that could join your team and be successful, the easier it will be for you to grow that team. If you require deep expertise in a language or framework to be productive, you either have to filter for that in your interview process, or be prepared for a long onboarding to get new people productive.

My entry to JS1k 2018: "Zap"

In short: check out my entry to JS1k 2018.

JS1k is a contest where developers must build something impressive using only one kilobyte of JavaScript. I like coding with constraints so I always enjoy entering.

My final submission to 2018's JS1k contest was my third idea. I originally made a coin-collecting game (source here) that was inspired by Kirby Air Ride, an old GameCube game I love. I couldn't quite get it to fit in the 1 kilobyte limit, but more importantly, I couldn't make it fun! I also abandoned a simple spreadsheet program (source here)—I found it hard to make an impressive spreadsheet at any file size!

I settled on an interactive page where you could control lightning bolts by moving the mouse. Check it out here!

The "game loop"

I start a lot of my code doodles with a skeleton that looks something like this:

// Create an array of entities (populated elsewhere).
const entities = []

// This function will be called on every frame.
let lastTime
function tick (t) {
  // Calculate ∆t, the number of milliseconds since the last frame.
  const dt = lastTime ? lastTime - t : 0
  lastTime = t

  // `tick` each entity with ∆t.
  entities.forEach((entity) => {
    entity.tick(dt)
  })

  // Request the next tick.
  requestAnimationFrame(tick)
}

// Request the first tick.
requestAnimationFrame(tick)

This is effectively a game loop, whether you're making a game or a visualization.

I modified some of the specifics of this design (shortening names and things) to keep my code under 1K, but it's conceptually the same in my submission.

A key component of this design is the dt variable. Every bit of movement is relative to this variable in some way. For example, when a ball moves across the screen, you should write something like this:

this.x += this.velocityX * dt / 1000
this.y += this.velocityY * dt / 1000

// Instead of something like this:
// this.x += this.velocityX

This means that the velocity isn't bound to the framerate—it works on a fast computer and a slow computer. This idea prevents slowdown on slower machines, but it has another interesting property: you can play with the pace of time much more easily.

For example, you can trivially introduce a timeSpeed variable to half the speed of the entire world:

// ...
let timeSpeed = 0.5
const dt = (lastTime ? lastTime - t : 0) * timeSpeed
// ...

Now everything will slow way down! To double the speed, you could set timeSpeed to 2 and you're done—no need to update anything else.

I used this design in my JS1k demo. The user can press Up or Down on the arrow keys and the equivalent of the timeSpeed variable (called x in my example to save bytes) will be moved up or down to change the whole visualization.

Staying under the limit

This is JS1k, so everything has to be hyper-compressed. I accomplished this in two ways: with tooling and some coding tricks.

Tooling

The bulk of the work was done with two tools: babel-minify and RegPack.

2017 was the first year that JS1k allowed ES6 code, but popular minifiers like Uglify lacked ES6 support. babel-minify came on the scene and let you minify ES6 code as, well, ES6! I chose this minifier to help crush my code down.

RegPack is a crazier tool. It compresses your code as a string, includes decompressor code, and then runs the decompressed code with eval. (That is about where my understanding of the tool ends.) The babel-minified code is barely readable, but the RegPack-compressed code is impossible to read. This tool is invaluable when trying to making something substantial fit under 1 kilobyte.

I wrote a file which takes in the raw source and spits out minified output using the above tools.

Code tricks

I typically use JavaScript Standard Style and this submission was no different. I only disabled one of its rules! But there were plenty of cut corners all the same.

At a high level, I endeavored to use single-letter identifiers unless I was declaring local variables. I maintained a comment at the top that noted the mapping—t was the current time, e was the array of entities, and so on.

I also had a fair number of local variables. Because I knew that babel-minify would rewrite these, I knew I could give them full, descriptive names. This made my life a lot easier!

Here's a grab bag of other tricks I employed:

  • Use 0 and 1 instead of false and true
  • Use myNumber | 0 instead of Math.floor
  • Use map instead of forEach
  • Use backticks for strings everywhere to compress better with RegPack

There are several spots where I could've done more to compress the code, but I was 13 bytes under the limit and didn't feel the need. For example, my code still has === instead of ==, which is a waste of bytes.

Making it fun

My brother isn't a developer but he sat with me while I worked on this. We iterated on the "doodle" for a couple of hours before we eventually got to the lightning bolts in the final scene. Initially, we had colorful triangles flying around on the screen. Sometimes it hurt our eyes. We experimented with changing the colors as a function of time (cycling slowly through the rainbow) and many other tricks. Eventually we noticed that we were building something that looked like lightning bolts, and we were off to the races.

❤︎ JS1k

Thanks to everyone who runs JS1k—the judges, Peter van der Zee, and the sponsors. I've enjoyed entering in past years and this one was no exception!

Show only production dependencies with npm

In short, npm ls --prod will show the tree of your non-development dependencies.

I try to limit the number of dependencies I use in my open source modules for security and simplicity. I wanted to see the tree of dependencies while working on Helmet to make sure I wasn't pulling in more than I needed, but npm ls gave me all of my dependencies, including development dependencies like my testing framework, which I didn't need to see.

Luckily, npm has a --prod flag for this! Run npm ls --prod to only see your "regular" dependencies, not your devDependencies.

If you want to do the opposite and only see devDependencies, give npm ls --dev a try.

Hope this little tip helps!

On modern censorship

From "It's the (Democracy-Poisoning) Golden Age of Free Speech" in Wired:

The most effective forms of censorship today involve meddling with trust and attention, not muzzling speech itself. As a result, they don't look much like the old forms of censorship at all. They look like viral or coordinated harassment campaigns, which harness the dynamics of viral outrage to impose an unbearable and disproportionate cost on the act of speaking out. They look like epidemics of disinformation, meant to undercut the credibility of valid information sources. They look like bot-fueled campaigns of trolling and distraction, or piecemeal leaks of hacked materials, meant to swamp the attention of traditional media.

And:

By this point, we've already seen enough to recognize that the core business model underlying the Big Tech platforms—harvesting attention with a massive surveillance infrastructure to allow for targeted, mostly automated advertising at very large scale—is far too compatible with authoritarianism, propaganda, misinformation, and polarization. The institutional antibodies that humanity has developed to protect against censorship and propaganda thus far—laws, journalistic codes of ethics, independent watchdogs, mass education—all evolved for a world in which choking a few gatekeepers and threatening a few individuals was an effective means to block speech. They are no longer sufficient.

Import Pinboard bookmarks into Standard Notes

In short: I wrote a tool to import Pinboard bookmarks into Standard Notes.

I care a lot about digital privacy and really appreciate the approach Standard Notes claims to take with my data. I started putting my bookmarks into the service instead of Pinboard. Pinboard is another fantastic service, but wanted to import my bookmarks into Standard Notes to have everything in one place.

So I wrote a tool to do the import! You can use it here.

It's not a terribly complicated piece of software—it transforms some JSON data into some other JSON data—but it was useful to me and I hope it's useful to someone else out there.

The code is open source if you want to give it a look.