Learnings as a Tech Lead

At the two year mark of joining my current team at Google, I became a TL somewhat prematurely due to the previous TL's departure. It has been one and a half years since then and I'm now transitioning into a TLM role on the same team. In this post, I'll share what I've learned about what makes a great TL.

Engage in design discussions

This is the most important aspect of being a TL. If you're only gonna do one thing well, it should be this.

Design discussions take many forms, from formal engineering design reviews to informal debate on how to write a specific piece of code during code reviews.

I've found that the most effective angle is to focus on reducing the project's overall risk. Think about the following during design reviews:

  • Is the project's scope clearly defined? Are all the non-goals called out?
  • Is the design making any assumptions that are not explicitly called out? Are we able to back up all the assumptions with solid evidence?
  • Is the ideal long term solution the same as the recommended solution? If not, is the rationale well explained? Is there a plan to move to the ideal solution?
  • Are there options not considered?
  • What's the riskiest part of each option? What are the unknown unknowns? Can we de-risk them with prototyping / experiments?
  • Are there any vague descriptions in areas that you believe to be critical?
  • If there is a dependency on another team's offering, is it production ready? Does its timeline fits with ours? Is the team in a good position such that future collaboration and investment look promising?

Similarly, when doing code reviews, focus on what reduces the risk / cost of future maintenance:

  • If the code author were to leave tomorrow, would their teammates have little trouble maintaining this code?
  • Will this code still be there in 6 months? In 2 years?
  • Does the complexity of the code come from the inherent complexity of the requirements? Or is it accidental complexity that stems from less-than-ideal abstractions or interface designs? Can we first refactor so that the eventual changes will be simpler?
  • Is the proposed implementation an overkill for the current scope and requirements of the project?
  • Is the code relying on any assumptions without verifying them?
  • Are we in a performance critical section of the code? If not, should we prioritize readability instead?

The cool thing about internalizing these is that all of them apply to your own projects as well.

One thing I've seen junior engineers struggle with in particular is to structure their design doc. A useful tip is to have a high level overview upfront, and break down the design into a series of critical design decisions. The design doc should then be structured around those, e.g. each critical design decision would make a separate section.

Lead by example

It's relatively easy to lead a team of ramped-up junior engineers to implement technical tasks and make progress toward a larger goal. But how do you help grow them into reliable teammates who can fully own their solutions beyond coding -- monitoring, alerting, testing, documentation, etc. How do you nudge them toward working on non-feature work that's in the team's best interest in the long run?

If you are their manager, you'd probably have more than a few tricks in your pocket for this. But as a TL, I found leading by example to be the most effective approach.

Set an example with your own projects. Design and implement something that adheres to a high quality standard. Then put cherries on top by building monitoring graphs, setting up alerts, adding tests, writing documentation, etc. Your junior teammates will see it's not that hard to do all this. And they will start mimicking your behavior in their own projects.

In addition, usually there are some parts of the system that are not owned by anyone. It pays to do some of the above in those parts (a TL probably ends up doing those anyway if nobody else does it). If you're seen personally doing something you've been encouraging others to do, it's much more likely they will agree it's worth their time too.

Create space for others

In most companies, being a TL means you need to delegate some of the work to others. For some, if not most, folks, this proves to be the most difficult aspect of transitioning from an individual contributor into a leadership role. But as a leader, it's crucial to create space for others to succeed.

For a given task, you probably can do it faster and better than your junior teammates. After all, that's probably why you were promoted in the first place. But now you need to learn to let it go and try not to want to do everything yourself.

As a TL, you should still actively look out for what to do. And you can write design proposals if you want (and you probably should). But then you would want to think about whether there is someone on the team who will benefit more from doing the task than you. If so, give it to them, and accept that they might do a slower and/or worse job than you.

After you've delegated the task, refrain from making "style" comments on their work -- how they should approach certain aspects of the task, like how to write an email to a partner team or what graphs to use in the design doc. Everyone is different, so try to focus on the quality of the work, instead of the "style" they finish the work with. This doesn't conflict with giving your teammates respectful feedback later on what they could do to be more effective and impactful.

Another practical tip for creating space for others is to consciously transition yourself into a support role. For example, in meetings, encourage others to speak more. Prefer asking questions that help guide their thinking process than making declarative comments yourself. Volunteer to take notes and follow up action items after the meeting.

Become better at context switching, but limit work in progress

For a TL that leads multiple projects, it's common to have to jump from project to project, often several times within a single day. And there is usually a constant influx of interruptions: document and code reviews, cross-team sync-ups, planning sessions with managers, production incidents, triaging bugs and feature requests, maintenance work, etc. There will be a lot of context switching. There is no escaping that. But to be successful as a TL, you need to keep it managed so that you can still perform your core duties efficiently.

It could feel very chaotic in the beginning. But as you gain more experience, you'll find that just like any other skill, you can become better at context switching through conscious practice. I won't go into details about how to approach this as it really depends on the individual. But for me I used to set aside one day every week to practice intentionally jumping between projects. The right habits help too. For example, if you keep good notes, it will save time whenever you have to switch.

But there is also a huge downside to frequent context switching -- it creates cognitive overhead. If you do it too often, your overall productivity will suffer. For that reason, some people would prefer a working style where you only work on one thing, e.g. in any given half-day time block. While I think that approach has its merits, I prefer a more flexible approach that enables me to switch when I'm blocked: fully focus on the current thing you're doing, practice so that you can context switch to the next thing with minimal overhead, and most importantly, limit your work in progress.

In short, don't keep too many ongoing projects. Early stage exploration is fine, but once the project enters implementation phase, it's essentially a liability cognitive burden wise until it's concluded. So when there are already too many open tabs, prefer spending more time on some to close them quicker than opening new ones.

Write everything down

Every engineer I know at every company is always complaining about inadequate internal documentation. As a TL, improving documentation is one of the few high-leverage activities you're uniquely well positioned to do.

Much of the purpose for having internal documentation is knowledge sharing and preservation. A TL usually possesses much undocumented knowledge valuable to the entire team and beyond. And the only way to scale that knowledge is to write it down. Otherwise you'll find yourself hoping on ad-hoc calls over and over to explain the same stuff to different folks.

And I want to emphasize "everything" here. It's far too easy to not write something down because it's "too trivial" or "too fragmented". But what's trivial to you might not be trivial at all to others; knowledge about something being too fragmented might be exactly why every time someone has to waste a few hours finding relevant information. You can always restructure, rephrase, or remove documentation. The point is to have it in the first place. And if it makes things easier, you don't need to make them public from the beginning -- start with a private note if you want!

Finally, writing is a simple yet effective process that helps you think. Almost all of the great engineers I know, TL or not, produce great technical writings.

Book recommendations

I've found these immensely helpful as I progress my career as a software engineer:

  • The Effective Engineer: Must-read for entry level engineers. Great resource for mindsets and behavioral advice that lay down a firm foundation for your career. Some content still resonates after reaching Senior roles. Check out my notes.
  • A Philosopy of Software Design: Must-read for entry level engineers. Rich with high level ideas on how to design a software system with less complexity. Check out my notes.
  • Staff Engineer: An invaluable guide towards Staff+ roles where the support system fades away and you have to create your own success. Check out my notes.

I haven't finished these but they are great as well:

Subscribe via RSS

CC BY-NC-SA 4.0 © 2019 - 2022 ❤️ Linghao Zhang