The Second Framework Is Always Easier (Except for the Setup)
I spent February and March searching for a junior backend role in the Öresund region with what I can only describe as a magnifying glass. Go and Ruby jobs exist there. You just need that magnifying glass to find them.
At some point the pattern became undeniable. The market wants TypeScript. It wants Node. It wants the ecosystem I had been deliberately avoiding because I preferred languages that made me think about what the machine was doing. Ruby was expressive and mine. Go was deliberate and fast. JavaScript had always been the thing I used to make a Rails page slightly less boring.
So I made a decision. The arts school client who came to me for a website could not care less what I built it in. I would use their project to learn the stack properly — not through tutorials, but through shipping real work for someone who was paying me.
The First Week
The first week nearly broke me, and I had not written a single route yet.
Node's ecosystem is fragmented in a way Rails never is. Rails is opinionated to the
point of being controlling, and I used to find that annoying. I do not anymore. With
Node you assemble everything yourself. There is npm, and then there is yarn which
came along because npm was slow, and then pnpm which came along because yarn had its
own problems, and then there is npx and nvm and tsx and tsc and a
tsconfig.json that needs convincing before it will cooperate.
None of these things are complicated individually. Together, on the first day, they are a lot.
I settled on pnpm for the monorepo. Fastify over Express because it worked out of
the box. TypeScript from day one because I came from Go and C and types are not
friction to me, they are information. I set up PostgreSQL locally to match production.
Then I Wrote My First Test
And nothing was different.
The same red-green-refactor cycle I had used in Go. The same discipline of writing the
failing assertion before the implementation. The same satisfaction when the thing that
was not supposed to work yet works. Vitest instead of go test, but the rhythm was
identical. I wrote a route, wrote a test for it, made the test pass, moved on. The
framework was new. The thinking was not.
That is when I understood something that sounds obvious in retrospect: I had not been learning Ruby or Go or TypeScript. I had been learning how to build software. The languages were just the dialect.
The Thing Nobody Told Me
There is one thing I wish someone had told me before I started. Not about TypeScript,
not about Fastify, not about async/await and why Node does not hold the thread by
default and why you have to explicitly tell it when something needs to wait for
something else. Those things I figured out.
I remember when all my tests tried to run at the same time. Even with await, the
config itself needs to be told not to do that. Goroutines and Ruby threads had got me
used to something different. Once I understood why, the fix took thirty seconds.
That is not Node-specific advice. It is the same thing that made Rails confusing when I first tried to write tests against scaffolded code I had not read.
Understand the setup. Then write the code.
The project is going well.
Nate Ivry is a self-taught software engineer freelancing in southern Sweden, currently building in TypeScript and looking for his first permanent role in the Öresund region. nathanielivry.dev