Build terrible things
An edict for mid-level engineers
A few years ago, I was a software engineer at a medium-sized company. I’d been there just under two years, and I was seven years into my career. I was doing…okay. At a glance, I was a quick, versatile engineer with above-average product intuition. I oriented myself in new codebases easily. If you needed something shipped, come hell or high water, I would build and ship it for you. Occasionally, I wrote tests.
My title was Senior Software Engineer, and I was restless.
I’d just gotten a new manager, someone I thought knew me pretty well. In our second 1:1, he said something that stopped me short.
“When you tech-lead, I see you focusing too much on the technical side of things,” he told me. “The job also includes team alignment, product support, communicating with other parts of the company, managing up…”
I was very surprised by this. Not because I thought I was amazing at the things he listed, but because in my mind, I was so painfully behind technically that everything else was barely worth stressing about. It was clear to me that I had miles to go, that it would be a mistake to move any further into people management before I was exceptional myself, that technical depth was my limiting factor.
“Impostor syndrome,” people said, because I’m a woman.
🤷♀️ Bad pattern matching.
Looking back now, I can more precisely describe what I was missing: I had no idea what a kernel was. People compared databases and I didn’t know the words they were using. I didn’t understand the difference between stack and heap memory, not really. I was afraid of the C languages. I could’ve told you some of the characteristics of a REST API, but not the underlying philosophy, not why it was better or worse than GraphQL. I had no opinions about dependencies or how to manage them. I’d never tried to make a webpage load faster. What’s multithreading? Is it different than multiprocessing? How does DNS work? What should you consider when selecting a library for front-end state management? Why use a type system?
At the time, I had no way to interrogate my blind spots. All I knew was that people were kind to me, but they did not need me. They wanted me to succeed so that I would be a success story, not because I had any real responsibility. When I looked for the engineers who, if they left, the company would be set back in a meaningful way, I was not among them.
If you talk to any senior engineer, they’ll cheerfully enumerate for you every stupid decision they ever made, that they and probably forty other engineers then had to live with for years. The language or library or platform they used because it sounded cool. The nine months they spent thoroughly reinventing the wheel. The data pipeline made of cron jobs that ran out of memory twice a week. The other data pipeline in the cloud that cost tens of thousands of dollars a month. The poorly-thought-through APIs. The wildly over-engineered log browser. The form builders. The code generators. The top-to-bottom rewrites. The sprawling mess of microservices. The NoSQL database they chose to store their extremely relational data.
Every senior engineer has these stories because making these mistakes is how you become senior. It’s how you develop good code taste, and an intuition for when things are getting too complicated or too abstract or too far from the problem you’re trying to solve. There’s no other way to get this knowledge. Trust me, every senior engineer I ever met tried to explain it to me, and I never got it.
But once you’re on the other side, you want to protect others from making the same mistakes. Especially women and under-represented minorities — there are so few already, even at mid-level. So you give everyone training wheels. You make them write the tech specs and unit tests and postmortems that you never did. You remove all consequences of failure.
Your engineers learn to win your approval instead of learning to build things that work and keep working. They look to you for opinions because they don’t have many of their own. You prevent them from making the mistakes that you made and learned from, so they do not learn.
When truly important projects come along, they are not ready to lead.
So you’re a mid-level engineer now. What to do? I have some suggestions.
Start optimizing for decision-making ability. Take on projects where you get to choose what your stack will be, what tools you’ll use, how you’re going to solve problems that come up, how much tech debt you’re going to accrue, what you’re going to build and when. You’ll do it all wrong at first, but your instincts will get better at a rate that will surprise you. You’ll fix mistakes where you can, and live with them where you can’t.
Be the primary engineer on projects that feel too big. If you can’t do this because somebody won’t let you, go somewhere else. There are a million startups with too few engineers and too much to build.
Look for places where things are a little chaotic. Before you have a track record of building and maintaining critical systems, it’ll be hard to talk people into granting you the kind of responsibility you want at a company with lots of structure. Even if you manage it, it’ll feel too precious, and you’ll be too careful with it. So go somewhere where responsibility is not scarce.
Your goal is no longer to find mentors to teach you everything. That strategy might’ve gotten you from being a junior engineer to a mid-level one, but it won’t make you senior. Start building things on your own, even if it’s scary.
Build things quickly. Build things for people. Build things that get used.
Build terrible things, and learn.