Spending Tracker: The Trap of Over-Designing the "Simple"
One of the defining shifts of entering adulthood for me was realising that financial responsibility wasn't optional. I envisioned a way to accurately track my daily expenditure, believing that by gaining clear visibility into my spending habits, I could spot patterns, optimise my budget, and build better long-term habits.
Being a programmer and a naturally curious developer, I fell into a familiar trap: "I can build a simple solution for this over a weekend and solve the problem once and for all."
Little did I know I was about to truly learn the meaning of the Swahili proverb:
"Ukiona vyaelea, jua vimeunda" If you see it float, know it was crafted.
What seemed like a trivial problem turned out to be an intricate lesson in user experience, data architecture, and human psychology. Here is how my journey to build a basic expense tracker turned into a multi-phase engineering evolution.
Solution 1: The M-PESA App โ Low Effort, Closed Ecosystem
The most direct and logical starting point was using the built-in transaction categorisation inside the M-PESA app. (Unfortunately, Safaricom has since updated the app and retired this specific version.)
When it worked, it was a smooth flow: you completed a transaction, and the app let you tag it into pre-defined buckets like Family, Bills, Transport, or Utilities โ or even create custom categories.
[M-PESA Transaction] โโ> [In-App Categorisation] โโ> [Walled Garden Storage]
The Friction
The Data Silo. To view my summaries, I had to physically log into the app every time. While great for security, it created an absolute bottleneck for analysis. There was no CSV or JSON export โ no way to run my own queries.
Sync Latency. Transactions wouldn't always appear instantly. If I bought food on a busy street and didn't categorise it immediately, the transaction might take 12โ24 hours to reflect. By the time I sat down to review it, a backlog had formed, and remembering what a specific random transaction code was for became a mental chore.
Edge Case Failure (Pochi la Biashara). The app flagged transfers between my own wallets as "spending," completely inflating my end-of-month calculations and ruining data integrity.
Verdict: Minimal implementation effort, but the lack of data control and frustrating sync delays broke the habit loop entirely.
Solution 2: The Excel Sheet โ Data Freedom, High-Friction Entry
Desiring live graphs and total control over calculations, I migrated to spreadsheets. Because most templates default to USD, I crafted a custom sheet in Kenyan Shillings (KES), complete with personalised functions, charts, and budget allocation thresholds.
Initially, it was sunshine and roses. I set a strict alarm for 10:00 PM every night to update my sheet. I could instantly see how each category tracked dynamically against my monthly budget.
[Read SMS on Phone] โโ> [Manual Memory Recall] โโ> [Manual Typing into Sheet] โโ> [Live Graphs]
The Friction
The Data-Entry Chore. The system relied entirely on manual data ingestion. Sitting down at the end of a long day to go through M-PESA text messages one by one and type them into a grid felt incredibly repetitive.
Cognitive Load. On an ordinary day, recalling context for 4โ6 transactions was easy. On a busy day with close to 20 transactions, it was an absolute nightmare. If I got home late and tired, I would skip a night โ and skipping one night meant doubling the workload the next day. Motivation drained quickly until one day my 10:00 PM alarm simply stopped ringing.
Verdict: The data visualisation was perfect. The user ingestion pipeline was a high-friction bottleneck that relied too heavily on human willpower.
Solution 3: The Hosted Discord Bot โ The Over-Engineering Trap
Reflecting on the spreadsheet failure, I realised I needed a system that let me input data seamlessly from anywhere, right from my phone.
At the time, I wasn't deeply fluent in frontend frameworks. But I did know backend development. I decided to use an existing interface โ a chat application โ to talk to a custom hosted backend.
Side note: I initially wanted to use Telegram, but for some bizarre reason, "The BotFather" indefinitely banned me from creating bots. So, Discord it was.
After diving into API documentation and surviving a few YouTube tutorials, I successfully configured a personal Discord server and a bot connected to my custom backend.
[Copy M-PESA SMS] โโ> [Append Category String] โโ> [Send to Discord] โโ> [Regex Parser] โโ> [DB]
The Friction
Brittle Input Parsing. To parse messages, I used regular expressions with a rigid format: <M-PESA Message> Category: [Type]. This proved to be a critical flaw. A misspelled "Category" crashed the parser. A typo on a predefined category name rejected the payload entirely.
The Syntax Matrix. M-PESA consumer wallets, business paybills, and Pochi La Biashara messages all have subtle structural variations. Writing regex to account for every edge case became an endless game of whack-a-mole.
Worse UX Than Excel. I had built an overly complex system that increased the steps required to log an expense. Copy the SMS โ open Discord โ paste it โ manually append the strict format string โ send. All without the live graphs I had enjoyed in Excel.
Verdict: I had over-engineered. I traded a financial tracking problem for a complex technical maintenance problem.
Where the System Stands Today
Currently, none of these systems are in use. The Excel sheet lost its momentum. Safaricom killed off the app version I relied on. The Discord bot proved too rigid to be practical.
I am back to square one โ but with a significantly deeper understanding of system design.
Lessons Learnt: The Software Engineer's Reality Check
UX over code efficiency. As an engineer, I often measured success by whether the backend handled requests efficiently. In reality, if the UX is high-friction, the software is a failure. Code efficiency doesn't matter if no one wants to use the interface.
Automation must minimise human volition. Any tracking system that relies on a person having the energy, memory, and motivation to manually format data every single day is doomed to fail. The human element is always the most unpredictable point of failure. A solution should never require more steps than what already exists.
Beware the "Weekend Project" illusion. Simple problems on paper often harbour massive edge cases when exposed to real-world variables โ changing SMS syntaxes, daily human fatigue, and platform changes you never anticipated. Respect the complexity of basic consumer applications.
The Ultimate Resolution: Designing for Zero Friction
Moving forward, I know exactly what the architecture needs to look like. The goal is to shift from active data entry to passive validation.
I want to build a lightweight Android background service that listens directly to incoming mobile money SMS notifications:
[Incoming M-PESA SMS]
โ
โผ (Background Service Triggers)
[Floating UI Overlay Prompt] โโ> (User selects 1 of 4 category buttons)
โ
โผ (Automated async POST)
[Centralised DB / Web Dashboard]
When a transaction hits my phone, the background service will immediately trigger a simple, non-intrusive floating UI prompt overlaying my screen. It displays the transaction amount and offers a few quick-tap category buttons. I tap the category, the prompt disappears instantly, and the service asynchronously pushes the cleaned data to a centralised dashboard.
This keeps input interaction live โ while I am already holding my phone โ turning a multi-step data entry chore into a frictionless, one-tap task.
Sam.