I want to take you back to my very first client engagement after I moved to Hong Kong in 2012. It was a culture shock in the best and most challenging ways, and this client where I was deployed as a single software developer consultant taught me more about resistance than any textbook ever could…
The start…
When I first walked into the small yet well-lit office of this Russo-phone origin marketing tech startup in Hong Kong in 2012, I quickly noticed by the heavy atmosphere this wasn't a typical startup with ping-pong tables, casual banter and happy hour Fridays. This was a company that had a distinctly hierarchical, command-and-control culture, borderline dictatorship right in the middle of Hong Kong tech scene.
The company was ambitious, well-funded, and had serious aspirations to disrupt the Russo-phone online advertisement market. But their approach to software development was, let's say, lacking. Think waterfall, detailed upfront specifications, and a clear chain of command where decisions flowed strictly from top to bottom, weekly meetings where leadership would scrutinize individuals’ contributions in terms of lines of code added. My mission was to introduce better quality practices and testing methodologies, which, in 2012, inevitably meant bringing some sort of Agile mindset into their world.
Meeting the Resistance
Every transformation story needs a main character who embodies the antithesis of what someone is trying to do. For me, this was Dmitri (not his real name), one of the company executives, and the gatekeeper of all development practices. Dmitri was brilliant, a skillful developer who built his expertise and knowledge out of actual practice. At the same time he was feared by the team (developers, QA, designers), he was absolutely trusted by management.
Dmitri wasn't openly hostile to new ideas, but his skepticism was like a negative force field. He had a way of asking questions that could make you question your own expertise, some would it called it “gaslighting” nowadays. His default mode was in-depth analysis, often accompanied by his signature quote: "This is interesting in theory but it won’t work for us."
In our early discussions about introducing test-driven development, automated testing, and more iterative approaches to quality, Dmitri was consistently the one raising the hard questions. Existing developers would nod along to whatever Dmitri was saying but when I catch up with the developers afterwards, it was always a different story, they totally wanted to try the things I was proposing.
Some fragments of actual conversations with him were like: "This test-driven development thing…..” with his accent giving enormous weight to each word, "requires writing tests before code. This results in double or more time for our development when we have committed delivery deadlines." And another example: "Automated testing sounds good, but our current codebase wasn't designed for testability. Are you suggesting we rewrite everything?"
The Initial Misstep
My first attempts to address Dmitri's concerns were textbook examples of what not to do. I would respond with standard benefits: faster bug detection, improved code quality, reduced regression issues and what not. I would show him articles about successful TDD implementations from Western companies. It was like trying to convince a master chess player that checkers was a superior game.
Dmitri would listen patiently, to the extend of even asking relevant clarifying questions, and then systematically explain why these approaches don't work in their context. The development team started seeing our quality improvement discussions as purely theoretical exercises rather than resulting in any practical solutions, and "getting Dmitri's buy-in" became the unspoken prerequisite for any change.
The Breakthrough Conversation
The turning point came during a late evening debugging session about two weeks into the engagement. We were both staying later than usual to investigate a particularly random production issue, the one that makes developer’s question their career choice. As we worked through the problem together with the team, I decided to change my approach entirely when reaching out to Dmitri.
After hours of debugging, during a toilet break, I dropped by Dmitri’s office and said: "I've been pushing these quality practices…. but I'm clearly missing something about what we are really facing. It makes me wonder why I’m brought up to this engagement at all… so what's the actual pain we are trying to solve here?"
This simple shift plus the fact we were all facing a big production issue to solve, from bringing up solutions to understanding the underlying problems opened a completely different conversation with Dmitri. For the first time, his defense mechanism lowered. He began explaining not just his objections to my proposals, but the broader context: the pressure from investors for rapid feature delivery, the technical debt accumulated from early rapid development stages, the challenge of maintaining a developer team at a high cost location like Hong Kong, and the very real fear that slowing down development (even if temporarily) could jeopardize their first mover advantage in the market they were entering.
He wasn't being obstructive; he was being extremely protective of the codebase, and the company's market position. His resistance wasn't about rejecting better practices; it was about managing opposing priorities and risks. This was my "aha!" moment: his concerns weren't just technical; they were valuable insights about the operating constraints I needed to work withi.
What worked back then
Based on this insight, I came up with a approach that gradually transformed Dmitri from skeptic to champion:
1. Listen to understand
Dmitri's words were about technical implementation challenges, but the underlying concerns were about delivery pressure, team capacity, and business risk. Once I started acknowledging these deeper issues rather than just his surface technical objections, our conversations became more and more collaborative problem-solving than objections after objections.
2. Reframing Quality as Risk Mitigation
Instead of positioning better testing as additional work, I explored how improved quality practices could actually reduce risks:
Automated tests could catch regressions before they reached production (reducing those late-night debugging sessions).
TDD could help document and validate the complex logics their product required (reducing the risk of costly errors)
Better testing practices could improve confidence when making changes to legacy code
Those items and specially incidents were quantified in terms of lost revenue to highlight the impact of neglecting such practices. If you read my previous episode, it was kind of a value translation table that I used as It was all about translating quality improvements into Dmitri’s language: risk reduction and delivery predictability.
3. Invite Co-Design, Not Governance Compliance
This was day and night change. Instead of asking Dmitri to mandate implementation of quality practices, we collaborated on approaches that worked within their constraints. "You know this codebase better than anyone so help me understand how we can deliver to your current deadlines while leaving the code in a better state than we started."
We worked together to create a "Quality Roadmap" that respected their technical architecture and delivery schedule.
By the way, co-designing a solution, also works well in many other cases, specially with your manager 😃
4. Start with Tactical Wins, Not complete revamps
I didn't try to transform their entire development process. It started with one specific pain point, their micro-services consumer contract driven approach that was causing the most production issues. I introduced TDD incrementally, measuring the impact on both code quality and development speed. This wasn't about proving TDD was perfect solution; it was about demonstrating we could improve quality without sacrificing delivery while better documenting the code and designing code fit for purpose based on tests.
5. Leverage Technical Expertise
Every technical concern Dmitri presented was crucial and presented with deep explanations of why that was the case. This validated his deep technical and product knowledge and demonstrated that we were enhancing not diminishing his figure as the tech lead of the company. The shift in his engagement was easy to notice once he felt his technical judgment was always respected and incorporated.
The Transformation Results
The change was gradual but steady. Dmitri began experimenting with test-driven development himself on new features. He started advocating for more automated testing in team meetings. His questions evolved from "why would we do this?" to "how can we make this work better in our context?"
The first real validation came 3 months later when a major partner integration was due to launch. Instead of the usual last-minute panic testing and call for action to stay overtime and deliver they used to have, this time was different, we had automated most of the cases and just a few manual test cases were needed to validate the integration delivery. That day, Dmitri happily announced "We will make unit testing a mandatory practice in our development process, progressively increasing the % of code coverage per quarter till we reach a minimum of 85% across all our micro-services." You might argue that mandate such a practice simply doesn't work but in that context, the developers were actually pretty much onboard for unit-testing and it was more of having the peace of mind they could actually perform their job the way the wanted to do.
After all, Dmitri became more than just a supporter, guiding both the implementation details and helping the broader company understand how quality practices could enhance rather than compromise their delivery capabilities.
Key Lessons
This experience taught me several insights about handling resistance in technical (as well non technical) transformations:
Resistance often means legitimate concerns. It's rarely about rejecting better practices; it's usually about managing conflicting priorities, technical debt, or business pressures that outsiders might not fully understand.
Your biggest technical skeptic can become your most valuable collaborator. When you involve them in designing solutions rather than implementing your solutions, they bring deep contextual knowledge that makes the approach much stronger.
Technical credibility is earned through collaboration, not expertise demonstration. Understanding their code, their constraints, and their pressures builds more trust than showcasing your knowledge of best practices.
Adaptation beats adoption every time. Instead of implementing standard practices, collaborate on adapting proven approaches to fit their specific technical and cultural context.
Respect existing technical decisions while introducing improvements. Acknowledge the reasoning behind current approaches before proposing alternatives.
Practical Application
The next time you encounter resistance in technical transformations, try the approach I just shared which boils down to:
Actually understand their context.
Reframe improvements as solutions to actual problems they care about
Collaborate based on adaptation
Start with small tactical wins
Leverage existing expertise
What technical resistance have you encountered in your transformation works? How did you learn to work with the existing expertise rather than against it? Let’s hear from your experiences and insights.

