If you have a full-time software engineering job, most of the time you spend writing code, reading code, and thinking through complex engineering problems is spent at work. Those working hours are an enormous opportunity for learning while doing, but we can just as easily stagnate or reinforce bad habits. So how do we make the most of this time and continuously improve?
Each day, we’re asked to complete a series of tasks. We get better at the ones we’ve done before and learn how to do those we haven’t. Learning on the job is automatic, but we can learn faster and retain more if we take control of our learning process and focus our learning goals. Learning is a skill that we can improve and evaluate. Let's consider five strategies for improving how we learn.
Code Reviews aren’t just a quality assurance mechanism. They’re also a great opportunity to learn. It's all too easy to review a set of diffs on GitHub and call it a day, but that doesn't help your coworker or you. So what is an "active" code review?
When reviewing your coworkers’ code, don’t just look for mistakes. Look for the things they do well. What problems have they solved that you haven’t seen before? How are their approaches to problems you’ve solved in the past different from your own? If you don’t understand what code is supposed to do or why it was written a certain way, ask the person who wrote it. The discussions you have will lead to better, more readable code.
Doing code reviews regularly will make you a more efficient engineer. You’ll have a larger knowledge base of solutions to common problems, you’ll pick up best practices, and you’ll start catching issues in your own code earlier.
The technologies we work with are constantly evolving, and keeping up with the latest advances and best practices is part of our jobs as engineers. There’s an endless list of things we can learn, so where do we start? Well, there are two relevant lists of goals to consider. One is the list of things that we’re personally excited about learning, whether it’s because they’re relevant to personal projects or longer-term career goals. The other is the list of things that relate to the objectives of our company. These are things that are required to build planned product features and make the development process more efficient. The key to maximizing the value we get out of learning is to find the intersection of these two lists. If you find that your personal learning objectives and those of your company are very different, it’s usually a good indicator that you’re in the wrong job.
There’s a vast selection of open-source, third-party libraries, and most codebases will make use of a number of them. Many of these libraries are used so frequently because they solve a difficult problem with quality code that has been refined by a community of engineers. There is a lot of value in exploring how a library solves a particular problem, but it’s sometimes difficult to find an entry point. A great place to start is to consider the third-party tools used in your codebase, find one that looks interesting, and follow the code. Define the problem that the library is solving for you and learn how the library is solving it. From there you can explore what else the library can do and whether it would be helpful in other areas of your codebase. You may find that you can improve on the solutions the library is offering. You may also find that you don’t really need the library, and you can remove a dependency. At the very least, you’ll understand more about your codebase and be better prepared to handle issues related to the library and the problem(s) it solves.
We don’t know ahead of time the full list of features we’ll have to implement or bugs we’ll have to fix. So, we try to learn as much of the codebase as we can in order to be prepared for any problem we’re asked to solve. A great way to do this is to organize code you haven’t yet worked with. When I say “organize code” I mean grouping code into logical sections, establishing patterns for ordering sections, making sure code files are in the right place, etc. The process of determining how code files should be organized will force you to read and understand the code. It will also give you a clearer picture of the overall architecture of your project. Along the way, take note of potential refactorings. If it’s not clear what a class or method does, it’s usually a good sign that it’s doing too much.
Teams are often reluctant to spend time organizing code because that time could be spent developing new features, fixing bugs, or testing and refactoring existing code. However, I would argue that organizing a codebase is not only a great way to increase your personal knowledge of the codebase; it will also save your team time by making code more readable and creating a map of where to focus refactoring efforts. This in turn leads to faster development of new features, easier bug fixes, and more testable code.
In a high-performing engineering team, development moves quickly. There are feature deadlines and critical bugs that need to be fixed immediately. As a result, our instinct when presented with a problem we haven’t seen before is often to find the minimum information needed to solve it. However, finding the solution to a problem without understanding it leads to fragile and incomplete code, and you will almost always save time by understanding the problem first and learning relevant concepts before implementing a solution.
We are fortunate to be developing software at a time when there are countless instantly available resources that will walk through relevant computer science concepts and their applications to common problems. They include blogs, free online courses from leading academic institutions, Q&A sites, and open source sample projects. Most popular languages and platforms also have detailed documentation and guides that will explain how to use language features and APIs.
Once you do find the resource you need to implement a feature or fix a bug, the temptation is to follow along with a tutorial or skim through a sample project and implement as you go in your own project. Again, you will save time by going through the whole tutorial and understanding all relevant parts of the sample project before you apply what you have learned. This will allow you to assess the provided solution as a whole and ensure that it is applicable to your project. You may also realize how you can improve on the solution or adjust it to fit your needs.
Learning before implementing will help you develop a knowledge base that is applicable to future problems instead of a collection of answers to specific problems.
All five of the ideas in this post take time to think about and implement, and investing time in them is difficult when the rewards are not always immediately apparent. However, when you take a focused approach to learning at work, you will find yourself implementing features and fixing bugs more quickly, writing more readable and durable code, having a better understanding of the platform in which you specialize, and feeling more comfortable with a larger portion of your codebase. You'll also get better at learning, which in turn will make you a better engineer at an accelerating rate!