What is Ledger Series
- What is a Ledger and why you need to learn about it?
- What is Ledger and why does it need Idempotence?
- What is a Ledger and Why Floating Points Are Not Recommended?
In the realm of financial transactions and ledgers, accuracy is paramount. However, using floating point numbers to represent monetary values can lead to significant issues due to their inherent imprecision. This is why it's crucial to understand the problems with floats and consider alternative approaches.
Why Floating Points Are Problematic
Floating point numbers are a common way to represent real numbers in computing. However, they are not suitable for precise financial calculations due to rounding errors. Here are a few examples illustrating the issue:
console.log(0.1 + 0.2); // Expected: 0.3, Actual: 0.30000000000000004
console.log(0.1 + 0.2 === 0.3); // Expected: true, Actual: false
These small inaccuracies can accumulate over many transactions, leading to significant errors in financial records.
Using Cents or Decimal128
To avoid these pitfalls, it's recommended to represent monetary values in the smallest units (like cents) or use a data type designed for high precision, such as Decimal128 in MongoDB. This ensures that all calculations are exact, maintaining the integrity of financial data.
Updating the Example to Use Cents
We'll update our previous example to store amounts in cents instead of dollars, ensuring precision in our calculations.
Define the structure of the ledger in MongoDB using cents:
{
_id: ObjectId("60c72b2f9b1d8e4d2f507d3a"),
date: ISODate("2023-06-13T12:00:00Z"),
description: "Deposit",
amount: 100000, // Amount in cents
balance: 100000, // Balance in cents
transactionId: "abc123"
}
Function to add a new entry to the ledger and calculate the balance using cents:
const { MongoClient } = require('mongodb');
async function addTransaction(description, amount, transactionId) {
const url = 'mongodb://localhost:27017';
const client = new MongoClient(url);
try {
await client.connect();
const database = client.db('finance');
const ledger = database.collection('ledger');
const existingTransaction = await ledger.findOne({ transactionId: transactionId });
if (existingTransaction) {
console.log('Transaction already exists:', existingTransaction);
return;
}
const lastEntry = await ledger.find().sort({ date: -1 }).limit(1).toArray();
const lastBalance = lastEntry.length > 0 ? lastEntry[0].balance : 0;
const newBalance = lastBalance + amount;
const newEntry = {
date: new Date(),
description: description,
amount,
balance: newBalance,
transactionId: transactionId
};
await ledger.insertOne(newEntry);
console.log('Transaction successfully added:', newEntry);
} finally {
await client.close();
}
}
addTransaction('Deposit', 50000, 'unique-transaction-id-001'); // Amount in cents
Of course, if you are in prod making a change like this one it will need a migration of database. With mongo, this is easier. You can check how we handle this in our blogpost Zero Downtime Database Migrations at Woovi
The goal here is show what you can learn from common mistakes
Woovi APIs Use Cents
Woovi, a modern financial services platform, utilizes cents in their APIs to ensure precision and avoid the pitfalls of floating-point arithmetic. By doing so, they maintain the accuracy and reliability of financial transactions, which is crucial for both their operations and their customers' trust.
Conclusion
Implementing idempotency in your ledger system is crucial for maintaining accurate and reliable financial records. By ensuring that each transaction is only recorded once, you can prevent duplicate entries and maintain the integrity of your data.
As we have seen, idempotency is not just a technical detail but a fundamental principle that helps build robust and fault-tolerant systems. Similarly, using cents instead of floating points ensures precise financial calculations. In our next blog post, we will explore more advanced topics in ledger management and how to handle other challenges such as concurrency and eventual consistency.
Stay tuned for more insights into building reliable financial systems!
Visit us Woovi!
Follow me on Twitter
If you like and want to support my work, become my Patreon
Want to boost your career? Start now with my mentorship through the link
https://mentor.daniloassis.dev
See more at https://linktr.ee/daniloab
Photo of Andrew Spencer in Unsplash
Top comments (0)