After nearly three decades in software development, I have learned to be suspicious when someone describes a problem as “technical.”
It may certainly look technical by the time it reaches me.
The application is unstable. A feature took three times longer than expected. Two systems cannot exchange data correctly. The database is slow. The mobile app does not match the website. A release introduced regressions. The team insists that everything is almost finished, although nobody can agree on what “finished” means.
These are real technical conditions. They require technical work. But the code is often the last place in the chain where the actual problem became visible.
The problem may have started when nobody decided who owned the product. It may have started with a sales promise made before engineering was consulted. It may have started when a founder changed direction during a call but never updated the written requirements. It may have started with a budget that could only support half the requested product, combined with an unwillingness to remove the other half.
By the time the contradiction reaches the developers, it has put on technical clothing.
Now it looks like an estimation failure, an architectural mistake or an unreliable engineering team. Everyone gathers around the visible symptom and asks how quickly it can be fixed.
This is one of the most expensive habits in application development: treating the place where a problem appeared as the place where it began.
A database does not decide that a company needs five different interpretations of what constitutes an active customer. An API does not create disagreement between departments about who may approve a transaction. A frontend framework does not repeatedly change the definition of the product.
Software merely makes those disagreements executable.
That is why technically competent teams can still produce deeply confused applications. The developers may faithfully encode every decision they are given, only to discover that the decisions conflict with each other. Each individual feature can work according to its own requirements while the overall product fails to make sense.
The code is functioning. The organization is not.
This becomes especially common with founder-led products. The founder often carries a detailed picture of the application in their head. They have discussed it for months or years. To them, the product feels coherent because they understand the history, motivation and intended connections between its parts.
The development team does not have access to that internal model.
They receive fragments: meeting notes, chat messages, feature requests, screenshots, corrections and examples from unrelated products. Important rules appear casually in conversation. Exceptions arrive after implementation. Decisions that sounded final on Monday become “just an idea” by Friday.
Eventually, the team builds what was documented, demonstrated or most recently emphasized. The result differs from what the founder imagined, and the difference is interpreted as a failure of execution.
Sometimes it is. Developers make mistakes.
But sometimes the team has been asked to reproduce a private mental model from incomplete and changing evidence. That is not software development. It is forensic reconstruction.
The same pattern appears in project planning. A client asks for a delivery date before the product has been defined. The team provides an estimate based on what is currently known. New requirements then enter continuously, but the original deadline remains untouched.
When the date slips, the schedule becomes a technical problem.
It was never a technical problem.
It was a refusal to acknowledge that changing scope changes time, cost or both.
No project-management system can repeal that relationship. No AI coding assistant can generate enough code to make it disappear. A sufficiently pressured team may temporarily hide it through overtime, shortcuts and deferred cleanup, but the cost merely moves elsewhere.
It returns as defects, fragile architecture, staff exhaustion and features that technically exist but were never properly integrated.
Budgets create another common disguise.
Organizations frequently describe a product in enterprise terms while funding it like a prototype. They want strong security, polished interfaces, native mobile applications, complex permissions, third-party integrations, real-time analytics, automated workflows and enough flexibility to support future business models that have not yet been selected.
Then they allocate the resources for a small website.
The technical team is expected to reconcile the difference without forcing an uncomfortable business decision.
Usually, this produces a strange form of compromise. Nothing is explicitly removed. Instead, everything is implemented more thinly than intended. Testing is compressed. Architecture becomes reactive. Operational tools are postponed. Edge cases are ignored until users find them.
Later, when the system struggles under real use, the conversation centers on technical debt.
Technical debt exists, but the debt was often authorized indirectly by a business that demanded more scope than it was willing to finance.
Calling it technical debt can be convenient because it removes the decision from its original context. It sounds like something engineers created and engineers should quietly repair.
Some of it is. Much of it is organizational debt stored in code.
Artificial intelligence is making this confusion easier to sustain.
When an AI system can produce visible application changes in minutes, it becomes tempting to believe that every delay is an implementation problem. If a feature can be generated quickly, then planning may appear unnecessary. Architecture can look like hesitation. Questions about ownership, permissions, data models or failure behavior can sound like resistance from people who are not moving fast enough.
But faster code generation does not resolve a contradictory business model.
AI can build the requested workflow. It cannot decide which department should own the workflow when leadership refuses to decide. It can create subscription tiers. It cannot determine what customers will pay for without market evidence. It can connect two systems. It cannot repair a partnership in which neither company accepts responsibility when the integration fails.
In these situations, AI often accelerates the conversion of unresolved assumptions into software.
That can make the product look more complete while making the underlying problem harder to see.
The dashboard exists, so the company debates its colors instead of deciding which numbers matter. The onboarding flow exists, so the team adjusts button placement instead of asking why users would complete it. The application is live, so the absence of adoption becomes a request for more features rather than evidence that positioning or distribution may be weak.
Development remains active because activity is easier to manage than uncertainty.
This is where experienced technical leadership provides value that cannot be measured in lines of code.
The job is not merely to solve the problem as presented. It is to determine whether the presented problem is the real one.
When a client says the system needs to be more flexible, do they have defined use cases, or are they avoiding a product decision?
When a team asks for another administrative role, is there a legitimate permission boundary, or has nobody agreed who owns the process?
When a release keeps slipping, is engineering underperforming, or is the project accepting unlimited scope under a fixed deadline?
When the founder says the application is not ready to launch, is there a material technical risk, or are they avoiding market judgment?
These questions can feel uncomfortable because they cross the artificial line between “business” and “technology.” But that line has never been as clean as organizations pretend.
Every meaningful product decision eventually becomes a technical constraint. Pricing affects billing architecture. Organizational roles affect permissions. Customer promises affect reliability requirements. Sales strategy affects onboarding. Regulatory exposure affects data storage. Unclear ownership affects nearly everything.
Software is where the business model becomes literal.
That means technical discovery must include business discovery. Before choosing frameworks, services and schemas, someone must understand what the organization is actually trying to accomplish, what it is willing to spend, who has authority to decide and which tradeoffs it will accept.
Without those answers, architecture becomes speculation with diagrams.
The socially difficult part is that clients rarely enjoy being told their technical problem is partly a leadership problem. Founders have often invested money, reputation and identity into the product. A direct challenge can make them defend the original assumption more aggressively, even when they privately recognize the contradiction.
The productive approach is to give appropriate credit while making the decision unavoidable.
The product may indeed have reached a point where the current workflow no longer scales. The founder may be correct that the experience needs improvement. The business may have identified a real opportunity.
Then the conversation can move toward the constraint:
“We can solve this technically, but the implementation depends on which business rule you want the system to enforce.”
That framing matters. It does not dismiss the client’s concern. It shows that the technical team understands it well enough to identify the decision underneath it.
It also returns ownership to the correct place.
Engineers should not quietly invent company policy because nobody else wants to choose. They should not decide pricing strategy through database design or determine organizational authority through whichever permission check is easiest to implement.
When those decisions are unavoidable, they should be made consciously, documented clearly and understood as business decisions with technical consequences.
This does not excuse poor engineering. A skilled team is still responsible for sound implementation, honest estimates, clear communication and reasonable anticipation of failure. “The requirements were bad” cannot become a universal defense for careless work.
But accountability must run in both directions.
The technical team is responsible for how the system is built. Leadership is responsible for creating the conditions under which a coherent system can be built.
That includes stable priorities, accessible decision-makers, realistic budgets, explicit ownership and some willingness to choose between competing goals.
The most effective organizations understand that software does not sit beside the business. It expresses the business. When the expression is confused, the source may be confused too.
So, yes, fix the bug. Improve the query. repair the deployment. Refactor the fragile component.
But once the immediate fire is contained, walk backward through the chain.
Ask why the system was placed in that condition. Ask which assumption was never tested, which decision was never made and which tradeoff was hidden from view. Ask whether the organization is about to reproduce the same problem in another part of the application.
The answer will often have very little to do with programming.
Most technical problems arrive wearing business clothes.
By the time we notice, they have usually changed outfits.