Becoming a Better Programmer
By Wessel Badenhorst
To become a better programmer, you need to decide to obsess about mastery. Every day is a new opportunity to become better than the day before. Every line of code is an opportunity to improve. How do you do that?
- When you must work on a piece of existing code, leave the code better than you found it.
- Try to complete a quick problem-solving challenge every day.
- Look for opportunities to work with people who are better programmers than you are (open source projects are great for this).
- Focus on deliberate practice.
- Practice systems thinking whenever you can find an excuse.
- Collect and analyze mental models.
- Master your tools and understand what they are good for and what they should not be used for.
Dr. Anders Erickson studied people who reached a level of performance we call mastery. He found that these people had a couple of things in common. The first, as popularized in Malcolm Gladwell’s book Outliers, was that these people all seemed to have spent a significant amount of time working on the skill in question. The actual numbers vary, but the time invested approached about 10,000 hours. That is a significant amount of time, but simply spending 10,000 hours, or ten years, practicing is not enough. There is a very specific type of practice that was shown to be required for master-level performance. The key to world-dominating skill is deliberate practice.
We will look at how this relates to programming in a moment, but let’s first look at what deliberate practice is.
Deliberate practice is slow, halting, anti-flow. If you are practicing the violin, deliberate practice would entail playing the piece extremely slowly, making sure you hit every note perfectly. If you are deliberately practicing tennis, this might mean doing the same shot over and over and over again with a coach, making small adjustments until you are able to perfectly hit that shot in that location time and time again.
The problem with knowledge work is that the standard deliberate practice protocols seem foreign. A sports task or playing an instrument is fairly simple when compared to the process involved in programming. It is a lot harder to deconstruct the process of designing and developing a software solution. It is hard to figure out how to practice a way of thinking. One of the reasons for this is that a solved problem tends to stay solved. What I mean by that is that as a developer you will very rarely be asked to write a piece of software that has already been written. Finding the “shot” to practice over and over is hard.
In programming, you want to learn different ways to solve problems. You want to find different challenges that force you to attack the same type of problem with different constraints. Keep working at it until you understand the problem and the set of possible solutions inside out.
In essence, deliberate practice has these components:
- Each practice session has a single focus.
- The distance (time) between attempt and feedback is as short as possible.
- Work on something that you cannot yet do.
- Follow in the path of those who have gone before you.
The reason you only want to focus on one thing during a specific training session is that you want devote all your attention to the element that you wish to improve. You want to do whatever it takes to do it perfectly, even if it is only once. Then, you want to repeat the process to get another perfect response, and then another. Every practice run is a single reinforcement of the skill. You want to reinforce the patterns that lead to the perfect result rather than those that have less desirable outcomes.
In the context of this book, I want you to target a single design pattern at a time. Really seek to understand not only how the pattern works, but also why it is used in the first place and how it applies to the problem at hand. Also, think about other problems that you might be able to solve using this design pattern. Next, try to solve some of these problems using the pattern you are working on.
You want to create a mental box for the problem and the pattern that solves it. Ideally, you will develop a sense for when problems would fit into one of the boxes you have mastered, and then be able to quickly and easily solve the problem.
One of the pieces of deliberate practice that is often overlooked is the rapid-feedback loop. The quicker the feedback, the stronger the connection, and the more easily you learn from it. That is why things like marketing and writing are so hard to master. The time between putting letters on a page and getting feedback from the market is simply too long to really be able to see the effects of experiments. With programming this is not the case; you can write a piece of code and then run it for instant feedback. This allows you to course correct and ultimately reach an acceptable solution. If you go one step further and write solid tests for your code, you get even more feedback, and you are able to arrive at the solution much more quickly than if you had to test the process manually each time you made a change.
Another trick to help you learn from the process more rapidly is to make a prediction as to what the outcome of the block of code you want to write will be. Make a note as to why you expect this specific outcome. Now write the code and check the result against the expected result. If it does not match up, try to explain why this is the case and how you would verify your explanation with another block of code. Then, test that. Keep doing it until you have attained mastery.
You will find yourself getting feedback on different levels, and each has its own merit.
Level one is simply whether the solution works or not. Next, you might begin considering questions such as “How easy was the solution to implement?” or “Is this solution a good fit for the problem?” Later, you might seek out external feedback, which can take the form of simple code review, working on projects, or discussing solutions with like-minded people.
What are the things that you shy away from? These are the areas of programming that cause you slight discomfort. It might be reading from a file on disk or connecting to a remote API. It makes no difference if it is some graphical library or a machine-learning setup, we all have some part of the craft that just does not sit comfortably. These are usually the things that you most need to work on. Here are the areas that will stretch you and force you to face your own weaknesses and blind spots. The only way to get over this discomfort is to dive deep into it, to use that tool so many times and in so many ways that you begin to get a feel for it. You must get so comfortable with it that you no longer have to look up that file open protocol on stack overflow; in fact, you have written a better one. You jump rope with the GUI and suck data out of a database with one hand tied behind your back.
There is no shortcut to this level of mastery; the only way is through the mountain. That is why so few people become true masters. Getting there means spending a lot of time on the things that are not easy, that do not make you feel like you are invincible. You spend so much time in these ego-destroying zones that very few masters of any craft have a lot of arrogance left in them.
So, what should you work on first? That thing you thought of as you read the previous two paragraphs.
Working your way through the design patterns in this book is another good way of finding potential growth areas. Just start with the singleton pattern and work your way through.
Stand on the Shoulders of Giants
There are people who do amazing things in the programming space. These people often give talks at developer conferences and sometimes have a presence online. Look at what these people are talking about. Try to understand how they approach a novel problem. Type along with them as they demonstrate solutions. Get into their head and figure out what makes them tick. Try to solve a problem like you imagine one of them would do it; how does the solution you come up with in this way differ from the one you came up with on your own?
Really great developers are passionate about programming, and it should not take a lot of prodding to get them to talk about the finer details of the craft. Seek out the user groups where this type of developer hangs out and strike up a lot of conversations. Be open and keep learning.
Pick personal projects that force you to use design patterns you have yet to master. Have fun with it. Most of all, learn to love the process, and don’t get caught up on some perceived outcome rather than spending time becoming a better programmer.
How Do You Do This?
Begin the same way Leonardo da Vinci began when he decided to make painting his vocation.
That is right. Begin by identifying some interesting problem, one that is already solved, and then blatantly copy the solution. Don’t copy/paste. Copy the solution by typing it out yourself. Get your copy to work. Once you do, delete it all. Now try to solve the problem from memory, only referring to the original solution when your memory fails you. Do this until you are able to reproduce the solution flawlessly without looking at the original solution. If you are looking for solutions to problems that you can copy and learn from, GitHub is a gold mine.
Once you are comfortable with the solution as you found it, try to improve on the original solution. You need to learn to think about the solutions you find out there—what makes them good? How can you make them more elegant, more idiomatic, more simple? Always look for opportunities to make code better in one of these ways.
Next, you want to take your new solution out into the wild. Find places to use the solution. Practicing in the real world forces you to deal with different constraints, the kinds you would never dream up for yourself. It will force you to bend your nice, clean solution in ways it was never intended to be. Sometimes, your code will break, and you will learn to appreciate the way the problem was solved originally. Other times, you may find that your solution works better than the original. Ask yourself why one solution outperforms another, and what that teaches you about the problem and the solution.
Try using languages with different paradigms to solve similar problems, taking from each and shaping a solution yourself. If you pay attention to the process as much as you do to actually solving the problem, no project will leave you untouched.
The beauty of working on open source projects is that there is usually just the right mix of people who will help you along, and others who will tell you exactly what is wrong with your code. Evaluate their feedback, learn what you can, and discard the rest.
The Ability to Course Correct
When exploring a problem, you have two options: go on trying this way, or scrap everything and start over with what I have learned. Daniel Kahnemann, in his book Thinking, Fast and Slow, explains the sunk cost fallacy. It is where you keep investing in a poor investment because you have already invested so much in it. This is a deadly trap for a developer. The quickest way to make a two-day project take several months is to try to power your way through a poor solution. Often it feels like it would be a massive loss if we were to scrap a day, a week, or a month’s work and start from nothing.
The reality is that we are never starting from scratch, and sometimes the last 10,000 lines of code you are deleting are the 10,000 lines of code you needed to write to become the programmer you need to be to solve the problem in 100 lines of code with a startlingly elegant solution.
You need to develop the mental fortitude to say enough is enough and start over, building a new solution using what you have learned.
No amount of time spent on a solution means anything if it is the wrong solution. The sooner you realize that the better.
This self-awareness gives you the ability to know when to try one more thing and when to head in a different direction.
About the Author
Wessel Badenhorst is deeply passionate about the process of attaining mastery, especially in the field of programming. The combination of a BSc in computer science and extensive experience in the real world gives him a balanced and practical perspective on programming, and the road every programmer must walk. He is currently writing his next book, Pro Deep Reinforcement Learning with Python.
Want more? This article is excerpted from the book Practical Python Design Patterns. Get your copy today and learn to write elegant "Pythonic" code to solve common programming problems, and identify design patterns that would be helpful given a specific problem or situation.