Deprecated Behaviour

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

Entity Objects in JavaScript

In my last post I looked at Value Objects and how I might implement them in JavaScript. This time I’m going to look at Entities. Entities are kind of the next rung on the ladder in the domain model. They can be composed of Value Objects.

Entities are not defined by their attributes in the same way as Value Objects, instead they have an enduring “Identity”. The canonical example is a person. A person isn’t defined by their name, their age, their height, or any other attribute. Any of these can change and they are still the same person (barring any deep philisophical discussion). In software systems, this is usually implemented by assigning an arbitrary key that uniquely identifies the entity for its lifetime.

Where this key comes from is irrelevant to this discussion, but it is common for it to be a value that is generated in the persistence layer when the data is saved.

So, from this we could say that an entity is an instance with an identity and a collection of mutable attributes. Using a similar validation style to the one I used for Value Objects, I might write this in JavaScript like:

1
2
3
4
5
6
7
8
9
10
11
12
function Trail(id, fields) {
  if (!id instanceof TrailId) {
      throw new TypeError('Expected: TrailId');
  }
  if (!fields instanceof TrailFields) {
      throw new TypeError('Expected: TrailFields');
  }
  
  this.id = id;
  this.fields = fields;
  return Object.freeze(this);
}

But, I just said that entities are mutable, so, why am I still calling Object.freeze? Because, I want this object – the Entity – to be immutable, its id can’t change but it’s fields are still mutable; I’m taking advantage of the shallow freeze semantics.

Side Note: If you’ve been paying close attention, you may have noticed I’m throwing exceptions here instead of returning them like last time. This is because I consider passing the wrong type to be a developer error, which is (hopefully) an exceptional situation, as opposed to a user entering an invalid value, which is to be expected.

Ignoring the TrailId, which will be a Value Object similar to the previous post. The only interesting part left is the TrailFields object. This will be slightly different to the Value Object and the Entity itself because it’s mutable. So, its validation must be performed in the setters instead of the constructor. Using the common setter/getter pattern, it looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
function TrailFields(name, distance, grade) {
  this.name(name);
  this.distance(distance);
  this.grade(grade);
}

TrailFields.prototype.name = function(name) {
  if (name === undefined) {
    return this._name;
  }
  if (!name instanceof TrailName) {
    throw new TypeError('Expected: TrailName');
  }
  this._name = name;
}

TrailFields.prototype.distance = function(distance) {
  if (distance === undefined) {
    return this._distance;
  }
  if (!distance instanceof Distance) {
    throw new TypeError('Expected: Distance');
  }
  this._distance = distance;
}

TrailFields.prototype.grade = function(grade) {
  if (grade === undefined) {
    return this._grade;
  }
  if (!grade instanceof TrailGrade) {
    throw new TypeError('Expected: TrailGrade);
  }
  this._grade = grade;
}

Even though we now have setters, all of the values are still required in the constructor. This makes it impossible* to have a partially instantiated instance running around.

* “Impossible” is an optimistic take on it. If you want to assign invalid values directly to the “internal” fields, this won’t protect you from yourself. This is JavaScript after all.

Another way of modeling the TrailEntity is to have the fields as properties of the entity but leave the id as null until it is persisted, then updating it. The advantage of explicitly defining TrailFields is, once again, less mutation and preventing the creation of incomplete instances.

Before the data is persisted we have only TrailFields. Once it is persisted then we have a TrailEntity. The different types represent the different stages in the lifecycle and the two states are less easily confused.

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 Error('Distance Value is not a decimal number');
  }
  if (Distance.units.indexOf(unit) === -1) {
    return new Error('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.