If you’re an engineer or you manage engineers, here are some questions which you may have thought about:
- How can I write better code? How can I help my team write better code?
- Why does it feel like any project that’s a few years old should be rewritten from scratch?
- Why can’t I understand the code written by
<insert-smart-engineer's-name>
? After all, they’re smart and they write good code.
I summarized my opinion to these questions in this tweet below, and I’ll expand on it in this post.
Code becomes unmaintainable for two reasons.
- It wasn’t written to be maintainable in the first place.
- It was once maintainable code, but the domain knowledge of why it was written the way it was has been lost.
From talking to friends and through my own experience, I find that engineering teams (especially in startups) spend a lot of time trying to solving the first reason, but not a lot of time solving the second. I know that’s a gross generalization, but stick with me.
Writing code as a team
All good engineering teams should have processes and tools to help engineers write high quality code. This isn’t anything new. In my team, we do this through:
- Tooling like ESLint / Prettier / TypeScript
- Code reviews before merging
- Encouraging test coverage
- Having open technical discussions
Your team may do something similar. These are all solutions to prevent engineers from writing bad code. It works. Ever since we introduced these processes in my team, code quality and consistency has improved.
However, even though our code became better, new engineers were still not as efficient as I’d like when jumping on a new project. This confused me. We had all these great processes and tools! What was the issue?
Code doesn’t answer “why”
You can have good coding processes in place, but unless engineers know “why” a piece of code is doing what it’s doing, it’s going to end up being unmaintainable at some point. The domain knowledge behind a piece of code is important.
When someone doesn’t understand “why” things were built the way they were, they usually rebuild existing things. This leads to duplicated code which quickly becomes unmaintainable.
To solve this, here’s what I’m now recommending to my team:
When building a feature, ask yourself “what can I do to help a new engineer who joins the team tomorrow understand this?”
Optimize whatever you are building for the new engineer.
Put your engineering hat on. When you asking yourself this question, you’ll often come up with different answers depending on the feature that you’re building.
- If you are writing an algorithm, you may feel writing tests is the best way to explain its behaviour.
- If you are writing a new feature, you may feel writing a technical document explaining the model schema and the route handlers is the best way to explain the way the feature works.
- If you are building UI components, you may feel that documenting each of them in something like React Storybook is a good way to explain their behaviour.
In a startup environment, teams are usually resource-constrained. We have too much to do, and not enough time to do it. We’d love to have 100% test coverage and specification documents for everything we build, but sometimes it’s not possible. In such an environment, I think having this thought of optimizing for the new engineer in the back of your head will help you write software that lives on for a long time.
Measuring success
You can tell your team to “optimize for the new engineer”, but unless that’s somehow measurable, it’s kind of pointless. After all, you need to know whether this is helping or hurting.
The success of a startup is dependent on hiring smart people and allowing them to become productive quickly. As you onboard new engineers, you’ll be able to see exactly where the pain points are in your existing codebase. This creates a nice feedback loop.
I recommend keeping track of all the pain points that new hires run into, and use them to shape existing projects.