Entity factories

April 14, 2021 on Eric Bower's blog

Entity factories are functions that are used to create an object conforming to a specific typescript interface. These functions are tedious to write but offer a ton of benefits. I use them for virtually every entity I need to build and on every single project.

What’s the problem?

Let’s say we have an entity called User. The user has a set of properties on it:

interface User {
  id: string;
  name: string;
  email: string;
  verified: boolean;
  admin: boolean;
}

Okay now we want to create a user entity in our project, the default way to do that would be something like:

const user: User = {
  id: createId(),
  name: 'user name',
  email: 'user@name.com',
  verified: false,
  admin: false,
};

Doing this once seems straight-forward, but what about 10 times? 30 times? What about when you want to write some unit tests and you have to create a user entity a bunch of times?

This is where the problem lies. It seems easy to just build the entity everytime you need it but other problems arise: what happens when you need to refactor the user object to add or remove a property? Now you have to traverse the entire codebase to make the change to all of the objects.

What’s the solution?

If we take the same User entity and create a function that builds the entity for us, we can reuse it everywhere:

const defaultUser = (u: Partial<User> = {}): User => {
  return {
    id: createId(),
    name: '',
    email: '',
    verified: false,
    admin: false,
    ...u,
  };
};

Now when we want to create a new user object, we can do this:

const user = defaultUser({
  name: 'user name',
  email: 'user@name.com',
});

If we need to make a change to the user interface, all we have to do is change the defaultUser function and all objects that were created by the factory will most likely “just work.” Obviously if we removed name, email, or changed the names of those properties, we will have to update them manually, but that is usually rare.

So what are the benefits of this paradigm?

Easy to create an entity

Creating a User entity becomes much easier. All we have to do is import and call defaultUser() and it will create the entity for us. In the beginning it seems very tedious to build these factories because it’s a hand-written function, but we only have to write it once and then we permenantly enjoy the ease-of-use forever.

A single entry-point for creating an entity

This is huge. There is only one entry-point for creating the User entity inside of your codebase. Once this entity factory is written, everywhere will instinctively use it because it is so easy to use.

Easy to bake in sane defaults

This was an idea that I got from working with golang. When creating a struct in golang, it’s very common to create a function like NewUser which does the exact same thing as the the typescript version written above.

In golang, there are zero values which provide sane defaults for all primitive types

If it’s a string the zero value is '' and if it’s a number it’s a 0. I have applied the same concept to typescript and it works incredibly well.

I bet you already do this an you don’t even realize it. For example, if a property is a an array then the zero value is an empty array []. That way, when we need to perform a map or filter on the array we don’t have to check if the value is an array. Make sense, right? Well I just apply the same concept for all types in typescript. Basically, I try to avoid null or undefined values as much as possible. I elaborate on this concept in a previous blog article: Death by a thousand existential checks

Ability to override defaults

Because we accpe a partial User object as a parameter to our factory, it’s easy to override the defaults. This makes it easy to use: pass in what you want to change and let the defaults do the rest of the entity building.

No libraries required

The paradigm is so simple you don’t really need a library to handle the factory building. I’ve thought about creating a library for this paradigm but honestly, part of the appeal is that it’s just a simple function. It’s easy to read, easy to understand, and there’s no magic required. All we do is leverage typescript syntax and that’s it.

Real examples

Here’s a list of examples in my listifi.app codebase:

Conclusion

It might seem obvious, but entity factories are a very critical aspect to how I build maintainable code that is easy to update, extend, or modify entities over time.


Articles from blogs I read

Generated by openring

The Self Provisioning Runtime

Improvements in DX in both programming languages and cloud infrastructure will eventually converge in a single paradigm, where you truly "just write business logic" and the platform mostly figures out the rest.

via Swyx.io RSS Feed August 30, 2021

Status update, August 2021

Greetings! It’s shaping up to be a beautiful day here in Amsterdam, and I have found the city much to my liking so far. If you’re in Amsterdam and want to grab a beer sometime, send me an email! I’ve been making a lot of new friends here. Meanwhile, I’ve als…

via Drew DeVault's blog August 15, 2021

npm audit: Broken by Design

Found 99 vulnerabilities (84 moderately irrelevant, 15 highly irrelevant)

via Dan Abramov's Overreacted Blog RSS Feed July 7, 2021