One of the most common things that I discuss with folks when talking about promotions or career progression is delegation. Without exception, engineering orgs want to see folks with Staff+ titles to be showing leadership. That’s been baked into every engineering promotion rubric at every software company I’ve ever worked at. And it makes sense: a single person can physically only write so much code. One of my favorite managers once told me something to the effect of “I don’t need you to be a 10x engineer, I need you to be a 2x engineer that makes everyone else into a 5x engineer.”
Despite being essentially ubiquitous and surprisingly consistent criterion between different orgs, this causes a great deal of confusion with engineers. For most of your career, you’re told to uplevel your skills: put code on Github, code in your spare time, learn to write better code, learn all sorts of techniques, code faster. And suddenly you want a promotion, and they don’t want you coding.
Everyone has a hard time letting go of the coding. Coding feels like ownership. You write the code, it’s your code. This is the first trial that must be overcome: it’s not your code, it’s the company’s code. That code will be read and rewritten far more by people who aren’t you than you could ever imagine, and that code is ultimately their code, not yours.
Some folks have a tough time getting past the impostor syndrome that comes with doing a job that has always required a specific skill that no longer requires you to do that skill. Up until now, the more code you wrote, the more productive you’ve been! It feels conceptually nice to be able to quantify your output as a way to justify your continued employment. Sadly, becoming Staff+ requires you to think about your value in entirely new ways.
It’s hard to intuitively understand that you don’t need to be coding for your impact to be appreciated. But companies don’t measure effectiveness by the number of lines of code that can be attributed to you, they measure (or should measure) effectiveness by the outcomes of the code. Was it mostly bug-free? Does it operate well? Do people have a nice time working with it? The code is purely a vehicle (an encoding, if you will) for the ideas you’re bringing into the real world.
When we frame our successes and failures not in terms of the code but on the outcomes of the project, delegating gets more intuitive. If you’re evaluated on outcomes, you’re being measured on literally anything that goes into that project, not just time spent writing code.
Maybe you wrote some specs. Maybe you met with people about requirements and constraints. Maybe you talked with stakeholders to address details that don’t make sense. Perhaps you updated the roadmap to avoid extra work caused by a parallel project. All of these things matter just as much as the time spent coding, if not more. If your coding output is the bottleneck for your projects being successful, it’ll be valued more highly than the other skills. But if you’re a Senior engineer working towards Staff+, it’s understood that your coding skills are essentially at a point of diminishing returns.
“But Matt, what if I could shave 20% off my coding time by getting better at coding?”
Diminishing returns! It doesn’t matter!
If you’re in a car traveling 100 miles at 30MPH, increasing your speed by 10MPH to 40MPH will make you arrive 14% (28 minutes) sooner. If your original speed is 90MPH, increasing your speed by 10MPH to 100MPH will make you arrive only 5% (4 minutes) sooner. If you’re already programming at the equivalent of 90MPH, programming at the equivalent of 100MPH isn’t a worthwhile difference.
You can instead spend your time doing things that help other people spend more time coding, and writing that code faster:
Offering domain expertise to other engineers
Making sure folks aren’t blocked
effectively communicating project details and context
code reviews
answering questions
connecting people across the company to address mismatches
pointing out drawbacks
Avoid problems (and avoiding time sinks)
making sure everyone is working in the same direction
making sure the output of the project is well-understood by stakeholders
making sure the project sufficiently addresses the problems it intends to solve
Tracking other projects with similar requirements or shared work
avoiding duplicated effort
avoiding conflicts between the projects
Effectively spinning up other engineers on a project and distributing work (multiplying efficiency)
Ensuring prerequisites are met
…endless other items…
You can be the fastest coder in the west, but if these things aren’t done well, the project is probably going to go poorly. And if they are done well, the project will be done faster with others than if you did it yourself.
faster with others than if you did it yourself
Meditate on this for a second. Necessarily, the only way you can beat your best possible personal completion time is by getting other people involved. And more specifically, making sure those other people are effective. And that requires very little coding.
You can write a fairly simple (naive) algorithm for this.
Is the goal well established? If no, go find out what the goal is.
Do you know what you’re building? If no, go figure out what you’re building.
Do you have other engineers to help you and the project substantial enough to benefit from other people helping?
If no, get more engineers.
Were you denied more engineers? You should do the work. You cannot delegate.
If yes, divide up tasks among the engineers.
Are there outstanding tasks that don’t involve coding? If yes, do those.
Is there outstanding coding work that hasn’t been delegated? If yes, do that.
This isn’t perfect (certainly it doesn’t cover [m]any failure modes), but it is a good starting point. Take care of wrapping your head around the project first. If you don’t have people and you could use people, ask for people. If you have people, put them to work. If there’s other stuff to be done, do it. If there’s nothing else, now it’s your time to write code.
As the lead, you’re going to be the point person for making sure PRs get reviewed and questions get answered and that everyone is on the same page. You are the person who checks that everyone’s work is building in the same direction. You are the person who should be discovering issues before they become a problem and talking to the right people about them. You’ve probably had people doing this for you in the past: think about what they did well and how they could be emulated.
Scaling an engineering org requires more people because there’s a fairly hard cap on how much coding one person can do. But simply throwing people at problems doesn’t help. Ever wonder how companies can have tens of thousands (or even hundreds of thousands) of engineers and not seem to make the same degree of progress that a 100 person startup can? It’s because even if everyone’s coding time is done typing at max speed, the effort of coordinating between all those individuals becomes the bottleneck. By a huge margin.
Scaling an engineering org means getting more useful work done. More useful work means reducing waste and keeping people busy for longer. Avoiding duplicated effort. Avoiding conflicting effort. Avoiding confusion and ambiguity and missing dependencies.
If you wanted to paint a building faster, the answer is not to give your team of painters more paint and brushes, or to pick up materials yourself. It’s to make sure everyone has assigned work that doesn’t overlap, that the colors of each room are well-understood, and that the job details you were given aren’t incorrect. Bright orange eggshell paint in the kitchen? You should probably check on that! Not coincidentally, Staff+ engineers exhibit the same qualities as a really good general contractor.
You’ll still write code as a Staff+ engineer. Or at least, I believe you should. But not every task is the right kind of task.
Sometimes it’s nice to pick up a little ticket and just write some JavaScript. Or fix a little bug, get a review, and ship the PR. A little treat to reward you for all your meetings.
Other times there’s some small-to-medium urgent blocker that needs to be addressed immediately, and it’s just faster and easier for you to do it than to have someone else stop what they’re doing and context switch.
More often than not, though, the code you should be writing is the code that you have unusual insight about. Let me give you an example.
Until recently, Runway had what I’ll describe as a DSL for choosing which queue to schedule work in. This DSL was complicated and required you to add new values when adding new types of work that could be scheduled. Under the hood, a poorly-defined scheme would concatenate values together to form the queue name. As you might expect, this was not just difficult to reason about, it was causing incidents and slowing everyone down.
Error-prone code is bad. And this is a perfect place where, as a Staff+ engineer, you can use your broad understanding of the goings-on of the org to address this rough edge. The refactor that I pulled off was about a thousand lines of changes (mostly deletions). What I brought instead allowed folks to write something as simple as:
scheduling: { type: 'queue', queueName: (task) => { if (task.isPriority()) { return '1x-image-priority'; } else { return '1x-image'; } }, },or for simpler kinds of tasks:
scheduling: { type: 'queue', queueName: 'gpu-1x', },No more guessing. Easily greppable. The minimum viable interface that satisfies the whole problem space. Since landing this, we’ve not had a single scheduling-related incident.
You’ll know when you come across work like this. For me, I like to write the rough edges that I find down and meditate on them for a week or two, giving myself plenty of time to think about the right solution. When you have some spare cycles to spend on coding, having a list to pull from is a great way to have something ready to go.
.png)


