This book is about accelerating your career as a programmer. It is not about programming.
Moving up the ladder from a first or second job to a senior role requires a set of skills that coding boot camps and computer science degrees don’t typically cover and that programmers often have to teach themselves.
There are plenty of books that offer new ideas and technical concepts to help you write better code. You can find books and courses that cover the ins and outs of a programming language, and tutorials that show how to build something while learning a new language or framework.
But much of the work you do during your career will be planning, reviewing, strategizing, collaborating, and many other things that don’t involve coding. To excel in your career as a programmer requires soft skills that are different from your technical abilities. As you’ll learn throughout this book and throughout your career, the soft skills are often what set you apart from other programmers and increase the impact of your work. They will factor into your manager’s decisions when it comes time for a promotion. And the best part is that almost none of them will be outdated in a few years, even as the industry evolves.
The practice of programming may feel like an individual activity, but the process of building software involves collaborating with other people, both technical and nontechnical. While reading, writing, and debugging code will challenge you, possibly the hardest thing you learn over the course of your career is how to work effectively with other people. You learn how to compromise and collaborate with people that may have different personalities and opinions than you do. You learn how to communicate your ideas and listen to other people’s points of view. All these skills are needed in a senior role.
Unfortunately, there aren’t many books that teach these soft skills. Many of these skills are developed with experience. You’ll make mistakes along the way, and that’s okay, because everyone does. What matters most is that you learn from your failures and gain the wisdom to avoid those same mistakes in the future. And you may learn enough to pass that wisdom along to others so they can learn to avoid similar situations. In fact, that is one that sets a senior programmer apart from others—the ability to lift their team to greater heights.
I started my programming career at a small startup called Mertado, soon after they completed the Winter 2010 batch at Y Combinator. Nine months into my new role, we were acquired by Groupon to help build out their Groupon Goods platform soon after they had gone public. After the dust had settled, I was placed on the team that built the machine learning system to personalize 100 million emails sent to inboxes each morning. I was responsible for taking the personalized outputs from the MapReduce jobs, rendering the results in our HTML email templates, and performing multivariate tests on different audiences in order to increase the conversion rate, where a one percent increase meant millions of dollars in additional revenue.
It turns out that working at a small, ten-person startup is vastly different from working at a public company on a large engineering team. Not only was I exposed to new technologies, development workflows, build systems, and enormous codebases, I also got first-hand experience observing how high-performing teams deliver software at scale. I started to see how all of my coworkers juggled different tasks and priorities, and as I observed, I started to learn from them.
What I noticed early on was that they didn’t just sit there and code all day with their headphones on. Yes, my coworkers delivered clean and robust code at a fast pace—but they were good at the entire software development process. The most impactful engineers combine technical depth with a broad set of soft skills, people skills, and product skills.
I’ve made many mistakes throughout the course of my career. It took hard work and trial and error to learn how to navigate office politics, manage risk, and work well with others to deliver quality software. I had to learn most of these soft skills on the job and by observing others as I navigated my career.
But I wish I’d had better resources to prepare me for the obstacles on the path to becoming a senior software engineer. My goal in writing this book is to pass along the knowledge I’ve gained so far in the hope that it will help the next generation of programmers be team players and build fulfilling careers.
This guide is focused on providing junior and mid-level programmers the tools they need to excel in their careers—the journey from first full-time engineering job to earning a first promotion.
This book is primarily for individual contributors: it does not cover the broader topic of managing other junior and mid-level programmers—but engineering managers and senior engineers may still find some of the material useful for mentoring or sharing with their team members or direct reports.
New programmers. If you’re just starting to learn how to program by teaching yourself, or you’re enrolled in school or a coding bootcamp, congrats! You’re just getting started on a fun and exciting journey. While this book won’t teach you how to program, it will prepare you for what to expect when you land your first full-time programming job. There’s a lot to learn, so be patient and take things one step at a time. You got this!
Junior programmers. If you’ve already landed your first full-time programming role, nice job! You’ve proven that you can build programs and solve difficult problems, so now it’s time to focus on being a team player. You may already know some of the topics covered in this book, but it never hurts to reinforce those ideas and build good habits. You’ll be reading a lot of unfamiliar code and asking questions, so you may find those sections especially useful.
Mid-level programmers. If you’ve been working as a full-time programmer for a few years, you’re probably starting to get the hang of things. You may know your way around the codebase and be comfortable working on a team, so some of the topics covered in this book may already be second nature to you. This book will still be helpful if you use it to focus on honing those skills even further to solidify those good habits. The latter half of the book should be especially useful to mid-level programmers as you begin to make more impactful technical decisions.
Senior programmers, mentors, and managers. We all had to start somewhere in our careers, and by now, almost all of the information in this book should be familiar to senior programmers and programming managers. It’s easy to forget just how far you’ve come and how difficult it was to learn certain skills. This book offers perspective to experienced programmers and reminds them of areas they can offer assistance in when mentoring and managing junior and mid-level programmers.
This book is meant to be a resource for junior and mid-level programmers on soft skills required to excel as a professional programmer. It’s meant to be your career guide as you learn to navigate the workplace, from learning the lingo and how the business operates to working as part of a team producing quality software and real value for your customers.
The book is not necessarily designed to be read from cover to cover, so feel free to skip around to different sections if a topic seems particularly relevant to you at the moment.
My goal is to help you establish a personal roadmap to guide you as you start your programming career or reach that next level of responsibility. I hope this becomes a book you revisit regularly to review your progress and recalibrate your priorities for your next career goal.
Let’s look at what we’ll cover:
Growing Your Career. In the first section, you’ll start off by learning how and why you should set expectations for your career. You’re at the very beginning of a years-long journey to becoming a senior programmer, so it’s important to set some long-term goals to work towards.
What Makes You a Senior Engineer? In this section, we’ll dive into specific characteristics that differentiate a senior engineer from a junior engineer. You’ll gain a better understanding of what you should focus on if you’re working towards a promotion to a senior title.
You’re Not an Impostor. Next, you’ll learn that everyone deals with impostor feelings during their career. You’ll learn how to recognize and understand these feelings as well as ways to reduce them when you’re overwhelmed.
Working with Your Manager. You don’t have to be friends with your manager. But, they’ll have a big influence on your career, so it’s important that the two of you work well together. In this section, you’ll learn how to understand your manager’s style and align your goals so both of you can succeed.
How to Recover from Mistakes. Even the best programmers make mistakes. What sets the best apart is how they respond when things go wrong. In this section, you’ll learn what you can do when you make a mistake and how you can recover quickly.
How to Ask Better Questions. Asking good questions is a simple and effective way to supercharge your learning early in your career. Here, I share tips and techniques for learning as much as you can from your coworkers and for tapping into their experience.
How to Read Unfamiliar Code. You’ll read lots of other people’s code throughout your career, which will have a big influence on how you write your own code. In this section, you’ll learn how to get up to speed quickly in an unfamiliar codebase.
How to Add Value. One of your main responsibilities as a programmer is to add value for your customers and for your employer. In this section, we’ll cover specific ways in which you can do this.
How to Manage Risk. Another top priority for programmers is to identify areas of risk and manage them in a way that’s consistent with business objectives. We’ll cover types of risk common in software development and ways you can help mitigate them in your own role.
How to Deliver Better Results. At the end of the day, your job is to ship code and deliver value to your customers. This section offers specific things you can do to work efficiently and to increase your productivity when writing code.
How to Communicate More Effectively. Communicating well sounds simple but can be deceivingly difficult in fast-paced work environments. In this section, you’ll learn how to improve your speaking and listening skills to better convey your ideas and stand out among your peers.
Work-Life Balance. Life isn’t all about work, so in this section, we’ll go over the importance of creating a work-life balance that works for you. We’ll cover ways in which you can expand your horizons and prevent burnout that can affect your productivity and the quality of your work.
Asking for the Promotion. This is it. This is where you ask the big question to your manager. You’ll learn what you should do to prepare for this moment and how you should approach the conversation. At this point, you’ll be ready to take on more responsibility.
By the end of this book, you should have a deeper understanding of the soft skills required to succeed as a software engineer, along with a path forward for applying those skills as you work towards a promotion to a senior role. At that point, it’s up to you to put these ideas into practice and make it happen. So, with that said, let’s get started!
Key points are highlighted like this:
important An important note.
caution A caution.
confusion A confusion or reminder.
In addition, you’ll find examples highlighted:
exampleAn example or scenario.
doAn illustration of something that’s recommended.
don’tAn illustration of something that’s not recommended.
important If you’re reading this Holloway Edition of the book online, please remember you can add comments and suggestions. This will help the guide improve in future revisions, and your helpful comments will be published to assist other readers.
This book is only possible because of the mountain of support from family, friends, coworkers, and new acquaintances I’ve met through people involved with this book.
I want to thank my parents for their unwavering support, for always believing in me, and for providing the foundation for me to build a life and a career.
Thank you to my brother, Brian, for inspiring me to begin writing down my thoughts on how to help people build a successful programming career.
Thank you to all my current and former coworkers who have had an impact on me, big or small, throughout my programming career.
You’re here because you want to learn how to be a better software engineer. You may already know how to code, or you might still be learning your first programming language. But that’s not what this book is about. This book won’t teach you how to write cleaner code or architect better systems. While the ability to write elegant and scalable programs are important skills to have as a programmer, they alone do not make you a successful programmer.
This book will teach you everything else you need to be a well-rounded programmer—a team player who collaborates well with others, who communicates effectively, and who knows how to manage risk while delivering value to customers. These skills, called soft skills, become increasingly important as you climb the career ladder.
In fact, while many programmers reach a certain level of technical ability during their career, not all of them possess the soft skills necessary to have the greatest impact on a team. Simply put, these soft skills are what separate good programmers from great ones in the later stages of their careers. They will help you unlock new opportunities as you take on increased responsibility and accountability.
Unfortunately, many programmers neglect these soft skills during their early career because they’re laser focused on improving their technical skills. As a result, they often have to change their habits as they learn how to collaborate, communicate, balance trade-offs, and lead projects—and changing old habits can be hard.
You’ve probably already put some thought into the engineering path you want to take. Perhaps you’re learning your first programming language, or you’ve found a framework you like and have built a few projects with it already. That’s great, because that’s the first step to choosing your engineering path.
The engineering path you follow will determine your journey to increasing technical mastery of one or more technologies of your choosing. The technologies you decide to learn early on in your career may seem inconsequential right now, but they will have a drastic impact on your career.
In some cases, the technologies you chose to focus on will dictate which companies and industries you’ll apply to when searching for a job. On the other hand, if you’ve already landed a job, you’ll want to do as much as possible to become an expert in the technologies your company has invested in.
Let’s dig a little deeper into each of those scenarios.
At some point, you’ll need to decide whether you want to branch out and learn additional languages and technologies, or double down and become an expert in one or two specific ones. Programmers can be successful in either path, so it mainly comes down to personal preference and some careful consideration about where you want to take your career.
Let’s look at each path in detail.
A programmer who views themself as a generalist typically wears many hats and will have an intermediate-to-advanced knowledge of many different complementary skill sets. They may work with many different programming languages, databases, and platforms. Their range of skills allows them to collaborate across multiple disciplines to solve customer problems.
In the early stages of your career, you’re probably going to be focused on developing your technical skills first before thinking about any kind of leadership path. While it’s good to have a sense of where your career is heading from a technical perspective, it’s equally important to start thinking about your career from a leadership perspective.
At some point, usually after you’ve been in a senior engineering role for a while, you’ll reach an inflection point where you’ll need to decide if you want to stick with the technical track as an individual contributor (IC) or make the jump to the management track. There are excellent leadership opportunities in both paths, but it’s important to understand what those responsibilities look like as you think about the direction you want to take your career.
Here’s what the paths look like at a typical tech company.
Now that we’ve looked at what things to consider when thinking about your engineering path—whether to generalize or specialize, and options for your leadership path—it may feel like there are a lot of things to think about. There’s a lot that goes into software development, but you don’t need to decide all of these things at once.
It may be overwhelming to think about all of this right now, so it’s important to give yourself a reasonable timeline when it comes to advancing in your career, and to keep things in perspective when setting goals for yourself, because you have a long career ahead of you.
Some skills take years to learn and decades to master, so be patient and take things day by day. Continuous improvement is the best thing you can focus on right now, as that will give you a strong foundation you can build on. Small improvements every day will compound over time, and soon you’ll look back and be surprised at how quickly you’re progressing.
Think about your career as if you’re running a marathon and you’re just starting your race. You wouldn’t want to sprint to the finish line right now because you might burn yourself out. Just be patient, and take it one career milestone at a time.
Additionally, try to focus on running your own race. At this point in your career, you’re competing only against yourself, not others, so try your best not to put pressure on yourself if your peers are progressing in their careers at different paces than you are. Even though it may seem like you’re running the same race, each person begins at a different starting line and is running to their own finish line. It won’t do you any good to compare yourself to others because you’re not even running the same race.
caution Keep in mind that as you get promoted and move up the org chart, you will have to compete against others as the number of available roles begins to narrow. You’ll have to shift your mindset from competing against yourself to competing against others, and this is where the soft skills become even more important.
People learn at different rates, and what may come easy to one person might take weeks or months for someone else to grasp. Learning a new skill often requires you to change your way of thinking, sometimes forcing you to change how you approach a problem. While it might click right away for some people, try not to get discouraged if it takes you a little longer to learn a new technology.
You should be proud of every raise, promotion, job offer, or other career milestone regardless of how long it took you to reach it. These things take a lot of hard work—and more importantly, a lot of patience. Just focus on growing each day as a programmer and as a person, because you’re in control of your career and only you get to decide when you’ve crossed the finish line.
It’s a question that’s been debated for decades within the software community—what qualities separate a junior engineer from a senior engineer? In this section, we’ll take a closer look at this question and help you understand why the answers vary so greatly. We’ll also explore a few topics that are absolutely critical if you’re working towards a promotion to a senior role. By the end of this section, you should have a concrete idea of the differences between a junior and senior engineer. Let’s get started.
If you were to pull up your preferred search engine, enter the query “what is a senior software engineer?”, and hit enter, you’d be presented with hundreds of different explanations of what it means to be a senior software engineer.
It’s interesting that as programmers, we work in an industry that has self-organized around standards and protocols such as TCP/IP, HTTP, HTML, IMAP, SMTP, and many others that play an important role in a connected society. These standards provide a basis for which we all agree on something—a mutual understanding. And yet the truth is that there are so many different interpretations on how to define a senior engineer precisely because there is no standard definition for what is actually required in order to call yourself one.
The software industry is still very young when you look at it in the context of history. While other industries have formed consensus on what standard requirements should be met in order to do business or practice an occupation, we’re still learning the best way to deliver software reliably and efficiently. You don’t have to pass a licensing exam in order to write software professionally, you just need to demonstrate that you know enough about programming to pass an interview.
The reason for this ambiguity is partly because of the diverse opportunities within our industry. As programmers, we can work for small seed-stage startups all the way up to Fortune 500 public companies, and across almost every industry—energy, healthcare, finance, entertainment, and education, to name a few. So, when you really think about it, how should we standardize a common definition? A senior engineer’s role and responsibilities at a seed-stage SaaS startup are vastly different from those at a public healthcare corporation, hence we see different interpretations for what it actually means to be senior.
When you’re first starting out in your programming career, you’ll be fixing bugs and extending existing features to add new functionality. Most of what you’ll be working on will be determined by a product manager, your engineering manager, or a senior engineer. It’ll be up to them to determine most of the functional and technical requirements, and it’ll be your job to implement a working solution.
As you grow into a senior role, you’ll be faced with more ambiguity in the problems that you need to solve. There won’t always be a straightforward answer, and oftentimes there will be a number of ways in which you could solve a problem. It’ll be up to you to weigh the trade-offs and determine the best path forward, which may not always be the ideal technical solution.
Senior engineers are often asked to solve difficult technical problems when there isn’t always a good understanding about how to get there, such as keeping a user’s shopping cart updated in real time across both web and mobile devices. It’s up to the senior engineer to break the problem down into smaller, more manageable pieces, determine dependencies between the pieces, and put together a plan for building a solution. Junior engineers, on the other hand, often have a known path set out in front of them and are tasked with working towards a goal, such as making sure orders are processed successfully and inventory numbers are updated accordingly.
Dealing with ambiguity is what sets a senior engineer apart from a junior engineer. This partly comes down to experience, but it also has to do with problem-solving skills, creativity, collaboration, and good communication. It takes all of these skills to keep projects moving forward and finishing on time, and senior engineers learn how to leverage them in order to reduce ambiguity.
In addition to being able to cut through ambiguity to deliver results, senior engineers are expected to be accountable to others and themselves. They are responsible for project timelines and ensuring that the features shipped to production meet all of the project’s requirements.
Junior engineers sometimes blame the quality assurance (QA) engineers or other devs who reviewed their pull requests for not finding a bug in their code, rather than accepting responsibility for it being there in the first place. Senior engineers, on the other hand, accept that responsibility and take full blame for letting bugs slip through, even the ones that aren’t caught by peer reviews and QA engineers.
When senior engineers make mistakes, they treat their peers as teammates, rather than adversaries. Being able to accept responsibility for your mistakes and work with your team to identify and fix the root cause is a sign of maturity, and it shows that you’re ready for a senior role.
Managing time effectively is one of the common traits among senior software engineers, and it’s also one of the hardest skills. As you write more code and build up more domain knowledge, you’ll start to become an integral part of your team. You’ll become the expert on certain features and areas of the codebase, and people will come to you with questions about how something works or if it’s possible to extend something you wrote with new functionality. You’ll spend more time tracking down bugs, planning new projects, building out feature specifications, and possibly even helping to interview candidates to join your team.
Time management gets harder the more senior you get. Your team will become increasingly reliant on you to keep things moving, so it’s important to get things done while not wasting your time.
As a junior engineer, it’s good to be generous with your time, because anything you work on will help you learn. But as you prepare for a senior role, you’ll need to learn to be careful with your time because it’s your most limited resource. Senior engineers know how to work smarter, not harder, because they know that using their time wisely gives them leverage.
They may spend a day or a week planning, without writing a single line of code, because they know that getting the solution right on paper will save them weeks of refactoring later in the project if the design needs to be changed.
Programming is naturally a detail-oriented task. Take any programming language’s syntax for example—you could have a codebase with hundreds of thousands of lines performing complex data processing, but if you misplace one semicolon or forget to close a parenthesis somewhere, your program will grind to a halt. Even worse, your logic may be flawed even though the syntax is correct, which will lead to frustrating nights trying to figure out why your program compiles but doesn’t behave the way you expect it to.
Almost every aspect of delivering software requires focusing on details—things like defining requirements, reading other people’s code, writing correct logic, implementing thorough error handling, and analyzing logs and other structured data.
As professional programmers, we’re expected to prototype solutions and write applications to solve customer pain points. But it’s not enough to focus only on the default use cases and ignore error handling or how our users interact with our programs. Good engineers try to anticipate every way in which a program can fail, and then work to put safeguards in place to prevent those scenarios from happening.
And they’re not just detailed in the code they write. They bring attention to detail throughout the software development process. They pick apart the technical requirements and clarify any ambiguity, because they know that well-defined specifications aid them when it comes time to handle edge cases in their code.
It takes persistence, determination, and many years in order to perfect a craft, but in the case of Jiro Ono, a sushi chef made famous by the documentary film Jiro Dreams of Sushi, he spent his entire life in pursuit of perfection.
Always looking to improve, Jiro worked hard every day to improve all aspects of his craft, from sourcing better ingredients, to preparing his dishes, to delighting his customers with the highest quality sushi. He was so determined to deliver the best experience possible that he fixated on every aspect of the meal, even changing the orientation of the sushi on the plate if the customer was right- or left-handed.
These small improvements compounded over the years, and Jiro’s small 10-seat restaurant located in a Tokyo subway station, Sukiyabashi Jiro, became the first sushi restaurant in the world to receive three Michelin stars.
Although programming requires a very different set of skills than making sushi, writing software is also viewed as a craft, and as programmers, we are always looking to improve our coding skills.
There’s a lot that has been written about teamwork, and for good reason. When you have a group of people all working towards a common goal, you can achieve great things. Each individual member on the team brings with them a unique set of skills, and when a team is able to leverage the skills from one of their team members, everyone benefits.
Senior software engineers recognize that shipping software is a team sport. While programming may feel like an individual activity when you’re deep in the code, developers rely on one another to review their code, answer questions, share knowledge, and teach each other.
When software developers work together, they can achieve so much more than what each individual could accomplish on their own. When they build off each other’s work, fix each other’s bugs, and share their knowledge, a team becomes greater than the sum of its parts.
A senior engineer recognizes the importance of the team, and they identify and complete tasks that benefit the team, even if the work isn’t planned or assigned to them. They understand that sometimes being senior means taking on the mundane tasks that no one else wants to do, because it will help unblock others to complete more work. Their focus is always a team-first approach, and they strive to lift up all members of their team because they know that when it comes to software, we all share the same responsibility to keep the systems running and deliver as much value to our users as possible.
As companies hire, grow, and promote from within, they often need to make decisions about the requirements and responsibilities for each role, including each individual’s salary compensation. Job levels are a tool that many organizations use to standardize these decisions and explicitly define and document the responsibility level and expectations for each role at a company. Job levels are typically associated with pay bands or salary ranges for each level, and different companies structure their levels differently depending on their unique organizational needs.
So, why do companies utilize job levels?
Job levels allow organizations to be strategic with their hiring decisions and bring more consistency to the hiring process. Levels provide a helpful framework for how a company should hire, promote, and retain their talent, as well as providing a way to highlight specific areas for improvement, while developing their employees along their career growth trajectories. Additionally, job levels bring fairness and transparency to promotion decisions by providing a structured approach to identifying when an employee is ready to move to the next level with a promotion.
So, how can you use your company’s job levels to leverage a promotion?
Have you ever sat in a room and felt like you weren’t smart enough to be there? Maybe the conversation moved too quickly for you to follow, or perhaps your coworkers debated a topic you weren’t familiar with. It’s an uncomfortable feeling that every programmer experiences at some point in their career. When you start to doubt your own abilities and feel insufficient at your job, you’re experiencing impostor feelings.
exampleFeeling like an impostor can come on suddenly in a number of different situations:
You question your ability to complete a task you’re stuck on.
You feel like you don’t belong on a team or at a company because you’re not capable enough to follow along during discussions.
Chances are you’ve heard people talk about feeling like an impostor, although they probably referred to it as having “impostor syndrome.” While this phrase is commonly used, it’s misleading because it tends to oversimplify the issue, but it does help you easily communicate the feelings you’re experiencing. It also does a good job of capturing a feeling of being overwhelmed or inadequate that you may be struggling with. While this may seem like a good thing, there are some negative consequences that come from using the term.
The solution is not to label yourself as having a medical syndrome that needs to be treated; it’s to recognize your feelings so that you can work towards improving yourself and building confidence. Slapping a label on something you’re feeling doesn’t make it go away, but recognizing that feeling is the first step towards self-improvement.
Additionally, the term “impostor syndrome” tends to imply several things for some people:
You either have it or you don’t.
As programmers, we’re expected to know a wide array of things in order to do our jobs. On top of fundamental skills like writing code that compiles without errors, we also need to know how to design our programs to be future proof, how to write automated tests so we can be sure the code works as expected, and how to deliver results consistently and efficiently.
It’s easy to feel overwhelmed with the amount of knowledge required in order to complete our day-to-day tasks, in addition to answering questions from project stakeholders, defending our technical decisions during code reviews, and planning for the future.
There will be plenty of times throughout your career where you won’t know the answer to a question or won’t know what someone else on your team is talking about. It happens to software engineers of all levels, not just junior engineers. The thing that makes good engineers stand out from the rest is that they are humble and aware that they don’t know everything, and they use that knowledge to learn and grow.
exampleSituations that might bring on impostor feelings include:
We’ve all been criticized at some point in our careers, and it’s safe to say that it’s never a great feeling. It can be difficult to receive criticism, even if it’s intended to be constructive. Criticism can be a hit to your ego and sometimes leave you feeling lost and confused, especially when you feel so confident in your work.
Whether you like it or not, criticism is sometimes necessary in order to foster a healthy engineering organization and to maintain an organized codebase that can grow and evolve over time. As a developer, you’ll receive feedback throughout your career in many different areas, such as:
Code reviews. Other engineers may find issues with the syntax, logic, or readability of the code you submit for review.
Design reviews or brainstorming sessions. There is always subjectivity when it comes to architecting solutions to solve problems. Sometimes your proposed design will differ from your coworkers’ ideas, or they may pick apart your design.
As developers, we have to maintain incredibly complex mental models about how codebases work, and those models change continuously as new code is written, merged, and deployed to production. Over time it becomes harder and harder to recall what you worked on. When you think back on what you’ve built over the last few months, it may be difficult to remember everything you worked on. Days, weeks, and months go by, and you may not feel like you’ve accomplished a whole lot, which sometimes leads to impostor feelings. In reality, you complete a lot more work than you probably realize. The hard part is remembering everything you’ve done.
A simple but effective way to curb those impostor feelings is to keep a log of what you’ve worked on each week. Keeping track of what you’ve accomplished has a number of benefits:
If you’re ever feeling like an impostor, it helps to look back at all the features you’ve built, bugs you fixed, and your major accomplishments throughout your career.
When it comes time for your quarterly or annual review, you’ll already have a list of accomplishments you can refer to when asking for a promotion or a raise.
Your professional relationship with your manager is one of the most significant factors affecting your career growth. You are ultimately responsible for your own career, but your manager has more influence over your career trajectory than anyone else in your company, so it’s critical that the two of you work well together. They sit above you in the organizational hierarchy, which gives them power to make decisions that can affect your career, both positively and negatively. This relationship has far-reaching consequences, such as which projects you work on and the opportunities you’re given. Many say that your relationship with your manager is the single biggest factor that affects your job satisfaction.
Some managers are great to work with, but others may prove more difficult. No matter how good or bad your manager is, it’s your job to make the relationship work. Every professional relationship between a manager and a programmer is unique, and you’ll have to work hard to figure out what works best between the two of you. Your relationship with your manager will evolve over time, and you’ll have to continue to adjust and make changes to how the two of you work together.
Trust is an important foundation for working well with your manager. If you can’t trust each other, your relationship with your manager will break down and your job will be more difficult than it needs to be.
If your manager can’t trust you can do the job they ask you to do, you’ll miss out on projects and opportunities to grow and be promoted. If they can’t trust you’ll communicate openly and honestly about the status of a project, they’ll have no choice but to micromanage you to get the information they need.
So, how do you build trust with your boss?
The first step may be obvious, but it needs to be said—do your job. There’s no way around this. It’s table stakes for everything else discussed in this section. If you don’t do your job, you’re going to have a very difficult time building trust with your manager, so that should be your number one priority. It’s literally just doing what is asked of you according to your job description.
Everyone works differently. There’s no single way to maximize your productivity that works for everyone, and everyone has their own way that works for them when they need to get things done. This is especially true when it comes to managing people and projects.
Different managers have different management styles, so when it comes to working well with your manager, you’ll need to figure out what style they prefer. You’ll need to consider the following questions when determining how your boss prefers to work:
How do they prefer to communicate?
Asynchronous chat
Voice or video chat
Face-to-face conversations
How often do they expect updates from you?
Once a day
Once a week
As needed
Having a healthy relationship with your boss makes your job easier, but there will be times when the two of you aren’t on the same page. If your boss is overcommitted, overwhelmed, or even if they’re not the best in a certain area of expertise, you need to learn how to manage up in order to make the relationship work.
To start, you need to recognize the situation you’re dealing with. Perhaps you’re dealing with:
A boss that has been at the company for years while you’re just starting.
A boss that has just started while you’ve been with the company for a while.
You and your boss are both adults. You’ll each have your own way of doing things, and you’ll have your own opinions on how something should be done. Hopefully, you’ll be able to figure out a way to work well together, but sometimes the two of you will have different opinions on how to accomplish a task.
If you have to disagree with your boss, do so politely and in private.
caution Do not surprise your manager with news in public. Doing so may catch them off guard and make them look unprepared in front of their colleagues, or even worse, their manager. It’s possible your manager may interpret your actions as being disloyal to them.
Recurring one-on-one meetings are your opportunity to receive direct feedback from your manager about how you can be better as a software engineer. A common misconception among junior software engineers is that one-on-ones are meant to give status updates on their current workload. The conversations with your manager during your one-on-ones should be about career growth, not your day-to-day work. Don’t waste your opportunity by giving a status update about what you’re currently working on. You should be talking about higher level things than individual tasks.
These meetings are just between you and your boss, no one else. It’s precious time for you to be honest and talk about personal things. Try to avoid talking about things that can be discussed in the open with the rest of your team, because that’s not a good use of your time during these meetings. Your one-on-one is a chance to talk about the difficult things that you wouldn’t want to discuss in front of your teammates.
important This can be awkward and uncomfortable at first, but the more open and honest you are about your feelings, the easier it gets.
Just be honest. This is your opportunity to get things off your chest. You have a direct and uninterrupted line of communication with your boss for a short period of time, so make the most of it.
At some point in every programmer’s career, they’ll go through the inevitable “oh crap” moment when some code they wrote suddenly breaks in production. It happens to the best software engineers, and it’ll happen to you. No matter how many steps you take to mitigate risks, sometimes bad code will slip through the cracks and cause a catastrophic failure in production.
In some ways, this is a rite of passage on your journey to becoming an experienced software engineer, because you’ll gain valuable experience identifying, triaging, fixing, and recovering from an incident in a high-pressure situation.
Software engineers work on complex systems. It’s impossible to fully understand how each new code change you deploy will behave in a production environment. We can take measures to mitigate risks, but it’s impossible to avoid them. So, what can you do if you’re not able to completely steer clear of breaking code?
Good programmers accept that mistakes will happen. They don’t know when one will happen, but they know what to do when things do go wrong. The ability to stay calm and collected and work through the problem under pressure, especially when alerts are going off and logs are filling up with errors, is a sign of an experienced programmer. They move with urgency and without losing their composure, because their main priority is getting the issue fixed and dealing with the impact.
We can’t predict every dependency between our systems, or even all the dependencies between pieces of our logic in the same system. This alone makes it difficult to avoid introducing breaking changes, but it’s not the only thing that contributes to broken code.
exampleLet’s look at other ways the code you write may break.
Untested code. You may think it’s a small change and you don’t need to test it, or you may be in a hurry to fix a bug, so you put your code up for review as soon as you finish writing it. While you may think you’re working quickly, this is an easy way to introduce broken code into production because you didn’t take the time to actually test it. While your code may look correct at first glance, it’s possible your logic may have unintended behavior that you would never know about unless you actually ran it.
Unknown edge cases. The data you use during development and testing may be clean, structured, and made up of expected values, but production data is often messy and varies greatly. Your system will need to handle inputs and events from your users (or other systems) that you didn’t know about or account for when writing your code.
The above examples are just a few ways in which your code can break—the list keeps going. Murphy’s Law states that “anything that can go wrong, will go wrong.” As a programmer, it’s your job to identify all the scenarios in which your program can fail, and then to take steps to reduce the likelihood of those scenarios happening. In some cases though, your program will fail in unexpected ways that you never could have imagined, which makes it hard to plan for.
Here are more examples of ways that your system can fail. Remember, sometimes it’s not just the code itself but other pieces of the system that can fail too.
Bad logic
Unanticipated inputs
So, your code was deployed to production, and now things are getting thrown left and right. What do you do? It can be stressful, especially for someone that doesn’t have a lot of experience dealing with production outages. The errors keep coming, and you haven’t been able to identify the root cause yet. You don’t even know where to begin looking.
First off, take a breath. Panicking won’t do you any good here and will probably make the situation worse. So, the first thing you should focus on is staying as calm and collected as you can. As you get more experience working during production incidents, this gets more natural, but it’s easier said than done the first few times.
Next, try to be methodical with your approach to identifying the root cause of the issue. There might be a million thoughts racing through your head about what it could be, but if you don’t slow down, you won’t be able to think clearly. Slow is smooth, smooth is fast. It may sound counterintuitive, but by focusing your attention on one thing at a time, you can often move quicker than trying to do too many things at once.
Try to eliminate potential causes one-by-one. And keep notes as to what changes were tried and which possible causes were eliminated, including why. That will help avoid rework and help document the final resolution, which may come in handy during a postmortem.
Asking questions is a natural instinct in humans. In fact, it’s so ingrained in our DNA that we begin asking questions about anything and everything from the earliest days of our childhood. Kids are curious about how the world works, so they ask questions as a way to help them make sense of the things they see. They’re full of endless questions, but there’s one that is simple, yet so powerful at the same time: why?
Why is the sky blue?
Why do I have to eat my vegetables?
Why do I have to go to bed right now?
There will be times when you’ll hit a dead end with your code. Either you’re getting an error or your code just isn’t doing what you think it should be doing. It’s tempting to drop everything and ask a coworker for help, but you shouldn’t ask them without being prepared.
Knowing what to ask is often the hardest part. You’re struggling to get the code to work because you don’t have a good grasp on the problem you’re trying to solve, but where do you even begin asking for help?
A simple thing to remember is that you should be asking for advice, not a solution. Don’t expect your coworker to fix your bug or code your feature for you. While most people will be happy to help you arrive at a solution, no one wants to do your work for you.
When you ask someone for help, you’re asking someone else to take time away from their own projects to help with yours. Switching context back and forth is hard when working on something that requires deep focus, and you need to respect your coworker’s time if you want to build trust with your team. Try not to waste their time with a question that you can easily find by querying a search engine.
When you’re working on a new feature, a bugfix, or almost any project, you may not have all the information you need in order to complete the task. The devil is in the details, and an experienced senior developer knows when they need to ask the project owners to clarify small but important details before proceeding.
Sometimes, the small details won’t change the implementation much, but other times, a slight clarification to the project’s requirements could have major ramifications for the design and implementation of your solution.
Here are a few things to consider when you may not have all the information you need to move forward with a project.
At the beginning of this section, we discussed why children ask questions, and how it helps them connect ideas and form a better understanding of the world around them. In a way, most engineers also do this without even thinking about it. By asking the different types of questions you’ve learned about in this section—asking for help and asking for clarification—you’ll naturally learn things from the answers you’re given. You’ll learn why you should choose one software design over another, or why you should consider a certain edge case when you didn’t think it mattered.
In some cases though, you’ll just have curiosity for how something works or why something is the way it is. You won’t necessarily be asking for help or to clarify anything, but you’ll still have questions. In this case, you’re just asking a question for the sake of learning.
Sometimes it’s good to challenge the status quo and ask your teammates why something is the way that it is. In some cases, the answer may be underwhelming. You may receive an answer such as “well, that’s just how we’ve always done it.” In asking these questions, you’re challenging the other engineers to think through why they’ve always done it that way, and what they could do to improve a process or part of the codebase.
In other cases, there may be a very good reason for why something is done a certain way that you may not have realized. There may be historical context that you were unaware of because you joined the team after some important decisions were made. Perhaps you never would have known this had you not asked the question in the first place.
It’s a common misconception among students and aspiring programmers that professional software engineers spend all of their time writing new code and building new systems from scratch. Many new developers face a rude awakening when they land their first job and find out that this is far from the truth. In fact, aside from planning and documenting, most of your early-career time will be spent maintaining, extending, and fixing bugs in legacy codebases. You’ll be tasked with making small- to medium-sized changes to the code that your team members wrote, and you may sometimes find yourself working on code written by someone who is no longer with your company.
Working on legacy code gives you the opportunity to get experience working on a mature codebase. In a way, it can be seen as a rite of passage on some teams because it allows you to get familiar with complex abstractions and business logic. There will be design patterns, coding standards, and test cases that the previous programmers established and that you’ll be able to follow when making your changes. Following established patterns when learning a new codebase will help you focus on the behavior of your code without getting too bogged down in details about the design and architecture of the code.
This is especially true when you join a new team, because you’ll be learning the nuances of the codebase and the business rules while getting up to speed. Your manager will probably start you off with some small bug fixes and enhancements before you graduate to larger projects. In many cases, it would actually be counterproductive for you to jump in and make large changes to a codebase that you don’t understand very well. That would be very risky, especially as a junior software engineer still learning the best practices.
Before you can run, you need to learn how to walk, which is why it’s so important to develop skills for reading and understanding unfamiliar code. The quicker you can read code and understand its intended behavior, the quicker you’ll be able to make changes, fix bugs, or identify edge cases that weren’t considered.
First things first—figure out where the program starts. To execute a program, the loader (typically an operating system) will pass control of the process to a program’s entry point, which begins the run-time execution of the application.
The entry point is the place where a program begins, and it’s important to know what the program is doing once it begins executing the code. When you follow a program from the entry point, you’ll be able to follow the application as it boots up and configures itself to do whatever work it was designed to do.
Some programming languages may enforce conventions for how or where a program should start, while others may give more freedom in how a program is executed.
C-family languages, such as C, C++, and Rust, and JVM languages such as Java contain a predefined function called main.
Your integrated development environment (IDE) is one of the most important tools you will use when reading code. Your IDE gives you a set of tools to analyze and manipulate your codebase, so choosing a good IDE will help you navigate the code efficiently.
When reading code, you’ll want an IDE that lets you jump to a function definition. This feature is crucial for learning and studying a new codebase, and most modern development environments should support this functionality. This allows you to jump through the codebase to see where a function is defined, which is useful whenever you come across a function call you’re not familiar with.
This feature gives you the ability to step through the codebase and follow the execution path, which helps you build a mental model of the code and what it’s doing. It’s a great way to explore unfamiliar code and can help you get up to speed quickly.
When you jump to a function, take note of the file name and directory structure where the function lives. You can learn a lot about the structure of an application just by observing how things are organized.
Development tools aren’t perfect, and sometimes our IDEs won’t be aware of the entire structure of the codebase. Perhaps you have some code that is called dynamically or your language supports metaprogramming, both of which can be difficult for IDEs to understand. In some cases, you may need to use other tools like grep
or git grep
instead, which give you the ability to search your codebase for specific patterns such as variables, functions, class names, or constants.
For example, you may come across a function called findNearbyLocations()
while reading some code. In order to find all locations where that function is called, you can run the following command from your projects root directory:
$ grep -r findNearbyLocations *
That command will recursively search all directories in your codebase and output the lines where the term “findNearbyLocations” occurs. With this information you can pull up each file to see how that function is used. When you can see where a certain term is used throughout the codebase, you gain a better understanding of what the program is doing.
When you’re reading through code, you may want to know when it was last changed. If you’re using git
, there’s another tool called git-blame
, which displays the last revision and the author who most recently modified each line of a file that you’re interested in. This is useful for determining when certain functions were last modified and by whom.
Use the command below to view the last revision and last person to touch each line of a file:
$ git blame <file>
confusion It should be mentioned that git-blame
’s intentions are not to actually blame someone for writing a bad piece of code, and hopefully you won’t use it for that purpose. It’s simply another tool at your disposal for understanding the code and how it evolved.
While git-blame
shows you who made the most recent changes to each line in a file, sometimes you might be more interested in the history of a single file and how it’s changed over time. Git offers a useful tool called git-log
that lets you inspect the commit logs for a given file.
Use the following command to view a reverse chronological list of commits where changes were made to a file:
$ git log <file_path>
This will give you a full history of all commits to the file so you’ll be able to see who made changes to it and, more importantly, when they made those changes. Just as with git-blame
, you can use git-log
to find the developers who made the most recent changes to a file, because they should be the ones you reach out to first.
As you’re reading through code, you will need to hold a mental model of the data in the system and how it is manipulated as the business logic is applied. Some code may be easy to follow, but you may find yourself deep in the codebase without any idea what the data looks like when it reaches a certain function. In these situations, it’s sometimes useful to lean on your logging system to print some data to your log files so that you can inspect it.
Add a few log statements with data you’re interested in. This could be certain values of variables or object properties, or it could be an arbitrary text string that will give you some useful information if you see it in your logs. Either way, setting log statements throughout your code is a quick and easy way to get a snapshot of what your data structures look like at a point in time when the code is executing. Sometimes, a well-placed log statement can reveal a bug you’ve been tracking down, or it can expose certain things that help you understand what the code is doing.
All programmers rely on logging to gain insight into what their code is doing, so don’t feel like it’s the wrong way to debug your code. Even the most experienced engineers rely on logging when they’re developing new features or tracking down a hard-to-find bug.
Occasionally, you’ll come across code that you won’t understand no matter how many log statements you add. Wrapping your head around confusing code is frustrating, especially if you’re trying to figure out how some piece of data is being manipulated. While you may be able to figure it out with enough log statements, it’s messy to add them all over your codebase just to piece together what’s going on. Sometimes a debugger is the better tool for the job.
When you distill a program down to the simplest form, it’s really just taking some inputs, manipulating the data structures, and producing output somewhere. To really get a grasp on how everything works, you need to understand how the data changes as it moves through the system. While it’s helpful to read through code and build a mental model of what the data structure looks like, it’s sometimes easier to visualize the program with a debugger and observe how the data changes as it moves through the system.
If you have a debugger configured, you’ll be able to see what the data looks like at each breakpoint you set. As you step through the debugger, focus on the data and how it changes as you step in and out of functions.
An underrated technique for studying an unfamiliar codebase is to read through the automated tests. While it’s not the most glamorous part of the codebase, there’s an enormous amount of institutional knowledge stored in the test files. Automated tests are where past and present developers have codified the specifications the application is expected to operate within.
Most young developers don’t realize that a mature test suite will show you exactly how a program should perform, because each test that’s added to the suite should be designed to validate a specific part of the program for a specific scenario. As you read through the test cases, you’ll see what edge cases the tests handle and what the expected outcomes should be.
Additionally, the assertions in automated tests will show you what the expected output should be when you call a function. Assuming the tests are passing, this gives you a clear picture of how the system works and what application states you should expect.
Codebases are complex, plain and simple. A codebase’s complexity can be roughly estimated as proportional to the number of engineers who have contributed to the codebase multiplied by its age. As more developers contribute to a codebase over time, the complexity continues to increase.
It’s almost impossible to understand every line of a codebase, especially if you didn’t write it yourself. In fact, even a solo developer who has written every single line of a codebase will forget the details and context of parts of the system over time. They may come back to a file they wrote months ago and struggle to remember how it works.
Setting the right expectations now will help reduce your frustrations in the future. It’s okay if you don’t understand how every line of code in a program works.
As developers, it’s our job to form a mental model of how a program works, and how the pieces fit together to form a complete system. You have a limited capacity in your brain to hold this mental model, and eventually, you’ll hit a saturation point where you’re not able to hold the entire mental model in your head at once. As you learn new parts of the system, you may forget other parts you haven’t visited in a while. It’s natural and common among all software engineers.
As software engineers, we often get caught up in the day-to-day details of our job without even knowing it. We make hundreds of decisions each day, such as the architecture of our programs, what to name our variables, when to add a new function, which ticket to work on, how to design our database schema, and so much more.
While these are all fun decisions to make, they require us to consider the long-term implications of our choices, debate the pros and cons, and ultimately settle on a solution. There are so many choices to make that sometimes we fail to see how an individual decision fits into the grand scheme of things. We lose sight of the bigger picture because we’re so focused on the details of the current problem we’re trying to solve.
As you gain experience and progress in your career, you’ll learn how your decisions fit into the overall system, and your decision-making skills will evolve. You’ll start to comprehend the trade-offs between solutions and understand the positive and negative impacts your decisions could have on the business. You’ll start to understand the implications of changing one part of the system and how it affects other parts. Eventually, you’ll improve your ability to know which decisions add the most value to the customers and the business, and to prioritize those decisions above the others.
A strong quality of senior developers is that they’re able to identify on their own where they can add value to the business. So, how do they do that? Let’s take a look at different ways in which you can add value, both with code and without.
An important thing to remember as you work towards a senior developer role is that your job is not to build perfect software, which is a common misconception among developers when they’re starting their careers. Yes, writing clean, reliable, and bug-free software is an ideal outcome, but ironically, that’s not what you were hired to do. Your real job as a software engineer is quite simple—to build value for your company. Sometimes that means shipping code that isn’t fully polished, and sometimes it means taking your time to get your design right before shipping a solution. In the end, it’s all about shipping code. The more code you can ship, the more value you can deliver and the more valuable you become to your employer.
It’s essential to understand the business and the industry you work in because you can’t deliver disruptive value unless you have a deep understanding of your customer’s pain points and how your products solve them. It may take a long time, sometimes even years, to fully understand the complexities of a business or an industry, but that domain knowledge is needed in order to deliver value. When you’re just starting a new role, you’ll only have limited experience, but there are still ways you can build value for your business that don’t require years of institutional knowledge, and it’s all about improving productivity so you can ship code faster.
There will always be one thing that you have full control over, and that is your own productivity. You may not fully understand the business context behind the changes you’re asked to make, but at least you are able to control how quickly you can ship code and deliver those changes to customers.
Think about your typical customer for a minute. When a customer buys your product or service, they’re looking to solve a specific need, whether that’s to save time or money, perform a difficult task, automate something, or even provide entertainment value. What they care about the most is that their needs are met by your product—that’s what makes your product valuable to them.
What they almost never care about is how your product is built. They don’t care what language you used or what data structures, algorithms, or application architecture you chose for your codebase. They may not even care about all the features that are available in your product. What they do care about is that your product solves their pain points, which is why it’s important to focus on the customer when writing software. Sometimes using a new framework or using fancy data structures is fun, but that doesn’t always add value for your customers. Solving a customer’s problems always adds value.
exampleHere are some good questions that will help you focus on your customers:
How am I adding value for the customer right now?
It’s satisfying to see your code in the hands of customers and providing them value, especially when they pay for your product. It’s even more fulfilling to write code that has a high impact, especially when it comes to helping your business grow. If you’re lucky, the code you write may become necessary to the success of the business, at which point it becomes business critical.
Business-critical code is typically complex because it’s required to handle multiple use cases for many different customers. The complexity grows over time as new use cases are discovered and new customers are supported. However, business-critical code doesn’t necessarily equate to state-of-the-art code. Surprisingly, the most profitable code is sometimes rather outdated and boring. The most important part is that the code works, is reliable, gets the job done, and is in the hands of the customer.
All business-critical code becomes legacy code over time. It’s just a fact. When you have a codebase that’s necessary to the success of the business, making changes to the code can be risky if not planned carefully. Small improvements add up over time, but you probably won’t be refactoring half the codebase to a new architecture. As they say, “If it ain’t broke, don’t fix it.”
As long as the critical systems are in place and still making money for the business, there will always be a need for people to maintain and support those systems. Depending on the expertise and domain knowledge required, you may be able to leverage your knowledge of the codebase for job security and a rewarding salary.
While somewhat counterintuitive, a common path to adding value is to ship code that reduces cost for your customers or for your company. If a product solves a customer’s pain point better, faster, or cheaper than if they built it themselves, the customer benefits from a return on their investment. When a customer purchases your company’s product, they’re doing it in order to free up capital or other resources. This allows them to shift resources to help grow other parts of their business. It’s a win-win for both your customers and your company.
While saving your customers money is a great way to add value for your company, writing code that reduces cost for your employer is another opportunity for you to have a significant impact. Operational efficiencies are vital in highly competitive industries, as that can make the difference in whether the company makes or loses money in a given quarter or year.
Businesses are incentivized to control their costs and increase their efficiency as they work to produce more goods and services with less resources. This usually means building internal automation tools, scaling existing infrastructure, and streamlining processes to gain efficiency. While you may not get to work on projects like these right away, there are things you can focus on that help reduce the cost of delivering software, such as writing clean and modular code.
Clean, modular, and extendable code adds value by reducing the amount of time it takes to make future changes to the codebase. Business requirements always change over time, and that requires frequent modifications to the codebase to support the requirements. Let’s look at some ways in which you can add modularity and extensibility to your codebase so you can ship more code with less cost.
While some people may embrace a well-defined process that provides structure, it may bring a negative connotation to others who value autonomy and independence. At some point, all programmers feel the frustration of dealing with “red tape,” or the lengthy process to gather the necessary approvals to move forward with a decision. But processes aren’t always a bad thing, as they provide a tremendous amount of value.
Whether you work for a large Fortune 500 enterprise, a development agency, a small scrappy startup, or even freelance for a living, you will follow processes every day and probably even develop new processes. Building a process provides value because it allows you to standardize a set of steps to complete specific tasks. By doing so, you are able to increase efficiency and scale your throughput by training others to follow the process.
When you take a set of steps, which may need to be done in a specific order, and formalize them into a process that can be followed by anyone anytime that task needs to be completed, you add value by creating consistency. You’ve defined a standard way of doing something that can be completed the same way every time, regardless of who is performing the task.
Assuming you’ve documented your newly formed process, you unlock numerous advantages. First, you can reference the steps in the process at any time, which can save you in the future if you forget how to perform a task you haven’t done in a while. Sometimes a process only needs to be performed on a monthly, quarterly, or yearly basis. As long as you have your process documented, you can always reference the documentation and be confident you’re performing the steps correctly every time.
While most of the ideas in this section so far have involved coding, there are other ways to add value without writing any code, such as writing documentation. Often overlooked by both young and experienced developers, the ability to write clear and concise documentation will set you apart from the rest of your teammates.
Transferring knowledge through written sources has been used by almost every civilization that’s ever existed. There’s a reason it’s so valuable, and writing is a skill that anyone can do and anyone can learn.
As a business matures, knowledge is gained. That knowledge is valuable, and it probably took a lot of effort on someone’s part to build an understanding of a specific problem, a customer pain point, or a nuance of the industry. When you work hard to solve a problem, fix a bug, or develop a new feature for a customer, try to document what you learned on an internal knowledge base.
It may seem like it’s extra work, but it adds significant value even if it goes unnoticed at the time. For starters, you can reference this in the future, as mentioned earlier. You may forget why you made a certain decision or chose to solve a problem in a specific way, and it’s helpful to be able to look back on your notes to figure out the context behind a decision.
As you can see, there are so many ways you can add value to make yourself, your team, and your company more efficient. It’ll take a little creativity at times, but the opportunities are there if you can find them.
The techniques outlined in this section only scratch the surface of ways in which you can add value, so you should constantly be looking for new opportunities. In doing so, you’ll prove to your manager that you’re a valuable asset to the team and that you’re constantly putting the team first while trying to improve the system. A rising tide lifts all boats, and you have the power to drive improvements within your organization. Now it’s up to you to find those opportunities.
Code-first vs. Product-first (thezbook.com)
What is value? (dwyer.co.za)
In the previous section, you learned that one of your primary responsibilities as a professional programmer is to create value. We looked at a number of ways you can create value, both with and without writing code. In this section, you’ll learn about a second major component of your job, which is to manage risk.
Before we jump into the details of how to manage risk, we need to take a step back and answer a fundamental question: what is risk?
Risk in software development is the probability for uncertain events to occur that can have a negative impact on an organization or other entity. In essence, risk is the probability for bad things to happen. Shipping buggy code, lack of communication, changes to consumer behavior, and missing deadlines due to poor project planning are all kinds of risk that can harm your organization. Risk comes in all shapes and sizes, and each one has the potential to cause harm in one form or another.
As software engineers, we’re focused on building scalable software systems, but what many developers lose sight of is that we’re also responsible for keeping those systems up and running and ensuring a seamless experience for our customers. Software has become a critical component of everyday life, and so managing risk has become a critical component of software engineering.
Unfortunately, because a lot of risk management comes down to experience, you won’t learn everything there is to know about it in this section. What you will learn, however, are the different types of risks so that you are aware of what to look out for in your day-to-day roles.
Technical Risks
Poor code quality
Poor technical decisions that prevent you from adapting to changing requirements in the future
Lack of documentation and knowledge sharing
Poor technology choices
Poor code performance
Scheduling Risks
Poor project estimation
Requirements that are not finalized and keep changing
Lack of visibility into the work that is in progress and what has been completed
Project scope creep
Operational Risks
Poor communication
Lack of proper training
Lack of effective processes or procedures
No separation of concerns, or checks and balances
Data breach due to poor security practices
Let’s look into some of the major contributors to technical risk that you should look out for in your day-to-day role.
Effective engineering is about shipping software quickly while preserving your ability to make additional changes quickly in the future. The goal is to move fast without putting yourself in a situation you’ll later regret. In essence, we need to build software that meets the current requirements for our customers but leaves enough flexibility to easily extend the code to handle additional requirements in the future.
Seems easy, right?
People often compare the ability to program a computer with superhuman powers. Sure, it may seem like that at times when you see programs do things that are seemingly impossible or futuristic, but programmers are only human. There’s a limit to how much the human brain can comprehend at any given time, and we often find that limit when learning a new codebase or managing a large project at work.
There are some projects that are so incredibly complex that they cannot be built or fully understood by a single individual. To complete these projects, a team of developers needs to work together to build individual components that fit together to build a complete system.
Large software projects are inherently risky. They take up huge chunks of the engineering organization’s time and resources in an effort to build something that no one fully understands and that no one fully knows will succeed or not in the end.
Failure is only the opportunity more intelligently to begin again.Henry Ford*
This whole section has been about managing and reducing risk, but an unfortunate fact of life is that it’s nearly impossible to completely eliminate all risk involved in writing software. With any moderately complex software, things will go wrong at some point. And sometimes things will go very wrong. Failure is inevitable, and at some point, you’ll be pulled into an incident. When these incidents happen, it’s important to use them as learning experiences and take the time to reflect on the preceding events in order to better understand how and why they happened. In doing so, you’ll be able to learn from your mistakes and make any appropriate changes to prevent them from happening again in the future.
The best thing you can do in the aftermath of an incident is to capture and document what happened leading up to, during, and after the incident so that you can reflect, learn, and share that knowledge with others within your organization. This process is known as a postmortem.
An incident postmortem should bring people together to discuss and document the details of an incident:
While progress may seem linear from the outside, behind the curtains it is sometimes a chaotic and sloppy process to get where you’re trying to go. Things never go according to plan all the time, and you need to learn to adapt to changing requirements and external influences.
As professional software developers, it is our job to master the art and science of delivering quality software on time and within the project requirements. To do this, we often reflect on our current processes and continually improve the way we deliver software. This act of continuous reflection and improvement is enabled by a framework called a retrospective.
The idea behind the retrospective was originally published in 2001 as the twelfth and last bullet point of the Agile Manifesto, which states that:
At regular intervals, the team reflects on how to become more effective, then tunes and adjusts its behavior accordingly.
We all want to write great code and feel like we’re contributing to the success of our team, but it takes more than just writing clean code or finding the perfect abstraction. Even as an individual contributor, there will be things you need to manage, such as your time and productivity. You’re directly responsible for making sure you’re using your time wisely and keeping your output high, but that’s easier said than done. Some days, you may feel like you’re getting a lot of work completed, while other days, you’ll feel completely stuck and not sure what to do next.
Delivering results is all about finding your personal groove that’ll allow you to churn through tasks and ship some actual code on a regular basis. That doesn’t mean you should lose sight of producing quality work, however. Your first focus should always be on quality code. If the code isn’t up to your team’s standards, then you should absolutely spend additional time cleaning it up so it’s ready for production. There’s no point in moving quickly if you’re shipping half-finished code that’s full of bugs—you’ll just be shifting the burden on to the rest of your team to find, fix, and maintain the defects in your work.
To be a productive software engineer, you should strive to continuously move forward and make progress toward building value and managing the risks involved in shipping code. So, let’s dive in and look at what you can do to increase your productivity and deliver better results.
The first point to remember is that perfect software doesn’t exist. There will always be multiple ways to solve a programming problem, and each comes with its own trade-offs. Some may be faster or scale more efficiently, while others may be easier to read and understand, maintain, or extend. Rarely will there be a perfect solution to a problem because there will always be compromises that come with each option.
There’s a model of constraints called the Project Management Triangle that states that the quality of work for a given project is bound by three things: the budget, the deadline, and the scope of a project. While it’s possible for the project manager to trade between these constraints, they’re only able to optimize for two of the three. Programmers and engineering managers commonly refer to this model when they state that software can be good, fast, and cheap, but the catch is that you can only choose two.
Fast and cheap projects tend to produce lower-quality software
Fast and high-quality software will be expensive to produce
If you ever talk to a great programmer, you’ll find he knows his tools like an artist knows his paintbrushes.Bill Gates*
As programmers, we have thousands of tools available that help us perform our jobs, and choosing the right tool for the job can increase your productivity tenfold. But a lot of powerful tools go underutilized because the programmer doesn’t understand how to use them to their full potential.
Before you can truly be productive as a programmer, you need to develop a deep understanding of the tools at your disposal. You should strive to regularly add new tools to your toolbox, but with each new tool you add, be sure to take the time to learn its advantages and disadvantages so you can know when (and when not) to reach for it. No tool is perfect for all situations, so don’t fall victim to relying on just one tool because you’re comfortable with it. Every tool has its strengths and weaknesses, and a good programmer knows when it’s best to use each one. These are the tools with which you will build great things, but you can’t do that until you know them inside and out.
As programmers, we commonly compare writing code to crafting software. Almost every line of code is handwritten for a specific problem you’re solving, so it feels natural to consider programming as a craft. There are quite a few similarities between programmers and other types of craftsmen like plumbers, electricians, and carpenters. Craftsmen are able to look at a problem, devise a solution, and use their tools to solve the problem. Sounds a lot like programming, right?
Once you’ve mastered your tools, the next thing to focus on is your own process for producing software. Every programmer approaches software development differently, and what works for some people may not work for others. There are several development methodologies and ways to solve problems, but I’m going to share a process with you that I’ve found works for a lot of programmers. It’s simple and straightforward, and it helps you stay focused on the important thing—delivering working software. So, here’s the process:
Make it work, make it right, make it fast.
That’s a quote from Kent Beck, the creator of extreme programming and one of the original signatories of the Agile Manifesto. Kent has shaped programming in many ways, and this technique will hopefully shape the way you approach programming. Following this simple pattern will help you manage the complexity of your own solutions and prevent you from trying to do too much all at once.
Let’s dive into it a little more.
In the earlier section about managing risk, we explored the importance of planning ahead when working on large projects. That idea also applies to smaller, individual tasks you work on as well. When you pull a new ticket to work on, what you should not do is start coding right away, even if you think you may know how to solve the problem. It’s a trap a lot of developers fall into, and it’s potentially a risk because you could be wasting your time and effort implementing the wrong solution.
If you don’t have a good understanding of the problem, the requirements, and the acceptance criteria, you run the risk of shipping code that doesn’t actually solve the issue or that may not be the optimal solution.
So, what should you do when you start a new task?
Read the task description and take note of any requirements. It’s sometimes helpful to make a checklist of requirements so you can be sure you’ve checked them all off before submitting your code for review.
If you’re working towards a promotion to a senior role, your manager may tell you that they’d like you to “take more ownership” of certain projects or tasks that your team is responsible for. To many people, “taking ownership” sounds vague and ambiguous the first time they hear it. Take ownership of what, exactly?
There are a lot of differing opinions on what taking ownership means, so if your manager encourages you to do so, the best thing to do is to simply ask them what taking ownership means to them. It’s always good to clarify their expectations to make sure you don’t miss something they are expecting you to do.
A developer taking ownership of something commonly means they are taking on more accountability for the success of a certain project or task. They are not necessarily the only one responsible for the success or failure of a project, but they will have a bigger influence on the outcome.
exampleA junior engineer will typically work on tasks as part of a larger project. The requirements for those tasks were probably defined by someone more senior than them, either a senior engineer or a manager, and the junior engineer is just implementing a solution to meet those requirements.
It’s a popular stereotype that programmers are often introverted, reclusive, and lacking in the social skills department. Even though this doesn’t accurately reflect the industry as a whole, it’s been perpetuated in anecdotal stories of old-school hackers in the early days of Microsoft, Apple, Facebook, and many more tech giants. There’s a common theme in Hollywood movies in which the genius coder hacks into the mainframe from his dark basement, surrounded by empty pizza boxes and energy drinks. But while the act of programming has always been between a human and a machine, the software products used by people throughout the world are a result of collaboration and communication between many different people. Shipping software at scale is a team effort, and it takes good communication skills to deliver quality products.
Over the years, we’ve gotten better at building software. We’ve learned from our mistakes; invented new algorithms, software patterns, user interfaces, and development methodologies; and built languages and tools that have increased the speed and quality with which we can produce software. As the industry changes, so has the role of programmers. It’s no longer enough to be technically competent—communication skills are just as important as technical ability and will continue to play a critical role in software production for years to come.
Although the act of programming is mostly an individual one, working on a team with other technical and nontechnical people will be one of the hardest things you do in your career. Human nature is incredibly complex and unpredictable at times, and as programmers, we’re required to interact with many people throughout the software development process in order to perform our jobs.
It may be uncomfortable at times, especially for junior programmers because you’re learning how to write code at an advanced level while simultaneously learning how to interact with other programmers and business stakeholders. There will be times when you’ll struggle to communicate your ideas clearly, and it’ll be frustrating. And there will be times where you’ll be intimidated because you can’t get your thoughts out while all eyes are on you. We deal with abstract thinking quite often in our industry, and it’s sometimes hard to convey those ideas to others in a way that helps them understand your exact point of view. Being able to convey technical ideas clearly and concisely takes good communication skills, and being able to communicate clearly is a skill that can be learned over time, but it requires practice.
Words are powerful, and you can hurt people deeply with just words alone. All it takes is a few select words to ruin professional and personal relationships that you’ve worked for years to build. It may sound a bit silly that “be good to others” is advice that will help you in your career, but when smart people with lots of passion work closely with one another, it’s easy to forget. Difficult decisions get made every day, at both the business and technical levels, and sometimes people come out on the losing end of those decisions. Sometimes your ideas won’t be chosen, or someday you may need to make decisions that affect people’s careers.
Words have consequences, and it’s important to choose the right words and do your best not to hurt someone’s feelings. Words can create harm to other people, and they can create conflict with your coworkers.
One of the most important things to remember is to be aware of your emotional state when communicating with others. You may be pulled into an incident that wasn’t your fault, or you may be participating in a heated discussion about the best design for a new system architecture. Regardless of what it is, you should always act and speak with empathy and professionalism. Keeping your composure when tensions are high is not something many people will notice, but losing your cool under pressure is certainly something that everyone will notice.
It’s not just about staying calm under pressure, either. It’s also about the tone you use in your conversations and that you use with other people, regardless of their seniority or job function. All of these variables affect how you should convey your thoughts if you want to get your point across and position yourself so people will take your ideas seriously. It starts with yourself, and that may be hard for some people to grasp. The sooner in your career that you focus on building rapport with your coworkers, clients, and customers, the easier it will be to gain support for your ideas. And it starts with awareness of who you’re talking to and how you’re talking to them.
Understanding the audience you’re communicating with is an important principle to keep in mind for effective communication. Knowing who you’re speaking with and their level of understanding about a topic will often dictate how the conversation will play out. Are you communicating with your boss, another programmer, a nontechnical coworker in another department, or an external client?
Depending on how technical your audience is, you may need to change how you explain certain topics. You might be able to discuss the details about API schemas, HTTP status codes, and how CORS requests should be handled between your backend and frontend applications with your fellow programmers, but a customer success representative or a marketing manager may have no idea what those topics mean. Sometimes it can be difficult to explain technical topics to nontechnical people, but at some point, you’ll find yourself coming up with analogies to explain a complex technical concept to someone who isn’t as technical as you are.
We deal with a lot of abstraction in our day-to-day jobs and deal with things like entities, instances, classes, interfaces, modules, and so many other concepts that are hard to articulate and explain to other people—sometimes even other programmers. Even though these concepts may make sense in your own head, finding the right words to verbalize your thoughts is sometimes difficult.
The most important thing to keep in mind in these conversations is to respect your audience, especially if they aren’t able to follow along when talking about technical concepts. The last thing you want to do is to be condescending because they don’t understand a complex technical topic that seems like second nature to you.
Once you’ve determined who your audience is and how you should approach the conversation, the next thing to be aware of is the channel you’re using to communicate. Whether the conversation takes place in person or through a written form of communication such as chat or email will determine how you approach the conversation.
The first channel we’ll dive into is written communication. As a programmer, you’ll be reading and commenting on a lot of code reviews throughout your career, and how you communicate your thoughts and ideas in writing can determine how well those ideas are received by your coworkers.
Code reviews are often one of the poorest areas of communication between programmers, which is unfortunate because it’s also one of the most important. Constructive comments from senior developers are one of the best tools to help you become a better programmer because you’re receiving direct feedback on how you can improve your code and your logic. Whether it’s more concise syntax, bringing clarity to your logic, ensuring maintainability, improving performance, or handling edge cases you didn’t think about, the act of having someone else peer review your work will improve your technical skills.
Speaking in front of a group of people can be very uncomfortable, especially for programmers. In fact, public speaking is one of the most common and stress-inducing fears there is, regardless of which profession you’re in. Almost all people experience anxiety before they have to speak to an audience, so you’re not alone if your nerves get the best of you.
While you may never need to speak in front of your entire company, you may find yourself in one-on-one conversations, team meetings, or larger all-hands meetings where you’re asked to speak on a certain topic. Improving your public speaking skills has many benefits and will help you be more effective at your job.
Let’s take a look at some things you can do to improve your speaking skills, whether you’re talking to one person, a small group of people, or a large audience.
Most people assume that communicating is all about how you write and speak to other people, but that’s only half the story. Communication also requires you to listen to other people’s thoughts, ideas, and concerns, and that’s equally as important for collaborating and working well with others.
Just as it can be frustrating when you feel like you’re not being heard, your teammates, coworkers, clients, and customers will also feel frustration if you don’t listen to what they have to say. Building rapport with others requires mutual respect between all parties, and everyone’s thoughts should be taken into consideration with equal weight. Other people’s opinions matter just as much as yours do, so make sure to listen to what they have to say.
So, what can you do to become a better listener?
Not all meetings are created equal. While your daily stand-up meeting may not seem too important, you will be in other meetings where crucial decisions are made. Depending on the topic of the meeting, it may be worth your time to prepare so you have an idea of what you want to communicate before you need to. That may involve scanning your project management board to remember what you worked on yesterday, reading through the codebase to refresh your memory about how a particular component works, or reviewing documentation for potential third-party services.
You may be called upon in the meeting to give your opinion or your input on how a particular part of the system works and how easily it can be extended. If it’s not fresh in your mind, it may be hard to give a complete answer during the meeting when everyone is relying on your input. By preparing ahead of time, you will be able to give an answer confidently so that important decisions can be made.
It’s also good to go into meetings with a list of predetermined questions you’d like to have answered. Don’t assume that everyone is on the same page about how easy or hard some change will be, or how the change should be made. Oftentimes, other people haven’t considered a solution you may be asking about, so asking the question can be helpful to others as well as yourself.
Finally, it’s good to keep a notebook and write down your thoughts and questions before starting the meeting. Conversations happen quickly in meetings, and if you try to keep it all in your head, you may not remember everything you wanted to bring up. Writing down notes also helps organize your thoughts, and you can cross things off your list as they are discussed.
Did you ever play that game called “Telephone” growing up? It’s a game where kids stand in a circle and one player whispers a sentence to the person next to them. The second player then repeats the message to the third player, and so on. When the message reaches the end, the last player announces the sentence that was whispered to them and compares it to the original sentence from the first player. Almost always, the two sentences are completely different due to each player interpreting and repeating the message with slight differences to the next person. With each iteration the message becomes less like the original.
The same thing can happen in professional settings as well, even if it’s unintended. If possible, try not to rely on someone else to pass your message along to the intended recipient, because it may not be communicated exactly as you intended it to be. Sometimes though, you may not have an option, such as if you need to convey important information up the management chain to the executive team. In general, the more people your message passes through, the higher the chance it will be misinterpreted by the receiver.
If possible, send a chat message, an email, or speak to the recipient directly rather than communicating through a chain of people. If you must pass along information through others, try to follow up with the recipient and confirm they got your message. It may seem trivial, but it’s yet another habit you can build now that could save you from headaches in the future when collaborating across teams and organizations.
Good communication is about being able to convey your ideas in ways that are properly received by your audience. It’s simply not enough to assume that just because you said something people will understand your ideas. You may not always be able to get your point across, which can be frustrating as a programmer when it comes to conveying technical ideas to your teammates.
Additionally, just because you tell someone something doesn’t mean it’s no longer your responsibility. As programmers, we’re prone to the bystander effect when it comes to the maintenance and operations of our systems. Individuals are less likely to take responsibility for something when there are other people present, because they assume someone else will step up to the plate and take care of what needs to be done.
don’tYou: “It looks like the build server is about to run out of disk space, which will block deployments and prevent tests from running on pull requests.”
Later that day, the build server runs out of disk space.
If you stick with programming long enough, you’ll eventually be a part of some emotional discussions. As programmers, we take pride in our craft, and it can be easy for individuals to get attached to certain solutions or architectural designs. You’ll deal with conflicting views at some point in your career, and emotions may run high.
It’s okay to disagree with your teammates, but how you handle yourself will speak volumes about your character and how your teammates view you. In fact, healthy debates are a sign of a high-functioning team, but the discussions must be respectful. While it’s good to debate the pros and cons of different designs and algorithms, it can be bad if things turn from a civil conversation to a full-blown argument.
In rare cases, passionate developers may get into tense arguments over which solution is the better approach. It’s possible that each approach has its strengths, weaknesses, and trade-offs, and that both developers are correct. No solution is perfect, and that’s okay.
If you find yourself in a heated discussion and you sense that emotions are running high, the best thing you can do is to keep the conversation as civil as possible. Take the higher road if possible, which sometimes means making compromises. It may even be best to table the conversation and walk away to let everyone cool off. You can always pick up the conversation again at a later time once people have the opportunity to reflect and think things over some more.
While it may be difficult to realize when you’re just starting out, poor communication skills often contribute to programmers plateauing in their career. As a programmer in a senior position, you will lead technical projects and mentor younger developers. To continue on the trajectory to staff and principal engineering roles, you’ll need to learn how to build support for your ideas and work cross-functionally with nontechnical people across your company. And if you choose to go down the managerial path, good communication skills are even more critical, as you’ll be managing projects and people constantly.
Complex software systems cannot be built by one person alone. Modern-day software solutions require multiple people, both technical and nontechnical, to collaborate and deliver products that meet evolving customer needs. Successful teams consist of a broad set of people with diverse backgrounds and skill sets, and the ability to connect, collaborate, and solve real problems with different people is a rare skill that is often overlooked by programmers.
Once you reach a certain technical level, everyone will have the necessary skills to solve the problems at hand in some way, but not everyone will have the communication skills to convey their ideas and gather feedback when they need to. The bottom line is that the higher up you advance in your career, the more you will stand out if you are an excellent communicator. The best programmers communicate with empathy and listen to what others have to say, and those who communicate the best will be the first to advance when it comes time for a promotion.
As programmers, we spend a lot of time in front of a computer. It’s not uncommon to go a full day staring at pixels on a screen as you click and type away. There’s a lot of pressure from employers to work long hours to reach the quarterly and annual goals set out by the management team, and it always feels like there’s too much work and not enough resources. The deadlines are tight, but we have to ship this quarter!
There are competing interests between employees and employers that may be hard to understand early in your career. When you’re young, you’re just happy to have a job and a good salary. But as you grow more experienced and progress through the different stages of life, your priorities may change.
Your employer, whether you like it or not, is motivated to run a streamlined and efficient business. Unfortunately, your employer’s goals probably don’t align with your long-term goals. Your company is incentivized to squeeze every ounce of productivity out of you while paying you as little as possible. Businesses operate on margins that they are naturally incentivized to increase by keeping costs low.
On the other hand, as a young programmer and individual contributor, your incentives are a bit different. Your goal is to maximize your salary, thereby increasing your quality of life, all while working as little as possible. Who wouldn’t want to make more money while working less?
You sell your time to your employer in exchange for money in the form of a salary. That might sound weird at first, but this is true for most people who work for a living. For people earning an hourly wage, it’s pretty straightforward: The number of hours they work directly correlates to the amount of money they make. More hours equal more money.
exampleLet’s look at some numbers:
Hourly wage: $50 per hour
Earnings per week: 40 hours x $50 per hour = $2,000 per week before taxes
A common misconception is that the more hours you spend in the office, or working from home late at night, the more work you’ll get done. While it may feel this way, it can actually have the opposite effect and lead to a negative impact on the quality of your work.
Working longer has diminishing returns, because at some point your brain will hit a wall where you’ll start to drift and lose your ability to focus. A 60-hour workweek is not the same as two 30-hour workweeks. While it may feel like you’re getting more done in half the time, it may be lower-quality work.
Instead, focus on working smarter and more efficiently during your workweek so you can get all your work done in 40 hours. Distractions and context switching can kill your productivity.
exampleHere are some examples of what you can do to stay focused:
Sometimes, you’ll find yourself working on a problem towards the end of the day and it’ll feel like you’re making good progress. You’ll want to keep the momentum going and will feel like working a little late to wrap things up. You’ve almost got your code working; just a few more lines of code and everything should compile without errors.
At some point, you need to find a good stopping point and just call it a day. For your own sake, it’s better to close up your laptop and unplug at the end of the workday. You can always pick up where you left off tomorrow, or next week, so don’t put too much pressure on finishing a task before heading home for the night. The work will always be there tomorrow.
It’s a marathon, not a sprint, so you need to set stopping points and take breaks from the computer. Good software takes years to build, so you’re never going to get it all done in one day or one week. Rome wasn’t built in a day, as they say.
We’re never done building software. There’s always something that can be improved, whether it’s fixing bugs for more reliability, implementing a faster algorithm or a better user experience, or reducing the cost of our infrastructure. There will always be more work to be done, so don’t put so much pressure on yourself to stay late and finish what you’re working on.
Writing software for work can be fun. You get to use cool technologies, and you get paid to solve tough technical problems. But writing software for fun can also be satisfying. When you’re at work, you don’t get to make every single technical decision, but when you work on side projects, you have a blank canvas. You can build whatever you want, however you want. It’s refreshing, satisfying, and frustrating all at the same time. Experiment and try new things, and don’t worry if the code gets messy because you don’t have other engineers peer reviewing your work. You’re able to cut corners in order to get something to work quickly, and this is where your creativity really shines, because there’s no risk of failing.
The excitement you get when you take an idea in your head, build it with code, and see it come to life is hard to describe. Lots of developers enjoy it so much that they’ll work on their own projects outside of work. It’s easy to get immersed in these projects because coding often doesn’t feel like work. We do it because it’s fun and we love the challenge of problem solving.
But it can be hard sometimes. Not because you can’t solve a problem, but because it often feels like there’s a stigma in our industry if you’re not working on a side project or contributing to an open-source project, especially when you’re applying for new jobs. There’s pressure to work on side projects so that you have some work to show a potential new employer, especially if you’re just getting started in your career and don’t have a lot of professional experience.
It’s completely okay if you don’t have any side projects or any open-source code you feel proud of to show off. You shouldn’t feel any pressure to contribute to the open-source community. If you do, that’s great, but don’t feel like you’re any less of a developer because you don’t code in public.
We’re all human, and we all need meaningful interaction with other human beings. It’s right there, sandwiched in the middle of Maslow’s hierarchy of needs. After our physiological and safety needs have been met, humans have a need for interpersonal relationships and a feeling of belongingness. This social belonging that we all strive for can come from friends, family, or a significant other.
As you learn to build a work-life balance that works for you, it will be important that you find time to break from the digital world and work on forming new friendships and relationships. And it’s equally important that you nurture your existing relationships with friends and family. We’re social creatures, and it’s good for our mental health to unwind with people we care about.
If you find yourself in a new city or feel like you’re lacking friends at any point, it’s up to you to make an effort to change that. Try to get out of your comfort zone a bit and meet new people. It’s extremely hard at first, but the more you do it, the more you’ll feel comfortable with it.
exampleHere are some ideas for meeting new people:
Programming is mentally taxing, but it also has a big impact on our physical health. You may be able to get by on pizza, energy drinks, and sleepless nights when you’re young, but as your career develops, you’ll need to put more focus on taking care of yourself in order to stay sharp. Your health is crucial to your well-being, and issues with your health may contribute to issues in your career and personal life.
If you take care of your diet and your physical health, improvements in your physical and mental health will follow. A few changes in your lifestyle can snowball into daily habits and routines that can pay dividends well into your future, and it doesn’t necessarily take a big time commitment each week to see results.
exampleImproving your diet and physical fitness will:
Increase energy levels
Reading is a great way to unwind at the end of the day, and it’s an easy way to avoid staring at a screen before going to bed. There’s nothing better than getting lost in the pages of a book that you can’t put down.
It doesn’t matter what kind of books you read; the only thing that matters is that you’re reading. In doing so, you open your mind up to new ideas, new characters, new feelings, and new ways of thinking. You can get lost in a fictional world with vivid scenery and a protagonist, or learn about the history of a famous figure that changed the world. You can improve your confidence with a self-help book, or even expand your skill set with a good technical book. Just pick a book or a topic that sounds interesting to you and start reading.
The hardest part is actually finding the time to read. For busy professionals, good times to read are in the morning right when you wake up, or at night right before going to bed. Try to find time in your schedule that works for you. The good thing about books is that you can take a break and pick up right where you left off, so even if your schedule is busy, you can still read when you’re able to find some time.
The more you read, the more you’ll come to realize what you enjoy and who your favorite authors are. Writing well is a difficult skill, and when you find an author you enjoy reading, they can take you on journeys you never thought possible.
We all need time away from work to unwind and relax. There’s no better feeling than closing up your computer on Friday afternoon after a long week. The weekend has arrived, and you’ve got a few days off to do whatever you want. Time to get out of the house and explore your city.
It’s exciting to find a new restaurant you like, a new park with a great view, or a hidden gem within your city. What’s even better, though, is traveling to a new city where every restaurant, park, or public space is waiting to be discovered.
Traveling to new destinations can be fun, relaxing, and inspiring, and sometimes stressful, but don’t let that stop you. Everyone should travel because it opens you up to new experiences and challenges you to get out of your comfort zone. You’ll need to plan ahead, make decisions on the fly, stay organized, and get to places on time in order to make your connections. Not all of these skills translate well to your professional career, but they give you good experience and help build confidence that you can solve problems on your own.
Traveling for an extended period of time helps to clear your mind so you can come back to the office feeling refreshed and ready to jump back into your work. It helps break up the monotony of your job when the weeks start to blur together. An upcoming trip will give you something to look forward to, and you’ll have memories and stories to share when you get back and are ready to jump back into work.
It’s entirely up to you to create the work-life balance that’s best for you. No one else can help you do that, so you’ll need to figure out what kind of balance you really want. If your current employer’s values and policies don’t align with the work-life balance that you’re looking for, it may be time for you to look for one whose does.
If there’s one piece of advice you take away from this section, you should always remember that you are a programmer by trade, but that should not define who you are. It’s not healthy to spend all of your time in front of a computer screen typing into a text editor. That’s not the way we were meant to spend our lives, so get out of the house and away from the keyboard as much as you can.
You won’t regret it one bit when you’re older and look back at the memories you made along the way. There’s more to life than just work, so have fun and make it a life worth living.
Work/life balance will make you a better software engineer (codewithoutrules.com)
We’ve covered quite a bit by now, and it’s okay if it feels overwhelming. You’re not expected to know all of these things right now, and it’s impossible for someone, even a senior developer, to be an expert on every topic covered in this book.
If you take what you’ve learned throughout this book and put it into practice each week, you’ll come to a point where you’ll be confident in your technical abilities and ready to ask for the promotion to a senior role. Asking for a promotion can be daunting, but if you feel like you’re ready to make the jump, it’s important to start having the conversation with your manager.
It may sound easy, but it’s harder than a lot of developers realize. You’ll be putting yourself out there and asking your manager to evaluate your technical abilities and your soft skills. If you’re feeling vulnerable, that’s normal. After all, you’re putting your career trajectory in the hands of someone else. Of course it’s nerve-racking!
In most cases, it will be up to you to get the conversation started. Yes, your manager should be thinking about the career development of their developers, but that’s not always the case. You shouldn’t assume that the business will automatically reward you for doing your job well. Sometimes your hard work may be recognized, but there’s no guarantee anything will happen automatically. Sometimes it takes a little nudging to get the ball rolling.
First off, it’s important to do your homework. You’ll want to get familiar with your company’s process. Every company handles promotions differently, and the process may differ depending on the maturity and size of your company.
Informal promotions. In smaller companies, it’s common for the managers to have direct authority over deciding who gets promoted. The managers may meet with each other and present the candidates they feel are most deserving before coming to an agreement on who should be promoted.
Semi-formal promotions. In growth-stage startups and midsize enterprises, a semi-formal process is common. The leadership team will begin to add some structure in an effort to standardize and encourage fairness in the decision-making process. The managers may still meet together to discuss potential promotions, but the candidates are evaluated against certain criteria, rather than individual managers’ opinions.
Formal promotions. More formality is common among public companies and large established enterprises, and in some cases, it can be a very long process. Candidates are evaluated against well-defined criteria for each level of the job ladder. You’ll most likely be asked to put together a self-review and potentially gather reviews and recommendations from your peers. Your manager will also write their own review of your performance. There will often be a committee of senior engineers and engineering managers that will evaluate your reviews and recommend a promotion if they feel you meet the bar.
It’s common for companies to promote employees who are already performing at the level they’re being promoted to. The actual promotion is a recognition that your work output is exceeding expectations at your current level, and it’s a nod from the leadership team that you’re ready to consistently deliver results at the next level.
So, in order to assess yourself, you need to determine how you’re doing in regard to what your manager expects from a senior engineer. This is much easier if you’re in a company that has a clearly defined leveling framework. It’s a good idea to read through the expectations for your current level first. Take notes on each criterion in your current level and give yourself a grade for how well you think you’re meeting that expectation.
confusion In almost all cases, leadership will expect you to perform very well at your current level in order to even be considered for a promotion at all. If you’re not meeting expectations at your current level, it’s going to be very difficult to meet them at the next level. Additionally, in some places you’ll be expected to already be performing at the promotion level, not just at your current level.
It’s important to be honest with yourself during this step. Writing down that you’re exceeding expectations for every criterion at your current level doesn’t help you at all. No one is perfect, and there is always room for improvement. You’ll be disappointed if you get your hopes up only to hear from your manager that there are still some areas that you need to work on.
Even if you’re not required to put together a formal self-review of your performance, it’s still a good idea to do it anyway. You’ll be able to use this to build a compelling case for why you think you deserve a promotion, and it will give you some good talking points when discussing the promotion with your manager.
Back in the You’re not an Impostor section, we talked about keeping a log of all your previous accomplishments in a notebook or notes app. This is the perfect time to pull up that document and review everything you’ve accomplished in the last 12 months, because that will give you plenty of ideas.
What should you write down?
Examples of successful projects. Think of the highest-impact projects you’ve worked on and stress the importance of the role you played in making the projects successful.
Building relationships in the workplace is always important, but especially when it comes to asking for a promotion. First and foremost, you’ll want to get your manager on your side, because it’ll be nearly impossible to get a promotion without the support of your manager.
How do you do that?
Do your job well. If you’re not meeting expectations for your current level, it’ll be hard to convince your boss that you deserve a higher salary and more responsibility.
Ask your boss to explain the promotion process at your company. This will let them know that you’re interested in advancing your career, but there’s no pressure to actually ask for the promotion yet.
Once you’ve put in the work to prepare and you feel like you’re ready, it’s time to ask for the promotion. To be clear, asking for a promotion is not a one-time conversation. Rather, it’s an ongoing conversation between you and your manager about what you need to do to be considered for the promotion. Very rarely will you be promoted on the spot, so it’s going to take some time and hard work to get across the finish line. Don’t expect things to happen overnight. Asking the question is just the first step to get the ball rolling on the process. So, how should you ask?
exampleOne way to ask for a promotion:
“I’d like to be considered for a promotion to a senior software engineer. I feel like I’ve demonstrated that I’m ready based on my recent performance, but I know there are still some areas that I can improve. I’d like to start an ongoing conversation with you to identify what I need to work on in order for me to reach the next level. What do I need to do to show you that I’m ready for the next step?”
The goal is to ask for the promotion, but not demand it. Humbleness goes a long way here, so it’s good to acknowledge that you know there are still some areas where you can improve. The idea is to work with your boss to put together a roadmap for what you need to work on to get to a point where they’re confident in your abilities and comfortable going to bat for you when submitting their recommendation for your promotion.
Once you’ve got the ball rolling and have a plan in place with your manager, it’s up to you to put in the work to show your boss that you’re serious about the promotion. Set weekly goals for yourself to work on the areas that your manager would like to see you improve. Write them down and review your progress regularly, like at the start and end of each week.
Some things your manager expects of you won’t be easy. You’ll be forced out of your comfort zone, and you’ll be asked to do things you’ve never done before. You may need to make important decisions, whether they’re technical ones or choices about how to handle certain processes.
You may not always make the right decisions, but the important thing is to learn how to think logically, creatively, and collaboratively with the rest of your team. Being a senior engineer is about taking on more responsibility and putting the team first, and your boss may set you up to gain experience in making bigger decisions before you actually get promoted. If you can demonstrate that you’re able to make decisions and lead within your team, you’ll be able to show your manager that you’re ready for the promotion.
If you take what you’ve learned throughout this book and put it into practice each week, asking for the promotion shouldn’t be that intimidating. The hard part is actually applying what you read here to the real world. Not everything is as black and white as it’s made out to be, but the learning curve is where you grow from a junior engineer to a senior engineer.
By now, you should have a much deeper understanding of what it takes to be a senior software engineer, and you have a roadmap for what areas to work on to prepare for your next review cycle. If you’ve learned something new from this book, that’s great! That means I’ve done my job. My hope is that this won’t be the last time you pick it up. I’d encourage you to revisit any section in the future if you need a little refresher or you’d like to refer back to any tools or techniques you learned along the way.
In Growing Your Career, you learned about the different career paths available to you, whether you choose to pursue the individual contributor path or the management path, and which one may be the best path for you. And don’t worry, you have plenty of time left in your career to make that decision, so there’s no rush right now.
We covered what differentiates a senior programmer from a junior one in What Makes You a Senior Engineer, along with what areas you should focus on developing in order to demonstrate that you’re ready to perform at the next level. These qualities take time to build and some trial and error to get good at it, but in the end it’s worth it.
In You’re Not an Impostor, we discussed impostor feelings. You learned to remember that everyone deals with impostor feelings, even the senior- and staff-level engineers, and management too. Hopefully, you picked up some techniques for how to handle those times when you’re feeling insufficient, and how to use it as a learning opportunity to fill in your knowledge gaps.