Tasks that engineers feel are important, like upgrading dependencies or dealing with tech debt, are things that creep in once a project has more than a couple of months of history. If those tasks are not dealt with, your engineering team’s productivity will drop quickly, no matter how fast they’ve been in the past.
So what should you do? This is an ugly crossroads to find yourself in.
If you focus only on shipping features and patching the most significant, scariest bugs, your engineers might feel like their priorities don’t matter as much. They might feel that technical quality is not an essential requirement for product managers and other people on the business side of the company.
Given that friction, the engineering team will stop caring about quality. Why should they? It’s not like those tasks get any priority anyway. Then, one day, the engineering team will start moving slower than before because of that technical debt. They should be moving faster since they are dumping all the non-essential tasks, but they are getting nowhere!
That spirals into a self-amplifying loop of caring even less for quality, as the team’s hands are full with the bugs that keep appearing and the features they want to build next.
On the other hand, if you focus on dedicating one sprint after another just to deal with technical debt, it can feel like it’s delaying the most important work you can do for your users and your business: delivering value.
This can be utterly frustrating to your product team – they know what needs to be done, but they can’t find somebody to do it. Even worse, you start losing customers since they are not getting the features they’ve been waiting for – or the bugs that have been bothering them – fixed.
The two-gear way of working
This usually gets fixed by trying to find some compromise: you try to interpolate product and engineering work in cycles. One thing comes after another, which allows teams to keep two different backlogs, and then it becomes a matter of negotiating between these two. Usually an engineering manager or scrum master would be discussing with a project manager or product owner about how many of these tech tasks can be embedded in a cycle, or how many ‘days off’ can be afforded between sprints for engineers to tackle their own priorities.
This is what I call the two-gear way of working, because it feels like there are two modes for a team in this situation: either focusing on customer-facing stuff or engineering-only tasks. They are either building features or removing tech debt.
And this is a fine way of working! But it comes with its limitations...
1. It creates a false dichotomy between speed and quality
If you frame your priorities within these two work modes as 'get these features out there as soon as possible' and 'this is your safe space to do all the improvements you have in mind', you are also generating some other implications.
Product work becomes something that not only has the focus of building a certain feature, but also building it with a mindset that has no space for quality – because that’s something that comes later.
Engineering work becomes something that can take longer because there are no real deadlines and more time can be spent exploring it.
Those two feel weird, don’t they? You are slowly building a culture where shipping something means writing code without caring for its impact on the current tech debt of the team, or any major technical implications; as well as creating the feeling that engineering tasks do not add business value at all – and they take a reasonable chunk of time!
2. It isolates areas of ownership that should work together
This way of working creates a gap between engineering and the rest of the product team. This becomes wider and wider as time goes by. The engineering team gets some extra time to do their stuff, but no one knows what it is or how it impacts the business. And we all hope we'll get where we want to be by the end of it.
Engineers feel like they don't have to think about the business value of technical-driven tasks, such as a refactor, upgrading a dependency, or fixing a security ticket, because they get their own space and time to do it anyway. But having engineers think about the business impact of any given task is something that we should encourage and build upon, not do less of.
3. At any given point in time, somebody in the team is frustrated because they're not focusing on their thing
We are creating this friction where either, engineers are frustrated because they can’t yet tackle some refactoring or other technical tasks they feel are important, or product managers are frustrated because engineers are not shipping new things.
Any of those stages can be detrimental to the overall team morale and creates a gap between what we try to do, and focus on, as a team.
Is there another way?
This process is not great. It leads to product stakeholders feeling like things are always put on hold because the engineering team is not able to adapt fast enough. Engineers feel like they’ve done things a certain way because of the need to ship things fast, and that tech debt is just a byproduct of that approach.
It feels like the only way to deliver code with higher quality and flexibility on a reasonable timeframe is with the byproduct of putting in extra hours.
How can you create a workflow that allows an engineering team to stay within reasonable boundaries of quality, shipping speed, and in general, high adaptability of the codebase to incoming changes and requests? Is there a way for product engineers to work only on the product?
I believe there is a way, one where you can reframe all your needs and perspectives, and merge them into a single way of working.
The single-gear work mode
What if, instead of creating those two different backlogs, and treating speed and quality as two opposing forces, you focused on unifying them? That's what I call the single-gear work mode.
Delivery speed and quality are not opposing forces
You need to change your team's mindset from ’delivery speed and quality are opposing forces’ to ‘how can we have both?’
This very first step can sound very motivational and fuzzy, but this is the keystone that every other step builds upon.
From individual contributors at the end of a task, to whole teams doing a retrospective at the end of a project, asking yourselves, ‘How could we deliver something like this in the future, but faster and with fewer bugs?’ sparks reflection and creativity. You can identify the areas of improvement in your processes (such as, ‘We are moving slowly because we are testing things manually’, or ‘When we thought we were ready to launch, we faced a ton of production-only issues’) as well as in your skillsets (‘We are testing things manually because we don't know where to begin writing automated tests’).
Asking 'How can we do this faster and better?' – almost as a mantra – will spark all these conversations and set your team in the right direction to identify their real pain points, rather than treating all this as business as usual.
Refactoring and dealing with tech debt is not something that comes later
This is something that I have definitely fallen into many times in my career. That idea of OK, everything is ready now, I need to clean up. Usually, when the deadline comes in, there's no time for that extra task.
What if we inverted this flow? If we are treating all this work as a product priority, we need to scope it as such. So, instead of creating a task in your backlog to deal with that technical debt, think about how that technical debt is impacting the tasks of your backlog. The team's performance on certain tasks is going to be impacted because of a lack of tests, or some messy implementations in a few files in the codebase. Use the tasks, bugs, and features that are going to require work on those parts of the codebase to kick off a refactor before you work on the task.
As Kent Beck put it, ‘Make the change easy, then make the easy change’. This inversion of flow in your process, and embedding those refactors within the tasks, is going to force you to scope and work in much smaller chunks. But that work, compounded over time, is going to unblock and massively improve your team's codebase. Most of the time, the changes are done in the same areas of a production codebase. The chances are that they are going to be kept in top shape, whereas other parts that initially you'd have created a ticket for just to refactor them, are not going to be touched because there's no extra product work needed there. And if there is no maintainability or evolvability needed, why tweak it?
Technical tasks have a product impact, and they should be treated as product priorities alongside the rest of the team's backlog
Dealing with security upgrades, making sure your team is not operated on deprecated libraries or versions, or performing database migrations, are things that are typically seen as ‘tech tasks’. We tend to forget we are doing them because they impact our customers and our business, and as such, they need to be prioritized as a team in just the same way you prioritize a feature or a bug.
For that, it's important for engineers to be able to communicate that business impact well, rather than labeling these tasks just as ‘something we need to do’.
Speed and quality are not opposing forces. A software that does not adapt to its expected change is just as bad as one that changes faster than the speed at which a team can maintain it. It's within that balance where we find the sweet spot of it feeling like the team is always delivering what it's meant to deliver. By identifying the challenges that the two-gear work mode can generate, and realizing the underlying issues, processes, and beliefs that pin us down to that path, we can start changing them by implementing these tips that get you closer to the single-gear way of working. Because there is indeed another way, and it’s one that doesn't put speed and quality at odds.