sladuca.com

Seb on Software Engineering Management

Here are some things I've learned so far. By virtue of having mostly worked at startups, much of what I say may not apply at larger companies.

Leadership

Communication

When you say a thing, your words map to a set of interpretations the listener could have based on their context. Your words are "clear" when that set has only one element.

Example with two possible interpretations
Seemingly-specific requests are often unclear.

If you're using Slack, DMs are the place where context goes to die - avoid them.

Trust

Everything is easy when you're operating in a high-trust environment, and everything is unnecessarily difficult in a low-trust environment.

In a high-trust environment:

In a low-trust environment:

Among your highest priorities should be ensuring that your team is a high-trust environment.

To increase the "trust level" on your team, create opportunities for positive-sum shared experiences.

Nicky Case's trust game
Play Nicky Case's trust game for a fun illustration of how trust is built and lost.

Here are some specific things that have worked well for me in the past:

If you've ever played Fire Emblem (any of them), building trust is a lot like increasing the pairwise support levels between characters. I think Fire Emblem is a great analogy for management in general, so if you like JRPGs, I highly recommend playing it.

Fire Emblem Support
In Fire Emblem: Three Houses, every character has a "support" level with every other character, which is raised when they have positive interactions both on and off the battlefield

Delegation and Ownership

Delegate as much as possible - there's little value in having a team if you micromanage everything yourself.

However, delegation should be subject to the following constraints:

  1. Don't delegate something to someone if you're not confident they'll do a good job. Build up the competence first, then delegate. Don't set people up for failure.
  2. Try to maintain a bus factor of at least 2, ideally higher if you have the people to spare.

When it comes to ownership, I like to map it onto the three kinds of authority in ancient Roman law:

  1. Potestas: authority granted by decree. In engineering land, this is essentially "As manager, I'm assigning you responsibility for this thing." This is the weakest form of authority because it's granted piecemeal and requires frequent consultation with others, making it less efficient in practice. Use this approach with new team members or those working in unfamiliar areas.
  2. Auctoritas: authority derived from trust. In engineering land, this is "you have done a great job with this thing, and everyone trusts and respects your ownership over it". Auctoritas is stronger than potestas, in that the holder makes enough decisions on their own that the team doesn't waste time on decision by committee, but they also have enough discretion to decide when others' input is warranted (for instance, when they lack the requisite context). This is primarily where you want to be operating when possible.
  3. Imperium: authority derived from military force. In engineering land, this is "you're the dictator of this thing - you have so much ownership over it that nobody else could meaningfully contribute, and you can do whatever you want within this domain". This is dangerous not only from bus factor, but it also creates a context silo that ultimately results in worse decision making. However, it is the most efficient kind of ownership, and you'll often not have enough people to avoid granting it. You should be very judicious about when, to whom, and over what you grant imperium.

Team composition

Everyone has strengths and weaknesses. Everyone has likes and dislikes. Your team is at its greatest when everyone is doing things they like and are good at.

For example, some engineers like to solve puzzles. Others just like getting shit done. Some engineers want to write "beautiful" code. Others just see it as an instrument of business. Each of these is better in some situations than others.

So when you hire people for your team, and when you decide who to delegate ownership of what, you should keep this in mind.

Blame versus responsibility

Build a culture of "responsibility" based on the following maxim: Something can be your responsibility without it being your fault. That is, responsibility is about the outcome and blame is about the person.

This maxim especially applies to you. As a leader, you hold ultimate responsibility for your team. It's very important that you lead by example and take responsibility for mistakes, in particular when they're not your "fault".

This is effectively a different framing of a "blameless culture", placing emphasis on the agency individuals have to solve problems. All of the "blameless culture" stuff still applies:

  1. All mistakes are a learning opportunity.
  2. Dwell on solutions, not problems
  3. Criticise behavior, not people.

Meetings

I like to create a document that makes it clear what the goal of the meeting is and provides necessary context, then orient my meetings around that. I typically share it beforehand, and then, in the meeting, ask people if they read it. If anyone says no, we take a few minutes for everyone to read it during the meeting.

This is more or less the "Amazon method", but I don't assume people didn't read the document beforehand because that's a bit of a "low-trust" smell. This assumes your team is a high-trust environment, but if that isn't the case, you have other problems.

Hiring

The right time to hire someone is when there's something that you currently do, but the scope has grown to the point where you can't do it anymore. This will give you a very clear picture of what their day-to-day will be like, which in turn gives you a very clear picture of the "slot" they need to fit and grow into.

Since you're the one currently doing the job, you have the most context regarding the role. Therefore, you should own as much of the hiring process for your team as you reasonably can.

When sourcing candidates, it's more useful to ask the question: "Where is the kind of person I want likely to be?" than it is to ask "What skills do they need to have?". If you search for skills, you end up wasting a lot of time interviewing candidates who aren't what you're looking for. This is especially true when you're working with people like recruiters who don't have an intuition for "what a good engineer looks like". It's better to say "The kind of person I'm looking for is likely to be found on the Android firmware team at Google" than it is to say "I'm looking for a systems programmer".

Interviews

An effective interview accomplishes two goals simultaneously:

  1. It filters for the specific qualities you're seeking
  2. It provides an opportunity to assess how candidates think and whether they'll mesh with your team

The delivery of an interview matters just as much as, if not more than, its format. I don't think people think about this enough.

For instance, I think the main reason algo interviews get so much hate is because they're done poorly. Most of the time, they're often administered by rank-and-file engineers at large companies who don't really care about the result and are only doing it because it's a requirement for them to level. Delivered well, algo interviews are actually great interviews. Delivered poorly, algo interviews are at best an IQ test and at worst a "did you solve it the way I would have" test.

Vibey things like the comfort level with tools of choice, the depth and specificity when discussing past work, and the way the candidate talks about themselves are pretty high signal. Often, I can determine within the first five minutes whether someone is going to end up in the running to receive an offer.

However, I also think many people overvalue vibes. Vibe checks are quite easy to get past if you're charismatic and good at communicating. While those traits are good traits to have in an engineering hire, they aren't necessarily correlated with technical ability. So it's also bad to entirely rely on it.

My (current) preferred interview format is to cook up an open-ended simulation of a real task that the role would entail, oftentimes far larger than I could reasonably expect anyone to complete within an hour. I'll make a GitHub repo with some starter code and/or docs, give them the lowdown, ask them to share their screen, and watch them complete the task, letting them use any language and tools they want, including AI.

Ref checks are very good. They're pretty low effort and quite high signal - you should do them in the final stages when you're choosing a winner from among your best candidates.

Onboarding new hires

My preferred approach is what I call the "onboarding ladder" - a series of progressively challenging tasks in three categories:

Inspired by Railroad Tycoon 3
This was inspired by Railroad Tycoon 3, a game I played a lot as a child. They designed their scenarios in a manner that incrementally introduced you to more complex facets of the game. It's also how I learned what stocks, bonds, net worth, opex, interest, and insider trading are.

The objective for the first one to two weeks is for the new hire to complete a gold-level task as quickly as possible. Once they complete a gold task, they've acquired sufficient context to be considered "onboarded", and they're done with the ladder.

The goal of this exercise is not for the new hire to complete as many tasks as possible. If tasks in the current bracket are too "easy", they should move up a bracket.

A good rule of thumb is that, on average, the new hire should be roughly 50% confident in what they're doing. If it's too easy, they're not learning enough, and they should skip to the next bracket. If it's too hard, they're also not learning enough, so they should drop down a bracket.

As for numbers, I typically assign 5-10 bronze tasks, 3-5 silver tasks, and 1-2 gold tasks.

Engineering practices

Context should flow, complexity should not.

Don't hide complexity - if you can't eliminate or contain it, communicate it.

Super-DRY Clean Code style programming is a viral disease you should not let into your codebase. This is more an IC thing than a management thing, but I'm including it here because it's so bad that it makes it nigh-impossible for context to flow, which is a management thing.