Engineering principles for building financial systems
Money representation & rounding
- Strong focus on avoiding binary floating point for money.
- Two camps:
- Use integers as fixed-point units (cents, micros, “1/10,000 of a cent”, crypto-style 128–256-bit ints). Rounding only at system boundaries / UI.
- Use decimal types (BigDecimal, Decimal) where available; these handle precision and rounding modes natively and map better to domain concepts.
- Several warn that JavaScript’s Number type is unsafe for regulatory-grade money logic; BigInt or backend-only decimal/int logic is preferred.
- Some argue arbitrary precision rationals/decimals are fast enough for “normal” accounting, but too slow for high-volume trading.
- Rounding rules themselves should be explicit, testable domain objects, often country / product specific, with regulators sometimes imposing precision rules.
Time, time zones, and leap seconds
- Debate over “just use integer timestamps”:
- Works for past events and controlled offsets (e.g., “48 hours from now”).
- Fails for future calendar-dependent events (cutoffs, tax year ends, holidays, DST moves, leap seconds, changing time-zone law).
- Suggested patterns: store UTC plus original timezone (or full zone, not just offset), and sometimes distinguish “observed timestamp” from “future scheduled time”.
- Leap seconds: most financial systems ignore them, but some markets and regulators have explicitly prepared for leap-second events.
Accounting system semantics: accuracy, consistency, completeness
- Several argue “consistency” is as important as accuracy.
- Real systems accept late and out-of-order events; multiple time dimensions (trade requested, filled, booked, settled, etc.) and multiple layered ledgers are standard.
- Systems must represent temporarily “wrong” or inconsistent states to reconcile later.
- Materiality is seen as a reporting/audit concept, not a system-design justification; internal records should be exact, even if reports aggregate.
Currency conversion & FX
- Strong view that systems should not convert currencies “for convenience”; amounts are legally in specific currencies.
- Conversion should occur only at defined business events (e.g., invoice issue, funds transfer), with explicit FX rates and gains/losses lines.
- Internal dashboards may use approximate FX averages, but that’s BI, not core accounting.
Identifiers and events
- Transactions often have many external IDs (per counterparty/system) and multiple timestamps.
- Recommended: model IDs as one-to-many relations with metadata (issuer, type, validity window) rather than assuming a single canonical ID.
Databases, ACID, and architecture
- Many advocate using relational databases with decimal types, ACID guarantees, and SQL-based reporting for bookkeeping-scale systems.
- Others warn that treating an ACID DB as the sole “source of truth” can clash with ledger/event-based accounting, where compensating actions, not rollbacks, are correct.
- Distinction emphasized between fast trading models vs slower, robust bookkeeping stores.
Batch vs streaming
- Disagreement with “batch is just a special case of streaming”.
- Always-on streaming and periodic batch runs have different reliability, performance, and migration constraints, especially when large historical datasets and external APIs are involved.
UI/UX for accounting software
- Multiple accountants/users complain that mainstream accounting UIs are far worse than paper or spreadsheets.
- Users frequently export to spreadsheets despite custom UIs.
- Desire for interfaces that surface double-entry structure more transparently and match real workflows.
Testing and auditability
- Heavy testing is considered crucial, but tests themselves become audit artifacts.
- Refactors may require a “write-then-solve” approach to keep tests and historical expectations explainable to auditors.