It's October 10 2025, and I am sitting inside of Venture13 in Cobourg working on the Elderado codebase.
And our backend is not happy...
Truth is? Latency is through the roof, and we're starting to see user requests hang as of this morning.
This performance issue comes directly from a choice we made months ago. We intentionally limited server resources and also under optimized certain API endpoints to speed up time to market.
We took the "I'll refactor this later" approach, and now "later" has come.
Which is great, because it means the system worked!
We took intentional shortcuts to boost business outcomes, and the early warning systems and processes we put in place to catch the issues associated with the "shortcut" worked.
I'll talk about how we fixed the issue in 20 seconds, but an easy fix isn't always the case, if the company culture doesn't align with "do it later" attitudes.
When not carefully managed, "future to do tasks" surface because of a mystery bug or performance bottleneck that harms user experience, is hard to track down, wastes dev time and not because somebody has sat down, identified a prior strategic shortcut is showing signs of failure and fixed it.
So while "I'll refactor this later" is the biggest lie software engineers say, it can actually be a smart and manageable approach.
If done intentionally.
Cutting Corners vs Intentional Deferment
If cutting corners and purposefully introducing tech debt is due to competing priorities and rushing to meet deadlines, it's a disaster in the making. A ticking time-bomb, destined to explode.
If the debt isn't documented, or systems aren't in place to "monitor" it, who's going to do it later? Who will assign the task, when it needs done? What happens if that dev leaves or moves to a different team?
The biggest risk of deferment without appropriate systems in place comes out as forgotten context, people scratching their head on why prior or other teams/devs made certain choices and a needlessly stressed team. Oh, and a buggy product. Sad face.
When "Refactor Later" Works
Intentional deferment is a great strategy, if it can be managed. It means we can free up key players on the team to solve more important problems faster.
This means smarter business outcomes, faster iterations on high value problems, and faster data gathering. Basically... this can help contribute to profit-driving business outcomes, not revenue-sapping buggy products.
Intentionality and traceability are the two corner stones of this approach.
It means even if a dev isn't present... they're not leaving behind "grenades" in the code-base, for other innocent people to deal with.
It also means the "problem" is pre-solved, so it doesn't turn into a midnight-page to the on-call dev.
The guard rails to effectively leverage the "refactor it later" strategy comes down to visibility, accountability and and measurement.
Simple questions to determine if it's a good idea or not:
Do we have visibility on the reasons why it was done, and by who/which team?
Do we have visibility on what the symptom will look like, should it surface?
Do we have visibility on the likely solution, should the symptom appear?
How can we use metric monitoring to surface coming issues specific to this debt?
An Example
As I mentioned earlier, Elderado was slow today.
I knew that because our server monitoring software told me so.
I also knew the exact reason:
Our PHP worker limit was being tied up, which meant requests were starting to hang for longer than usual before being taken on and completed by an available worker.
This was expected, because when we built the backend we intentionally left the PHP worker limit to 10. Can the server handle more? Oh, yes! But why should it need to? 10 is a solid number for where we're at, company wise.
So when I saw this issue surface, the action plan became simple:
Immediate short term solution: Boost the number of PHP workers to 15.
Boosting the number of workers is a temporary action, while we implement the actual fix.
The real reason why workers are hanging is because many of our geo-spatial heavy queries do not use caching. This was done intentionally, as we didn't have the traffic for it to matter when we originally shipped to production in early 2025.
But the reality... we're now more than triple the number of requests on these APIs, and change is needed.
The fix? Reduce latency by introducing caching. Instead of doing expensive database level operations on every request, cache data for a reasonable amount of time and only do the database query if we need to update the cache.
Adding caching immediately dropped those "heavy" queries by 200ms-400ms on average, which meant the PHP workers were being tied up for far less time per request.
With this simple fix, we can bump worker count back to 10, and continue on our merry way.
And no... we didn't spend all day introducing caching.
We added caching to one, very specific set of APIs... because we know it is the "biggest offender" here. There's still tons of unoptimized code in the database, but it isn't posing any sort of immediate risk to spend resources on fixing, at the moment.
A "Do Later" Culture
Done correctly, delegating performance optimizations that aren't immediately useful, but will likely be needed later is a gift, not a burden.
Transparency and trust in decisions is paramount here. Understanding that future engineering schedules must allow for this "debt" to be tackled is critical. Without this, the "do later" simply turns into a mess of a codebase, that becomes painful to work on.
Practically speaking, there are some simple strategies to keep on top of tech debt of this nature, while catching things before they become an actual issue that impacts revenue or user experience.
Automated notifications: Probably the easiest, when available.
A simple example here is if we knew a certain user experience is not tested as thoroughly as it should be due to the unlikely scenario where a lot of people go through it. A simple automated email that triggers when that situation arises a certain number of times it occurs is an easy way to know when to do the "missing work" here and test it more thoroughly, or tag in the UX team to dial in the user experience.
Of course, tons of automated systems exist built into tech stacks we all use. For example, a lot of cloud database tools will send notifications as certain limits are hit, or performance lags occur.
Basic project management: Add Github issues or cards in Trello, Jira, Asana or whatever project management tool you use. This means when symptoms appear, we have a single place to go to determine what may be the cause.
Logging: Setup logs for "weird" things, and ensure they're categorized correctly. Logging certain things under a "warning" makes it easy to remind devs that this "occurrence" has potential problems attached to it. You can even add a ticket number or Github link to the logs to quickly get up to speed on what tech debt exists here, and how to identify if it is the issue.
Comments: Commenting the "why" behind seemingly odd decisions that depart from industry best practices are useful in scenarios like this. It immediately allows devs to see why something was done, and they understand the context before jumping in and "fixing" something based on their own instinct, why may clash with the original approach.
With leadership buy in, "do it later" becomes a cultural discipline, not a dodge.
Takeaways
- “I’ll refactor later” isn’t a lie if you treat it like a loan - not a gift.
- Deferred optimization can accelerate innovation when tracked and time-boxed.
- Visibility, monitoring, and ownership turn tech debt into a managed asset.
- Every shortcut should have an owner, an issue, and a plan.
- Engineering maturity isn’t about avoiding tech debt - it’s about managing it intentionally.