Back to Blog
Reflection

Spending Tracker: The Trap of Over-Designing the "Simple"

I set out to build a simple expense tracker over a weekend. What I got instead was a masterclass in UX, data architecture, and why human willpower is always the weakest link in any system.

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.

More Posts