What I’ve Learned from Math as a Software Engineer

My Two Confessions

Let me start with two confessions, two things I’ve learned the hard way as a software engineer.

First, the more I understand the problem, the better my chance of building the right solution. That’s something DDD taught me early on: to listen deeply, study the domain, and let it shape the model.

Second is a mindset shift that took longer to internalize. I’ve come to believe that what customers, stakeholders, and domain experts express are often not their true needs but rather “wants,” surface-level expressions that hint at deeper, underlying problems. These “wants” act as clues, guiding us toward the real domain truths. If I stop at face value, I risk solving the wrong problem.

Here’s the tricky part: these two lessons can pull in opposite directions. On one hand, I need to fully trust the domain and the people closest to it. On the other hand, I need to question what they say and dig deeper to uncover what’s really going on. I learned to treat their words as clues, not instructions.

I must both trust the domain and question its experts.


The Philosophical Question

That tension confused me for a long time, especially in tricky domains like accounting and payroll. I struggled early in my career, thinking I needed to invent novel solutions for established ideas like double-entry bookkeeping. But over time, I realized my job was to discover those concepts, not invent them, to understand their underlying principles and meanings.


The turning point came when I stumbled upon a philosophical question: Is math invented, or discovered?

Two simple words, “invented” and “discovered,” I’ve said countless times. But when paired in that simple question, they unlocked something much deeper for me. Hearing different perspectives on it made me curious about what it meant for my work as a software engineer.

By following the second lesson above, treating what I hear from domain experts as a set of clues, I started wondering what to do with foundational concepts like double-entry bookkeeping. Should I try to invent a new way to model something that has already been solved hundreds of years ago? Accounting has been around almost as long as human history; surely, they’ve already figured these things out.


The Real-World Dilemma

Then a big moment hit me. An accountant once told me, with full confidence, that a ledger is just a table of financial transactions, with one field used to mark the financial year. He said he saw this idea in many well-known accounting systems that worked well in the past, so they stuck with it.

Now I had a real dilemma. According to DDD, I should listen carefully to the domain. But in this case, should I just follow what the expert says, even if it feels like they’re describing a legacy implementation, not the core idea behind the concept?

That’s when I saw the conflict clearly: I need to listen carefully to domain experts, but not take everything they say as absolute truth. Instead, I should treat their words as clues, not instructions. That was the mistake I had made before.

And that’s when the old question popped back into my head: Is math invented or discovered?

This time, it wasn’t just a fun question. It helped me see my work in a new light and understand what it really means to discover versus invent in software design. That question completely changed the way I think about modeling. It helped me see the balance between exploring what’s already true in a domain and inventing better ways to represent and work with those truths in software.

I struggled with the dilemma of respecting a domain’s foundational concepts while also questioning expert advice. A key experience led me to realize that I must treat an expert’s words as clues, not absolute truth. This insight, framed by the question of whether math is invented or discovered, helped me redefine my role in modeling as a balance between uncovering truths and inventing solutions.


The Dichotomy Between Discovery and Invention

It is my responsibility to invent better ways of modeling and implementing these discovered concepts in software. A ledger, for instance, is not just a table with a “financial year” column. That’s how it was often built, but that approach misses the essence. A ledger carries meaning, structure, and behavioral rules, and it deserves a thoughtful model that reflects its real nature.

Balancing discovery and invention has been a constant tension in my work. I have to listen to domain experts carefully and respect the domain’s internal logic. But I also must recognize that their language often masks the core truths. My job is to listen and then treat what I hear as raw material for either discovery or invention. Often, it’s both.

Eventually, I came to understand that my role wasn’t to reinvent foundational concepts, but to discover their essence, to understand why they exist, how they evolved, and what makes them reliable. That shift in mindset was critical. It freed me from trying to be overly clever and instead pushed me to be more curious and respectful toward the domain itself.

At the same time, I also realized that while I don’t need to invent new financial principles, I do have a responsibility to invent better ways of representing and managing those principles in software. A ledger is not just a table of transactions with a “financial year” column slapped on top, even though that’s how it was commonly implemented in systems I inherited. A ledger is a deeper concept. It carries meaning, history, and structure. My job was to uncover that meaning and then model it in a way that preserves its integrity while serving the system’s needs.

Balancing these two perspectives has never been easy. I need to listen closely to domain experts and let the problem domain shape my design. On the other hand, I have to recognize that what’s said is often just the tip of the iceberg. I can’t treat their words as final answers; I need to treat them as starting points that guide me toward deeper insights.

So in practice, I find myself somewhere in the middle. I’m constantly listening, observing, and questioning. Sometimes I’m rediscovering ideas that already exist in the domain, like double-entry bookkeeping. Other times, I’m inventing new ways to express those ideas in the language of code, making them more useful, maintainable, or aligned with the system’s goals.

That’s where math and modeling come in, not as dry, abstract exercises, but as powerful tools for understanding, clarifying, and expressing ideas. And that’s why this reflection on “discovery vs. invention” matters so much to me as a software engineer.

I’ve realized my role is a constant balance between discovery and invention. My job is not to reinvent foundational concepts that have already been discovered, but to understand their core essence and then invent a thoughtful model to represent that truth in software. This process requires me to listen closely to domain experts, but to recognize that their language is raw material for both discovery and invention. The tension between uncovering a domain’s truths and creating solutions for them is what makes modeling so central to my work.


The “Math Is Discovered” Perspective

Some people believe math isn’t something humans invented, it’s something we discover. In this view, math is already out there in the world, just waiting to be found. We humans give it names, symbols, and meaning.

They say math is the language of nature.

Geometry, for example, wasn’t invented in a vacuum; triangles and rectangles are shapes we saw everywhere: in buildings, stars, shadows. Numbers came from the need to count real things: sheep, apples, debts. That’s why addition and subtraction feel inevitable; they describe how things in the world behave. Mathematicians didn’t create those truths; they discovered them, sometimes centuries ago, and those truths remain unchanged.

Triangles, ratios, and π existed long before we gave them names. Mathematicians just put words and symbols around patterns that were already there. In philosophy, this view is known as Platonism, the idea that mathematical truths exist independently of us, and our job is to uncover them. If humanity vanished, prime numbers would still be prime, and π would still be irrational. It’s just that there’d be no one to notice.

How that feels in software modeling

I realized that some rules in software aren’t up for negotiation; they’re discovered truths, like financial laws in accounting or payroll.

Think about double-entry bookkeeping: debit must equal credit. That’s not a creative choice. It’s a discovered relationship that holds across time in every accounting system.

Or net pay = gross pay – deductions. That formula isn’t up for redesign; it already reflects reality.

These aren’t arbitrary rules. They’re principles that emerged through centuries of trial and error, and they’ve stood the test of time. I don’t get to redesign them; I get to honor them in code.

Here’s my confession: at first, I tried to reinvent those rules. I thought I could design something better. BUT I WAS WRONG. My job wasn’t to invent those truths; it was to discover and model them correctly.

In those moments, I felt more like an explorer than a creator. I wasn’t generating ideas; I was uncovering what was already there and doing justice to it in code.

Example: Modeling the ledger

A ledger is not just a spreadsheet. It’s a record with meaning, timestamps, version history, audit trails. But legacy systems often built it as a simple table with a “financial year” column. That’s a model, but it wasn’t capturing the real domain.

It worked until the business needed to: support multiple fiscal systems, correct past entries, and produce overlapping reports for different tax rules. Suddenly, that simple table broke. That’s when I had an “aha”, I needed to discover the true structure of a ledger, and then design a model that honored it.

Why this aligns with DDD?

DDD teaches me to listen deeply to experts, not to ignore them, but to go beyond them.

I’m not just copying what domain experts say; we’re discovering the underlying truth and building models that reflect it.


The “Math Is Invented” Perspective

Now, let’s look at the other side of the story. Not everything in math (or modeling) is discovered. Some things were very much invented by humans to solve specific problems.

Some thinkers say math isn’t discovered at all; it’s invented. We didn’t find them lying around in nature; we built them, piece by piece.

That all the rules, symbols, and formulas we use are just tools made up by humans to make sense of the world.

This isn’t just a random idea. Philosophers like George Lakoff and Rafael Núñez talk about this in their book Where Mathematics Comes From. They say math comes from how our brains work, from how we experience the world physically and emotionally, and then create metaphors to describe what we see. In their view, math isn’t some universal truth waiting to be uncovered; it’s a creative system that we shape to suit our needs.

Think about this: the number zero didn’t always exist. Someone had to come up with that. The same for negative numbers, for a long time, people didn’t believe they made any sense. Even coordinate systems, that X and Y axis stuff, had to be invented. They’re not “found in nature,” but they became essential once we had them.


So, what does that mean for me as a software engineer?

When I looked at my day-to-day work as a software developer, I saw this everywhere. Even in domains where I thought I was just “modeling what exists,” I was actually doing a lot of inventing. Yes, maybe double-entry bookkeeping is a discovered idea, that part of accounting has been around for centuries, and it works. But how I represent that idea in code? That’s not handed to me by nature or by domain experts. That’s on me.

Example

Let’s take one painful example I faced: handling financial years in an accounting system. The domain experts told me it’s simple, just one table with a column for the year. They even pointed to previous systems that did exactly that. But deep down, something didn’t feel right. When I looked closer, I saw that the table approach caused all sorts of problems: data leaks across years, reporting issues, even bugs in closing balances. So, I made a call: to invent a better structure. I separated ledgers per year, gave each their own identity, and allowed for proper linking between them. The concept, a ledger, was discovered. But the solution, how I implemented it, was invented.

The same thing happened when I was modeling payroll rules. On the surface, the formulas were clear: gross pay minus deductions equals net pay. But as I got into real-world scenarios, the complexity exploded. Deductions could vary by location, family situation, date ranges, or even politics (laws change!). There was no single “discovered truth” for how to do it in software. I had to invent a rule engine that made it possible to plug in new rules, version them over time, and test them across different scenarios.

So, this was my second big “aha” moment: discovering the truth is only half of it. The other half is invention. And good software needs both. The domain gives us structure, but it rarely gives us clean, scalable, digital solutions. That’s our job. We don’t just copy reality into code; we transform it. We create models that serve both the domain and the system. And we need to know when we’re in discovery mode and when we’re in invention mode.

Discovering the truth is only half of it. The other half is invention. And good software needs both.

That’s where the philosophy of math became personal to me. It wasn’t just a debate for academics; it helped me name the conflict I was feeling every time I tried to stay “true” to the domain but still needed to make the system work.

The realization that math can be both discovered and invented gave me the language I needed to reflect on my role. When I get inputs from domain experts, I now know: some things they say reflect timeless truths I need to respect. Others are just clues, and I need to invent the right abstractions and solutions to make those clues work in software.


The Nuance Between Discovery and Invention

By now, you might be thinking: Okay, so is math discovered or invented? Which one is it? But maybe that’s the wrong question.

Some thinkers, like George Lakoff, say the whole either/or idea is too simplistic. In their view, math isn’t purely discovered or purely invented. Instead, it grows out of something deeper: our human experience. We see the world with our bodies, interact with it, move through it, compare sizes, shapes, quantities, and from those basic experiences, we build up abstract ideas. Then, we give them names, symbols, rules, and that becomes mathematics.

To me as a software developer, this feels spot on. It reflects what I do every day. When I’m modeling a new problem, whether it’s payroll, a loan system, subscription billing, or logistics, I start by exploring what’s already there. I try to “discover” the natural laws of the domain. These usually show up as constraints, relationships, edge cases, patterns, and mental models that domain experts rely on, even if they don’t express them clearly.

But then comes the next part: invention. I need to design something that doesn’t exist yet. A model. An interface. A behavior. A solution that works within the rules of the domain, but is shaped by code, not by the physical world. Something that’s understandable, changeable, scalable, testable.

This mix of discovery and invention is everywhere in software. Take design patterns, for example. We didn’t invent the problems they solve. Those problems showed up again and again, across different teams, projects, and technologies. That part was discovery; we noticed the repetition. But the moment we gave those solutions names like “Strategy”, “Observer” or “Repository”. and defined how and when to use them, that was invention. We turned a raw truth into a reusable tool.

The same goes for software architecture. Think about event sourcing. At its core, it reflects a very real way the world works: events happen, time moves forward, and state can be built from past actions. That’s discovery. But implementing an event store, defining event schemas, and handling replay logic, that’s invention. We’re building machinery that expresses a truth, but didn’t exist until we built it.

I’ve come to realize this is the core rhythm of good software work: we discover patterns, limits, and rules in the domain, and then we invent models, structures, and systems to bring them to life. We’re not just engineers or coders. We’re translators between reality and computation.

This view, that discovery and invention are intertwined, helped me stop trying to pick one side. It made me more comfortable listening carefully to domain experts, but also confident in pushing back when I see a better, clearer, or more scalable solution. The question isn’t whether math, or a domain model, is invented or discovered. It’s when you’re doing which. And knowing that difference changes everything.


So, Why Does All This Matter?

If you’re a developer, architect, CTO, or even a product person trying to make sense of complex systems, this way of thinking can really change how you approach your work.

Too often, we either blindly follow what the domain experts say, turning their words into code without question, or we try to outsmart the domain and invent things from scratch, hoping to design something “better”. I’ve done both. I’ve made both mistakes. And the result was usually frustration, waste, or over-complication.

What math, and this whole debate about whether it’s discovered or invented, taught me is this: great modeling is a rhythm between the two. You need the humility to listen and observe what’s already there, and the creativity to design something new that expresses it well in software.

That “aha” moment helped me write better models. It helped me push back respectfully when something felt off. It helped me realize that some truths in a system, like how a ledger works or what a financial transaction really is, are discovered. But how I shape that in code? That’s on me. That’s invention.

So the next time you’re faced with a messy domain or unclear requirements, don’t just ask, “What should I build?” Also ask, “What’s already true here? What needs to be discovered? And what needs to be invented to make it work in software?”

That mindset shift changed the way I design. And I think it can help others do the same.

Leave a Reply

Your email address will not be published. Required fields are marked *