What makes a cracked junior SWE?
I was recently hired by a client to train their junior software engineers (SWEs).
“Give them tasks that you know they’ll fail.”
I asked, what kind of tasks do you have in mind?
“Nuances with TypeScript. Type unions. Funky closures. Race conditions. Things that would stump a CS grad with a 4.0 GPA.”
I didn’t go to school for computer science so I don’t know what would stump a new grad. But I would imagine that it’s not anything technical.
The biggest thing that junior SWEs lack is knowing why to build anything.
Why do programmers build anything? Usually, because it’s a feature in a product that makes money. Our code turns electrical energy into money literally at the speed of light.
The bottleneck is rarely performance. It’s that we don’t know what makes money.
We can learn what makes money, but that costs money, and your org only has so much of it before it runs out. So the real question isn’t, “how fast does this code run?” Usually, the real question is, how fast can your organization learn how to make money?
Organizational learning velocity is the number one “metric” that most junior SWEs should index on and get good at improving. I put metric in air quotes because I’m skeptical of attempts to measure such a thing. I’m also skeptical that most orgs have this level of foresight. I think that it’s the right goal nevertheless.
The first way to help your org get faster at learning is to write as little code as possible. The more code you write, the more time you will spend maintaining and explaining it.
Sometimes writing less code later means writing more code now, like in the case where you replicate a little utility function to avoid adding a utility library as a dependency. Junior SWEs don’t know when to go with which.
The second way is to build like IKEA: write quality code, but only with as much quality as is required. Any level of effort spent improving performance beyond what is tolerable is wasteful and usually counterproductive.
If you’re refactoring loops with parallelization, remember that some poor schmuck six months from now is going to have to understand that parallelization. Some for caches, microservice orchestration layers, and any number of clevernesses. How long will it take that person to understand your clever thing? And will it distract them from building something else that could help the org learn how to make money?
Every once in a great while, if you’re lucky, technical performance really is the bottleneck. I say lucky because this usually means that you’ve grown to a certain point, which is not the norm. (Failure is the norm—of organizations and of feature releases—and you should optimize for that in your career and your code.)
The problem is that you can’t prematurely optimize for this unlikely bottleneck. But at the same time, you can’t completely ignore that it might happen, because if it does and you’re not prepared, then you’re really cooked. (Ever try sharding a Postgres db in production with millions of users once you’ve maxed out your cloud provider’s db capacity?)
So what do you do? You build in a way that’s easy to undo: modules, service boundaries, tests, APIs, etc. The easier it is to undo, the easier it will be to scale when and if you really need it.