How do we get a tech team to make a big technical change
Big changes need more than technical chops to get them implemented.
The bigger the change we’re making to a code base, the more obstacles we have to overcome. No time before the deadline. Business won’t cooperate. Intractable technical constraints.
So imagine you’ve gotten past all of those—secured time, obtained sanction from the business, investigated technical feasibility. Maybe you even have a working spike of your solution in a pull request. It feels like the hard part is over. With pride, you stand up in a full-team meeting and announce your brilliant solution…
…to crickets. Your team seems disinterested, or maybe avoidant, or maybe they even resist the idea.
After the meeting, you try to nail down individuals to get their opinions on your solution. Folks respond noncommittally. “Maybe later.” They want to get out of meeting with you.
Two things happened. First, your solution probably threatens team context—or at least seems like it does. Second, you presented it in the format least amenable to letting the team express that.
# Context is king
We reward developers for building new features; for delivering tickets and merging lines of code. But the lines of code themselves are not the currency of technical power. That currency is context—it’s knowledge about the system and how to change it. Who has context on the system is who has power on the team. And that drives more technical decisions than we’d like to admit.
Whole code bases get deprecated on a regular basis because the team considers them “legacy” and “unmaintainable.” Not because they don’t have features or they don’t work: they have features! They work fine! But the current tech team no longer understands them. I’ve seen a team deprecate a service because it was in Rust and rewrite it in a language they considered easier to find devs for: Python. I’ve seen a team rewrite a functioning mail service because the variables in the old one were named “b”, “u”, and “m”—by an architect who had retired. I’ve seen several teams rewrite a monolith as microservices, run into the authentication challenges of microservices, and promptly rewrite the whole thing again as a monolith—but newer this time.
Just as often, some developer springs up a new service that they’re excited to use to add a new feature or replace an old one. The new service is in some completely different stack than the existing code base because the developer saw a YouTube video and got excited. The stack is Django and somebody went with Vue. The stack is RESTful and somebody went with GraphQL. The database is postgres and someone spun up Neo4j. The rest of the team groans. Why? The new service has features! It works fine! But it increases the amount of context that every team member needs—by an entire framework—to be able to move freely within the system for feature development and maintenance.
Those are extreme examples, but it reflects what’s happening any time you change a code base. Because when individual contributors understand how a system currently works, changes make some part of that understanding obsolete. And the obsolescence of that understanding means an initial investment in rebuilding the understanding to restore one’s ability to maintain the system. To restore one’s power on the team.
The bigger the change, the larger the amount of individual and team context you’re wiping out. Like chemotherapy—designed to attack fast-growing cells like cancer cells but also, sadly, hair follicles and wound-healing cells—large refactors make sweeping changes that wipe out swathes of context. Hopefully most of that lost context is a benefit: frustration, regret, or concern about some aspect of the code base (I talk a lot about what sorts of changes those might be in this self paced course on technical debt) (opens new window). But in the process of improving the system, the change wipes out team context on the existing system and poses collateral damage to perfectly desirable feature development efforts.
Context begets power to such a degree that an extreme enough change can upset the team power structure. I once worked on a team where an iOS developer unilaterally changed all navigation in the app from the standard default approach, segues, to a custom, functionally-oriented central navigation module. Not only did this completely change the backbone of the app; it changed it to a custom, un-Googleable approach. The whole team went immediately from being able to Google their questions about screen navigation to depending entirely on Jim. Without Jim, no one could create a new screen in the app. If Jim was out for the day, whole tickets became blocked. People left it that way because no one wanted to upset the now-most-powerful member of the team.
Then Jim got a new job. His last day was a Friday. The next Monday, the team got to work un-refactoring the app back to segues. It took five days. It was worth every expensive, profanity-filled minute to restore the team’s ability to work in its code base.
# Presentation matters
In the movies, failing companies experience their big turnaround after a lone genius stands up in a meeting, slams their fist on the table, and announces “Here’s what we’re gonna do!”
In addition to being dramatic and fulfilling, that mechanism for introducing changes feels efficient: tell everybody about it at once! The problem is, it doesn’t work in real life. When you announce a giant change that threatens teammates’ power in a joint setting where people aren’t expecting it, you set your team up to resist your idea. This is a big surprise to them, and announcing it in a big meeting makes it clear that you expect this change to go through—whether or not they agree with it or even understand it.
Even if you say you are open to questions, the team at this juncture is completely unprepared to ask questions because you’ve sprung this change on them. They’re stuck operating from whatever context they walked into the meeting with. Since context is king and you’ve given them no opportunity to gain context on your change before you announced it, you’re not demonstrating to them that their precious context is safe with you. This isn’t a collaborative way to suggest a change.
A very real part of the work of making large changes is to socialize them. Tech heads don’t like it, but it’s true. And it makes the difference between the big changes that sail through with support and the ones that get stuck in the mud because the team dragged their feet or outright resisted them.
# Socializing your change
What does the socialization process look like? First of all, it involves going to teammates one on one. That doesn’t feel efficient, but it creates an environment in which people are able to ask questions and express concerns. When you chat one on one with someone before announcing a big change, you indicate that their input matters to you. You care how this change is going to affect them. Their precious context is safe with you.
Second, start by talking to this person about the problem you’re trying to solve with your change rather than the change itself. What is the pain in the code base? Does your colleague also experience this pain? What does it look like to them? Establish that the problem you’re trying to solve is bad enough to merit a solution like yours. In the same way it doesn’t make sense to prescribe chemotherapy to someone who doesn’t have cancer (or who has a very localized cancer that can be surgically removed), it doesn’t make sense to propose a huge refactor to fix a problem that no one actually experiences or one person experiences rarely.
Third, if the person you’re talking to does experience this pain, ask what obstacles they see for fixing it, and what solutions they might propose. Your colleagues have a different perspective on the system than you do; they might think of obstacles and solutions that had not occurred to you. Don’t refute these ideas in this meeting, even if you don’t like them or don’t think they’re worth considering. Your job, in these meetings, is to make colleagues feel heard, so that a) you can propose a solution that is most beneficial for the team and b) your audience will feel compelled to hear you out when it’s your turn.
Once you’ve talked to each of your teammates individually about the problem, take the time to revisit your solution and incorporate their input. If they brought up things you had not considered, think about how to address them. If they brought up solutions that look different from yours, consider the tradeoffs of each.
Once you have done this, it’s time for another round of talking to teammates. Explain that you’ve been thinking about the problem, and ask what they think of the solution you’ve come up with at the end of your revisiting period. Here, because you requested their input and you’re talking to them one on one, they’ll be more likely to share their objections than they would be in a big meeting. These objections are gold to you: they are the reasons why your team might resist your solution, and you’ve given yourself the chance to address them up-front. To the extent that you can address them, you reduce resistance to the change. For those you cannot address, you have at least made your team feel heard. I offer more ideas about what to say in this meeting right here (opens new window).
Once you’ve completed a second round of talking to your team, you have reached a more appropriate time to introduce your idea in a large meeting. This introduction, however, should include specific attention to the context problem: how are you going to restore the context that you’re about to destroy by making this change? What preventive and therapeutic treatments will you use to preserve all the context you can and heal all the context you can’t? Are you going to meet with the team to collectively design the solution? Will each pull request require some number of reviews from your team? Will your documentation strategy address any process changes you’re introducing, and will you specifically notify the individuals that the process changes affect?
Your context mitigation strategies will help you address even the hidden objections your colleagues may not have mentioned to you—their worries about their own context and their own power. Your change is not only more likely to get through; you’ll have also strengthened your trust relationships on your team.
These sorts of strategies can feel superfluous to the individual contributor who is accustomed to thinking of the code as the work. To this person, all of this talking and revisiting and reflecting and convincing feels, as Michael Feathers puts it in Working Effectively with Legacy Code (opens new window), “suspiciously like not working.” But we’re knowledge workers in an environment where context is king. Building a shared understanding, more often than not, is the work. And the further we progress as engineers, and the larger the change we get to implement and oversee, the more critical it becomes for us to integrate this work into our daily habits. At scale, it’s exactly how we’ll get anything done.