How do we get a tech team to make a big technical change?
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). 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.
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.
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, “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.Tags: change management, management
This is a magnificent text. A lot of professionals need the mentality described within – it’s interesting how ultimately it reads “how do I stop working for myself and start working towards shared goals”: A developer harnessing context for himself is setting the entire solution and company they work with towards complete failure, but obviously culpability never sounds pleasant to the cocksure so we can’t say it like that – so, the article attempts to make it about how the “team must be convinced” when it is in fact the instigator that must be convinced that their team matters.
There’s a lot of “mental gas” for upwards movement in the tech rat race, pricey salary increases, and “self-improvement”; using new tools nobody understands for things nobody knows if they have need for. Yet you’ll hear close to nothing about creating actual value: sustainable solutions, quality knowledge transfer so teams grow together, documentation. Hence you have characters like “Jim” in the story whose tendency as a character is to leave ungraciously from the scene after offering their ignoble “contribution”, soon to move on and “contribute” elsewhere.
We can only hope management scholars start understanding what it means to develop in the coming years, because the problem in the article lies within their payroll: “Management approved it, but the team did not” – Why would the management be separate, and not be part of the team? Hence the problem, contemporary managers do not understand the work they are managing. Meanwhile, Developers like Jim will simply keep moving through the set up race like the rats they are.
It depends whether the change makes the developers’ jobs easier or, as in your example with Jim, harder.
If the change makes things harder, forget about it. You’re only shooting yourself in the foot. If it makes things easier, there should be no resistance. Good developers love an opportunity to refactor and appreciate an employer who recognizes that it benefits them in ways that are not easily quantifiable.
Often when someone proposes what they see as a systematic change or solution, it is because they have a particular goal in mind and have developed a way of achieving it. Other people might not see the issues the same way or think of the process and solution that way. I think that if a solution involves convincing people to change their preferred way of working or of seeing the process, it will probably fail. If it was an obviously good solution either someone would have seen it already, or they are unlikely to accept it when they do.
Perhaps I am pessimistic. Or perhaps I have produced many and various solutions over my career which were effective, trouble-free and long-lived yet ignored and discarded. I can understand someone who develops something single-handedly which gets the job done, and leaves others to figure it out later. Why didn’t they build it themselves first? There is no second place prize in development. Do it right, now.
Keyword in this comment is “effective”. Duct tape is effective for a lot of things, but in the grand scale of things, particularly making boats, it is not “efficient”.
Nevertheless, “effective, trouble-free, and long-lived” followed by “ignored and discarded” sounds like a paradox. How can it be long-lived if it was discarded? If it was trouble-free and effective, why was it discarded?
After all – Is one meant to spend time going after buzzwords to spew out in their *next* job interview, instead of reading the room and doing what’s best for the team and for the solution? If something needs to be done, like Kevin said, getting everyone on board is not difficult. And like the article suggested, giving everyone context to move through the any problem is superior to some sort of magic bullet, a jerry rigged fluke. Maybe Jim in the story had the right, “trouble free”, effective solution for their application, but because it gave nobody context it was ultimately discarded and ignored since it was a one hit wonder.
By the time you’re even presenting the new idea for a major technical change to the business, you’d darn well better have the entire technical team on board. If you don’t, and more often than not even if you do, you get eaten alive by stonewalling business people who see any technical change or technical debt tickets as a waste of time that prevents new functionality from being implemented.
Case in point, previous company I worked for we had been warning the business for YEARS that the database engine they were running on would be going out of support in 2019 because the company that sold (and supported) it was going out of business. It took the business until 2020 to start taking it seriously, and grudgingly approve we spend some time on changing to a different database engine as long as it didn’t influence the cadance of releasing new functionality.
Then in 2021 we got managment breathing down our necks for still not having got rid of that now long out of support database engine, when they had been the very people that had prevented us from doing just that not for the last 2 years.
Suddenly it was peak priority, BUT new functionality was STILL considered more important. When I left we were still plugging away at the upgrade while keeping the old database alive with virtual duct tape and paperclips.
One thing missing from this article is the recognition that your big important change might actually be the wrong move. Socializing a change and getting objections is more than just “being able to address them” – it’s giving you an opportunity to learn about the downsides that you might not have considered, and possibly revising your choice to make the change at all. This is incredibly hard to do – you’re giving up your chance to make a big, impactful difference to your team and/or the company – but recognizing when the right thing to do is to stop is critical as a technical lead.
I’ve driven many large changes within my team(s) over the years – probably two or three of them landed and ended up being as useful as I’d hoped. The rest fizzled, or weren’t used widely. Some took years to slowly get traction. Others got used by some portion of the devs but not all. Not all of this is because I wasn’t able to explain myself – it’s because there are legitimate downsides which I hadn’t known about and/or hadn’t taken into account properly.