"Every financial system handles money. Surprisingly few model it correctly."
Most software developers have heard the advice:
Never use floating-point numbers to represent money.
The usual recommendation is to replace floating-point numbers with decimal types. While that avoids many precision issues, it still misses the real problem.
Money is not a number.
Money is a business concept.
And confusing business concepts with implementation details is one of the most common reasons financial systems become expensive to maintain.
A decimal value tells us almost nothing.
100.00
What does it represent?
100 SEK?
100 euros?
An invoice total?
Outstanding balance?
VAT amount?
Foreign exchange rate?
The number alone has no meaning.
The business concept gives it meaning.
In many systems, money is treated as a primitive value.
In reality, money carries rules.
Those rules belong to the domain—not scattered across services, controllers, or database queries.
It knows:
which currency it belongs to
how it should be rounded
how many decimal places are valid
whether it can be added to another amount
how it should be formatted
when an exchange rate must be applied
how gains or losses should be calculated
which accounting period it belongs to
These are not implementation details.
They are business rules.
A Money object should protect those rules instead of relying on every developer to remember them.
Imagine two values:
100 SEK
50 EUR
A decimal implementation happily adds them together.
100 + 50 = 150
From a programming perspective, nothing is wrong.
From a business perspective, everything is wrong.
Currencies cannot be added without first applying an exchange rate.
The software should prevent this from ever happening.
A well-designed Money object makes invalid operations impossible rather than hoping developers remember every rule.
Financial systems rarely fail because of one large mistake.
They fail because thousands of tiny mistakes accumulate over time.
A one-cent discrepancy may seem insignificant.
One cent won't wake anyone up.
Ten million one-cent differences will stop an entire reconciliation process.
Suddenly those tiny differences become reconciliation breaks, manual investigations, delayed settlements, customer complaints, and regulatory reporting issues.
I've seen systems where two perfectly valid applications used different rounding rules. Individually, both systems produced correct calculations.
Together, they produced different financial results.
Neither system was technically wrong.
The architecture was.
Programming languages change.
Frameworks change.
Databases change.
Cloud platforms change.
Business concepts remain.
Money has existed for thousands of years and will continue to exist long after today's programming languages have been replaced.
Architecture should therefore model the business first.
Implementation comes second.
This is why financial systems benefit from strong domain models.
The domain model represents reality.
The code simply implements it.
Although this example comes from banking, the principle applies everywhere.
Throughout software architecture we repeatedly encounter concepts that should remain independent of implementation.
An information model is not a database model.
An account is not a transaction.
Architecture is not a framework.
Requirements are not implementation.
Business concepts are not programming types.
Money is simply one of the clearest examples.
The role of architecture is to protect these business concepts from becoming implementation details.
Because technologies change.
Business concepts endure.
Modern AI is becoming remarkably good at generating software.
It can produce classes, APIs, tests, and even complete applications.
But AI cannot invent your business model.
If your architecture tells the AI that money is simply a decimal value, it will faithfully generate thousands of lines of software based on that assumption.
The result will be consistently wrong.
AI amplifies architecture.
A good architecture produces better software faster.
A poor architecture produces poor software even faster.
This principle extends far beyond money.
Many financial concepts deserve their own models:
Money
IBAN
BBAN
Bank Account
Settlement Date
Exchange Rate
Interest
Tax
Payment Reference
Balance
Working Capital
Each carries its own rules, constraints, and behaviour.
Treating them as strings, integers, or decimals moves business logic out into the application, where it becomes duplicated, inconsistent, and difficult to maintain.
Encapsulating these concepts inside the domain keeps the rules in one place and allows the software to protect itself.
Good architecture is not about choosing the latest framework.
It is about modelling reality accurately.
When implementation details become more important than business concepts, the software slowly drifts away from the business it was built to support.
That drift is rarely visible during development.
It becomes painfully obvious during audits, production incidents, regulatory changes, and large-scale maintenance.
The most expensive systems are rarely the ones with poor code.
They are the ones with poor models.
Software doesn't fail because developers use decimals.
Software fails because we confuse implementation with business.
Money isn't a decimal.
It never was.
It is a business concept with behaviour, rules, and responsibilities.
Technology changes.
Business endures.
Architecture exists to bridge the two.
Money is not a number.