In this blog, I’ll share my experience developing a bill payment tracking system, the challenges of managing overdue payments, and why trusting administrators can sometimes be the best solution. This system helps track scheduled payments for users who have fallen behind on their bills, making it easier for companies to manage outstanding balances. If you have any questions or want to connect, feel free to email me!
If you want to understand my approach and the reasoning why I did this, please read the following blog:
First approach
Sometime between June and July 2024, I was assigned a task: implementing an interest and installment calculator for overdue bill payments.
At first, I had no idea how to calculate installments based on time and interest rates, so I turned to YouTube. I found a useful tutorial that used Excel formulas, which I then translated into code. This part was straightforward—calculate the installments, send them to the frontend, and let users see where they stood in their payment schedule.
However, the real challenge wasn’t in calculating payments. It was in tracking which payments had actually been made and ensuring accurate data synchronization between the frontend and backend.
The Problem: Who Should Handle Payment Status Updates?
Imagine this scenario: a user selects which installments have been paid in the frontend, and the system sends this data to the backend for storage. But what happens if they accidentally mark an unpaid installment as paid? Should we allow them to undo it?
Initially, a friend suggested simply adding a confirmation popup to warn users before submitting changes. If they mistakenly selected the wrong payments, that was on them. At first, this seemed like a reasonable solution, but something about it felt off—why should the system blame users for simple mistakes?
Overcomplicating the Logic
To handle edits, I needed to compare the stored payment data with incoming frontend updates:
- If a user checked an installment but later unchecked it, we’d need to roll back the operation.
- If a user checked an installment and left it checked, nothing should change.
At first, I started writing if statements to check every possible scenario. But as I implemented this, I realized I was making things unnecessarily complex. Why validate changes when someone else already does this manually?
The Key Realization: Trust the Administrator
In this system, users don’t update their own payments—an administrator does. The admin receives physical payments and logs them in the system. This means the admin already knows which payments are correct, and there’s no need for the system to second-guess their inputs.
Instead of writing logic to validate every change, the system should simply mirror the administrator’s actions:
- If an admin checks a payment, it must be true.
- If an admin unchecks a payment, it must also be true.
The Role of the System
This approach shifts the system’s role from auditing administrators to accurately storing payments. The admin is responsible for correctness, while the system ensures:
- Payment records remain immutable for other types of users.
- Operations are atomic, preventing issues like the “double spend problem” (in this case, double payment tracking).
- Changes are logged for traceability but not questioned by the system.
Why This Works
In many regions, users don’t handle online payments themselves due to lack of familiarity with technology, internet access, or even smartphones. Instead, a trusted intermediary—an administrator—manages payments for them.
In such a setup, the best solution isn’t more software logic but human trust. A fully automated system might seem ideal, but context matters. The admin is the authority on payments, and the system should simply reflect their decisions.
By trusting the administrator, we remove unnecessary validation logic and streamline the payment tracking process.
Conclusion
This experience taught me that not every problem needs a technical solution. Sometimes, the simplest and most effective approach is to trust the human in the loop.