← Back to context

Comment by amluto

1 year ago

Does anyone have a good explanation for why a ledger database should care about credits and debits and normal balances? This has always seemed more natural to me as a front-end / presentation layer concept. Your ledger entries always sum to zero for each transaction, your income account has a negative balance, and you display it in a sensible manner.

I’m also surprised that this whole article starts by discussing stock trading but has no mention of how to represent stock trades. I assume they are “Sagas” consisting of money moving from the customer to the clearinghouse (or prime broker or PFOF provider or whatever) and shares moving from that provider to the account at which the shares are held. And maybe other associated entries representing fees? It seems to me that this is multi-entry accounting, which is quite common, and that entries don’t actually come in pairs as the article would like us to think.

That part of the article felt quite wrong to me as well. I've built accounting systems that worked well for a decade, where internally the values were a single amount column in the journal table. If it was a debit, it'd be positive, if a credit, it'd be negative.

In fact, we could call these values yin and yang, for all it mattered.

Also, I'm not able to really follow what he means by "money = assets in the future".

Money is money, but if you wanted to track the intermediate state until the customer gets receipt, you would use an In Transit account (Good In Transit / Service In Transit etc.)

Yet, it doesn't change the fundamental definition of the value in the accounting system. I think the author confuses an engineering concept (sagas, or thunks, or delayed but introspectable/cancellable actions in general) with accounting.

  • > Also, I'm not able to really follow what he means by "money = assets in the future".

    I’m guessing it’s one of two things:

    1. A transaction might fail. If you enter a transaction into your bank’s website or your credit card company’s website, you should probably record it in your ledger right away. But the transaction might get canceled for any number of reasons. And the money will not actually move instantly, at least in the US with some of the slower money moving mechanisms.

    2. In stocks and other markets, settlement is not immediate. A trade is actually a promise by the parties to deliver the assets being traded at a specific time or range of times in the future. One probably could model this with “in transit” accounts, but that sounds quite unpleasant.

    FWIW, I’ve never really been happy with any way that I’ve seen accounting systems model accruals and things in transit. I’ve seen actual professional accountants thoroughly lose track of balance sheet assets that are worth an exactly known amount of cash but are a little bit intangible in the sense that they’re not in a bank account with a nice monthly statement.

  • IMO it's entirely wrong, and it also makes it a lot more difficult to programmatically create transactions with 3+ legs (For example: A payment with a line item + sales tax).

    I think the author is just wrong on that point, but the rest is sound. (Source: I've built bookkeeping software)

    • There are no 3 leg transactions in a ledger. You described an order. Ledger transactions is one layer deeper. Order creates 2 different transactions: Payment correspond to payments accounts, taxes to the Taxes Payable. That is how classic bookkeeping works.

      3 replies →

It is best explained by common scenarios an Italian merchant in the Middle Ages experienced. The basic concept is Assets==Liability (plus Equity). Where positive Assets are entered on the left hand side (debit). And positive Liabilities are entered on the right hand side (credit). In accounting, debit and credit just means left and right.

1. Merchant takes out a loan for $5,000 and receives $5,000 in cash. • Assets (Cash) increase by $5,000 (Debit). • Liabilities (Loan Payable) increase by $5,000 (Credit). • Equity remains unchanged.

2. Merchant buys inventory for $1,000 cash. • Assets (Cash) decrease by $1,000 (Credit). • Assets (Inventory) increase by $1,000 (Debit). • Total assets remain unchanged, and liabilities and equity are unaffected.

3. Merchant sells all inventory for $1,500 cash. • Assets (Cash) increase by $1,500 (Debit). • Assets (Inventory) decrease by $1,000 (Credit) (recording cost of goods sold). • Equity (Retained Earnings) increases by $500 (Credit), representing the profit ($1,500 sales - $1,000 cost).

4. Customer1 deposits $500 in cash for future delivery of goods. • Assets (Cash) increase by $500 (Debit). • Liabilities (Unearned Revenue) increase by $500 (Credit). • Equity remains unchanged.

5. Customer1 transfers half of the future delivery of goods to Customer2. • No changes to assets, liabilities, or equity occur at this point. The merchant’s obligation to deliver goods (reflected as Unearned Revenue) is still $500 but now split between two customers (Customer1 and Customer2). Internal tracking of this obligation may be updated, but the total financial liability remains the same.

  • Actually it is clear as long as you remember that main point you made: debit and credit just means left and right.

    We are all spoiled by thinking of debit/credit as equal to decrease/increase respectively because that how we interpret our bank accounts. That understanding totally collides with formal accounting where debit/credit DON'T mean decrease/increase respectively. I think this is the root cause of all confusion about double-entry accounting. I may be wrong about this, happy to be corrected but that is the bit my brain grinds against when trying to make sense of things.

    E.g. I replaced all instance of debit with "Left" and credit with "Right" in your example:

        1. Merchant takes out a loan for $5,000 and receives $5,000 in cash. • Assets (Cash) increase by $5,000 (Left). • Liabilities (Loan Payable) increase by $5,000 (Right). • Equity remains unchanged.
    
        2. Merchant buys inventory for $1,000 cash. • Assets (Cash) decrease by $1,000 (Right). • Assets (Inventory) increase by $1,000 (Left). • Total assets remain unchanged, and liabilities and equity are unaffected.
    
        3. Merchant sells all inventory for $1,500 cash. • Assets (Cash) increase by $1,500 (Left). • Assets (Inventory) decrease by $1,000 (Right) (recording cost of goods sold). • Equity (Retained Earnings) increases by $500 (Right), representing the profit ($1,500 sales - $1,000 cost).
    
        4. Customer1 deposits $500 in cash for future delivery of goods. • Assets (Cash) increase by $500 (Left). • Liabilities (Unearned Revenue) increase by $500 (Right). • Equity remains unchanged.
    
        5. Customer1 transfers half of the future delivery of goods to Customer2. • No changes to assets, liabilities, or equity occur at this point. The merchant’s obligation to deliver goods (reflected as Unearned Revenue) is still $500 but now split between two customers (Customer1 and Customer2). Internal tracking of this obligation may be updated, but the total financial liability remains the same.
    
    

    I find this much more easier to reason with.

    • Yes exactly. With assets liabilities and equity having a left and right entry, they were following the convention when posting a journal entry to the ledger, left entries must equal right entries. (Debits must equal credits). Because A=L+E, we get assets to the left and liabilities to the right.

      2 replies →

  • I understand this. But we’re talking about computers, not Italian merchants. Italian merchants had actual pieces of paper. Computers have tables and views and frontends that are separate from the tables.

    Any self-respecting accounting system should be able to produce a balance sheet that matches the conventions you’re describing. I don’t think it follows that the actual numbers in the database that get summed to produce the total liabilities should be positive.

    • I've often wondered about this in the shower. Why debits and credits, when we can just make income negative and let everything sum to 0? Then you can track the balance for each account in a single field in the database.

      And the answer is that "0" first entered Europe around the time they invented double-entry bookkeeping there. Negative numbers reached Europe centuries after that.

      I showed the internals of a number-line-based accounting systems to an accountant once, and he was so confused by the negative incomes.

      https://en.wikipedia.org/wiki/Negative_number#History

      https://en.wikipedia.org/wiki/Double-entry_bookkeeping#Histo...

    • I think we are talking about two different things. Yes, of course you can build an accounting system using whatever database algorithm and programming framework you like. But your users expect debits and credits and A=LE or A-L=E because that’s what their auditors expect.

      In the scenario four I presented earlier, I believe it is intuitive to think of unearned revenue (liability) as a positive number. When the customer picks up the order, the unearned revenue will be transferred to equity.

  • Thank you for an example. But I don't see how it explains why debit/credit should be used instead of simple signed amount. Like how Transaction(from, to) where `from` and `to` are Entry(account, credit|debit, unsigned amount) make things easier than Entry(account, signed amount).

    You basically used different labels for positive or negative amount in the example.

    • The story I was told and what I believe is that the journal entry is and always is the source of truth. A merchant may have several journals. A separate one for each line of business and maintained by separate clerks. The different journals would then be consolidated into a single ledger. So he can tell what his equity is. When transferring the journal entry to A=L+E. Those early accountants used their version of Excel. For Assets, They took a page and drew a vertical line. For Liabilities, they also drew a vertical line. Same for equity. They called the left side debit and the right side credit. We don’t know why the Italians named it this way. We can only assume the first ledgers dealt with paying down amounts of credit they owed others. Anyways this early “excel” allowed simple ledgers to have two columns. Positive asset changes go to the left and negative to the right. Positive liabilities changes to the right and negative changes to the left. Same thing for equity. I assume this was mantra they told themselves to ensure correctness or reconciliation. When transferring a journal entry to the ledger there must be a debit and a credit or there is fraud. For example an unscrupulous clerk may have taken a loan out. The journal entry may not tell where that money went. When transferring to the ledger, the loan would be entered as a credit. Because the there was not a corresponding debit, either an increase in cash assets or decrease in equity. The balance would have been off and would have told the merchant something was wrong.

    • Money can't appear and disappear. There should be always a destination. It helps accounting a lot. If someone owes anyone, liabilities increases (active/passive accounts), but this liability is spent somehow, which could become an asset (Goods Purchased using a Loan), so you can track all the chain through account statements.

      Destination is the key. You can't just arbitrarily change an account balance using a transaction in a ledger. There should be a destination and this the second record.

      This what GAAP, IFRS and even all the Basels for banks describe in strict detail. But every accounting system and practice is based on double entry and not just keeps the balance sheet consistent but adds a meaning to every transaction using predefined types of accounts.

      1 reply →

    • I think that's because double entry bookkeeping precedes the concept of negative numbers. To be more precise, double entry bookkeeping was invented by people who had not yet been introduced to negative numbers.

      At least that's how it's been explained to me.

    • As someone pointed out just below, you do not need two rows. You can have one row: (amount, credit_account, debit_account).

yes, agree, I think a 'source' 'destination' model is significantly more straight-forward. Just record the 'source' account and the destination account and you essentially end up with a ledger as a directed graph (Martin Kleppmann wrote a great post on it)

I also wrote a super short post on how to model such a system on postgres https://blog.nxos.io/A-simple-double-entry-ledger-with-sourc...

Blockchain actually kinda nails it, that's in essence a source/destination ledger, no 'postings' or similar needed, and from a balance calculation POV has been working pretty well

One reason this model isn't applied in accounting, in my personal view :), is simply historical and the fact that the number 0 didn't exist when accounting principles were created.

Wrote another post on how to model debit/credits on a source/destination ledger here: https://blog.nxos.io/Debit-and-Credits-on-a-Source-Destinati...

It's very straight-forward, you just have to accept that asset accounts have negative balances and present the absolute amount instead of a negative amount in a view.

  • It isn't always clear which is "source" and which is "destination" and now you need a bunch of new conventions about these things. Accounting already has these (admittedly arbitrary) conventions so we might as well use those.

  • > you essentially end up with a ledger as a directed graph

    The page contains a comment from Matheus Portela who pointed to a blogpost of his about "Double-Entry Bookkeeping as a Directed Graph" [0].

    "I've also had the same problems you described here and double-entry bookkeeping is the way to go for financial accuracy. As a programmer, things clicked when I realized this system is an extended directed graph.". It turned out that: "Hi Matheus! Would you believe me if I told you that I read your post in preparation for this article?"

    [0] https://matheusportela.com/double-entry-bookkeeping-as-a-dir...

  • Source/destination seems fail on actual DB implementation. How to sum all entries for a particular account? It could be on either side. It complicates queries and could trigger unoptimal query plans.

    • An account could be only on one side. The side and chapter is the meaning of this account. Account on the left just negates the increase/decrease direction.

      In a bank ledger when a loan appears on a checking account, both increased. Loan on the left, checking on the right. DT Loan → CT Checking. Loan is an asset for a bank, Clients money is a liability.

      On a client's balance sheet everything is mirrored. Checking is an asset, Loan is a liability.

      Queries are quite simple. Volumes are problematic. In a big institution you would find several ledgers included in the general ledger by totals. You just don't need all the details in one place.

      2 replies →

  • okay but how do you model a three-party transaction? say you want to collect fees or taxes

    • you simple create two records linked by one 'transaction', the source in both cases is the same account, while the destination for one of those postings is the fee account and the other destination is a merchant or similar account. And you can link as many of those postings under a single transaction

      2 replies →

    • You never have 3 party transactions - if you do, you would not be able to track money flow.

      You can have multiple transactions. One to pay tax, one to pay fees and one to pay the actual thing.

      You bundle these things in another abstraction, eg. An invoice.

In double-entry, a transaction is the tuple (amount, credit_account, debit_account).

In singly-entry, it is the tuple (amount, account).

  • > In double-entry, a transaction is the tuple (amount, credit_account, debit_account).

    Every “double entry” accounting package I’ve ever used can easily handle transactions that are awkward in this schema and transactions that don’t fit at all.

    Moving $1 from one current account to another? I guess you declare that the $1 needs to be a positive amount, but your two accounts have the same normal balance, and calling one a “debit account” is a bit awkward.

    Adding an accounts payable entry that is split between two expense accounts? Not so easy.

I've never understood that either. As a computer guy it always struck me as a redundancy -- the kind of redundancy where one thing will always eventually be wrong.

I assumed it has to do with the fact that it was invented for bookkeeping by hand. Accountants assure me that it's even more important with computers, but I've never managed to figure out how that works

  • Double entry accounting is still error prone, but single entry accounting is fraud prone.

  • A single debit can result in many credits.

    A single record can (and will) be lost. Network issue, db issue, etc., some transactions will not make it to the db.

    With double entry you at least have a chance of reconciling the lost transaction.

  • > As a computer guy it always struck me as a redundancy -- the kind of redundancy where one thing will always eventually be wrong.

    That's the purpose. If you have a system with no redundancy, it's equally true that something will always eventually be wrong. But in that case, you'll have no way of knowing what's wrong.

    With the redundancy, you can detect problems and often determine what happened.

  • It is not a redundancy. Actually the meaning of a transaction encoded in a pair of accounts. You will need to store it somewhere anyway in a real world scenario, but predefined account pairs is the universal language. The accounting system.

  • I've been doing this so long that I've finally realized that if someone can't explain why something is the way it is, that means it's wrong, or at least some arbitrary choice among several equally good alternatives.

  • Neither have I. It always seems like a massive cargo culting. Human accountants are liable to make very different kinds of mistakes than computers.

Double entry book keeping implements an error correction and detection algorithm.

> This has always seemed more natural to me as a front-end / presentation layer concept.

Consistence is a property of the backend, if that is wrong there is not hope for later

> Your ledger entries always sum to zero for each transaction, your income account has a negative balance, and you display it in a sensible manner.

'sensible manner' is the problem here. The data/money will be diverge with time, and without proper storage of the data it will by impossible to figure out.

The problem here is NOT store 'a transaction'. That with a RDBMs works. Is to store the FLOW of MANY transactions and the divergent ways things works.

Like, your bank is telling you has $100 and your system $120. And your system sum right, but the bank rules.

Or when you do a return and cents are lost in the interchanges and chargebacks.

Or, just wrong data entry, sync, import/export, etc.

---

The way to see this is that `double entry` is a variation of `inmutable data that don't mutate and always track the flow of it' that is golden for business apps.