As a payment operations startup, accounting principles are core to our work. We have seen them implemented at scale at some of the largest fintechs and marketplaces. Yet, accounting seems like an arcane topic when you’re starting out. This HackerNews thread, for example, is rather representative of the state of confusion around the topic.
Over the years, there have been many accounting for developer guides published (two great ones are Martin Blais' and Martin Kleppmans’), but we wanted to add our two cents to the discussion. In our experience, a concepts-first approach to explaining accounting comes in handy when you are designing systems that move or touch money.
This post is divided into two parts. Part I covers the foundational accounting principles. Part II will show how to bring it all together by walking through how to build a Venmo clone.
Is this guide for you?
This guide is designed for developers that work on applications that handle money in any way. You may work at a fintech company (the data you handle is money), or perhaps you are responsible for managing the fintech integrations in your startup (you handle data and money). We think that every engineer that builds or maintains such systems benefits from knowing the core principles of accounting.
Does accounting really matter in software development?
Double-entry systems are more reliable at tracking money than any other viable alternative. As a payments infrastructure company, we often get to see the architecture of some of the most successful software companies. One design is constant: they use double-entry accounting in their code. Some build their applications from the start with accounting concepts in mind, but in most cases, companies begin incorporating these concepts only after their original code starts causing problems.
When software fails to track money properly, it does so in a number of common patterns. The most common failure mode is software accidentally creating or destroying records of funds. This leads to all sorts of inconsistencies. Every developer we know has horror stories about explaining to their finance team why a customer is owed money or what caused a payout to have an unexpected amount. Internal records differing from bank statements, reconciliation engines gone awry, balances that don’t make sense given a set of transactions—these are all problems that can be mitigated with double-entry accounting. For more evidence that double-entry systems are a good standard for scalable applications, see the stories of Uber, Square, and Airbnb.
The core principle of double-entry accounting is that every transaction should record both where the money came from and what the money was used for. This guide explains why that is and how it works.
The building blocks of an accounting system
A good starting point is understanding accounts and transactions.
An account is a segregated pool of value. The easiest analogy here is your own bank checking account: money that a bank is holding on your behalf, clearly demarcated as yours. Any discrete balance can be an account: from a user’s balance on Venmo to the annual defense spending of the United States. Accounts generally correlate with the balances you want to track.
In accounting, accounts have types. More on this later.
Transactions are atomic events that affect account balances. Transactions are composed of entries. A transaction has at least two entries, each of which corresponds to one account.
Let’s use a simple Venmo transfer as an example. Jim is sending $50 to Mary:
The entries in this transaction tell which accounts were affected. If each user’s balance is set up as an account, a transaction can simultaneously write an entry against each account.
Now, let’s expand this model with more accounts and a handful of additional events:
Here I have a ledger—a log of events with monetary impact. We often see developers mutating balances directly rather than computing a balance from a log of transactions. This is suboptimal.
While mutating a balance directly is more efficient and simpler to implement, it’s more accurate to store immutable transactions and always compute balances from those transactions. Mutating balances directly creates a system that is prone to errors, as it becomes non-trivial to detect and reconcile inaccuracies.
Notice how each transaction has multiple entries. Each entry belongs to a transaction and an account. By comparing entries side by side, one can clearly see where the money came from and what it was used for. Double-entry ensures that, as transactions are logged, sources and uses of funds are clearly shown, and balances can be reconstructed as of any date:
This core idea—one transaction, at least two entries, one representing the source and the other representing the use of funds—is one of the foundational ideas of double-entry accounting . We’ll expand more on this later.
As mentioned before, another big innovation of accounting was giving types to accounts. The two types we will cover here are debit normal and credit normal.
- Accounts that represent funds you own, or uses of money, are debit normal accounts.
- Accounts that represent funds you owe, or sources of money, are credit normal accounts.
Let’s illustrate that with a simple table with two columns, the right side listing credit normal accounts and the left side listing debit normal accounts. We will place accounts that track uses of funds on the debit normal side and accounts that track sources of funds on the credit normal side.
Examples of uses of funds are assets and expenses. Buying inventory, making an investment, acquiring physical property, and so on. The term “use” here is broadly defined: letting cash sit in a bank account is a use of funds, as well as selling on credit to someone else (you are effectively ‘using’ the money you’d get on a sale by extending them credit). The accounts that represent these balances are all debit normal accounts.
Conversely, sources of funds—such as liabilities, equity, or revenue—can mean bank loans, investors' capital, accumulated profits, or income. “Source” is broadly defined here, too: if you are buying on credit, for instance, that is a “source” of money for you in the sense that it prevents you from spending money right now. Accounts that represent these balances are credit normal accounts.
Here is a handy table with the different account types:
(Notice that debit cards hold money you own, while credit cards hold money you owe.)
Debits and credits
Some of the guides we mentioned at the beginning of this post advise developers to “save the confusion and flush out debits and credits from your mind.” We do recognize that debits and credits can be challenging to grasp, but we think fully mastering these concepts is important when creating transaction handling rules.
Part of the confusion is that “debits” and “credits” are often used as verbs: to debit or to credit an account. Debits and credits can also refer to entries, for example:
This sample transaction has two entries: we’re debiting our cash account and crediting our equity account for $1M. Save for a few special situations, accounting systems only log positive numbers. The effect on balances will depend on whether the entry is on the “debit side“ or “credit side.”
Debits and credits are a shorthand for the expected effects on accounts, depending on their type. A credit entry will always increase the balance of a credit normal account and decrease the balance of a debit normal account. Put differently:
Let’s continue to model out a few transactions to drive this point home. Let’s use a fictitious startup called Modern Bagelry—an eCommerce store for premium bagels.
In this example, we will use four accounts: Cash and Inventory (both debit normal accounts) as well as Equity and Loans (both credit normal accounts). Let’s say this ledger starts on a day T, and we are measuring time in days.
A common misconception is that one account needs to decrease while another needs to increase. However, they can both increase or decrease in tandem, depending on the debit and credit entries in the transaction and the account types. In the first transaction cash increases because it’s a debit entry in a debit normal account (cash); equity also increases because it’s a credit entry in a credit normal account (equity). Conversely, in the last transaction both balances decrease because we are adding a debit entry into a credit normal account (loans) and a credit entry into a debit normal account (cash).
Balancing debits and credits
Tracking sources and uses of funds in a single ledger with double-entry is helpful to clearly show clearly that balances match.
Let’s say we are aggregating the balances for each account in the example above right after each transaction takes place:
A system of accounts will balance as long as the balance on debit normal accounts equals the balance on credit normal accounts. The ending balances of Cash ($1.22M) and Inventory ($250k) sum to $1.47M. That is equal to the sum of ending balances of Equity ($1M) and Loans ($470k). It is said that our accounts in this example are balanced. Not matching would mean the system created or lost money out of nothing.
We’ll walk through how to implement these concepts in more detail in our next post.
Let’s recap the principles we reviewed so far:
- A ledger is a timestamped log of events that have a monetary impact.
- An account is a discrete pool of value that represents a balance you want to track.
- A transaction is an event recorded in the ledger.
- Transactions must have two or more entries.
- Entries belong to a ledger transaction and also belong to an account.
- Accounts can be classified as credit normal or debit normal.
- Entries can be added onto the ledger “on the debit side” or “on the credit side." Debits and credits refer to how a given entry will affect an account’s balance:
- Debits—or entries on the debit side—increase the balance of debit normal accounts, while credits decrease it.
- Credits—or entries on the credit side—increase the balance of credit normal accounts, while debits decrease it.
- If the sum of balances of all credit normal accounts matches the sum of balances of all debit normal accounts in a single ledger, it is said that the ledger is balanced. This is an assurance of consistency and that all money is properly accounted for.
In part two, we’ll add some complexity to transaction structures, and we’ll bring everything together by doing a walkthrough of how to build a Venmo clone.
If you are a developer who works with money, Modern Treasury Ledgers simplifies the process of building a double-entry system. Reach out to us here if we can be helpful.
Given this system has been used and perfected for 800 years, this is no small feat. If you’re curious about how this system came about, here’s a biography of Luca Pacioli, considered the father of accounting.