“*Utils” classes can be a code smell: an example

You might have heard that “*Utils” classes are a code smell.

Lots of people have written about that before, but I tend to find the reasoning a bit vague, and some of us work better with examples.

So here’s one I found recently while working on this bug: you can’t know what part of the Utils class is used when you require it, unless you do further investigation.

Case in point: if you place a method in VariousUtils.js and then import it later…

var { SomeFunction } = require('VariousUtils');

it’ll be very difficult to actually pinpoint when VariousUtils.SomeFunction was used in the code base. Because you could also do this:

var VariousUtils = require('VariousUtils');
var SomeFunction = VariousUtils.SomeFunction;

or this:

var SomeFunction = require('VariousUtils').SomeFunction;

or even something like…

var SomeFunction;
lazyRequire('VariousUtils').then((res) {
  SomeFunction = res.SomeFunction;
});

Good luck trying to write a regular expression to search for all possible variations of non-evident ways to include SomeFunction in your codebase.

You want to be able to search for things easily because you might want to refactor later. Obvious requires make this (and other code manipulation tasks) easier.

My suggestion is: if you are importing just that one function, place it on its own file.

It makes things very evident:

var SomeFunction = require('SomeFunction');

And searching in files becomes very easy as well:

grep -lr "require('SomeFunction');" *

But I have many functions and it doesn’t make sense to have one function per file! I don’t want to load all of them individually when I need them!!!!111

Then find a common pattern and create a module which doesn’t have Utils in its name. Put the individual functions on a directory, and make a module that imports and exposes them.

For example, with an `equations` module and this directory structure:

equations
  linear.js
  cubic.js
  bezier.js

You would still have to require('equations').linear or some other way of just requiring `linear` if that’s what you want (so the search is “complicated” again). But at least the module is cohesive, and it’s obvious what’s on it: equations. It would not be obvious if it had been called “MathUtils” — what kind of utilities is that? formulas? functions to normalise stuff? matrix kernels? constants? Who knows!

So: steer away from “assorted bag of tricks” modules because they’ll make you (or your colleagues) waste time (“what was in that module again?”), and you’ll eventually find yourself splitting them at some point, once they grow enough to not make any sense, with lots of mental context switching required to work on them: “ah, here’s this function for formatting text… now a function to generate UUIDs… and this one for making this low level system call… and… *brainsplosion*” 😬

An example that takes this decomposition in files to the “extreme” is lodash. Then it can generate a number of different builds thanks to its extreme modularity.

Update: Another take: write code that is easy to delete. I love it!

If using ES6 `extends`, call `super()` before accessing `this`

I am working on rewriting some code that used an ES5 “Class” helper, to use actual ES6 classes.

I soon stumbled upon a weird error in which apparently valid code would be throwing an |this| used uninitialized in A class constructor error:

class A extends B {
  constructor() {
    this.someVariable = 'some value'; // fails
  }
}

I was absolutely baffled as to why this was happening… until I found the answer in a stackoverflow post: I had to call super() before accessing this.

With that, the following works perfectly:

class A extends B {
  constructor() {
    super(); // ☜☜☜ ❗️❗️❗️
    this.someVariable = 'some value'; // works!
  }
}

Edit: filed a bug in Firefox to at least get a better error message!

Don’t force users to install node modules globally when you can avoid that

How often have you seen instructions for installing a project that are something like this?

git clone https://wherever/the/project/is
cd cloned_folder
npm install -g gulp # <-- 😱

(or, instead of gulp, any other utility that the project requires for development)

This is not a good idea. You’re installing the same version of a utility globally, and perhaps the project has not been tested with that version. Things might break or even worse, work not-so-well in a strange, undebuggable way!

Don’t do it.

A better way is to use npm scripts, which belong to the project, and specify development dependencies in package.json, so when you run npm install, it also installs devDependencies locally to the projects’ node_modules folder. This keeps everything under control and does not pollute other people’s computers global space.

So, for example, if a project was asking users to run npm install -g gulp, they should do this instead:

  1. Install gulp locally as a development dependency, saving it to package.json:
    npm install --save-dev gulp
  2. Add a new entry to the scripts array in package.json:
    "build": "gulp"
  3. Ask users to run
    npm install

    the first time. And

    npm run build

    each time they need to build the project

The reason this works is because when npm runs a script, it modifies the current PATH variable to add node_modules/.bin, which contains any binaries that you installed as part of your modules. So your computer will search for binaries starting in the .bin folder, before searching in any other default location for binaries in your computer (e.g. /usr/bin)

You can find more documentation about this behaviour in the run-script page of the npm manual. I really encourage you to read it as it has lots of good stuff and Things You Wished Had Known Before 🙂

And in case it makes things clearer, this is how a hypothetical package.json would look before:

{
  devDependencies: {}
}

And after:

{
  devDependencies: {
    "gulp": "12.34.56"
  },
  scripts: {
    "build": "gulp"
  }
}

With this, the devDependency is clearly stated on the package.json file, the project developer will be developing with that version, and will not get surprises! (and the users of the module won’t either).

Another advantage of this approach is that you are not tying the project to a specific utility.

If you decide to use grunt instead of gulp later on, you just need to do whatever changes you need (Gruntfile instead of Gulpfile, edit package.json etc), and yet users of the project will still start the build process with npm run build.

It’s invisible to them (except perhaps running npm install again)!

You’re hiding internals that they do not necessarily need to know about, so it’s a good abstraction. Seriously—you won’t even need to update your getting started guide! Good stuff.

Hope that helps!

If you want to learn even more cool npm scripts tricks, I recommend Kate’s talk and accompanying post. Actually, I just realised she explained the same thing I did, so here’s her take, haha!

Extreme decoupling or all-as-a-module

I opened my laptop in the morning and found one of my open tabs in Nightly was for Vue.js. I don’t even remember how I ended up there. Was I reading about frameworks? Did anyone send me the link? Who knows!

But I was curious. I am not a megafan of frameworks, but I like looking at them. One, because their idioms are often adopted by other developers, so it’s good to be aware of where are things going. And two, because frameworks do lots of “magic” in the background, and I always want to know how they implement their “magic”—maybe I’ll want to adopt some of it!

So instead of closing the tab, I perused the page. It has a virtual DOM as React does, but they seem to take great pride on their overall minimalism (small file size, little intrusiveness). The examples are amongst the most readable I’ve found for frameworks when it comes to the JavaScript API; the HTML directives are as alien-feeling as most frameworks.

Later I was discussing this strange incident with friends (“I found an open tab in my browser—do you think this is a signal from the universe that I should get into Vue.js?”) and Irina also highlighted the fact that Vue.js “components” might be simpler to build than the equivalent in React, and also be less coupled.

This derived into talking about The Dream:

You know what the dream is? Have everything be an npm package that I can plug in to any framework I like. And everything is packages packages packages

📦.js

Oprah giving free packages away to everyone
You get a package! And you get a package! And you get a package! And you get a package! And you get a package… everyone gets a package!

(Irina demanded an Oprah themed meme)

And of course this reminded me to earlier conversations with chameleonic Jen about modularising everything and maximising reuse. She would propose, for example, abstracting a card game into separate modules; one for handling the rendering, other for handling card games in an abstract way, another one for handling a specific type of game. This way you could build multiple games by just providing an implementation for the specific game. (Games are notoriously often not built this way).

Likewise, Aria talked about radical modularity at Web Rebels and the notion that if your modules are small enough, they are done. Finished. You rarely need to ever touch them again (unless there’s a bug). Watch the talk: it’s very inspiring.

I really like this “pure” idea, and can work very nicely as long as you keep your data and logic separate from your view.

Unfortunately, the issue is that UI code often intermingles both data and view, so you end up declaring your data as instances of whatever base component the UI is using, which is not very maintainable on the long run. If you want to change the UI you will need to take the ‘data’ bits out of the UI code, or write some sort of adapter between “UI code” and “data”, to have to only change “adapter” when you decide you don’t like your current view layer. This could be a performance hit, so you might want to sacrifice flexibility for performance.

But hey… everything in computing is always a trade-off!

 

Notes on JSConf Australia 2016

I spoke at JSConf Australia in Melbourne at the beginning of this month. Like in CSS Conf Australia, the videos haven’t been published individually yet, but the event was streamed live, and you can watch it again… and again… and again…

My brain got into one of those intensely obsessive focused moments pre-talk so I will admit I could barely pay attention to the talks prior to mine—I’m really sorry, specially because I heard so many good things about them!

These notes will be shorter because of that. Apologies if you were expecting a full conference review… but sometimes you cannot get everything you want! 😔

And now to the talks!

Jessica Lord: “Electron: A Tale of Two Processes”

This one was a really enlightening talk about Electron’s architecture. I had no idea it worked that way, and my assumptions were basically wrong. It was good to be shown the truth in an amicable way—like Jessica’s! I really enjoyed this talk and that’s big, considering it was right before mine!

Ruth John: “How to be a Web A/V Artist”

Ruth explained the secrets behind her “Web VJ*” set-up and also managed to produce an even smaller MIDI controller than the last time I spoke to her. It’s as if she kept getting Bluetooth miniatures!

She introduced some comedic elements into the talk but I’m not quite sure they worked for everyone… I felt some of the “funny samples” (like the Windows 9x error sounds) were lost on parts of the audience… that were younger than expected!

*Web VJ sounds so much like a new and upcoming API. Maybe… maybe… navigator.webvj.... 😏

Michaela Lehr: “An Introduction to WebVR”

She had an slightly different take on WebVR, which was really refreshing. She also mentioned things rarely mentioned such as the fact that VR can cause strong psychological and physiological responses on some people, and we need to be mindful of that when we design the new experiences in the web. If certain things are VR only, are we going to exclude some people this way?

Lena Reinhard: “Debugging the Tech Industry”

I have huge respect for Lena—she’s always delivering these immensely difficult talks. It’s hard to be the bearer of bad news. And there are plenty in tech!

Weeks after the talk, I’m still thinking about the message, and trying to come up with ways in which we can build tech that is not “accidentally” hostile to everyone who is not the creator of said tech.

Live.JS + Karaoke(.js?)

After the talks were done and we took the “family photo” and announcements were done, the room was cleared and Matt McKegg and Ruth John set up shop to have one of their Live.js events, like the one in Singapore.

I challenged Matt to “dubstepify” his act, which sort worked because his music is super improvisational.

Once they were done, an impetuous bunch of karaokers took up the stage and starting singing with lots of energy and heart and soul, but also lots of misplaced notes. I described this as “this is when the bar is closed, the last patrons get out and they really want to keep singing the last song the bar was playing, and so they keep singing it in the streets”…

This is when I left—and I was so tired anyway, I could barely stand on my feet, no energy left to listen to extremely eager karaokers—let alone join in the party 😜

Overall

Like CSS Conf, this was a really chill and enjoyable conference. I had again lots of interesting conversations–more so on this day because people had seen me speak, so they wanted to ask me questions or just discuss ideas they had had!

I also learnt a few things. All good stuff!

If you are ever faced with the possibility of submitting a proposal for this conference, don’t even think about it—do it! It was really lovely and well organised—I’m very glad I was invited to apply and my proposal was accepted!

Also: Melbourne is such an interesting city… lots of things to look at and explore, from street art to museums to neighbourhoods to just buildings, and of course great food and coffee, although I still can’t stop feeling so confused with “Jingle bells” playing on the background while signs for “Happy summer!” and “Merry Christmas” live side by side on the storefronts!

I feel like I’m missing out on the part of Australian culture that has warm reggae Christmas songs instead. If that doesn’t exist—it MUST be invented!

And this is the last installment of “notes on…” for this year, at least!