How to tell what level of developer you are, junior to senior

The developer you are today is a cleverer, more capable version of the developer you were yesterday. The scope of task you can handle today is ever so slightly bigger and more challenging than your peak yesterday. It’s one of the most exciting aspects of becoming a software engineer. The career progression opportunities are massive. Likewise, the satisfaction you can get from solving very hard problems goes right up to the edge of as-yet unsolved problems by any human. For example, human eyes had never actually seen a black hole until Dr. Bouman plied her craft to create an algorithm to do it. Not a lot of industries have this quality. It’s quite special.

A related aspect of working in tech is that your professional level is independent of many factors that would decide your career growth in other industries. For instance, you don’t have to be 10-years-senior in your career to be a ‘senior’ programmer. Likewise, being a developer for 10 years doesn’t make you senior by default. You don’t have to have diplomas and accreditations to do the work. You just have to have the skills and be able to demonstrate them.

Honestly, it’s perhaps the thing about the technology industry that I love the most. Nepotism might make you the foreman on a construction site or the manager of a restaurant, but it won’t help you understand how to scale a poorly architected codebase. Tech is far from unbiased, but it’s significantly meritocratic compared to many other fields.

The fact that great people can progress very quickly can also make it hard for people to know where they are in their journey. Not every team knows how to nurture its rising stars. Not every manager knows how to foster someone who is stuck between two levels. What this post aims to do is give some clarity about the different software engineering levels in terms of skills and performance. About team dynamics and independence. If you’re lost in a world of “We’re seeking developers with 5+ years of experience,” it might offer you a counterpoint that focuses on what you’re actually capable of rather than some arbitrary tenure.

A brief aside about terminology: In this post and in general, I’m going to use the terms “developer”, “programmer”, “coder”, and “engineer” interchangeably. In all cases, I’m talking about someone who knows how to turn ideas into code that solves real problems. Some people make very fine grained distinctions between these titles. The people I find investing significant energy in these kinds distinctions always happen, by random chance I’m sure, to be on the high side of the chasm they’re insisting exists.

Intro made — let’s walk through the broad strokes of the technical career progression. Each of these descriptions is meant to be an entry point into the conversation about the level. You can follow the links in each section below to a more detailed description of the levels.

Junior Developers

The junior developer level is all about learning things in order to immediately apply them to real work. It’s a very exciting level because every day contains both mysteries and answers to those mysteries. It’s all about overcoming the relentless confusion of what these tools are and how they work. What this “internet” thing is. How this server works. How that CI pipeline works. The junior developer is constantly discovering connections between things that blow her mind.

As a junior developer, she’s living in a world where some people around her definitely know the answers to her questions all of the time (or at least they ought to…). The junior developer is often making a tradeoff between how much confusion she’s feeling and how much she’s costing the more senior people around her by bothering them for explanations. As you might guess, this means that her experience of being a junior is in many ways dictated by how supportive her team is toward her. Good, nurturing tech leads and patient mid-levels can make the junior’s experience really exciting and challenging. The junior engineer is likely looking to these folks daily or roughly every other day for help.

Exiting the junior developer level means finding some foundation within the chaos. It means learning enough of the practical art of software engineering so that, mostly, she knows what to do when she sees a problem to solve. When the junior coder starts to know instinctively how to solve most of her day-to-day work without diving headfirst into documentation and Stack Overflow, she’s probably trending toward mid-level. By contrast, if she’s still mucking about in MDN, W3Schools, and copy-pasting stuff to see what works, she’s certainly still a junior developer.

For a much deeper dive about the junior developer level here, check out this expansion on the topic.

Mid-Level Developers

Where the junior developer level is all about learning, the mid-level is all about learning how to harness all those new skills efficiently. The junior dev learnt to write good code fast. The mid-level dev now has to learn what code to write. What problems to solve. The mid-level developer is a bit like a kid in a candy store. Suddenly, she has all these new problem solving abilities. Suddenly that random error isn’t so random — it’s something that can be debugged. That mysterious issue with Git that required her to dump all her changes and reclone the repository isn’t so mysterious now. She can fix her repo and get back to work. Her productivity is way up compared to her junior-level self. Most of the time she’s just motoring through work, occasionally hitting some place where she’s not sure what to do. She might need support from a senior engineer every few days, maybe once per week.

The mid-level engineer is still in search of answers, much like the junior. However, the mid-level dev is looking for “why” answers where the junior is still working on “how” questions. The mid-level wonders why the backend uses a particular object schema within the REST API. She wonders why the code for this key piece of infrastructure is so old and broken down, yet no one has fixed it. She wonders how she could refactor this UI library to be more elegant, since the current implementation is hacky and brittle.

It’s exactly this newfound ability that makes the mid-level challenging. The mid-level dev can now handle abstractions and complexities that were inaccessible before. Now she has the higher-order problem of needing to decide what work to do. At the mid-level, it’s not uncommon at all to see engineers diving deeply into some interesting problem without thorough consideration about whether or not that work is actually worth doing. The discernment between “Ooh, this is fascinating!” and “Ooh, this is fascinating and let’s never do it,” is a key example of the difference between mid-level and senior. Bridging the gap between mid-level and senior is largely about sharpening that judgment. It’s also about learning how to find answers to key questions. Where the mid-level engineer often comes with tough questions that demand answering, the senior engineer will often already know the answers. And when she doesn’t, she rolls up her sleeves and finds them.

Update: It was pointed out to me by a very successful engineering director that my writeup carries forward a certain bias of tech companies. That is, we push people hard to attain technical seniority and then spring on them the challenge that they’ll also need “people skills” (whatever those wacky things are!) to become senior. I think this criticism is absolutely fair and the bias is absolutely present. As a mid-level developer, you may be under-developing your tech lead skills. You might find that your lack of such skills are blocking you from proceeding to seniority, even if no one is telling you so.

For more on what it means to be a mid-level developer, check out this expanded discussion.

Senior Developers

Once an engineer has acquired significant technical abilities, mastery of her tools, and enough people skills to facilitate a small team of engineers, she’s likely crossed into the domain of seniority. Seniority as an engineer is a very mixed landscape. What’s “senior” at one company is not “senior” at another company. If you talk with an advertising agency about what their senior coders are capable of, you’ll find they have a different set of expectations than, say, Google. What I’m describing in this post is technical seniority. Closer to what FAANG-esque companies would think of as “senior” or “tech lead”. My definition of senior would be insufficient in, say, a hybrid project management/software consultancy where client management and presentation skills are prized. However, this definition of senior does cover the most critical quality: To be senior, you need very good technical intuition and even better judgment.

It may surprise some readers that many senior engineers are no more skilled in terms of raw coding ability than their mid-level counterparts. It’s true though. Once she’s made it to the upper regions of the mid-level (on a decent team, with code review), she’s probably about as good at writing code as she’ll ever be. As a senior engineer, she can continue honing her coding skills. Especially with respect to managing higher complexity code and higher complexity codebases. There are many way to deepen her skills in terms of raw coding ability. It boils down to what sort of senior engineer she is. In the expansion post, we’ll talk about different types of senior engineer and what makes them who they are.

The senior engineer learns a new dimension of skills. She’s faced with hard constraints, like timeframes for delivering work that don’t allow everything to happen. She has to murder some darlings. She’s faced with a panoply of things she and her team could do. She has to decide what work actually needs to get done. She satisfices rather than indulging. She chooses pragmatic solutions rather than elegant ones. Most of these skills are learned the hard way. She learns mentorship skills because now she has to mentor. She learns behavioural interviewing skills because now she has to hire.

A mid-level engineer is likely to build elaborate castles in the sand — nifty and whizbang abstractions to solve small, often irrelevant, problems. She obsesses about particular implementation details trying to optimise them away or achieve the unachievable. After a year or two of this, the mid-level engineer wearies of her toils. She looks back at the hundreds of commits. At the brilliant microframework she created which no one is using. At the hours she spent trying to find an elegant solution to a completely intractable problem. “No,” she says, “No more.”

When an engineer turns toward senior, she grows a specific kind of incisive judgment. She’s well past being technically competent enough to understand the topics being discussed. Instead, she’s listening for time being wasted. For holes in the collective understanding of a problem. For senior engineers, it’s no longer about the naive joy of doing technical things. She has her sights set on delivering real work. She’s the pillar of her team not because of the work she does but because of how thoughtfully she spends her energy.

If you’d like to read more about the senior engineering levels, check out this detailed expansion.

Conclusion

I hope this is a helpful discussion of the different engineering levels. I haven’t found many other write ups online that discuss these points meaningfully. As an “All ‘Rounder” senior engineer turned manager, it means a lot to me to be able to help other people grow in their career. This writeup is an attempt to take away some of the mystery about what separates the juniors from the mid-levels from the senior folks.

If you enjoyed this writeup, I’d love to hear from you. If you hated it, I’m all ears, too. If you have questions or you want more details, please just ask. I’m happy to expand on any topic here.

11 thoughts on “How to tell what level of developer you are, junior to senior

  1. Can you share some insight into what fast looks like in the context of this exert in your article – “The junior dev learnt to write good code fast.”?

    1. Absolutely. It’s a great question and I completely glossed over what that means in the post. “Fast” here doesn’t mean at 100WPM. It means efficiently. Some of that is wall-time. For instance, the first time you ever have to write code to interact with a binary tree of data, you’re super slow at it. You’re having to really use your brain to think about the data structure. About how to manipulate it. You’re slowed down by the cognitive overhead of learning that data structure in the first place. Once you’re familiar with it, you’re able to move way faster. You’ve already done that hard brain work and now you can focus your brain time on other things.

      The second way you’re slow when you start out is that you don’t know the APIs. How do you look at the top entry in a stack? Oh, right, there’s a “peek” method. That’s different from an Array. The first time you come across something like Promises in JavaScript, it’s a huge amount of work to make sense of what all the `then` and `finally` stuff is all about. The lack of familiarity makes you move slowly.

      As you progress towards senior, you’re not slowed down by this. At some point, your speed of delivering code is actually wall-time bounded by how fast you can type the code out. When you get to that place, you’re probably a “fast” coder. I can’t think of a single senior engineer who considers their typing speed to be the limiting factor on their output. Instead, they tend to be slowed down by ambiguities, unexpected outcomes that emerge from complex systems, etc.. Those are more or less fixed costs, no matter how senior you are. However, the senior engineer doesn’t lose any time to trying to figure out why their for-loop isn’t working, only to find out they had their `>=` flipped the wrong way. Junior engineers lose time to these sorts of trivial bugs all the time.

      Likewise, senior engineer code tends to go through code review very quickly. Not because they’re blessed and privileged and therefore get to drive in the fast lane. Instead, they produce code with fewer defects and anti-patterns. There’s less to criticise in their code, which means the conversation code review can be focused mostly on the content of changes, not the trivial details like “You don’t need this `if` statement” or “There’s an uncaught exception here when the input is null.” This comes down to a base line of professional coding ability that every senior engineer will have. Whole books are written about it. Things like Code Complete are fantastic resources for being able to write your code in a clean, easy-to-maintain way that makes it easier to review.

      So, in summary, “writing good code fast” means having most of the problem already in your head when you start to type. It means having enough familiarity with your language of choice and with professional coding standards to produce code that works, is clear, and easy to reason about. When you get to this point, the time you spend coding is mostly figuring out what work to do and how to approach it the right way. That work is the same whether you’re junior or super senior.

      1. Thanks for the response. A follow-up question, if want to continue the discourse:

        While familiarity of the standard lib’s APIs, data structures and such is a defining separator between someone who is more junior to someone more senior, where do you place an engineer’s ability to structure a non-trivial feature/program/piece of code?

        I know this might sound daft, but I do find there is a non-negligible amount of time spent on this task and it usually involves a certain degree of rehashing. I find this where I spend time coming up with names for concepts/classes/functions and the right way to stitch it together for the next developer to discover/understand/extend.

        From here, it extends to designing multiple components and the APIs to communicating between them. Here I find the time is mostly lost spending time agreeing on contracts with other engineers or teams. In some cases, it is even agreeing on the approach.

        Would love to hear your thoughts. 🙂

  2. Thanks for the great post Jackson. One question on the senior developer. You mentioned that she has “very good technical intuition and even better judgment”. While I agree, I often found the idea of “technical intuition” (as for any definition of intuition) to be vague and subjective. Given this, it would be interesting to hear your take on it.

    1. You raise an interesting point. “Intuition” is definitely vague and subjective. In fact, it means something different to literally every single person since we all bring our unique life experiences to bear as “intuition” when it comes to decision making. At the very least, we’re talking about “fast brain”/System 1 work rather than “slow brain” / System 2 work. Because intuition happens fast and only semi-consciously, it’s incredibly powerful and incredibly dangerous.

      Broadly, a person’s “technical intuition” means all the perspective they bring to bear when doing technical work that gets funnelled through their System 1 brain. That is to say, the automatic inclination they feel towards a problem.

      From here, it’s all subjective. It boils down to some vague definition of “good”. I don’t think I can absolutely define what “good” technical decision making looks like, but I can compare and contrast some good and some bad technical decisions.

      Situation:
      There’s a new error message and the engineer is not sure what it means.

      Good technical intuition:
      The engineer thinks about what parts of the system could possibly produce this error. Immediately rules out most or all of the aspects of the system and hones in on the specific area of the codebase that could possibly be producing such an error. This includes intuitive connections around what work has recently been done, what aspects of the system create errors that look like this error, and what specific details can be gleaned from the error message.

      Bad technical intuition:
      The engineer thinks about what parts of the system might cause a problem like this, but jumps to an incorrect conclusion. This engineer will spend lots of time exploring parts of the system that are unrelated to the problem. Importantly, even very senior engineers will follow this path when they first start working with a new codebase. However, as they get familiar with the new system, they will develop a sharper intuition that matches the current codebase.

      Situation:
      In an otherwise well-running company, two teams have done incompatible work and now there’s tension about who has to change their work.

      Good technical intuition:
      The engineer who spots the problem also thinks about what led to the mismatch. She decides to speak to the tech leads involved to understand exactly how things went wrong. From experience, she knows that the company typically doesn’t make these mistakes and that there must be some specific cause here. She goes on a small fact-finding mission to understand where things went off coarse. Whatever root cause she finds, she implements a specific solution for.

      Bad technical intuition:
      The engineer who spots the problem has read about software development methodologies that solve these kinds of problems. She doesn’t explore more deeply what the root causes were in this case. Intsead, she proposes additional team process to overcome “these difficulties.” This usually involves more meetings, more task management, and more bureaucracy within the organization.

      Situation:
      A mid-level engineer has written some very, very complex code to provide a highly generalised solution to a specific problem in the codebase. He’s asking the engineer for code review.

      Good technical intuition:
      The engineer reviewing this code looks at the complexity of the solution and has an immediate sense of how much complexity this mid-level engineer is creating relative to the problem he’s trying to solve. The engineer reviewing his code doesn’t spend the time required to understand every nook and cranny of the solution, but instead pulls up a level and gives feedback to the mid-level engineer about whether or not generality is valuable for this part of the codebase. The mid-level engineer then refactors their code, massively simplifying it.

      Bad technical intuition:
      The engineer takes the implementation at face value and spends hours understanding the full complexity of the solution. The engineer reviews nitty gritty details of the code first rather than assessing the overall form and context of the work. In this case, the code gets checked in eventually in all its byzantine complicatedness. The codebase slowly degrades over time because complex code is harder to get right and less maintainable.

      I hope these examples illustrate some underlying principles of what “good” looks like. Totally agree it’s hard to pin down.

Leave a Reply to Jackson Gabbard Cancel reply

Your email address will not be published. Required fields are marked *