Dev Therapy, part I: How to not get stuck (as a solo dev)

I’m a solo developer in the middle of a 3+ year full time project.

3+ years sounds like an excessive amount of R+D.

It feels that way too. I’ve been programming for 25+ years (gulp) but this project is in C++. I knew nothing about C++ going into this project.

It took me a week to properly animate a tooltip. One week. One tooltip. It wasn’t a fancy animation. Just a tooltip moving to follow a slider thumb. 🎚️

Funnily enough, this wasn’t me being a total n00b. This was after 1.5 years of working with the language and framework. Conclusion: UI and C++ aren’t the best of friends. That tooltip still has some painting glitches.

Anyway, it’s a precarious road. Motivation, momentum and hygiene are crucial. But so is play! And being easy on myself.

Here are strategies I’ve been experimenting with to help me run the marathon.

Disclaimer: Hello! This content is a snapshot in time. It’s not a recipe for my future self (or anyone else). It’s a description of the past. I’m sharing in part to have something to ship. In part as therapy. And in part because I know others will relate…

Complete things, one at a time

“One thing at a time” is the exact type of generic productivity-hack advice I’ve always happily avoided.

But at some point along this journey, the root of this run-of-the-mill-ism finally clicked: Knocking out a task gives me a feeling of momentum ✨.

Even if it’s a small task. It could be a tweet. It could be a tiny bug. It will be this very blog post. It’s just a mechanical truth.

By default, I tend to chip away at 10 tasks, cycling through them when I feel like it. But if I do too much cycling (and the tasks are large enough) things start to feel like they aren’t going anywhere.

This affects my motivation, my mood, my sense of optimism.

So I make sure to regularly give myself the satisfaction of completing something, anything, no matter how small.

I’ve come to treat this as a rudimentary need. Like feeding a pet. I need to feed myself “task completions” so I don’t get antsy or demotivated. πŸ¦”

Generate the small wins

“Celebrate the small wins” is another piece of generic advice I used to furrow my brows at.

My wife advised me to try it out for this project. I wasn’t exactly sure how to implement. I find it hard to identify “wins” if the overall big needle didn’t move very much.

And then there’s the pile of work in front of me. That can loom so large that it eclipses anything that happened today. And when today is yet another “tooltip day”…

The main strategy I’ve been using is to explicitly “unbundle” my larger goals.

Normally I only see big goalposts like “completing wonderful amazing feature X” as “having accomplished anything.” 🏁

I’ve been practicing breaking that down to acknowledge and “celebrate” the steps in between.

At first, this feels akin to celebrating climbing a single rung of a ladder. A participation prize. If my goal is to replace a lightbulb on the ceiling, why celebrate making it up a ladder rung?

Well, because climbing one ladder rung took a full fucking day. Or a week!

On closer inspection, even that one rung could contain a fractal amount of other mini-successes that I could choose to unbundle and explicitly name.

These days, I’ll even invent tiny things to complete and immediately complete them. Little instant ladder rungs. πŸͺœ

I do this a lot when making todo lists. Nothing better than creating a todo list and immediately add a few “todones.”

Tracking time

Time is the lowest common denominator of work evidence. Not terribly useful, but it confirms there was an attempt.

I normally find it easy to get my ass in the chair (or standing at my desk). The problem is I forget how much time I spent, as well as what I even did. I’m just not clear on what, if anything, was accomplished.

Time tracking provides rudimentary evidence of work attempted. It forces me to write down what I actually did, as I’m doing it.

I’m not great at it, but it does create a paper trail. It helps me to give a name to the small wins in progress.

It’s also a ritual thing. Settling into a session of work? Let’s get that timer going…⏳

The next time I feel like complaining that things aren’t going fast enough, I can look at a list of things I did. I rarely ever do this. It’s usually just a write-only log. But I know the evidence is there. I can’t pretend otherwise.

Acknowledging “true” scope

A new software feature typically includes conceptual work, design work, prototyping, refactoring to make space, debugging, UI implementation, cleanup, testing, etc.

This is days, if not weeks, of work. And then maybe another round or two, months later.

It’s important to me that I acknowledge the full cycle ahead of time. This helps me set reasonable expectations. Prep (and cleanup) usually take longer than the actual change, so it seems silly not to consider where the bulk of the work actually lies.

The big benefit: when a week passes by and I’m still working on the same feature as last week, panic is less likely to set in.

I expected this. I signed up for this.

I might not have completed a full feature, but maybe I completed a prototype. Or I refactored to make room for the full feature. Big meaningful ladder rungs.

Too much focus on estimation leads to panic too! Source.

Upfront acknowledgment of the expected process helps me to break down a task from “build feature X” into discrete and predictable steps.

This is usually required when working on a team, or when delivering to a client, but is tougher to do solo, when there’s zero external accountability. It’s just one of those things that takes just a bit more effort up front, but pays off every time.

I don’t bother making time estimates. I just acknowledge the work required. At best I usually think about a task being for “today”, the “next few days” or “a big refactor” which is usually a few weeks.

Attention to Pace

With the scope of a particular journey acknowledged, there’s no longer a valid reason to sprint. πŸƒβ€β™‚οΈ

However, that doesn’t stop my brain from trying. Since everything can feel slower than it “should” at times, it can feel like it’s always time for a sprint.

The best way I’ve found to counter this instinct is to have some concept of a “normal” pace. This can be a specific routine, or just a feeling, ideally somewhere comfortable on the spectrum between “relaxed” and “motivated”.

For myself, I need my “default” pace to be a bit slower than ideal. There are a few reasons for this.

One is that I tend to run “hot” (do more than I should) when motivated. So I like to take preemptive action to balance that out. πŸ₯΅

Don’t force the particular thing

I have a policy that I’m not allowed to worry too much about the “what” in “what I am working on.”

I love to second guess myself. Is this feature actually important? Maybe the fundamentals matter more! Maybe UI is the only thing that matters now…. maybe maybe maybe MAYBE.

My general solution is to trust my short term self. I let it decide what it wants to work on. I don’t top-down decide what I’m doing tomorrow or next week. It’s a hour-by-hour, day-by-day thing.

If I wake up and feel like procrastinating a particular feature and working on something “trivial” or fun or small β€” great! I trust myself. It’s probably needed to feel good about the project’s quality, momentum, etc. Justification isn’t even necessary.

It’s important to me to feel a lot of latitude. If I feel too boxed in like I must do some task, it removes joy and motivation. And those are THE two big propellants on this journey.

Feeling free to table big scary things

As a project grows in complexity, it’s common to regularly run into IMPORTANT_TASK. Oh shit, I forgot about it completely! And it’s Very Important!

The instinct is to immediately shift gears and tackle it head on. It feels like The Responsible Thing To Do.

Or worse, combine it with Big Task I’m Working On Now, turning it into a deep messy refactor.

Sometimes a new rabbit hole is a good idea. However, if rabbit holes keeps happening, productivity dives and panic creeps in β€” nothing is getting done, and there’s so much to do!

My strategies are

  • Write IMPORTANT_TASK down so it isn’t forgotten (bug tracker or project board).
  • Decide on IMPORTANT_TASK‘s priority β€” is it next? Or just “sometime soon”?
  • If my brain keeps thinking about it, reminding myself that after this current task, I will attend to it, it’s on my list

It’s the same therapists recommend for people with anxiety having decision making issues: decide to decide later.

The key is: the time to decide is not right now. I’ve decided to decide later, so my brain can stop flip-flopping and constantly reassessing. πŸ”‘

So outside of productive procrastination (see below), I try not to switch what I’m working on. I try to save bigger context switches for between “pushes.”

Productively procrastinate the thing

There’s always a bit of friction when I start things.

It often takes me a particular mindset or a certain amount of “tension” to push through that friction.

I like to “do homework around the topic” to gain confidence and drive:

Learn about the thing.
Blog about the thing.
Google about the thing.
Watch a talk about the thing.
Play with similar ideas to the thing.

I’m one of those people who thinks procrastination has a bad reputation. I almost always allow myself to productively procrastinate. It builds excitement, motivation, and confidence.

When it feels like I’m playing chicken with the work, that’s when I know it’s the right amount of procrastination. πŸ“

And hey, to be honest, productively procrastinating some other task is probably where my current work came from in the first place.

My favorite way of looking at procrastination is growing the impatience required to complete a task. If I can’t get impatient about it, it’s not important.

Get stuck on the “why” of basics

Procrastination can be good. But getting stuck can be also be good.

Part of my goal on this journey (project/life) is to learn. Learning requires taking the time to understand why things work at a fundamental level. This can take more effort than just accomplishing the task. It can feel tangent-y and slow.

It’s important to me that I don’t leave “mysteries” when it comes to the fundamentals: for example, programming syntax or framework API. Those concepts will come up again. Understanding them now will help me get things done faster in the future.

So I allow myself to go down learning rabbit holes πŸ•³πŸ‡ if I believe they provide a return on investment.

I’m also terrible at remembering things unless I fully understand them. So I often:

  • Write down how things work (such as in a blog)
  • Read framework code (vs. just the docs)
  • Trawl the forums to understand the challenges and solutions others ran into.
  • Cook up toy examples

This can temporarily feel like being “stuck” in technical details, but I try to look at it as an investment which in all likelihood will pay me back two to ten fold.

It’s an additive beast with 1000 oscillators
and a ton of fun sound shaping tools

Check it out

Don’t get buried by technical trivia

That being said, my top priority is building my synth. I love making music and have all sorts of ideas for software tools and instruments.

Sometimes, I forget this premise entirely. When doing technical work, it’s easy to end up 10 layers deep.

I’ll forget I’m building a synth and instead think I’m trying to build beautiful software, well-tested software, elegant algorithms, beautiful UI, new framework features, new developer tooling.

All of these narratives are at times temporarily true…. but not as true as “I’m building an instrument.”

For example, as a C++ dev, understanding the most esoteric corners of C++ is not on my list of things I’m doing. That doesn’t help me further my primary goals. C++ is filled with endless quantities of booby traps and trivia β€” overly complex concepts that (supposedly) trade brain cycles for CPU cycles. Meanwhile, the bulk 85% of work that actually needs to happen (the UI of course) isn’t progressing.

If my goal was to “build the best C++20 audio plugin framework” then understanding the esoteric corners of C++ would be paramount. I just don’t buy that caring about SFINAE edge cases will help me build my audio plugin any faster.

Other folks have fun doing “C++ puzzles”, which is awesome. I know many audio plugin developers more well versed in C++ than I am and respect their process and skillset.

Let the thing breathe

It’s normal that things take longer than expected.

Sometimes this feels like it matters a lot. “So close, so close….”

This feeling can last for days, even weeks. Frustration can start to build….

Until I remember it’s not a sustainable path. I don’t do my best work with that kind of tunnel vision.

As soon as I can identify frustration, my policy is to back off and take a break. The earlier and more preemptive, the better.

For me that means getting out of the house, spending more time on musical instruments, etc. There’s a world of life out there, my vaporware can wait!

Here’s a related quote I ran across this morning:

Fanaticism consists in redoubling your efforts when you have forgotten your aim

George Santayana

Smart vs. Dumb persistence

I think all of us in software are good at “dumb persistence”: trying things until they work. Banging our head against something until it’s done. Most of us are good at that “keep trying again” thing.

I used to consult for teams of devs. They’d run into brick walls with application performance. When it got bad enough that their customers noticed, they’d call us in. The main skill I brought to the table wasn’t technical. I didn’t know their code better. I didn’t know their language or framework better. But I had lots of patience, hygiene and process around problem identification and solving.

I like to think of that as “smart persistence.” Methodical problem solving. It’s “trying again”, but in an orderly, efficient way that places value on the time spent trying and the commonalities across problem domains.

Examples: Creating and methodically eliminating hypotheses. Adding tests. Refactoring. Backing out of complexity and simplifying. Creating isolated examples to reproduce issues. Rubber duck debugging. Asking my wife to take a look (she’s a clearer logical thinker than I am).

Dumb persistence is that emotional certainty of “knowing where the problem should be” when it’s clearly not there. It’s resorting to endless trial and error and whim. Oh wait, didn’t I try this 3 times already? I’m not sure, but maybe I’ll get lucky this time…

Dumb persistence is a solid first default. It’s cheap. But it’s also blunt. It can quickly gobble up momentum. It’s easy to stall out, repeatedly hit brick walls, etc..

Smart persistence initially feels like it might waste more time because we have to stop actively probing at the problem. But it’s an illusion. It’s a bit of front-loaded effort to guarantee smoother sailing.

Have fun with the thing

People who build tools for creatives carry an interesting additional challenge β€” we are building something to play with β€” that’s easy to forget!

It’s a different challenge from building something like productivity software. There’s not an explicit user goal or flow to optimize for. It’s less utilitarian and more nebulous. It’s about creating an environment that enables, anticipates and rewards exploration and play. It’s about people stay in their flow state by setting expectations and providing a good balance of predictability and surprise.

That makes it especially important to switch “roles” away from being a “dev” and spend time as the “player”, the musician, the user of my software.

It can be harder to always “have fun” when the software is incomplete and full of bugs, but it’s worth dropping into that role every single time I do it.

It’s ok to be all over the place

I’ve been trying to normalize feeling a bit scattered. I tend to have tunnel vision on goals, so I’ve been trying to be more scattered on purpose.

One easy strategy: I treat Mondays as a day to handle miscellanea. It’s nice to start the week from the most zoomed out picture of the project. I like to take little tangents before starting in on the big known juicy bits of work.

If I’ve been too tunnel-vision-y at home, I’ll visit my shared office. Not to work, but to disrupt the tunnel vision, get some new input, do some light admin, see some friends, etc…

Reinvention is necessary

Strategies, narratives and even the goals seem temporary and position dependent.

I can’t be too proscriptive with “what works.” I’m not sure these strategies right now are even working. They are all in flux. New data is coming in daily. And my personal needs change as well.

That reminds me. I should finish this blog post. I keep revising it as my thoughts change over the weeks and months… it’s time to press publish and consider it a small win.

I’m interested in strategies and descriptions from other solo devs chewing on long term projects. Let me know!


Responses

  1. […] Also check out Dev Therapy I: How to not get stuck (as a solo dev) […]

  2. Chris (from Airwindows) Avatar

    This is both wonderful and relatable. Count me as a big fan πŸ™‚

  3. The Him Avatar
    The Him

    Such a great article, very recognisable.. πŸ™‚ You offer some great ways to look at things!

Leave a Reply

Your email address will not be published. Required fields are marked *