If you work in software engineering, do you love your job? Do you feel like you’re expected to? If you were independently wealthy, would you still do it?

Like many job fields, software development suffers from an ecosystem of stereotypes that exclude people and hold back the industry overall. Specifically I mean the stereotypes about what a “good programmer” looks like. Many of these are related to race, gender, or other aspects of identity. Those are important problems that I’m not very qualified to talk about. Another stereotype that I want to break down is less about identity and more about how you’re “supposed” to feel about your work.

I could summarize this stereotype as something like, “Good programmers love code.” Does that sound familiar, or conjure any images? What comes to my mind is a 25-year-old in a hoodie, hunched over a laptop in a dimly lit room, fingers flying over the keyboard without pause, except to take another sip of energy drink. They never hesitate, never need help, never have to draw pictures to figure out what to do, never need to coordinate. They are like a bandsaw, ripping through the work until it’s done, fuelled by the dopamine hits from neon syntax highlighting and mastery of fun keyboard shortcuts (and also caffeine).

This isn’t a dig against 25-year-olds, or hoodies. If any of the above resembles your work style, power to you. Personally, the only part I identify with is the caffeine (okay, I’m also a keyboard enthusiast).

Now, stereotypes exist in an ecosystem. So the image I described is really the intersection of the “I love code” stereotype with the “10x programmer” stereotype. There could also be a kinder, gentler version of “I love code.” Maybe it’s the presenter from that talk you watched who explained how this new coding framework solved all their problems and made them love their job, and will do the same for you. Because, you should love your job, right? Is that the measure of success? I mean, programming is fun. Right?

Well, if you’re still reading, you’ve probably cut code before. You may be a professional, or aspire to be. Is it fun?

Should it be?

Read on to know the simple, concise, one-size-fits-all answer! 😄

❤️ ❤️ ❤️

I first wrote “code” in 1998. I was definitely having fun. I was 12 or 13 and a classmate had told me how to “view source” on web pages. “Hey,” I thought, “this HTML stuff is basically intelligible!” One free tutorial later, when I wrote my own HTML file and the browser did what I told it to do, it was pure dopamine. On top of that, I suddenly felt intellectually connected to people way smarter than me who had designed all this stuff. (I basically thought I knew computers now. I had no idea how deep the stack went…)

I hit my first wall one day when I came across a website that somehow made the buttons change colour on mouseover. Now, this was the late 90s. CSS was barely a thing. If you wanted styled buttons, you used images; and if you wanted mouseover action, you used … wait, what was that??

I viewed source on this magical site and saw something horrible crouched in the midst of the well-mannered HTML. Seemingly random curly braces surrounded weird expressions like “i++“. Snippets like the following were all over the late-90s web:

var imageSources = new Array(
  "images/button1.gif",
  // , ...
)
for (var i = 0; i < imagesSources.length; i++) {
  var img = new Image(imageSources[i])
}
 
var imageSources = new Array(
  "images/button1.gif",
  // , ...
)
 
for (var i = 0; i < imagesSources.length; i++) {
  var img = new Image(imageSources[i])
}

My tender spirits fell. It seemed this mouseover magic required real programming. Here be dragons. It was beyond me (I assumed).

The few lines of Javascript I’d discovered were actually quite context-heavy. Even if I’d understood the linguistic meaning — running through a loop of image URLs and constructing a new “Image” object for each — its purpose would have been unclear without the additional insight that the browser needs a few seconds to load an image for the first time (dial-up 😅), and constructing that object in memory has the side-effect of loading the image file into cache, allowing the mouseover to work instantly when the time comes.

Looking at that code gave me the opposite of a dopamine hit. But I really wanted that sweet mouseover effect on my site, and it bothered me not to understand things, so eventually I found the free JavaScript tutorials too (bless all those people writing free web dev tutorials in the 90s, you literally changed my life).

Phew! I’d been scared for a second there when I was afraid of code instead of loving it. But then I understood it and all was love again.

It was okay. Code and I had just had our first fight, but now we were happier than ever together and things were perfect. And it’s a good thing too, because as every young teen knows, the moment your relationship isn’t perfect, it’s ruined. 😛

♥️ ♥️ ♥️

That “this is beyond me ➡️ oh this is awesome now that I understand it” cycle repeated many times through the next couple of decades, without my really seeing the pattern. There was always something I assumed was beyond me and felt scared of, without remembering that I’d been through that before and come out the other side. At some point it was cookies. Then it was server-side programming. Then it was e-commerce (you know, what we called commerce back when some of it still happened offline). Unit testing. Single-page applications. Memory management. All things I once hoped I’d be able to avoid forever, then felt empowered once I got my hands dirty.

Eventually the pattern changed. By 2017 I was in my second full time job, had some sophomoric opinions about “clean code”, and was generally proud of the work I did. Then I came across a couple of talks by some veteran game developers I really admired, on the subject of software quality. What I took away from these talks was basically, “Hey, you know that thing you think of as ‘tech debt’? Like when a project is rushed and you come back later to make changes and just want to throw the whole thing away and start over? Sooo, that’s basically all of modern computing. There’s a reason software breaks constantly; there’s a reason most apps feel slow on computers that can also render 60fps 3D graphics, and it’s tech debt. Modern computers are tech debt all the way down to the CPU instruction set. And you as a web developer are working in the tippiest toppiest most teetering tower of abstraction, far from the reality of a computer. That’s what you’ve spent two decades learning.”

The seal was broken on my naive view that learning programming always meant standing on the shoulders of wise giants — and I swung all the way into extreme cynicism. Without meaning to, I crafted a depressing narrative: The web had begun as interlinked static documents. Then came some seat-of-the-pants scripting at either end. A couple of decades later, software had become a broadcast medium. The problem was that the prototype architecture for the new paradigm had cemented into undeserved permanence. The new way of building stateful, broadcast-to-many software was on top of a stateless, peer-to-peer networking paradigm designed for trading static documents. The mental backflips were a full-time job.

I wondered why we hadn’t simplified things, once the software industry knew what it was about? If we really just wanted broadcast software, why not just have the OS load native binaries over the network and run them in an OS-level sandbox, instead of reinventing that entire wheel up the stack? Was it a trade-off for universal compatibility? Accessibility? No. The decades of work put into achieving those on the web could have been put into operating systems. Instead, browsers now rivalled the complexity of yesterday’s operating systems. The reason we hadn’t simplified was inertia, which is to say, tech debt on a worldwide scale. The name “web” was apt for such a sticky architecture.

Because of this cynical outlook, I began having a different reaction to tech things that I didn’t understand. I replaced one assumption — “this is beyond me” — with another: “this is stupid.” I began losing motivation in my job. I longed to learn something more fundamental about computing, and get back that feeling of learning from a wise tradition. But I had no marketable skills outside of the web stack. No one doing low-level programming was going to hire me.

Up until this point, all my work had been client projects, either freelance or as part of an agency. I applied to a SaaS company thinking that, even if it wasn’t low-level programming, it would be different. I wanted exposure to more serious software engineering and a higher standard of quality, within the web stack that I already knew. There had to be some wisdom to absorb there. In short, I hoped I would find more to love. Maybe even more fun.

Well, I certainly found more … something. The most obvious thing was more code — more than any individual could ever understand completely. There was also more history — the codebase was already a decade old when I started. The number of decisions that had to be understood to stay oriented in any given piece of code was mind-boggling. There were also more old code frameworks kicking around. More colleagues. More customers. More scale.

Also more unit tests! More branch management. More code review. More production monitoring. It was indeed a higher standard of software engineering. But at first, all the “more” just blurred together into overwhelm.

The context was heavy, and the tiny pieces I was able to learn at a time felt like they would never add up. It had been 21 years since my first “view source” moment, and I thought of myself as experienced — but in my new environment, I felt like a junior developer.

I was not having much fun. For every one time I learned something cool, there were nine times that my “this is stupid” assumption would kick in and lead me to depressing thoughts about being stuck in a senseless profession, giving the best part of my energy every day to problems that shouldn’t exist. Once I even took a half sick day because I was in such a low mood by afternoon that I couldn’t accomplish anything. Talking to a therapist helped keep me functional in life, but it didn’t help me love my job. Code and I were basically broken up, but couldn’t move out because we couldn’t afford the rent separately.

💔 💔 💔

I spent several months absorbing context and asking for help what felt like constantly, though not as often as I should have. Finally, I could often put up a PR independently, or know where to start an investigation. After a year, having changed teams and gotten some better focus opportunities, I was occasionally the one writing the tickets. I had learnt enough to be moderately effective, but I still didn’t feel belonging, for a simple reason: I looked around at my colleagues and perceived enthusiasm and curiosity where I felt apathy. I gravitated toward tasks that would flex my existing skills and knowledge, rather than face the unknown and incur my “this is stupid” reaction, and the resulting feeling of not belonging.

Soon into my second year, I noticed something that was able to cut through that noise. I’d been helping to finish the new billing system for several months, and we were building the new Customer Support tooling to go with it. I found myself in meetings with members of CS team, hearing about the pain points of the existing tooling. When I heard human stories about common user issues and the manual workarounds used to solve them, it turned the gears in my head. I realized I had accumulated enough knowledge to envision how to remove that pain. When I looked at my job that way, I didn’t focus on things I couldn’t control, like whether the entire web stack was well founded. History was messy, but the point was, I knew how to make someone’s life better in the present.

It wasn’t an immediate game changer. I ended up advocating for UX improvements in CS tooling that I was told were not justified for internal tools. And I still felt apathetic towards much of my other work, where any concept of “the user” felt distant and abstract.

After a parental leave, at 18 months since hiring, I moved back to what was essentially the same team I had originally started on. Different team name, same domain — and a few new people. I saw the new people being baffled by the same things that had once baffled me. Mentoring them was rewarding, but more than that, their pain points inspired me to look more deeply into the tech debt in our domain. Just like before, I realized I knew how to remove some of that pain.

I began pitching cleanup projects. I had discovered a kind of passion. I still didn’t care about the tech itself. But I cared how it affected my colleagues, how it constrained what we could do for users, and I was excited that I knew what to do about that.

Another year of experience showed me what good roadmapping can do: tear down the artificial wall between product managers and engineers. Identify relationships between foundational and feature work. Surface forgotten feature knowledge, because tech debt and product debt are always related.

Maybe I didn’t have to love the code itself, if I cared about what could be achieved through knowledge of it.

🧠 💪 🫂

My relationship with code now feels complicated. Sometimes I enjoy it, but not in the truly creative way that I used to. Other times I agree with Jack Diederich: “I hate code, and I want as little of it as possible in our product.” I find myself eager to do my job, but code often feels like my enemy instead of my companion.

Some people talk about the Joy of Programming, a mixed rush of creativity and technical insight, but I’ve generally found less of it the more I get paid. It’s actually not that hard to find, in my experience — just grab any API that lets you place individual pixels — HTML5 Canvas will do — and write a loop that correlates colour to position in some way. Then make it weirder. Then make it animate. Painting with math! It’s an amazing feeling. But also, it doesn’t pay. Well, maybe you’ll make it into a game that people want to buy, but along the way, you’ll probably have to get through a lot of non-joy to have a shippable product. Or ideally, hire other people who find joy in those parts of the work.

Anyway, joy is great, but chasing joy is a poor guiding principle for software engineering. Important parts of the job require tolerance for the opposite. The colleagues I value most are good stewards who think of future colleagues, rather than joyriding through mysterious refactors without documenting their thinking.

That said, I don’t want to do any gatekeeping. There may be people for whom this job is entirely joyful and who are really good at it. And the web stack has changed qualitatively since 25 years ago. I mean, I still wish we didn’t effectively have operating systems in our operating systems (insert yo dawg). But the reasons for the inertia are better than ever. The modern web offers a development experience unparalleled at any other layer of the stack, plus the social motivation of being able to instantly share your work.

So if you do love code, huzzah. There are many good reasons why you might, and your passion is sure to light the way for others.

If you hate code, or are indifferent, that’s not incompatible with having a lot to contribute to software engineering. You may have other motivations, and your feelings about code may help you avoid creating too much of it.

So many of our technical foundations have hobbyist origin stories. Those tinkerers in their garages or dorm rooms must have loved code, right? Isn’t that why their work changed the world? Well, we can’t really know. Most people are more complicated than that. What we do know is, they did change the world and now it’s different. Software engineering was once an irresponsible diversion, rather than a profession with a past and future. Professions with a past are always less than ideal. And professions with a future thrive on diversity of all kinds, including diverse motivations.

❤️ 🧡 💛 💚 💙 💜 🤔

const canvasWidth = 256
const canvasHeight = 256
const canvas = document.getElementById("draw_here")
canvas.width = canvasWidth
canvas.height = canvasHeight
const ctx = canvas.getContext("2d")
ctx.clearRect(0, 0, canvasWidth, canvasHeight)
const imageData = ctx.createImageData(canvasWidth, canvasHeight)
for (let i = 0; i < imageData.data.length; i += 4) {
  const pixelIndex = Math.floor(i / 4)
  const x = pixelIndex % canvasWidth
  const y = Math.floor(pixelIndex / canvasWidth)
  const r = Math.round((x / canvasWidth) * 255)
  const b = Math.round((y / canvasHeight) * 255)
  const g = 255 - Math.round(Math.sqrt(x * x + y * y))
  imageData.data[i + 0] = r // R value
  imageData.data[i + 1] = g // G value
  imageData.data[i + 2] = b // B value
  imageData.data[i + 3] = 255 // A value
}
ctx.putImageData(imageData, 0, 0)
 
const canvasWidth = 256
const canvasHeight = 256
const canvas = document.getElementById("draw_here")
canvas.width = canvasWidth
canvas.height = canvasHeight
const ctx = canvas.getContext("2d")
ctx.clearRect(0, 0, canvasWidth, canvasHeight)
const imageData = ctx.createImageData(canvasWidth, canvasHeight)
 
for (let i = 0; i < imageData.data.length; i += 4) {
  const pixelIndex = Math.floor(i / 4)
  const x = pixelIndex % canvasWidth
  const y = Math.floor(pixelIndex / canvasWidth)
 
  const r = Math.round((x / canvasWidth) * 255)
  const b = Math.round((y / canvasHeight) * 255)
  const g = 255 - Math.round(Math.sqrt(x * x + y * y))
 
  imageData.data[i + 0] = r // R value
  imageData.data[i + 1] = g // G value
  imageData.data[i + 2] = b // B value
  imageData.data[i + 3] = 255 // A value
}
 
ctx.putImageData(imageData, 0, 0)

🤔 🤔 🤔

🥰