Software Engineering: Puzzles and Dilemmas | by Matt Schellhas

Setting people up for success means more than assessing their capability. How to pair programmers with the work they love.

Photo by Taras Hrytsak on Unsplash

I am fond of saying that software engineering is all about tradeoffs. You can’t make one program solve every problem, so much of the work is deciding which problems you are going to solve. But that isn’t entirely true. Software design is all about tradeoffs. The actual implementation is less uniform.

Consider a basic API that reads and writes to a database.

What are the endpoints to make, how to structure your database, and generally what the interface looks like is flexible. Your design will make tradeoffs — perhaps to improve ease of use at the expense of runtime performance, or perhaps to make maintenance easier even if time to market is slower. And while there are some clearly rubbish designs you could choose, there is no objectively Best Solution to these problems. The dilemma of which tradeoffs to make when none are clearly superior is one that software engineers face regularly.

But that’s not all that goes into the API. You still need to write the code to communicate with the database, you still need to do input validation, you probably need to add some authentication, and you will still need to deploy the damned thing. There are far fewer tradeoffs here. Once the schema is designed, the programming language chosen, the API surface area defined, the names and function separation figured out (including the dreaded ORM debate)… the rest is mostly connecting the dots. This part of software engineering is more like solving a puzzle. Getting data to and from a database has a very unambiguous success criteria. Either the data is right or it is not. Even high level things like authentication and deployment are effectively solved problems these days. Just like any other puzzle, once you know the trick the whole thing becomes a matter of execution.

Because in my experience, this separation is one of the most important “shapes” when it comes to getting the shape of the team to match the shape of the work. I personally despice puzzles. Just executing a known algorithm is boring to me. It is drudgery. The payoff at the end when the puzzle is solved isn’t nearly enough motivation for me to overcome all of the work necessary to get there. Some engineers love that part of the job though! Having a clear path to follow, and an unambiguous measure of success is extremely comforting to them. The process of solving the puzzle is satisfying to them, and the feeling when the work is complete is something they love to chase.

Every non-trivial software engineering project has both kinds of problems. It will have dilemmas where there is no single correct answer. Some dilemmas might not have any good solutions! You’ll need people who are comfortable working with that sort of ambiguity. And there’s going to be some problems that have known solutions. Some will be tedious, difficult puzzles to crack. You’ll need people who enjoy that sort of challenge as well. The problem is that very few people are great at both.

I hire around it. Yes, part of “make the shape of the team match the shape of the work” is about experience with different technologies. If I have a bunch of hard UI work, then I’m going to hire mostly experienced frontend people. But it also includes these dilemmas versus puzzles preference and other, less prominent preferences. If I can pair work up with people’s strengths (what really engages them; not necessarily what they are great at), then people are happier and simply more effective because they’re doing what they love.

How do I do that? Well, I ask them. In an interview, I will talk about different common motivators (pleasing customers, cracking a puzzle, designing a solution, accomplishing tasks, cleaning up a codebase, contributing to the company’s mission, etc.) and then ask what sort of work gets them out of bed in the morning. Then I ask what sort of work do they dread. It’s not about effectiveness, it’s about how the work makes them feel (as cliché as that might sound). Occasionally there is some follow up questions to understand why Something like UI work or meetings might fill them with thrills or dread, but most folks can provide insightful answers. And there’s no wrong answer! Sometimes my team needs someone who thrives in ambiguity, and sometimes I need someone who is driven to finish the puzzle.

Unfortunately, there are a few ways that companies make their lives harder when it comes to the different sort of problem solvers that teams need.

The first is the current FAANG style hiring process used by most tech companies which has a coding portion, a design portion, and a behavioral portion. The coding portion is often leetcode style problems for candidates to solve. There’s usually only one way to manipulate that list in O(n) time, and if you know the trick, the puzzle is easy. The design portion is usually a nice, ambiguous sort of dilemma that will have multiple potential solutions (if your interviewer is open-minded/competent). I can accept the argument that a top tier software engineer should be good at solving both sorts of problem, even if they don’t enjoy it. But that doesn’t change the fact that this sort of interviewing practically guarantees that candidates will dread some part of the process. And knowing what they’re good at is usually less important than knowing why they love to do some things.

Then when engineers join they’re often rewarded differently. “Senior” levels often come with leadership or mentorship expectations. Some companies will only hire engineers with leadership ambitions or can interface with customers. All of that work is filled with ambiguity. Even if puzzle loving folks can make good leaders, the entire concept of vague people work with no clear success is a terrifying prospect to overcome. Many will just look at all of the great implementation work they did, and wonder why they have to do all of that other crap to get promoted. More likely, you’ll just end up with a bunch of folks who hate puzzles trying to do a bunch of puzzle work, leading to grumpy engineers and worse team performance. Or worse yet, you get a bunch of people doing as little puzzle work as possible, since that’s not what will get them promoted.

The last failure mode comes when companies try to separate the valuable architecture work from all of the tedious puzzle work. Some even go so far as offshoring the puzzles. They think that if it’s just a matter of executing some algorithm, then anyone can do it. Software engineering work is not so easily separated in practice. In the API example, the line between design and implementation is a fuzzy, curving beast that sometimes includes implementation details like function and variable names. In the end, you need the shape of the team to match the shape of the work. Separating architecture from implementation means your now-separate teams don’t match the shape of their cohesive, intertwined work. Just because someone dreads puzzles or dilemmas doesn’t mean they get to be completely free of them. It’s still part of the job.

Leave a Comment