We end up needing to troubleshoot things because those things are doing something different than what was intended. This is my strategy for troubleshooting all the things, especially code.
My first tip is to take notes.
- Write in a notebook.
- Type in a text document.
- Add comments to code that you won’t keep.
- Create unit tests that you might not keep.
- Just do something to keep yourself from trying to keep all this information in your head at once!
We deal with complex systems. It is impossible for most of us to keep everything straight without writing things down somewhere.
Read Code for Intent
Pay close attention to the names of classes, functions and variables. Read the code as if it works as intended and tell a story using those names to find out what the author of the code wanted to do. Use variable names as nouns, classes as adjectives of those nouns and functions like verbs. Write this intent down. Look at definitions of classes used for variables to understand the intent of those classes. Classes that include words like
Controller, etc. tell us the intent of those classes.
When we see something like
await commentService.CreateComment(createCommentForm) we can tell that the author’s intent is to asynchronously use a service for comments that is a CommentService to create a comment using the information contained in a
createCommentForm and by looking at the class definition of the variable we can get an idea about what kind of information is being used.
If we cannot figure out the intent of the code we’re reading, then find the code that calls this code to see if we can understand the intent of the of calling code. None of this is magic. All data and definitions must come from somewhere.
Take notes that help understand the intended behavior because we need to forget all about intent for the next troubleshooting step.
Read Code for Execution
The computers that run our code do not care about our intent. They don’t about the names of classes, functions or variables. They only do exactly what they’re told to do with the types and values given.
When reading code for execution, we should also not care about intent but only care about what the code is actually doing. When reading code for execution, focus on types and values more than names. Some strategies for reading code for execution:
- Change the names of classes and variables if you need to.
- Add comments everywhere!
- Create unit tests that you may not keep just to check your understanding.
- Create a proof-of-concept application to check understanding.
- If we cannot understand the execution of something, use other resources like library documentation, StackOverflow and coworkers to help us understand the execution of that thing.
- Take notes!
When we see something like
await commmentService.CreateComment(createCommentForm) in this context, we can tell that some variable (commentService) is going to do something (CreateComment) with that variable (createCommentForm).
Compare intent and execution to find the bug
After reading for intent and reading for execution we can now compare the intent and execution to find our bug!
Take those names of things and compare those names with what the execution of the code says those things are. If the name of the thing and the execution of the thing do not make sense we’ve either found our bug or found some new knowledge. This is the best time to use coworkers to check understanding.
We can then use some of the notes we wrote to clearly define our bug and/or come up with a fix!