Learning from the Mistakes of a v1

@frontstuff_io

Sarah Dayan
Software Engineer, Algolia

const price = Dinero({
  amount: 5000,
  currency: 'EUR'
});

const tip = price.percentage(20);
const fullPrice = price.add(tip);

fullPrice.toFormat(); // "€60.00"

@frontstuff_io

years

2

commits

400

releases

29

@frontstuff_io

A v2 usually marks
a turning point.

@frontstuff_io

It uses numbers to represent amounts

🔢

@frontstuff_io

@frontstuff_io

const price = Dinero({
  amount: 5000,
  currency: 'EUR'
});
.1 + .2;

// 0.30000000000000004

(1 + 2) / 10

// 0.3

@frontstuff_io

@frontstuff_io

const price = Dinero({
  // 5000 cents, or 50 euros
  amount: 5000,
  currency: 'EUR'
});
Number.MAX_SAFE_INTEGER;

// 9007199254740991

Number.MIN_SAFE_INTEGER;

// -9007199254740991

@frontstuff_io

@frontstuff_io

Enter bigints.

const calculator = {
  add(a, b) {
    return a + b;
  },
  subtract(a, b) {
    return a - b;
  },
  // ...
};

@frontstuff_io

import { Decimal } from 'decimal.js';

const bigDinero = createDinero({
  calculator: {
    add: Decimal.add,
    subtract: Decimal.sub,
    // ...
  },
});

const price = bigDinero({
  amount: new Decimal(Number.MAX_SAFE_INTEGER),
  currency: 'EUR',
});

@frontstuff_io

It doesn't handle different exponents

💰

@frontstuff_io

@frontstuff_io

1 euro = 100 cents

1 x 10^2 = 100

const price = Dinero({
  amount: 5000,
  currency: 'EUR',
});

price.toFormat(); // "€50.00"

@frontstuff_io

@frontstuff_io

const price = Dinero({
  amount: 1000,
  currency: 'IQD',
  precision: 3,
});

@frontstuff_io

const IQD = {
  code: 'IQD',
  base: 10,
  exponent: 3,
};

const price = Dinero({
  amount: 1000,
  currency: IQD,
});

@frontstuff_io

It expects a REST API for conversions

🔄

@frontstuff_io

const options = {
  endpoint: 'https://api/?base={{from}}',
  propertyPath: 'data.rates.{{to}}',
  headers: {
    'user-key': 'xxxxxxxxx',
  },
  roundingMode: 'HALF_UP',
};

Dinero({
  amount: 5000,
  currency: 'EUR',
}).convert('XBT', options);

@frontstuff_io

const price = Dinero({
  amount: 5000,
  currency: 'EUR',
});

price.convert('XBT');

@frontstuff_io

const rates = new Promise((resolve) =>
  resolve({
    XBT: 0.00012,
  })
);

Dinero({ amount: 5000 })
  .convert(EUR, { rates });

@frontstuff_io

const rates = {
  rates: {
    XBT: 0.00012,
  },
};

Dinero({
  amount: 5000,
  currency: 'EUR',
}).convert('XBT', {
  endpoint: new Promise((resolve) =>
    resolve(rates)
  ),
});

@frontstuff_io

It relies on the ECMAScript I18n API

🌎

@frontstuff_io

const amount = 5;

amount.toLocaleString('en-GB', {
  style: 'currency',
  currency: 'EUR',
});

// "€5.00"

@frontstuff_io

const options = {
  style: 'currency',
  currency: 'EUR',
};

amount.toLocaleString('en-GB', options);

// "€5.00"

amount.toLocaleString('de-DE', options);

// "5,00 €"

@frontstuff_io

const price = Dinero({
  amount: 500,
  currency: 'EUR',
}).setLocale('en-GB');

price.toFormat();

// "€5.00"

@frontstuff_io

@frontstuff_io

Tight coupling

@frontstuff_io

Lack of flexibility

@frontstuff_io

Inconsistent
implementation

const price = Dinero({
  amount: 500,
  currency: EUR,
});

price.toFormat(
  ({ amount, currency }) =>
    `${currency.code} ${amount}`,
  {
    digits: 2,
    roundingMode: Math.round,
  }
);

// "EUR 5"

@frontstuff_io

function i18n({ amount, currency }) {
  return amount.toLocaleString('en-GB', {
    style: 'currency',
    currency: currency.code,
  });
}

price.toFormat(i18n, {
  digits: 2,
  roundingMode: Math.round,
});

// "€5.00"

@frontstuff_io

const currencySymbols = {
  EUR: '€',
  USD: '$',
  // ...
};

function manualI18n({ amount, currency }) {
  const { code } = currency;
  const symbol = currencySymbols[code] || code;
  
  return `${symbol}${amount.toFixed(2)}`;
}

price.toFormat(manualI18n, {
  digits: 2,
  roundingMode: Math.round,
});

// "€5.00"

@frontstuff_io

You can't tree-shake it

🌳

@frontstuff_io

const price = Dinero({
  amount: 500,
  currency: 'EUR',
});

price.add(price).multiply(4);

@frontstuff_io

const price = Dinero({
  amount: 500,
  currency: 'EUR',
});

multiply(add(price, price), 4);

@frontstuff_io

@frontstuff_io

It's written
in JavaScript

🐞

@frontstuff_io

@frontstuff_io

Maintaining types

by hand doesn't scale.
And it's a pain.

@frontstuff_io

Static typing is extremely helpful.

@frontstuff_io

🐦

TypeScript hits two birds with one stone.

@frontstuff_io

What happened?

@frontstuff_io

First library

@frontstuff_io

No real-world experience

@frontstuff_io

Many assumptions

@frontstuff_io

Scalability
Flexibility
Agnosticism
DX

@frontstuff_io

Links

Why Javascript Numbers Are Weird (And How to Fix It)
youtu.be/Wq2AqONg7rs

Dinero.js on GitHub
github.com/dinerojs

Sarah Dayan
Software Engineer, Algolia

Thank you!

Made with Slides.com