The role came with a brief. After Returns, I was promoted to a formal tech lead position inside another logistics product. It had a different domain, different squads and different codebases, but the same organizational dynamics I had been watching in WMS for the previous two years. I came in as the tech lead of an existing team, which already owned a specific sub-product. The product had a working team structure for local delivery. What it did not have was a team, or anyone, formally responsible for the space between squads. That space held the patterns repeated across codebases and the debt that had no shared owner. It also held a fragmentation that was visible from outside and invisible inside each squad's roadmap. That gap became my second mission, on top of the first, without extra time or formal authority to act on what I found.
The brief was specific. I was asked to understand the problems of the product and to give leadership visibility of them. Part of the question was whether they were the same problems I knew from WMS. I was also expected to build a technical backlog and to raise the technical bar.
Visibility was the main deliverable I had been hired to produce. I did not question that framing at the time, because it matched how I had been effective until then. I had made patterns visible, gathered evidence and influenced decisions. The playbook had worked.
What I did not understand yet was that visibility is a useful output for someone doing analysis. For someone whose real job is to make many teams behave more coherently than the structure allows, it is much less useful. The two roles look similar from outside, but they require very different work.
The state of the product when I arrived
From far away, the product looked like a reasonable architecture. Several squads had clear ownership boundaries. Applications were separated by domain. A proxy layer defined how requests reached those applications. Teams knew what they owned. On a whiteboard, the system looked like it could scale.
Then you looked at how the system actually behaved.
There was copy-paste across projects, at a volume that was far from occasional. Entire files, modules and integration layers were copied across applications owned by different squads. Endpoints were re-implemented inside different applications. Sometimes they had the same path, and sometimes the same path with a resource id in front of it. They always carried the same behavior, with small local differences. Business logic had been pushed into client applications, which made them harder to change and harder to test. Often the people who could have objected to that logic had already moved to other teams. Component code was tightly coupled, with no clear boundary between domain behavior and interface structure. There was dead code that nobody felt confident enough to remove, because nobody could say for sure what it was still doing.
The most telling symptom was the routing. In several of the product's applications, the framework did not handle routing. Teams implemented it by hand inside components, sometimes with giant switch-case flows standing in for what should have been system structure. This was a general pattern across applications from different squads, and not an accident in one codebase. The same improvised approach had been reinvented so many times that it no longer felt improvised.
None of these issues existed alone. They reinforced each other. A system that absorbs business logic also tends to absorb routing logic. A team that re-implements a shared endpoint also tends to re-implement the transformations around it. A codebase that has lost the discipline to delete dead code also loses the discipline to refactor drifted patterns. Each symptom made the others easier to produce and harder to fix. Under all of them was the same root. Each squad had been correctly solving its own product problems, and nobody was responsible for the space where those problems overlapped.
The production symptom that made the problem undeniable
The symptom that made this impossible to treat as internal engineering hygiene came from the field. The operation opened a ticket, and the complaint started to escalate. Nobody knew what to do, or how to fix it at the root. The application did nothing wrong that anyone could point to in its code. The device was reacting to the way the applications were routed and exposed to the outside.
The applications were web applications, running on handheld Android devices used inside warehouse operations. They were supposed to feel like one coherent operational environment. An operator moves through a workflow, triggers actions, receives feedback and completes tasks, all inside what feels like one system. The architecture said otherwise. The spread across several domains had split the product along the lines of operational sub-areas. When an operator moved from one part of a workflow to another, the navigation crossed a domain boundary. The handhelds ran Android Chrome, but not the Chrome of an ordinary phone. Its security layers changed standard behaviors. Keyboard and window events, for example, did not arrive the way they would on a phone, and we could not control them or predict the environment. When the navigation crossed to another domain, the browser asked the operator which browser should open the destination.
That sounds like a small inconvenience until you remember where it happened. These were managed operational devices, with security restrictions that did not let operators freely change browser contexts. When the prompt appeared, there was often no valid choice to make. The operator got stuck, and the flow felt broken. A boundary the architecture considered clean became a break in a physical operation, in the middle of a shift, with work waiting behind the person looking at the prompt.
This is one of the fastest ways to learn whether your architectural boundaries are honest. Users may experience the domain as one continuous workflow while the system keeps showing application boundaries as friction. When that happens, the architecture reflects team ownership, and not what users live. In this product, the two had drifted so far apart that users paid for the mismatch in the middle of their work.
The fix that didn't propagate
I spent about a week analyzing the problem in depth. I studied how the routing model, the proxy behavior, the domain structure and the application scopes interacted across the product. I spent another week designing a better path. The solution was not mysterious. It needed an explicit mapping between routes and scopes, and a domain strategy that did not force users across browser boundaries inside one workflow. It also needed the removal of the unclear proxy rules that had made the sprawl possible.
Then I applied the solution inside the applications my team controlled, where I had local authority and did not have to negotiate with another squad. It worked. Navigation became predictable, and the browser prompt stopped appearing. The experience improved in the places we had fixed. The system felt coherent, at least locally.
At that point I made what proved to be the biggest mistake of that phase of my career. I assumed that once the problem was visible and the solution had worked locally, adoption would follow.
So I did what had always worked for me as an engineer. I documented everything. I explained why the existing model was creating fragmentation, and I walked through the trade-offs. I showed the working example and talked to other teams. I made the reasoning available, clear and easy to trace.
Then I waited for the system to move. It did not.
The pushback was not irrational
Weeks passed. The same patterns continued, and the same fragmentation shipped. The documentation sat where I had left it.
When I tried to understand why, I kept hearing the same argument from teams. It never came as one sentence in one meeting. It was the shape the conversation kept taking, and it went roughly like this. The proxy layer should only define application boundaries at the outer level. Internal routing belongs to each application. Interfering with how a team structures its own navigation is an overreach.
From a local technical point of view, that position is defensible. It protects team independence and matches a clean story about modularity. It also saves teams from negotiating every internal route with whoever is proposing the change of the week.
Its flaw is that it assumes the applications are independent. Inside this product, they were not. They were parts of the same operational journey, used by the same people, on the same restricted devices, in the same physical warehouse. The user did not know where one team's ownership ended and another's began. The warehouse did not care, and the device certainly did not. In this context, routing was part of how the whole system behaved. It was also part of how the business expected operators to move through their work without interruption. Treating it as a local concern ignored that.
This is where local rationality and system rationality split. Each team's argument was correct locally. Together, those correct arguments produced a system that was incoherent as a whole. That is the normal outcome of optimizing for local ownership in a space where users experience one continuous flow. A correct solution can improve one part of a system, but it does not reorganize many teams around the same conclusion on its own.
What I got wrong about the role
The failure of that effort was mostly mine.
I had been given a formal leadership role, and I performed it with the instincts of a senior engineer with a larger scope. I identified problems, designed solutions and produced documents. I tried to influence people through clarity. I assumed that a good analysis and a good fix would be enough to move the organization in a coherent direction.
That playbook had worked for me as an individual contributor. It stops working the moment your job depends on other teams acting against their own local incentives.
At that scope, technical leadership is less about producing the right answer. It is about building a system where the right answer becomes the easiest path. The teams in that system have their own roadmaps and deadlines, and their own reasons to keep doing what they already do. That is a very different kind of work. It requires building alignment and shared ownership across teams that did not ask for it. It requires working with the real incentives, which are not always the ones the org chart describes, and sometimes changing them. It requires mechanisms that make system-level concerns harder to treat as someone else's optional improvement.
I had built none of that. I had built a diagnosis, a fix and a document that explained both.
Looking back, the brief reinforced the mistake. "Understand and give visibility" is exactly the framing that produces analysis, documentation and presentations. It does not produce change across teams. Nobody around me pointed this out, because nobody around me had a different model of the role either. Technical leadership at the scale of the organization was not yet well defined inside the product. So I defined it by default, with the instincts of the work I knew how to do.
The result is predictable in hindsight. I did well what I knew how to do, and what I knew how to do was not the work the position required.
What chaos actually meant
I had started that role thinking chaos meant bad engineering: messy code, weak discipline and systems nobody had designed. That definition is comfortable for engineers, because it places the cause inside the engineering layer, where we feel able to fix it.
The more precise definition is harder to accept. At this scale, chaos is what happens when a system keeps producing independent, rational local decisions in places where users experience coordinated behavior. The code reflects it, and so do the architecture and the UX. But the cause is upstream of all of them. It is in how decisions are allowed to be made, by whom, and without which constraints at the level of the system.
The fragmentation in that product was not a failure of individual engineers. None of those patterns had appeared out of nowhere. The copy-paste had shipped a feature on deadline when no shared abstraction served the purpose yet. The manual routing had solved a navigation problem inside one squad's scope when the framework was too slow to adapt. The business logic in the client had unblocked an operator workflow without waiting for a backend release. Each of those shortcuts had made sense on the day it shipped.
The browser prompt showed this in a single image. An operator, in the middle of a physical task, was stopped by a software decision that nobody on any team had deliberately made. No team had shipped code that said "interrupt the operator here." The friction came from where several correct decisions met. Each squad had made reasonable choices about what its application was responsible for. Nobody was responsible for what happened when those scopes collided in the middle of an operational flow.
That was the lesson of the chaos period that took me longest to extract. The most revealing question is less "where is the bad code?" and more "where is the seam that no team owns?" The browser prompt appeared at a seam between domain applications. The user flow crossed a boundary that no single application had been designed to support. The seam did not appear on the architecture diagram. The operator saw it clearly, as an interruption. Seams like that multiply in any distributed system where each team designs its own application and nobody designs the transitions between them.
To find those seams in any product, read the user experience and ask where it stops feeling like one thing. The answer almost always matches an organizational boundary, a place where one team's ownership ended and nobody formally took over. In this product, the match was easy to see. The places where the product seemed to load a different system, follow different rules or show errors in a different way were the team boundaries. The operators who used those systems every day knew which transitions felt wrong. If anyone had collected that knowledge and sent it to the teams producing the fragmentation, it would have worked as a real-time diagnosis of the organizational design. Nobody was collecting it.
As long as cross-team repair stayed optional, it would keep losing to every team's roadmap.
The engineering work of that period had been right. The routing fix was correct, the documentation was thorough and the analysis was accurate.
But leadership at this scope cannot be a larger version of engineering work. It has to work at a different layer, where alignment is produced, ownership is distributed and system-level concerns stop being optional. Better diagnosis does not build that layer. It takes mechanisms, authority, structure and the design of incentives.
That realization did not settle anything. I knew I had used the wrong tool for the job, but I still did not understand exactly what the right question had been. I had been describing the failure as a problem of propagation: the solution was correct, the documentation was clear, and adoption did not follow. The more I looked at that framing, the more it seemed one layer too shallow. The routing fix had solved something real. What had I actually been trying to fix?
The next chapter begins with that question. The answer took longer than I expected, and it came through a detour: a parallel set of work that was making the same mistake in a different form.
Next: Chapter 4 — There Are No Technical Decisions