Two new Javascript libraries: ramda-decimal and year-month

John Hartnup
Wealth Wizards Engineering
3 min readFeb 26, 2020

Wealth Wizards has released two of our home-grown Javascript libraries as open source NPM libraries.

Ramda-Decimal

Firstly we have ramda-decimal — a very small wrapper around Decimal.js that makes it more convenient to use with Ramda.

At Wealth Wizards we do a lot of financial calculations, and for that floating-point maths just isn’t good enough. Decimal.js gives us arbitrary precision decimal maths, which is great.

But we also write a lot of our processing code using Ramda, and although it’s not exactly difficult to use, there’s a tension between Ramda’s verb(noun) style and Decimal’s noun.verb() style:

const value = R.pipe(
n => new Decimal(b),
d => d.times(growthRate)
)

ramda-decimal simply provides functions that wrap Decimal’s methods. All the functions use Ramda’s curry() so you can use them in a point-free style:

const RD = require('ramda-decimal');
const value = R.pipe(
RD.decimal,
RD.times(growthRate)
);

If you’re using Ramda and need arbitrary precision maths, give it a go. We’ve implemented all the functions we currently need, and many more of the basic operations Decimal provides. We plan to add more of Decimal’s functions, but feature requests via GitHub’s “issues” will encourage us — or better still, we love to get pull requests.

Year-Month

Next, we’ve released year-month. One of the fundamental things we do at Wealth Wizards is to model a household’s projected finances. As it happens, the smallest unit we model is a month.

We were using Moment.js to represent dates. Moment is a great date-handling library (Luxon, by the same team, is better still, as it embraces immutable objects). However we noticed that our code got more complicated than it needed to, as our code used to-the-millisecond Moment objects to represent a whole month.

We also noticed that some operations on Moment were really slowing down our processing. This was entirely our fault, because we were asking Moment to do something that wasn’t really its strength, and we were doing that in a big loop.

thousandsOfEntries.forEach( e => {
if(moment.utc(e.startDate).isBefore(someDate, 'month')) {
doSomething();
}
});

It turns out that for unavoidable reasons, moment.utc() is expensive, and so is moment.isBefore(m, 'month'). This is because in both cases it has to translate between a year and month, and some number of milliseconds, taking into account leap years, leap seconds, the number of days in each month, etc. None of this expensive computation is necessary if we’re only interested in months.

Enter year-month, which uses immutable objects like Luxon does, and works by making a very simple conversion from year and month, to the integer number of months since January 1970, assuming all years have 12 months.

year-month is in production use, and the API is considered stable. We’re on the brink of making that official by bumping the version to 1.0.

We still use Moment and Luxon in the parts of our code that need to measure smaller units of time than a month.

Again, we love communication. If you think there’s a way we can make year-month better, let us know via GitHub. Or better still, we really love a pull request.

Links:

--

--