Depth-first development 📋
When programming, I always keep a document open to capture any ideas, related tasks, or test suggestions that pop into my head. This helps me stay focused on my current task while ensuring nothing gets forgotten.
Getting sidetracked #
If I don’t do this, I find myself getting sidetracked.
I’d be working on a task, perhaps creating a new endpoint for an API. “It’s a simple one”, I tell myself. “I’ll just read some rows from the database and return them as JSON.”
But when I start implementing the endpoint, I realize that there is an error case I hadn’t thought about. “I better add an if statement to check for that error”, I think to myself. “I’ll do it directly so I don’t forget it.”
After having done so, I realize that the new if statement is very similar to another if statement right next to it. “Would it perhaps make sense to merge them? I think so. Let’s do it. Boy scout rule!” In fact, it seems that several other endpoints would need this check as well. “I better extract it to a middleware. I can use an annotation on each endpoint to determine whether the middleware should apply or not. That sounds like a great abstraction, let’s do it!”
During implementation of the middleware I realize that there are no tests for this error. “I better add one! Oh, would this perhaps be a good use case for parameterized tests? Could be, let’s do some research!”
Five hours later, I’m still no closer to having implemented that new endpoint.
Going deep #
This example illustrates how easy it is to get sidetracked. One well-meaning improvement leads to another, and suddenly, the original task is lost. Having a place to write down ideas is a great tool for avoiding that trap.
I like to think of this as applying the depth-first search algorithm to development.1 Just as depth-first search is an algorithm that explores a path fully before backtracking to explore others, you follow the original task for as long as it takes to complete it. This contrasts with breadth-first search, where multiple paths are explored simultaneously.
Depth-first development provides several benefits:
- First and foremost, you become more productive. By keeping focus on the current task, you can get it done much quicker. You may very well be surprised at how fast you can finish tasks when you stop doing everything else at the same time. This can be very useful for perfectionists, who tend to procrastinate on the original task.2
- It is a form of scope control. A way to avoid yak shaving.3 It helps you determine what needs to be done now, and what can be postponed for later.
- You avoid the mental trap of fooling yourself that you are making progress just because you are writing code.
- Writing ideas down provides psychological relief and frees up mental space.
- Focusing on one task at a time helps you avoid context switching. If you find yourself constantly doing half a task before jumping to the next, there will be a lot of contexts to keep in memory.
- Once you’ve reached full depth and a first complete task is done, it is a perfect opportunity to commit. You will be able to write a very clear and concise commit message4. You may even be able to merge it to main directly.
The idea of writing down thoughts to keep focus on the task at hand also plays well with Test-Driven Development. Kent Beck describes this in his book Test-Driven Development.
Programmers are good at imagining all sorts of future problems. Starting with one concrete example and generalizing from there prevents you from prematurely confusing yourself with extraneous concerns. You can do a better job of solving the immediate problem because you are focused. When you go to implement the next test case, you can focus on that one, too, knowing that the previous test is guaranteed to work.
Going wide (maybe) #
Once the first task is complete, you can go back to your list. Does it contain further ideas worth exploring? Which tasks should be done now? Which ones can wait until later?5
Depth-first development helps you see tasks more clearly. When you’ve finished the original task, the urgency of side ideas often fades, letting you prioritize what’s truly important.
You may very well find that the original task was all that was needed.
Featured comments #
Timothy Wolodzko: I do similar thing. The thing that works the best for me is the TODO comments in the code. That way, you can make the notes to yourself shorter because they're closer to context (so you don't need to write "do this here-and-here" since the note is already where you see the change to be done) and it is easier to recall what you meant when you see it in the context where it came to your mind. I use Todo Tree extension in VS Code, so I can easily find them.
-
Another computer science metaphor for focused work is that your mental “related tasks” data structure should be a priority queue, not a stack. ↩︎
-
A perfectionist procrastinates to avoid confronting her imperfection, and delays complex and uncertain tasks to numb the fear of failure. ↩︎
-
Yak shaving is a term coined by Carlin Vieri to to describe a series of tasks or activities that are undertaken as a means of preparing for a larger task, but that ultimately have little to do with the final goal. ↩︎
-
I’ve discussed the value of small focused commits in an earlier blog post. ↩︎
-
Asking yourself “Will it be harder tomorrow?” is a good way to separate what should be done now, and what might as well be done later. ↩︎