What I Learned In My First Two Years as a Software Engineer
University and the Workplace
It was 2015 and I was a student at the University of Florida. During that time, I studied under a professor who, for what was probably the hardest class in the department, would assign multiple team based projects throughout the semester. At the end of each project, the professor would evaluate each student individually. When the next project came around, this professor grouped the best students from previous assignments together, and the worst students on their own teams. By the end of the semester, each student either fought their way into a strong team and succeeded, or ended up failing on a team full of low performers. It was beautiful. The strong were not forced to carry the weak, and the weak could either get strong or die. This environment could be aptly described by the word meritocracy. This system rewards the most talented students and allowed the students who didn't work hard to sink with their own ship. I loved it.
A year later, I graduated. I was energized, idealistic, and ready to make my mark on the field I had spent the last four years studying. After an internship, I received an offer for a position as a software engineer at a large company with a great reputation. I walked in on my first day, eager to become a great software engineer.
I started on a project with a crippling lack of resources. We were building a web application that did what most web applications do: expose some data and allow users to manipulate it. I was working with two other engineers on development, and one Quality Engineer on the testing side. It only took a few months before I thought I was the keystone holding everything up. The users needed a new feature built? I can handle it. We need somebody to facilitate a retrospective? Sure thing. I quickly found myself in a place where very little moved without my efforts. At 22, I was playing the role of lead engineer at a Fortune 25 company.
But wait a second… despite carrying the vast majority of the weight for nearly a year, I was still paid a fraction of what my more experienced team members were taking home. I wasn't getting an "A", and they weren't getting an "F". I didn't have stock options. I had less vacation time. What gives? It didn't take me long to notice these things, and it took me even less time to wear the frustration on my sleeve. I struggled to be a patient and helpful teammate when pairing with engineers less familiar with the software. My apathy grew and my productivity plummeted. If I pair with another engineer and move at their pace (even if it's 5% of mine), I'm still doing my job, right?
I spent the final three months like this, and the project landed in its final resting place with a bit of a crunch. Team morale was low. Nobody was really celebrating the culmination of this 14-month endeavor. More importantly, I knew a few of my teammates wouldn't be excited at the prospect of working with me again in the future. I started to realize how much my attitude toward the work environment had adversely affected myself and the people around me.
A couple of weeks later, I sent out a survey seeking feedback on how I could improve as a teammate. The results of the survey made one thing really clear. Performance isn't everything. Coming into my career, I assumed the golden standard of meritocracy I had so appreciated in school would be the same standard upheld in the workplace. There would be appropriate reward for the strong and swift justice for the weak. This perception poisoned my ability to work well with others, to be grateful for their contributions, to be humble in learning, and patient in teaching. People's perception (of me) had become, "He's too focused on performance".
Lesson 1: Your relationships with your coworkers (interpersonal/leadership skills) and your technical prowess (hard skills) are equally important
To be a great software engineer, you need to hone your craft over the course of many years. Over time, you'll travel up, down, and back up again the plot of the Dunning-Kruger chart. As you go you'll make mistakes, learn from others, and share your knowledge. You must have strength in your technical discipline. However, if this is the only strength you have, you're going to find yourself in an unhappy place. If your goal is to become the best software engineer possible, that journey must include a pursuit of becoming the best teammate (and perhaps leader) possible. This begins with making the people around you as much of a priority as you've made yourself.
The Best Engineer I've Ever Worked With
One September morning, two new contractors joined our team. Our team pursues pair programming as a discipline, so I ended up sitting next to one of the two contractors on a "pairing station" to begin the day's work. Over the course of the next seven or so hours, this engineer (let's call him Bob) asked questions. When we were working on a new feature, Bob asked questions about the language and framework we were using. When we were ironing out details of business rules, Bob asked questions about the product and the problem we were solving. Bob didn't write much code that day. At the end of the day, I was a little disappointed in Bob. I had high hopes for his skill as an engineer, and had hoped he was somebody I could learn from.
The next day, Bob and I worked on writing another feature. As I wrote out the initial test case for that feature, ran it, and grinned when all the green check marks showed up on the screen. Bob looked on, pensive. After the tests came back green, he went into the method being tested and changed a line or two. I started to object "Wait! That behavior is incorrect." He nodded, and then proceeded to run our test cases again. All tests passed. Yikes.
Weeks went by as Bob and I continued to pair. He continued to ask questions as we went about our work. He started making suggestions as I was driving (actively on the keyboard/mouse) and would step in to drive himself when he saw fit. He answered a few of my own questions about our framework and language's inner workings, and introduced an OO Design Pattern that I wasn't familiar with. His questions about the domain and our business problem started poking holes in our software. He revealed bugs and flaws in our code that I could've promised you didn't exist. Yet there I saw them, clear as day. As time went on, Bob and I resolved the bugs he discovered, bullet-proofed the software design, and vastly improved the relationship between the business problem and our code (see Domain Driven Design's idea of ubiquitous language for more on this).
In our team's conversations, Bob didn't steamroll anybody when he thought they were wrong. He asked questions. As they answered those questions, they often found themselves where (I suspect) Bob had been the whole time. At the heart of nearly every software-related decision the team made I found Bob's questions. Bob didn't make assertions about his contributions to the team. He never referred to his skill as an engineer. He didn't seem to care how much time he actually spent on the keyboard when he was pairing. Bob is the best engineer I've ever worked with.
Lesson 2: Your ability to influence others is most prominently determined by your ability to help them reach the same conclusion you did, on their own
Bob rarely stated, "this is what we should do and why". He asked questions about the other ideas that were on the table. At the end of most conversations, his questions would have led the others to remove pretty much any other idea from the table. Now, Bob didn't have all the perfect ideas. Very often he would get an answer to one of his questions that would cause him to say something to the effect of, "Good point. Let's go with that." However, he had by far the most positive influence on the quality of our software because he possessed a powerful ability to influence our team's reasoning. Yet, he spent much more time asking questions than he did sharing his own thoughts.
Lesson 3: It is the mark of a great problem solver to ask many questions before beginning to think about a solution
As software engineers we are, at our cores, problem solvers. Learning something new is a problem to solve. Coding is a problem to solve. Communicating is a problem to solve. Great software engineers are great problem solvers, and great problem solving starts with understanding the problem by asking questions. Asking questions demonstrates respect for others' ideas. Asking questions helps you gain understanding you wouldn't otherwise garner. Asking questions improves the odds that when you do share an answer, that answer will be appropriate. The people who most often come up with a great solution are the same people who took the time to understand the problem.
A final note about Bob. He was easily technically talented enough to be an anchor and lead teams. I'm sure he could be an architect if he had the desire. He doesn't. Bob likes writing code. He likes doing domain analysis. He likes designing business objects and writing robust test suites. He likes delivering quality software.
Looking Back
My first two years were an adventure. I built software, broke software, and fixed software. I sat in meetings where people quite literally fell asleep at the table. I had my hand smacked a couple of times (often by my future self). I threw myself into the work, with all of the joys and pains bundled in.
Looking back, here are some regrets:
- The times I let the work take priority over the people. The work (product) always sorts itself out. The relationships, however, can be much more difficult to repair and maintain.
- The time I spent looking around instead of looking up and looking in. You don't become a better teammate by being focused on what others could improve on. You get better by recognizing your weaknesses and strengths.
- The time I spent talking when I could've been listening. Nobody gets smarter or gains more empathy when they're speaking.
- The times I was frustrated about something and didn't communicate it openly and honestly to my leader(s). They can't help if they don't know what the problem is.
- The time I spent learning AngularJS. RIP.
If you try hard and care about the work you do, you'll step on somebody's toes. You'll probably offend somebody. You'll fail, constantly. When you do, keep the people first. Take responsibility, apologize sincerely, and move forward. The ability to do this is the difference between the individuals that plateau at "Software Engineer" and the individuals that end up leaders in the industry. An aside: you're probably the former if you could offer me multiple criticisms about everyone you work with, but don't think there's that much wrong with you or your performance.
As I move forward, here is what is top of mind:
- Goal: become the best software engineer possible. It's a journey of a thousand miles and it happens one step at a time.
- Goal: become the best teammate possible. Being the best engineer means very little if I'm not a positive relational force. Team cohesion beats individual talent.
- Goal: maintaining priorities. Software is not more important than my relationship with God, my marriage, my friendships, or my health. Think about what your top priorities are. I'm not planning on sacrificing any of those things to be more "productive".
Two years ago, I set out on this journey to become the best software engineer I can be. I'm much closer now than I was then, and now am much more aware of how far I am (is there a destination, really?). These stories and thoughts represent some of that journey. With any luck, they'll be able to help you in some way on yours.