Deprecated Behaviour

The inane, sometimes insane, ramblings from the mind of Brenton Alker.

Value Objects in JavaScript

Value Objects are awesome! Many of the JavaScript applications I have encountered don’t explicitly define their domain objects at all, instead passing primitives or raw object literals around. Value Objects can define the values in an way that allows discussion and reasoning about the values being passed around. As well as a logical place to “put code”.

To explore their use, lets start by defining a simple Value Object – Distance – because I don’t claim to be creative in these matters.

About the simplest way of defining a Value Object is like this.

1
2
3
4
function Distance(value, unit) {
  this.value = value;
  this.unit = unit;
}

This is a good start and really isn’t much more difficult that using object literals. Given the other advantages (that can be added incrementally), I don’t see a down side.

But, but we can do better!

Immutability

My first step would be to make it immutable. Immutability is a great property to have, especially for things being passed around a lot. For Value Objects, I think it is a reasonable default.

1
2
3
4
5
function Distance(value, unit) {
  this.value = value;
  this.unit = unit;
  return Object.freeze(this);
}

Now, Object.freeze isn’t perfect. It only freezes the object itself; nested properties can still be mutated. But, I still think it’s worth it to prevent accidental mutation, or third party code mutating your objects without your knowledge (I’m looking at you, ng-repeat).

Validation

The next issue to look at is validation of the fields. new Distance(12, 'parsecs'); would ostensibly give a valid Distance, but it probably wouldn’t be very useful. We can use the constructor function to check the parameters, ensuring only valid values can be created. In this case, say – A distance is a positive whole number measured in centimetres, metres or kilometres.

It might be implemented this way:

1
2
3
4
5
6
7
8
9
10
11
12
13
function Distance(value, unit) {
  if (parseInt(value, 10) !== value) {
    return new TypeError('Distance Value is not a decimal number');
  }
  if (Distance.units.indexOf(unit) === -1) {
    return new TypeError('Distance Unit is not is not valid');
  }

  this.value = value;
  this.unit = unit;
  return Object.freeze(this);
}
Distance.units = ['cm', 'm', 'km'];

The decision to return the Errors instead of throw them is probably debatable, but I don’t think validation errors are “exceptional” and find it composes better with higher order functions (eg. map, filter, reduce) which I generally use a lot of. Either way, the point is it won’t get back a valid Distance object. And, since they are immutable, a valid Distance only ever be valid.

Logic

Once a Value Object is defined, it becomes a great place to put some logic. Normalization and comparison logic is a good candidate. For example, adding methods to compare two distances.

1
2
3
4
5
6
7
8
Distance.multipliers = [1, 100, 100000];
Distance.prototype.toCentimetres = function () {
  var multiplier = Distance.multipliers[Distance.units.indexOf(this.unit)];
  return this.value * multiplier;
};
Distance.prototype.isCloserThan = function (other) {
  return this.toCentimetres() < other.toCentimetres();
};

It’s also a good place to add domain logic; the application may define how far is considered “walkable”. By having the Value Object, it provides somewhere for this knowledge to go and prevents if (distance < 5) being duplicated across the application.

1
2
3
4
Distance.walkable = new Distance(5, 'km');
Distance.prototype.isWalkable = function () {
  return this.isCloserThan(Distance.walkable);
};

Then, when I decide I’m too lazy to walk 5km, it only needs changing in one place.

Getting the Tools: Haskell Edition

I prefer to reserve the system-level package manager for system-level packages, which my development tools generally are not. As such, my tools are installed in my ~/opt/ directory where possible (then symlinked to ~/bin/).

In this post, I’m looking at how I did this for my Haskell tool-set.

Haskell’s cabal is a great dependency management/build tool with built-in sandbox capabilities. It is also often used to install many Haskell tools, such as hlint, pointfree and doctest.

I was originally installing these tools by creating a subdirectory per tool (e.g. ~/opt/haskell/hlint/) and using cabal sandbox init; cabal install hlint to install the tool (hlint in this case) within the sandbox.

But, I didn’t like having a set of “empty” directories (containing only the hidden .cabal-sandbox and cabal.sandbox.config). With a few extra arguments (thanks to some tips from Ben Kolera at the last BFPG hack night) we can forgo the superfluous subdirectories and reveal the sandboxes.

Here is an example of installing hlint:

1
2
3
4
# in ~/opt/haskell
PKG=hlint
cabal --sandbox-config-file=$PKG.sandbox.config sandbox init --sandbox=$PKG
cabal --sandbox-config-file=$PKG.sandbox.config install $PKG

This creates a sandbox config file called hlint.sandbox.config and a visible sandbox in the hlint directory.

You can then symlink the executable onto your path:

1
ln -s ~/opt/haskell/hlint/bin/hlint ~/bin/hlint

This is how I have installed all of these tools and is my currently preferred method. There are other variations on this that can also be used, for instance, adding the package’s bin directory to your path, or copying the actual executable out of the sandbox (then you could even delete the sandbox if you choose).

This works for all of the packages I mentioned above, and probably any others that you want to install just for the executable binary.

Open and Close SSH Tunnel in Script

I have been using SSH tunnels for a long time. Usually, I just manually open the tunnels I require. But, setting up my new machine (archlinux on a Thinkpad t440s.. shiny!) I’ve been writing a lot of shell scripts to automate much of what I used to do manually.

In that spirit, I wanted a script to create an ssh tunnel and connect my irc client (irssi) to my bouncer (znc), behind my home firewall.

So, this is what I’m using:

#!/bin/bash
ssh -f -o ExitOnForwardFailure=yes -L 6667:localhost:6667 user@home.example.com sleep 30
irssi

The -f -o ExitOnForwardFailure=yes combination makes ssh wait until the forwarded ports have been established before backgrounding. Effectively, this blocks the script until the ports are ready to use.

The sleep 30 keeps the connection open (in the background) for 30 seconds before ssh terminates. However, if there is an open connection on the tunnel, ssh will wait for it to close before terminating. This means, you have 30 seconds to connect to the forwarded port, then it will stay open as long as you’re using it. So, once I quit irssi, the tunnel closes.

Then, irssi configured to connect to localhost:6667 which is tunneled to localhost:6667 on the target machine, where it finds znc!