One key trick to becoming a wizard developer

Yesterday, I pushed my first branch to a new project. Well, I tried — it gave me an error.

sh: npm not found.

This is unexpected, especially on a Windows computer, where sh is not a thing! (The other developers on this team use Macs.)

The error message also said that I could add --no-verify to skip whatever check was failing. So what do you think I did?

I dig in to the git hook.

Why is this push failing? I start tracing it. I know that git will run hooks before operations like push, and this script lives in .git/hooks/pre-push. I look there, and find a shell script. Why is this shell script even running on Windows? Probably using git-bash. That would explain where sh comes from.

The script calls another script, which uses npm to call into a module called husky. It finds npm just fine for this purpose, so why the error?

I know where npm puts these modules, so I look there. package.json‘s bin property tells me what .js file it’s running. I dig into that, follow another indirection, and find it forking a call to sh that this time runs the npm command that’s failing.

I add console.log and echo statements to output the current path, each time running git push again to repeat the error and see the output.

In the end, the path was fine, and my npm installation was borked: the shell script version of npm was missing. (I did that a long time ago while fighting a different error.) I fixed it.

Now I run git push and I don’t get this error anymore. I did get “Invalid branch name” along with suggestions for how to make my branch name conform to project standards. Useful.

That was a yak shave.

I had to learn a lot about husky, some about npm, and some about git-bash. None of that related to project work. I didn’t tell you about all the things I googled, or all the false trails I found in those scripts — like, what the heck does exec < /dev/tty do? Even Avdi doesn’t know.

Why dig into that instead of running the push with --no-verify? Three reasons: one about my work, one about the team, and one about me.

My work will be better if I run the same checks as everyone else. Otherwise, my pushes can be rejected for things the check would tell me about, like invalid branch names.

This time, the problem turned out to be local, and it’s unlikely someone else will have the same one. More often when I track down these problems, it helps other people on the team.

For instance, the branch I was pushing contained a fix to make the build work on Windows. To fix that, I had to learn more than I wanted to know about gradle and node plugins for it. Turns out that build.gradle files can be in Kotlin scripting language, who knew? Who wanted to know? Some days you learn what ya gotta learn to get the problem solved.

Even though this particular yak didn’t help the team, it had the most important, longest-term effect: it broadened my knowledge. Yesterday, it wasn’t my first intention to learn how gradle loads build files, or where sh comes from in git hooks on Windows. But now I know. These things come in handy at unpredictable times.

For instance, my past experience digging into git hooks and into npm file structure made this yak more tractable. I even used a silly npm module I created a while back while digging in to npx for a RubyTapas episode.

Dig in a little farther to every yak that confronts you, and you’ll become a sharper developer every day.

In his article on “Blub studies,” Ben Kuhn goes deep on the value of learning the tools that are in front of you, even if they’re not the latest hotness, even if they’re ugly. The biggest value happens when you read deeply enough to grasp the model of the tool, like how git thinks about object graphs, or how npm nests dependencies. These concepts apply in other tools, and give you vocabulary to talk to more people.

Worst case, you’re out a few minutes or a day. Best case, you find a new career direction or write the talk that gets you into international conferences. This is called the “fat tail of success,” where the most likely outcome is not much, but some possible outcomes are better than you can imagine.

Learning is crucial to our development. That doesn’t mean it is easy.

This kind of incremental deeper learning is core to my career success as a developer. I’m fortunate to have started in circumstances that made this easy enough to do.

It’s hard to stop and learn when you’re under pressure to deliver a minimum solution by 3pm to make the daily build.

It’s hard to dig deeper when you feel your manager or teammates looking over your shoulder. Want to hamstring a new developer’s whole career? Ask them “Why are you reading about that?”

It’s hard to read a full blog post while pairing. Mobbing though, mobbing is great for this because one person can dig deeper while others google and try random stuff.

When your circumstances make this hard, that’s not your fault. Sometimes the only learning time we get is personal time, and not everyone has that either.

When you can, do both: go forward and dig in a bit.

When I saw saw that git push error, the first thing I did was:

git push --no-verify

I got my work saved to GitHub first, and then started digging around. That way, I could create my pull request and dig into the error.

For the Windows build, I first kluged it to make it work, when I couldn’t find a real fix. Later one night I thought of something else to try, and sure enough, that fixed it correctly. Then I made a pull request for the benefit of the next dev who joins the team with a Windows computer.

This is the power of working as a software developer: we can change the world we work in. When it gets in our way, we don’t have to sit there and take it. At least, not forever.

Every surprise we hit is an opportunity to learn something, and maybe to help the whole team. Take some of them.