Back to blog
Economics+IT?
EconIT

Economics+IT?

Khurli JumamuratovaFebruary 9, 202621 min read

How studying economics changed the way I write code

There is a specific moment I keep thinking about. I was in my second year of university, halfway through a finance and financial-technology degree, and I had just taken my first real backend job. The team was small, the codebase was already big, and on my second week somebody asked me to add a field to a money calculation. I opened the file. The amount was a float64. I remember looking at it for a long time, the way you look at a sentence in a contract that you are pretty sure says something different from what the lawyer told you it said.

The textbook from the previous semester had been very specific about this. You do not represent money in floating point. The textbook had used the word impermissible, which felt dramatic at the time and now feels exactly right. I asked, very carefully, whether we were sure about the type. Somebody senior said it was fine, it was just an internal calculation, we round at the boundary. I said okay and went back to my desk and felt, for the first time, that my degree and my job were actually talking to each other instead of just sharing a calendar.

That was the start of noticing how often the two were going to be in conversation. I want to write down some of those conversations, because the older I get the more I think they are the most useful thing I picked up at school, and they are easy to miss if you are not looking for them.

The thing about events versus state

In my first accounting class, the professor wrote two things on the board. On the left she wrote "Alice has 100." On the right she wrote a list of dated entries that added up to 100. Then she pointed at the left side and said, very calmly, that this is what amateurs do. The right side, she said, is what banks do, because banks have lawyers.

This was an annoying thing to say, and it stuck with me for years. The deeper I have gotten into building real systems, the more I have come to think she was almost completely right. The trouble with storing the answer is that the answer cannot defend itself. If someone asks why the number is what it is, the answer is just the number again. The list is the only thing that can answer the question. The list is also the only thing you can rebuild from when something goes wrong.

When I started writing backend code, the default everywhere was to keep the answer in a row and update it. I notice now that I instinctively reach the other way first, even when I am building things that have nothing to do with finance. Order systems, audit trails, status histories — they all benefit from being modeled as a series of events with a derived view, and they all hurt when you try to model them the lazy way. I did not figure this out from a software book. I figured it out from a sixty-year-old woman holding a piece of chalk and being a little bit rude.

On reading a payments ledger article and disagreeing with it

A while ago I read a piece by the engineering team at Slope titled "Solving the Five Most Common Pitfalls From Building a Payments Ledger". It is one of the better short writeups I have come across on the practical side of building a ledger from scratch. I recommend it to anybody who is about to write one. They walk through the things that go wrong in roughly the order you discover them, which is exactly how a good post on this topic should be structured.

The piece argues, among other things, that you should use signed integers and a single direction column instead of separate debit and credit columns. The argument is reasonable. Their queries get simpler. Their joins get cleaner. Their reporting gets faster. I have read the piece more than once, and I still think they are right for their problem.

The thing is, the system I work on does not do this, and I have come around to the opinion that it is right too, for our problem. Our postings keep the two sides on the same row, with a single amount and two account references. That structure is not the most query-friendly thing in the world, but it makes one specific kind of bug impossible, which is the bug where the two sides of a posting disagree about how much money moved. You literally cannot construct a half-posting, because the same field is the amount on both sides. I find I like that property more than I like the joins being clean.

This is the part where studying economics has been most useful to me, and I want to be honest about it. The degree did not give me one right answer to copy. It gave me the vocabulary to argue with people whose context is different from mine, and to recognize when an argument I read on the internet is correct for a payments processor in California and not correct for a retail bank in Tashkent. The Slope team is solving a payments problem, where the ledger is internal and the regulator is mostly the IRS. We are solving a banking problem, where the ledger is the thing the central bank audits and where any drift between the two sides is a finable event. Both designs are good. Neither is universally right. I think I would have taken much longer to figure that out without the coursework, because I would have read the Slope post, gone "this person works at a tech company, they must know more than my professor," and just copied them.

On refusing to do the obvious thing

The first day-close workflow I designed in this codebase, I had a small fight with myself over what to do when the books were not clean. There were transactions sitting in pending status. There were contracts without repayment schedules. The obvious engineering instinct, the one I had been taught to chase by every productivity-oriented blog post on the internet, was to handle the missing cases gracefully. Skip the bad ones. Log them. Keep going.

I built it that way first. Then I deleted it.

It is hard to overstate how unnatural this felt at the time. Refusing to start, on a workflow that is supposed to run every day, when the only reason it cannot start is that one corner of the data is messy, feels like bad engineering. It feels lazy. The pull request looked like I had given up. But the version of me that had been graded on whether trial balances balanced, and who had watched a senior accountant in an internship spend two hours hunting down a one-cent discrepancy because she literally could not let it go, knew that the graceful version was wrong. You do not run accruals on a day where you do not know the starting state. You stop, you write down what was wrong, you wait for somebody human to fix it, and then you start. There is no acceptable shortcut.

That is the workflow that exists today. It generates a report listing every reason it cannot proceed, waits for a retry signal, and refuses to do anything in the meantime. I think it is the single most important piece of code in the system, and I think I would not have written it that way if my degree had been in computer science.

Boring on purpose

For most of my first year as a developer I had a small private guilt about how boring my code looked. The other engineers in the company were doing things I admired — clever caching, smart abstractions, the kind of work where you read the diff and think "I would not have thought of that." My day-close routine was, by comparison, the most pedestrian thing imaginable. It walked contracts in a loop. It evaluated conditions in a loop. It produced postings one at a time. It wrote them to the database one transaction at a time. Then, the next year, it did exactly the same thing again.

I felt for a while that I should be making this code more interesting. I had ideas. I could batch this. I could parallelize that. I could replace this giant in-memory accumulator with something more elegant. I sketched some of those ideas and then, every time, I would talk to one of the accountants in the building, and the conversation would go the same way. They would ask: but if it gets the wrong answer once, how would we know? And I would explain. And they would ask: but how would we know which posting was wrong? And I would explain. And they would nod, very politely, and say something like that sounds complicated. Which is the polite, professional way of saying no.

This is the lesson I keep relearning. In banking, the clever solution is the one that does something unexpected when the inputs are weird, and the inputs are eventually always weird. The boring solution is the one that any engineer in the building can step through with a pencil at three in the morning, and pencils do not lie. The bank does not want me to be a clever loan calculator. It wants me to be a loan calculator whose output matches, posting for posting, the spreadsheet that the senior accountant has been keeping on her desktop for fifteen years. Anything more interesting than that is a problem waiting to be discovered.

I do not know if I would have made peace with this without coming from a finance background. The whole culture of engineering, especially online, is built around showing off the clever thing you figured out, and the people who get rewarded for it tend to work in domains where cleverness is cheap. In banking, cleverness is something you have to apologize for later. You do not see a lot of conference talks about that, because nobody wants to give a conference talk about how their code is conspicuously not impressive. But the longer I am in this industry, the more I think the boring engineers in finance are quietly some of the best ones, and it is a shame they are too busy being responsible to write blog posts about it.

The other places I learned this

The Slope article was one of the better things I have read on the engineering side of ledgers, and I keep coming back to it even when I disagree with parts. The other things that shaped how I think were less internet-shaped and more textbook-shaped, which is unfashionable to admit but true. The accounting textbooks I used during my degree were, in the post-Soviet tradition, very specific about the mechanics — the chart of accounts, the active/passive split, the contra accounts, the way provisioning works for loans. They were not fun reading at the time. They were the reason I could open this codebase on my first day and recognize most of the words.

I also learned a lot, slowly, from the actual accountants who use the system. They are the ones who tell me when a number looks wrong, and they are the ones who can explain why a regulatory form has the field it has. There is no substitute for sitting next to somebody who has been doing the work for fifteen years and listening to them complain. The complaints are where the real domain knowledge lives.

The engineering blogs from payment companies — the Slope piece, and a handful of others from teams like Modern Treasury and Square — were useful as a counterweight. They taught me how engineers in a different regulatory environment think about the same problems, and they kept me from assuming the way we did things in our system was the only way. I think reading those is genuinely important even if you ultimately do not adopt their ideas, because they pressure-test your own.

What I want my younger self to know

I have been writing this in a kind of loop in my head for a while, and the thing I keep coming back to is that I did not expect any of this. When I started backend work in the second year of a finance degree, I assumed I was going to be an engineer with an irrelevant academic credential. It turned out I am something else — a finance person who writes code — and the finance part is the part that makes the code worth anything in this particular industry.

I would tell second-year me that the degree is not the boring part. The degree is the secret weapon. I would tell him that the chalk-on-the-board moment about events versus state is going to come back, hard, in every system he ever builds. I would tell him that the float-vs-decimal thing is a bigger deal than the senior engineer said it was, and that he was right to ask. I would tell him to take the regulator's documents seriously, even when they are written in the worst possible PDF, because they are encoding a kind of precision that engineers normally do not have to think about, and it is a privilege to learn how to read them. I would tell him that the day he writes a workflow that refuses to do anything until the books are clean, and gets reviewed for it, and ships it anyway, is a good day. I would tell him to read the Slope article and disagree with parts of it on purpose.

And I would tell him that the most useful skill he is going to develop is not the ability to write clever code. It is the ability to write code so boring that the person auditing it five years later can read every line and find nothing to argue with. That is the skill the degree is quietly teaching him, even when it does not feel like it.

He does not know it yet, but he is going to be fine.