There’s a big difference between writing code and being a great programmer.
Writing code is the output–and almost anyone can learn the basics of syntax and formatting. But what makes someone a skilled developer? It’s much more than just understanding the basics, of course. It’s mastery of the fundamental concepts and logic that make one capable. But, in order to be great, there must also be a way to measure, evaluate, and improve that performance.
While there are a plethora of ways to learn the basics of coding, developing the supporting skills can sometimes be much more difficult. There’s no simple online course that can teach you how to better collaborate with your team.
And there’s no single way to improve your own cognitive or problem-solving abilities.
So, how exactly do developers go from capable to good? From good to great?
This handbook is meant to be a guide to developer performance–how to understand it, measure it, and improve it.
Our Microsoft ALM Ranger Lineup
For help with this, we reached out to the Microsoft ALM Rangers to get their insight on developer performance, measurement, and growth.
- Gerson Dias, Consultant at Lambda 3
- Etienne “ET” Tremblay, Senior ALM Consultant at Imaginet
- Ken Muse, Consulting Director at Wintellect
- Niel Zeeman, Owner at Team Foundation Consulting
- Richard Hundhausen, Professional Scrum Trainer at Accentient
- Josh Garverick, Senior Cloud Architect at Willis Towers Watson
- Jesse Houwing, Trainer, Coach, and Tinkerer at Xpirit
Chapter 1: Mindset
The well-known 10,000-hour principle, popularized by Malcolm Gladwell, illustrates an important lesson for developers. (For those not familiar, the rule states that it takes 10,000 hours of deliberate practice in order to become world-class at any particular skill or activity.)
It takes extreme dedication to become a master at anything–and programming is no different.
Sure, there are some innate abilities that may give certain programmers an advantage over their peers. And others may struggle to grasp the basics. But, the barrier for most engineers looking to go from good to great is not genetics or luck.
It’s dedication–it’s passion.
In order to become a “rockstar” engineer (cringe), one must not only be smart and capable. You have to want it. You have to be willing to dedicate a whole heap of time and energy into becoming masterful.
Gerson Dias shares his thoughts. “Knowledge and experience come with time, and raw talent is nothing without passion,” he says.
“If you have passion for what you are doing, you will be productive and have excellent performance, because you are putting your energy [into it]. Of course, it’s tough to find a job that you can say, ‘I really like to build that!’ But is important to have your ‘spiritual bindings,’ even to think, ‘Okay, I hate this, but while nothing better comes, I’ll do it because [I need to support] my family and my skills will improve.’”
And you must be deliberate in your approach. No one becomes an accidental master of anything. It takes focused effort and a clear vision for what it is that you want to accomplish.
Then it takes a plan for how to achieve that mark.
Now, this isn’t to say that it’s all-or-nothing. There’s ground to be gained for programmers at all levels–from novice to experts. And it doesn’t take 10,000 hours just to move the needle a little bit. But it’s important to understand the fundamental gap that exists between the majority and the truly extraordinary.
Beyond just dedication and passion to the craft, the engineering mindset is also a hallmark of those who are successful at problem solving of all types.
This is typically defined by its 8 main characteristics.
While some developers may be predisposed to have these characteristics, that doesn’t mean that the engineering mindset is entirely predetermined. It can be learned and consciously developed over time.
In order to develop your ability to evaluate and solve problems, you need a way to measure and assess that performance.
Otherwise, how do you know if you’ve improved?
Chapter 2: Measuring Performance
Before we talk about how to improve, we need to define what improvement means.
What makes someone a good developer in the first place?
Almost every one of the people I spoke to for this guide agreed that performance is both subjective and relative. This means that there is no single, definitive way to measure performance (there are a lot of ways not to measure it, but that’s not helpful) and that there is no static scale by which you can compare performance between two developers or teams.
In other words: The best way to assess a developer’s performance is to measure their growth over time.
“Measuring your ability is about reflecting on each release and trying to find ways that you can be more efficient and effective going forward,” Ken Muse explained. “If your continuously evaluating your progress and making changes, then your performance will improve.”
If you want to become a better runner, what would you do?
You probably begin by setting a goal and developing a plan. But, how do you know if you’re making progress toward your goal?
You measure your abilities.
You time your runs, track your distance, and compare your speed. The same applies here.
Whether it’s the number of story points completed within an iteration or the quality of code written–it should be measured as a continuous trend over a defined period. If your score was 10, than your goal should be 11.
As with running, the process is this:
- Define a way to measure your performance
- Measure your performance
- Set a goal
- Continue to measure and compare performance over time
- Identify and test new strategies for improving performance
- Once you’ve reached your goal, repeat
Are you becoming objectively better, quicker, or more efficient?
This is the main reason we advocate for time tracking across software teams. Not because it’s a great way to whip developers into shape and make sure they’re hitting their arbitrary quotas, but because it gives developers themselves–individuals–a simple and universal way to measure and compare their own abilities.
Muse summed it up by saying, “Understanding the time it takes to complete a development cycle and refining those cycles can be a valuable way for a teams to collectively and individually improve.”
If it took you 50 hours of work to complete 12 story points last month, then your goal should be accomplish that same amount of work in less time for this month.
Admittedly, many people I spoke with for this guide did not advocate for time tracking. And how many companies have implemented time tracking is not a good way to help developers manage their own time and abilities.
Certainly, it’s fair to say that using time as a measurement of performance is not right in every scenario.
But, no matter what benchmark you use, you need to define a KPI–an objective and consistent way to measure and evaluate your own performance as a developer. Which metric(s) you use is ultimately up to you, but just decide on ones that can be easily and consistently measured and compared.
Richard Hundhausen explained his thinking on this topic. “If the team decides (without any outside influence) that they want to track time for whatever reason (again, not because someone or some policy outside the team requires it), then they should do it,” he wrote in an email. “Because one of the rules in Scrum is to let the team decide how they want to work.”
Chapter 3: Mastering the Fundamentals
Understanding the fundamentals of any particular skill is the most essential step toward mastery.
Consider the game of chess. Before someone can become a Grandmaster, they must first understand the underlying principles of the game. Not only do they need to know how the bishop moves across the board, but also understand openings, positions, and tactics.
For developers, there are two categories of fundamentals that are critical to mastery:
- Engineering fundamentals
- Language/framework fundamentals
The first set is universal for nearly all types of programming. It’s about understanding the underlying structures, processes, and frameworks for effective programming.
In the second set, we look more to specialized fundamentals–specifics to certain languages or frameworks that are being used within a certain context. Programmers may not be experts at all languages or frameworks, but having a solid foundation can often make it easier to pick up new technologies.
For our purposes, we want to focus on the engineering fundamentals.
What does that include?
Although these look different in different languages/frameworks/paradigms, the fundamental logic is relatively static.
It may be tempting to think that if you are already capable of writing functional code that you must already know the fundamentals. But, do you really understand all of the underlying science?
I can build a pendulum in my garage. But, that doesn’t mean that I understand the physics.
Even competent engineers sometimes lack a true understanding of why and how things work in gory detail–they just know which keys to press in which order to make it happen. The interesting paradox is that these fundamentals actually become more important later in your career and as your work becomes more complex and further from the basics of writing and understanding code on a screen.
This means that many developers go years–even decades–without truly understanding the fundamentals.
But, eventually, they hit a wall.
As problems become more complex–as you attempt to grow and become a better engineer–you must master these fundamental concepts.
Otherwise, they will eventually become a barrier to your development. So you need to be deliberate about dedicating time to this basic part of the craft. As with anything, this means carving out time for deliberate and focused effort–training.
Chapter 4: Exercises for Improvement
But, knowing the underlying components of programming != being a good engineer.
“I think we are in an industry of continuous learning and if you are not learning then you’re not going to be performant,” said Etienne Tremblay. “I think if they can genuinely say they learnt something (not superficially) then they should be happy about it.”
Programming is fundamentally a problem-solving exercise. It’s about taking in data, understanding context, and formulating the best possible solution. Probably the most important part of developing any problem-solving ability is repetition and pattern recognition.
It takes practice.
“Learn, learn, learn. Read books, try new things, fail and try again. Stay abreast of the latest technology, watch conference videos (they are free). I can’t stress enough how things change so fast in our industry if you are not learning you’ll be left behind.”
– Etienne Tremblay
The more use cases you encounter, the more context you have for how to solve each subsequent problem. You’ve seen more problems and developed more solutions, which gives you a greater pool of knowledge to draw from in the future.
So how can developers apply this mechanic to improve their individual abilities?
Practice diffuse and focused thinking
It may seem improbable that you can somehow train your brain to be a better engineer.
But there may be some scientifically backed ways to accomplish it.
One is to simply practice the kinds of thinking that are important to problem solving. And, maybe more importantly, practicing our ability to switch between these types of thinking in order to better and more easily discover solutions.
In general, we have two kinds of thinking that are deployed when solving problems or learning new things.
- Focused thinking
- Diffuse thinking
With focused thinking, we concentrate on a particular problem or question and actively try to come to a solution. With diffuse thinking, we let the idea incubate in sort of a latent or passive thinking mode–we’re not actively concentrating on it, but it remains somewhere in the back of our minds and we continue to look for solutions or patterns.
When it comes to improving your abilities as a developer, it turns out that both of these types of thinking are important. Some problems can be solved through sheer will and concentration; but others may just require more time and contemplation.
Practicing this is pretty simple, actually.
You can easily alternate between the two types of thinking.
First: Start by focusing deeply on something you are trying to do or solve.
Spend some time turning it over and thinking through different solutions. Focus closely on the problem, examine its different elements and weigh different options and considerations.
Then, after you’ve internalized the idea and the context, go and do something else.
Let the question remain in the back of your head, but take on another task that will take your mind off of it and allow you to deploy diffuse thinking.
This simple, two-step cycle is a fundamental process for problem solving. And, even if you don’t know it, you will often apply the same kind of system when trying to solve problems throughout your career. We often call this “incubating” a solution or taking a break from the problem at hand.
Either way, it’s a practiced strategy. Apply it to different problems you are trying to solve, strengthen your ability, and solidify it as a go-to approach for solving difficult problems.
Create side projects
Not only are side projects often an indicator of passion and drive, but they have some broader benefits for you as a developer.
Latish Sehgal wrote an article explaining the importance of side projects. He outlines these benefits:
- Teaches you to add value (not just write code)
- Pushes you to take action
- Improves focus
- Rewards perseverance
- Makes you more empathetic
The major difference for side projects versus a day job is that you are exposed to more perspectives.
Rather than simply being a developer as part of a team, you become a project manager, a CTO, and perhaps a CEO as well.
Wearing these different hats–and without any external pressure–you’re able to better grasp the context of projects and products. You step outside of your role to understand the bigger picture and use that to make better decisions.
Read other people’s code
Can you imagine that authors like Hemingway or Steinbeck would have been great if they had not read the works of other great authors before them?
Of course not.
We learn and grow, in large part, by consuming the work of others.
While it can sometimes feel a bit abstract to consider your work outside of the context in which you created it, analyzing another person’s work gives you the chance to step outside of the code and try to deconstruct and understand the thinking in a new way.
Make a habit of partnering with different team members to review or analyze each others work.
You don’t need to make it a formal process, necessarily. But, simply taking the time to examine and consider the thought behind someone else’s code or structure can inspire new ideas or push you to improve your own abilities.
Chapter 5: Solidifying Knowledge
Learning is great. But retaining and applying knowledge is really what’s important.
It can often be difficult to take something you’ve learned and recall it later when it’s time to use that knowledge.
There are some tricks and strategies that will help you solidify the knowledge you have learned and identify opportunities to apply those learnings well into the future.
Use interleaving to learn new concepts
The idea behind interleaving is pretty simple. Studies have found that people are able to better learn and recall new concepts if they mix up what they’re learning–alternating between a few different concepts or practices.
While time blocking can be effective for developer productivity, the concept of interleaving may actually be better for learning and recall.
One study found that students performed 25% better on a surprise test when they had learned with interleaving techniques versus peers who learned in traditional blocks. But, more amazingly, those students were much better able to recall the test material later on.
Students who originally learned through interleaving performed 76% better when given a test a month later.
So, interleaving appears to both aid in short-term learning and also improve long-term retention. As you’re learning new things or trying new techniques, you may want to mix in multiple concepts and learn them together in an alternating pattern.
Teach what you’ve learned to others
For many, the best way to learn is to teach.
If you understand a complex problem enough to explain it to someone else, then you’re much more likely to be able to apply that knowledge in a meaningful way.
This is also backed by plenty of science. In particular, the Forgetting Curve explains how information is lost over time. If there is no active effort made to retain that knowledge, it will slowly disappear from your memory.
In addition, science has shown that practicing active recall of knowledge can boost retrieval and memory by more than 100%.
Teaching is, of course, an exercise that encourages and requires knowledge to be actively recalled, explained, and applied.
So, teaching what you learn can be a fundamental strategy for retaining new knowledge and improve your ability to recall and apply that knowledge to your own work later on.
As developers improve their skills, it’s often helpful for them to solidify that knowledge by sharing with others. Either through formalized teaching or coaching, or though informal mentoring of other teammates.
Chapter 6: Teamwork
At the end of the day, an individual’s abilities or knowledge will only play a small role in the outcome of the entire team.
Being the smartest person in the room won’t make you a great developer unless you use that knowledge the foster and improve those around you.
“We don’t want heroes on the team”, wrote Hundhausen, “unless those heroes are sharing their knowledge, pairing up, being respectful to others, and not command- and-controlling the work.”
Josh Garverick put it even more bluntly.
“No one wants to work with a jerk who doesn’t feel like he/she needs to be taught anything,” he said.
Teamwork and collaboration are just as important as the ability to write elegant code or solve difficult problems. In fact, it may actually be more important for have a functioning team than any one person be a particularly high-performing developer.
Application development is a team sport. Period. Full stop.
Sure, there may be mythical stories floating around about individual developers who performed some Herculean task of building programs all on their own. And that’s great for them.
But that’s not the real world–and it’s not a sustainable way to build software.
As you progress through our career, you will work with (and may embody) many different types of developers. And in order to do your job well, you will need to learn how to traverse different personalities and work most effectively with these different types of people.
More importantly, diversity can help you grow as a person and also make your team better at solving problems.
But, “being good at working as a team” is a bit too abstract. How do we actually assess and improve our skills and collaboration, discussion, and giving/receiving feedback?
According to a 2012 study from MIT, the following characteristics are important for building a successful team:
- Equal contribution from every member of the team
- The team shares a lot of energy
- Team members communicate directly with each other
- The team conducts back-channel conversations
- The members explore the outside world and report their findings back to the team
Understanding your strengths (and weaknesses)
As an individual within a team, it may seem like your role in facilitating teamwork is limited. But you can take steps to become a better team player, which is just as important as a leader or manager facilitating teamwork from the top-down.
- Understand and communicate your strengths
- Understand and communicate your weaknesses
- Understand the strengths and weaknesses of others on your team
This is not easy. It requires being vulnerable and honestly assessing yourself–and asking your peers to do the same.
But, that’s no excuse to ignore it.
Each person on your team should be aware of their abilities and have an understanding of how they are able to complement one another. If your weakness is algorithms, the best way for you to improve on that weakness is to understand who is better than you and actively work with them to develop your skills.
You can only do that if you’re open and honest, communicating clearly with the rest of the team.
Defining your role
Secondly, you should consider how your strengths or weaknesses then define your role within the team structure.
Are you the one who is seen as reliable and efficient? Or are you the out-of-the-box thinker who pushes the team to explore new ideas? Whatever your ultimate role is, you need to consider how it plays a part in the overall team dynamic and how you can play that role in a way that helps drive better outcomes.
Ted Bauer published an article about teamwork and outlined 4 types of people within a team.
As he points out, you do sometimes need troublemakers to push things forward.
But, it’s up to the person in that role to understand when it makes sense to make trouble–how to pick and choose their battles. If you are, within your team, the one who is likely to push for change or progress, then you must do it selectively.
Otherwise, you quickly slide into the “Jerk” territory and rather than driving progress, you will quickly impede it.
Chapter 7: Developing Context
Beyond just being a proficient programmer, the most effective software developers have a broad understanding of the context within which they operate.
What does that mean?
It means that software is not created in a vacuum.
Strong developers understand that there are institutional considerations that go beyond just writing functional code and checking off user stories in the backlog.
Software is created to serve a purpose. And it operates under a particular set of conditions, within a specific budget range, and for users that have a certain level of knowledge or ability.
In other words, software is not just software. It is, ultimately, a solution for something.
Moving beyond understanding the fundamentals of programming and being a competent or effective developer, there is another level of performance that comes from a broader understanding of the application lifecycle.
This understanding about the user, the constraints, and the context allow skilled developers to make smarter and more effective decisions about how to solve problems.
It’s easy for competent developers to spend their entire career with their head down, writing and checking in code. They may be a great teammate and a valuable asset.
But, to level up, you need to look beyond what’s on the screen.
In order to improve your abilities–and your value–as a developer, you should strive to zoom out from the day-to-day monotony of writing code and ask why.
Gain context and understanding about how decisions are being made and how they will impact your work. But, don’t just do it for selfish reasons–do it because you want to be included in that decision-making process and able to better understand the purpose and importance of what you do.
Chapter 7: Additional Resources
While this guide is meant to include many ideas and strategies for leveling up your skills as a developer, the heart of everything is learning.
It’s actively seeking out new knowledge and ideas, and then finding ways to apply that new knowledge in your day-to-day work.
In that spirit, there are many other resources for you to consider as you look for ways to improve and grow in your abilities and your career. Here are some recommended by the Microsoft ALM Rangers we talked to when developing this guide.