a sprinkle of SWE advice

Note: I originally wrote this to a coworker back in 2018, who had asked for Software Engineering advice. I recently rediscovered it and decided to post it here.

We will make mistakes

Everyone will make mistakes. It’s inevitable! They may be big, they may be small. One of my first engineering managers in my rising junior summer internship told me that all software engineers will have at least one major catastrophe that’s caused by a mistake on their part. That’s why we have a system designed to present mistakes, or even just mitigate them when they inevitably happen - code reviews, automated tests, rollbacks, database backups, etc.

When we write software, we want to make sure we don’t paint ourselves into a corner. We should be a bit defensive with our logic - being too defensive will strangle our velocity - but sane checks so that we have some protection. We can’t expect the planets to perfectly align every time we want our code to run properly.

This is to say - relying too much on strict conditions for an important trigger or action or other behavior will often result in upstream changes causing unrelated issues in our code. If we need to be strict, we will want to build in ways to be notified when those strict assumptions are wrong. Flexibility and visibility allow our systems to grow with minimal changes - strictness often results in small changes breaking many things and legacy systems when the original author is no longer working on the project.

Further, there’s a human element - it’s easy to be frustrated when a mistake by another person or by another team results in an issue or more work on your plate. There’s a time and a place for discussing how we can prevent this from happening again in the future. But it’s a glass house situation - we too will make mistakes, and should approach other’s mistakes in the way we’d like our own mistakes to be approached. We hope for empathy and understanding to work toward a good solution without open expression of frustration. We hope people do not perceive us as failures or as flawed for a mistake. And we must always keep that in mind when dealing with other’s mistakes. Without it, blame becomes a game of hot potato and a culture emerges where mistakes are hidden only to pop up at a later time with much graver consequences.

“Should we do it?”

Saying no to a project, task, or piece of work request does not admit that the project cannot be technically done. In small companies it’s easy to say yes to a lot of requests or ideas, which in turn flood the short-term priorities and results in piling onto the list you’ve already committed to.

One thing I’ve struggled with, and I think many business-facing engineers have to deal with, is saying no. Early on, it felt like saying no was admitting defeat - that saying no was just saying work was not going to be able to be completed because I was technically insufficient and that I had to prove myself.

There are many aspects here that make every situation unique - importance of task, organizational structure, current priorities both at a team and company level, etc. Often even though saying no feels like the right thing, it may not be possible to say no. It’s an art to figure out which items are important and which aren’t. Ultimately, it comes down to how you feel the best way to spend your time is, and if the company and your manager are aligned with that. In a small organization, there isn’t usually the “protection” you might find within a highly rigid organizational structure by a larger company.

The more you know the less you know

The depressing part of a software engineering career is realizing how much you don’t know. Maybe that’s not depressing, but inspiring. Every deep dive, spike, language, or new open source project seems to enlarge the circle of information you know that exists.

Rather than being defeatist about it, we can see this as an endless opportunity for us to learn new concepts and ideas we can incorporate into our daily work. It’s easy to stay within the current mental framework we have, continually sharpening the same tools we use day in and day out. However, I’ve found it most enlightening when I encounter a completely new programming perspective that flips the ideas I’ve always held as true on their head. This might be moving from a dynamically typed language to a statically typed language, or object-oriented vs functional style programming. It may be using the idiomatic style of new languages. It could be reading books about concepts you’re not familiar with.

When we entertain concepts and ideas we haven’t included in our work previously, it can do a few things:

  • Validate or invalidate the choices we’ve made and the methods we’ve used to implement behavior
  • Demonstrate an alternative to the method in which we’ve implemented behavior. Does this new concept strengthen the work we’ve already done? Does it provide for a better future programmer experience?

It’s too easy to become stuck in one method of doing something. We must always strive for improving our work and the way in which we think about things. It’s easy to enter a project and think “well, this isn’t how we do it in node.js land, so it’s wrong.” If we learn to be idiomatic with the tools we’re using, we can sometimes reframe our ideas and expand our vision, and potentially bring these back to our daily work.

I don’t think this section is structured too well, and has a puddle of a theme. Overall, it just comes down to not living on a flat earth, and constantly challenging the ideas we’ve held by exploring all the other work people are doing. I think we can always stand to learn something new, which will improve how we think about our own work.