What Makes a Senior Software Developer?

By Bevan Mardiros

What is valuable to a software development company in senior developers? For this post, first I will list the ways that a senior develper can provide value, and then detail how this value can be demonstrated, especially by distinguishing a senior from a junior developer.

It must be noted that these categories are interconnected, and the recognition of this fact is itself a component of what can set a senior developer apart. For example, although developers should independently analyze the overall development process, seek to improve it, and proactively identify problems and solve them, this must be done within a collaborative atmostphere, so that the organizationally-determined priorities are respected, or else initiative may result in conflict and waste. Where possible, I will also point out interconnections between the different elements listed above.

For all statements below, these are simply my opinions, informed by my experience, observation, and occasionally things I have read. They are not absolute truth, and it is very possible for reasonable people to come to opposite conclusions based on their own experience.

Initiative

A major component of what can set a senior developer apart is their ability to indepedently analyze the development process, identify sources of waste, and anticipate problems. This may involve identifying a problematic module and suggesting it be refactored, identifying a security flaw, adopting a new tool, writing a script to automate a manual process, etc. Whereas a junior developer will typically work only within an existing system, completing only the tasks assigned, and only within the scope described, a senior developer should be able to adapt to a particular development process, while maintaining a critical attitude. As mentioned above, it is important that this be done collaboratively, and issues brought up, and their resolutions argued for, and the work inserted into the project plan; no one should take on major tasks without informing team members. There are some exceptions. Generally, refactoring should be considered a part of normal development work, and a senior should expected to independently identify suboptimal code within a module and correct it prior to working within that module; though larger refactoring projects must be discussed. Major security flaws or critical bugs are another example. It is okay to identify such issues and immediately begin rectification, setting aside other tasks, as long as the team is notified, if the problem is such that any objection to immediately prioritizing the work is unlikely.

Initiative connects to the other elements, because your ability to evaluate better options will scale with your knowledge of alternatives. So a senior developer, experienced with a modern development process, when transfering to another team, could hardly avoid bringing that modern process with them, such as suggesting adoption of linting, formatting, version control, CI, etc. if they are not already present (while being respectful and understanding of the team's other members and their perspectives), whereas a junior developer is more likely to simply integrate into the new teams practices.

Initiative is difficult to demonstrate in the moment; if events occur which demonstrate initiative, then your should type up the story so that you can tell it if it becomes relevant.

Wholistic technical competence

This category covers familiarity with tools and best practices (or opinionated practices) across the development process and the development stack. The DevOps handbook advocates for teams with "T-shaped" developers: those who are very experienced in a small number of fields, but which have substantial understanding of many fields. Understanding in these other fields will of course be shallower than in one's specializations as no person can be an expert in everything, but having such breadth allows a developer to avoid tunnel vision: "to a hammer, every problem looks like a nail". To a pure specialist (as the handbook puts it, an "I-shaped" developer) it is easy to make mistakes by not considering how a problem could be solved better by a different technology, even if they are the best person able to implement it in the selected technology. For example, a common error of a junior developer, would be to make the "late-processing" error by using an existing DB query function, but performing a complex backend (or worse frontend) processing operation on it, or filtering it after fetching. The result is inefficiency, as writing a new database query would most likely produce a solution that would run far faster, and would avoid transmitting superfluous data over the network.

This covers broad knowledge of the tech stack within an application, but the same is true more broadly - it is necessary for a senior developer to understand most or all of the tech within an application, but also containerization, orchestration, how to write good automated tests, best practices in the development process (though these will tend to be subjective), automation, deployment pipelines, monitoring, and cloud architecture. Further, a senior developer should be opinionated. Within any of the above categories, they should be aware of multiple alternative practices & technologies, and be able (and all too willing) to argue for their favourites using facts, and in reference to the explicit requirements of the project (and not their own aesthetic preference). Other opinionated developers will inevitably disagree; it is difficult to avoid having ego play a role in such disagreement, but by being careful to base the discussion on facts and having all parties be open to different ideas, the best option will tend to rise to the top. Not everyone will always be convinced, which is fine; concensus is nice but we must also often defer in the end to specialization, or experience, or hierarchical authority, etc.

Specialized technical competence

Specialized competence is extremely valuable; it is required in order to create optimal solutions, diagnose complex problems, develop quickly or reliably (if you have an excellent process you may even do both, whereas juniors will produce obfuscated buggy code, and do it slowly). Specialized knowledge allows one to train others in a given technology, or to outline the pros and cons of multiple solutions to a single problem. Specialized knowledge is also required to evaluate whether others have similar knowledge. This can also lead to a catch-22 in hiring: if you need someone with specific specialized knowledge then the first indication that a candidate lacks such knowledge may occur only after they are hired; when they fail to solve the enterprise's problems.

Mentoring

An essential task for a senior developer is mentoring. Mentoring is the main method by which junior developers rise to the competency of senior developers. There are other methods, especially in startups where it is common for tasks to be assigned beyond what a developer might otherwise be considered qualified for, and where initiative plays a far larger role in the direction of the organization. In such a "sink or swim" situation, the developers may rapidly gain competency because there is simply no alternative; certain tasks need to be done, and the experience pool of available developers is extremely limited. There may not be senior developers to guide the juniors but the developers must nonetheless do their best to build an effective process and develop the minimum viable product so that cash can eventually flow. They will make many mistakes in the process, and in identifying and correcting these mistakes the developers will become battle-hardened and skilled. This is limiting in the long term though, and may result in developers who have lopsided skillsets; they may be extremely competent in some areas, but lacking in others.

In a more advanced enterprise, critical tasks are more likely to be done by qualified developers, limiting junior's exposure to the possibility of making costly mistakes. The result is that juniors, if they are to advance, must be deliberately mentored. If senior developers do not specifically aim to share their knowledge and develop both wholistic and specialized technical knowledge in juniors as well as train them in effective development practices, then the junior developers' skills may stagnate over the long term. This phenomena is sometimes referred to as "1 year of experience 10 times", as if an individual does not continually push their limits and learn, then their years of experience may not translate into a qualitative change in their competence.

Some practices I have found effective in mentoring is:

Many of these can be done informally, or combining them. For example, if during peer programming a junior says something that reveals a knowledge gap, then the mentor should take the time to explain in detail whatever the junior may be missing, and possible assign some readings; either a book, or article, or official documentation.

When a mentee comes to the mentor for assistance, it can be worthwhile to put preconditions. Ex. asking: "what solutions have you tried so far?", and "what documentation or forum posts have you consulted about this thing?". This will teach effective problem solving techniques while also encouraging the junior to at least attempt to solve the problem independently. This is important for learning, since even if you could solve a problem in 5 seconds, it may be better for the organization in the long run if the junior takes an hour. Don't emplace to many requirements though, and yield if they seem tired or frustrated. It is important that developers feel their are productive, are contributing, and are making progress, so use your better judgement. Another approach during pair programming is to ask questions like "what state would you expect the program to be in at this point? Why would you expect that?". This will teach the junior to reason about software and to reconsider their assumptions. This is much more useful than simply saying "I see your bug on line 276, fix it like this." The problem will be solved, but nothing has been learned.

Organization

A senior developer will have a number of responsibilities that they will have to balance. This is to an extent a good thing, and unavoidable, but we must also keep in mind the confusion or over-complexity in one's job description is one potential source of inefficiency, as is overwork and excessive concurrent tasks. Although these problems, if they are present should be addressed, a senior developer should also be able to handle such situations temporarily while also recognizing the root problem and attempting to address it. That is to say, if the developer is overworked, or if their job description has too many areas of responsibility, then this should be escalated in the organization, but until it is fixed the senior must nonetheless be effective in their work; which requires effective personal organization and time management. Note that there is a difference between having many responsibilities and having excessive concurrent tasks. The latter is inevitable for a highly competent individual who can contribute in many ways, but the latter refers to having many things which must be worked on at the same time. This results in inefficiency due to context switching. So while one may have multiple responsibilities, one one task should be in progress at any moment. Refer to "The DevOps Handbook" for more info on the wastefulness of excessive in-progress work.

Even though only one task should be in progress at any time, it is still useful to keep a list of tasks in general, organized by area of responsibility and urgency. There is much discussion to be had about how such a list should be organized, or the benefits of any specific platform, but there are some pitfalls I have noticed:

Planning

Effectively planning and tracking the work of multiple people in accord with the priorities of a larger organization is very difficult. There are various methods that server to mitigate this difficulty. Sprint planning ensures that only small periods are planned in detail. This can be effective, as it avoids wasted time which may result from changing requirements and priorities, however I have also seen some anti-patterns in sprint planning:

Its also useful to use tooling to assist with planning. Example include:

Design

See "A Philosophy of Software Design".

The goal of design is to minimize complexity. "Complexity is anything related to the structure of a software system that makes it hard to understand and modify the system". Complexity is caused by dependencies and obscurity, and its symptoms are change amplification, cognitive load, and unknown unknowns. This is all form the book.

Aside from what the book lists as the many, many methods of reducing complexity, I have found the following are useful:

Collaboration

Effective practices

Pitfalls include

Concerns with collaboration:

Communication