Recently, I joined a new-to-me team at Mozilla and started working on Firefox. Its not been an easy transition - from the stuff I was doing in the Connected Devices group to getting back to fixing bugs and writing code every day. And not just any code: the Firefox codebase is large and spread across a couple of decades. Any change is an exercise in code-sleuthing, to understand what it does today, why it was implemented that way and how to implement a patch that doesnt fix one thing while breaking a dozen others.
My intuition on how long a task should take has been proven so wildly wrong so many times in the last few months that I’ve had to step back and do some hard thinking. Do I just suck at this? Or am I pushing hard but in the wrong direction. Sometimes I think I’m just getting worse as a developer/software engineer over time, not better.
In truth, I have good days and bad days. On the bad days, the slightest snag, obfuscation of the problem, or ambiguity around how to proceed can freeze me up. I stare at it, futz with it. Procrastinate. Every possible action seems too complicated for my small brain, or to highlight something I haven’t learned well enough to proceed with. On these days, I count any movement forward at all as a success. Some trivial bug fixed, some observation noted down - its better than nothing.
Then there are the good days. By their nature they are not as note-worthy or memorable. I work through the tasks in front of me, fixing bugs and getting stuff done. I follow the trail to the end, note the solution and implement it. Maybe I see opportunities for future improvements or help out a colleague. The day ends and I go home feeling satisfied and ready to go at it again the next day.
I’ve tried out lots of ways of turning bad days into good days. I have a list of check lists that I sometimes have the presence of mind to consult. One example goes like this:
- Q: What needs to be accomplished? Is there a logical set of steps to get from here to there?
- Q: Has this been done before? What patterns already exist for solving this kind of problem?
- Q: How many problems are you trying to solve? (Hint, the answer should be one)
- Q: Could the next step be simplified and still be useful?
And there are others - for starting a new feature, for code reviews, for wrapping up and landing a patch. Check-lists are great - they are a concise way of distilling hard-won experience into something actionable and repeatable.
I keep notes on each task or bug I’m working on. I find a good first step is to write down all the questions that pertain to the problem, however obvious or simple. This list of questions then forms a task list and I can start filling in answers. Finding an answer to a question like “Q: wtf is this function supposed to do?” is a discrete, achievable task that removes an unknown and builds momentum. (A search of the code repository and bug database can tell me when it was introduced, by who and what problem it solved at the time.) Further questions start to close up the gaps in my knowledge and point to a path forward.
Sometimes, just re-writing out the problem as I understand it is enough to nudge me out of paralysis. Its a kind of rubber duck debugging. Re-reading my earlier notes might jog something. Other times, the best thing I can do I stand up and walk away for a bit - breathe some outside air and observe other humans going about their business.
I’ve had stints of success with the Pomodoro technique. I find breaking the day up into chunks, and having this focus and rhythm does sometimes help drive me forward. Again, its about building momentum. But, my experience is that sometimes its just not a good fit. I no longer attempt to do this every day, but treat it as a useful tool to be employed when the time is right.
I’m a “remotee”. I work as part of a distributed team, spread across the globe and separated by distance and time-zones. I work alone most of the time. That has advantages and disadvantages. One of the things you miss is the collective energy of your co-workers and office neighbours that boost you and help ride out the bumps and troughs. When all the above has failed to light a spark, I sometimes go looking for that energy. It turns out watching someone else tackle problems engages those parts of the brain that have thus far failed to engage. It takes time out of the day, but if the day was otherwise shot, its time well spent. Handmade Hero and Mike Conley’s Joy of Coding are two “channels” I turn to at these times. Both hosts have a knack for taking objectively difficult problems and proceeding to dismantle them into smaller, easier problems in a way that seems obvious with hindsight. And simply sharing this journey for a while is usually enough to clear the fog in my own brain and allow me to get back into the groove with my own work.
Of course, history tends to only record successes. When you see a project launch, or a patch land - fully formed and functional - it represents the end-state of a process. There might have been many dead-ends, hours of head-scratching and frustration before finally finding success. This phenomenon is a variation of the drunkards walk: why does he always end up in the ditch rather than just bouncing off the wall on the other side? He doesn’t. But, once in the ditch he’s not getting out, and he is only there to notice at all when that happens. Similarly with our efforts, to the observer we appear to glide gracefully on the surface, with the commit history showing neatly interlocking solutions stacking together until the goal is met. While the thrashing below the surface goes largely un-recorded.
These are the things I remind myself. Its not supposed to be easy. I’ve done it before and I can do it again. I do know how to do this and I’m privileged to work on a project where the outcome really matters.