A recent task of porting from faker to chance reminded me of the process that I go through when refactoring code to fully replace the use of a given library.

There are reasons you might want to move off of the faker library. If you haven’t read the story before12 or other stories like it3, there are many layers to unpack on why a library may become a risk to your production service4.

It also serves as an exercise in identifying what it is you rely on from a library and if you are using it how you originally intended.

Identify Target Replacement

There are good tools out there that help find libraries that perform similar roles (See: pkg.land).

A few key criteria come into play:

  1. Community Usage
  2. Community Support
  3. Feature Parity
  4. Interface Parity
  5. Effort to Port

Community Usage & Community Support

Items 1 & 2 are a critical part of Open Source Sustainability5 and are critical when identifying software to use and support. It is up to you and your team to determine if you want to go with a well established project or invest in a newer project. I tend to lean towards a middle ground where I want a supported and feature rich project with the addition of evaluating the focus of the project such that I avoid bloated, broad projects.

Community Usage

How broadly is this project used within the development community?

How widely is the library adopted? Typically, the wider the use within the community, the better the overall support. Another point to consider is that with wider adoption, you have more perspectives applied to the use case of the project as well as :eyes: on the code. This can reinforce the feedback loop on improving functionality, but most importantly it can be a strong signal for bugfix and security vulnerability support.

Community Support

How active is the development community within the project?

How many Issues have been opened and resolved on GitHub? How many PRs? What is the community discussion like around the project? These are strong indicators of the overall support for a project. Keep an eye out for reported bugs or security concerns that have not been addressed.

Feature Parity

This is typically the most critical item when considering porting from a library. You first need to identify the features your project requires of a package and how deeply integrated these features are within your code base.

Interface Parity

This is the a big one.

You’ve found a library you really like. It meets the feature parity needs and you are feeling the itch to start implementing the migration to the new library. One of the biggest hurdles in this can be the Interface Parity challenge. While the resulting outcomes of two libraries may be similar, it is often the case that they interfaces for the libraries can differ drastically. Both on input and output.

A great example of this is momentjs compared to date-fns. The object oriented foundation of moment creates a class heavy implementation path. You are always working with an instance of a moment Date Object and all of the syntax sugar that comes with that. date-fns has a Functional foundation with most (if not all) outputs being native Javascript types (string, Date, etc).

import * as moment from 'moment';

moment().subtract(5, 'days').fromNow()

/** VS. **/

import { formatDistance, subDays } from 'date-fns';

formatDistance(subDays(new Date(), 5), new Date());

There are advantages and disadvantages to each approach, but for the sake of this section, we can focus on the interface differences as an example of why we need to consider this when picking a library for replacement. An interface parity as low as the example above will greatly impact the next item, Effort to Port.

Effort to Port

Considering the findings in Interface Parity, how complex will the migration be? In the case of momentjs to date-fns, this would be a complex change due to the drastic difference in interface. That said, the complexity of the code base and the breadth of feature usage would come into play.

Also, while a change have been “simple” (i.e. regex search replace), it if touches 40 files is it still “simple”? 400 files?

What is the effort to validate the migration? Do you need to support Feature Flag release of the new library? Do you want to run both libraries in parallel and phase out the migration across the code base?

When migrating libraries, it’s a great opportunity to tackle that Tech Debt that gets deprioritized around better test coverage.


In total, migrating libraries is rarely about finding a

Next up, part 2. A deeper dive into moving from faker to chance. (coming soon)