Table of Contents
Every day, we come upon problems where something isn’t working. Our productivity is often limited by how quickly and effectively we can get better at figuring out what is going on and moving to a solution.
One of the keys to successfully debugging problems is being able to generate good hypotheses and being able to validate them.
How do you get better at that? By studying. Let’s look at what you can study and some ways to study it.
Study the problem space #
Gaining a deeper understanding of what you are working with will improve your ability to generate and validate hypotheses. First, develop an understanding of the context of your system. Who uses your system? What are they trying to do? Why are they trying to do that? Second, build an understanding of how your entire system works, for as much of the stack as you can internalize. Third, improve your knowledge of practical computer science.
Understand your users #
If you understand the users of your system, you’ll have a sense for what the system is supposed to do. Maybe there are a wide variety of users, with different levels of skill using your service. Or, maybe what you own is only used by other computers. By understanding what kinds of users and use cases your system must support, you can better think about the impact of your changes. You’ll have a better chance of understanding why a piece of code exists. If you learn why users are using your system, then you can make decisions that help them ultimately succeed at their goals.
Generally, it is the job of a product management team to understand the user, but other ways to get this information include talking to some of your users, someone on your support team, someone in sales, or someone in marketing. Each will give you a different lens on how your company interacts with the world and how the world interacts with your company.
Understand the system #
Understanding user gives you context, but you won’t be able to debug anything unless you also understand how the system works technically. You can grow your understanding of your project in an ad hoc way over time as you work through bugs, but you should also push yourself to systematically understand more. Some questions to ask might include:
- How does the system (or sub-system) start up? Where does it get its configuration?
- What is the full life-cycle of a request? Where does the input come from? (i.e., who are your clients? is it the front-end? is it another service? a mixture?) In processing a request, what data sources (and caches) are involved, what kinds of edge cases are considered, what kind of data gets logged, etc. You can break this down by different kinds of requests: reads, writes, etc.
- What are the libraries and services that your service relies on? What are they used for? Who maintains these libraries? What are the semantics of the various APIs?
- If you run a service, where do the logs for QA and production instances live? Can you search them to find logs for a given request? Can you find more instances of a bug occurring?
And as you spend some time each day learning this, can you find bugs? (There are bound to be bugs.) Think about what might break. Take notes, ask questions.
Understand the practical computer science #
In school, you will almost certainly have learned some basic data structures and how to do big O analysis of some algorithms. To be effective at debugging problems, you will also find it useful to understand how to practically apply core CS concepts. Violating best practices here is a good way to introduce bugs; recognizing violations is a good way to find bugs.
For example, what more can you learn about software development?
- Are you familiar with how to structure code for maintainability? Have you read things like Design Patterns or Clean Code?
- What are the best practices for testing software? How do you balance unit tests with integration tests?
What more can you learn about how computers work?
- How do you make a program fast? How fast are different components in a computer (registers, CPU caches, RAM, disk, LAN, WAN, etc)? What are the bottlenecks here?
- How does a database/file system/operating system work? What makes an operation slow? What makes an operation fast?
- How does a scheduler work?
- How does memory allocation and garbage collection work?
- What failures can occur when there is concurrency? What techniques can be used to mitigate these failures?
- What must be considered when designing a distributed system?
What more can you learn about your programming language?
- Java? Read Effective Java. Try to make sense of the Java Language Specification. Learn about JVM flags.
- Using a build system (such as Gradle, Maven, Gulp)? Read its documentation, learn how it works.
There are so many resources online these days, so just pick one and learn. You can find free textbooks, free academic courses, and free conference videos that you can learn from.
Study with your colleagues #
Your colleagues are a valuable source of knowledge. Your manager or tech lead is an obvious first place to start. They have an interest (and even a responsibility) to help you grow, so stay humble, and take all their suggestions to heart.
Outside of direct mentorship, there are other ways to learn from more experienced developers. For example, if your team uses code review, follow along with reviews conducted or submitted by experienced developers. What kinds of concerns do they have about the codebase? How do their changes look relative to yours? Can you get a sense for how they approach problems and apply that approach?
Your peers are valuable as well. Regardless of your level of experience, you can gather a group of peers to learn and improve. Some ideas:
Work through any of the topics listed earlier in this post. Improve internal documentation. Try something new (e.g., a new methodology like mob programming, pair programming, or test driven development; a new framework that you haven’t used before; a programming language that makes you think in a different way). You might be surprised at what you can learn that way. Organizing a group also demonstrates initiative, especially if you make sure to document what you’ve done and how the organization has benefited from it. (You should definitely ask your manager if you can expense lunch or snacks after you’ve had some successes with your study group!)
Study yourself #
The agile/scrum methodology practices retrospectives for the team so that the team can constantly improve its effectiveness, but this can also be applied personally.
How do you reflect on your own experiences? Often, this can be something that your manager does with you in a 1:1, but you can also do it for yourself. One of the best ways to absorb knowledge is to manipulate it, so try journaling or blogging about your experiences. Spend just 5 minutes at the end of each day reflecting and taking some notes.
What can you reflect on? Suppose you recently completed a task. How did it go? What went well? Did code review or the deployment process reveal anything you missed yourself? What can you do differently next time so that you don’t miss the same thing? Or, suppose you attended a meeting. How did it feel? Was it productive? Why or why not?
Getting better is a lifelong process, and I’m still working on it. What approaches have you found successful? I’d love to hear what has worked for you.
This post was originally published on LinkedIn Pulse as Three Ways to Get Better at Debugging.