As a web engineer working across multiple projects and platforms, there are many things we’re expected to know. However, it’s important to stress that we don’t need to know every single technology or concept we’re likely to come across.
Rather, it’s how you manage the unknown that tests your mettle as an engineer, and there are ways to get better at facing unknown problems.
I like to think of managing unknowns like this – everything you don’t know is a risk that could cause obstacles or delays, but there are ways to consciously manage that risk which safeguard against getting stuck.
Occasionally, we work with legacy code, touching arcane tools like Backbone.js, various opinionated page builders, meta field management plugins, or browser compatibility shims. We also work with greenfield codebases where we get to push the limits of webpack and React, or we work with Altis, Elasticsearch, or similar.
Sometimes we inherit code that is optimised or structured in a way we’ve never seen before. Sometimes a project will face a genuinely new problem, or we’ll have to experiment with novel ways of organising code or tackling a common problem. In such cases, there’s no option to simply Google the answer.
The point is: there’s no way any engineer can be expected to know everything going into a project. So how do you give yourself the best chance of overcoming problems you haven’t encountered yet?
One of the most frustrating situations for a developer is to spend time building a piece of functionality, only to find out it wasn’t what the client needed. This can happen when a ticket includes terms that have a specific technical meaning, but the ticket writer was using them loosely. For example, a ticket might request a “block”, which to an engineer means a block editor component, but to a designer it may be shorthand for a bit of markup that could be achieved by a template part, shortcode, or a widget. The reverse can also be true – a specific word in a ticket might be mission-critical, but an engineer might assume differently.
In this instance, communication is key: if a ticket isn’t immediately clear, make sure you understand what’s needed before starting work. Writing pseudo-code can also help clarify what the steps in a problem are, and provides a first product you can share with the rest of the project team to make sure you’re all aligned in your understanding of the problem and desired solution. As a bonus, once you have the problem written out in pseudo-code, it should be much easier to see which parts of the problem you already know how to solve, which parts you have a vague idea about, and which parts are still complete unknowns.
Don’t avoid the problem
If you’re asked to estimate a task that you don’t have any idea how to tackle, it’s natural to make what you think is a high estimate, and maybe double it to be safe. This might seem like a good idea at the time, but if the unknowns are left vague at this point, even the most conservative estimate might not be enough.
We use consensus estimates (like planning poker) as a way of sharing knowledge about unknowns and validating concerns. Use these tools to your benefit! Communicating what you do and don’t know at this stage will help you get pointers early on and will prevent wasting time chasing down wrong assumptions or unlucky guesses. Transparency also helps to build trust in working relationships – we’d all rather be told the honest truth up front than be disappointed later.
That said, it’s not necessary to have a strict breakdown of how you’ll tackle an issue going into estimations, but you should be able to justify your estimate in some way. For example, “I don’t know how to do this, so I’ll give it a week” isn’t a useful estimate, and you’re just as likely to miss the estimate as you are to hit it if you pick up a ticket with that vague an understanding. But on the other hand, “this ticket involves creating an admin field, outputting that value on the front end, and somehow adding it to a REST endpoint so that I can add a block control” makes it really clear which elements are fixed and which may shift. No one expects you to have a crystal-ball window into the future, but clearly stating any obstacles you foresee will go a long way towards eventually overcoming them.
Isolate then treat problems
Sometimes, even after you’ve broken a task down into small chunks and tackled them in a logical order, you’ll still get stuck at a problem that feels too big to track down or explain: this is the point where it’s hardest to ask for help. It’s a small thing to be able to ask “how can I register a REST field for this post meta field”—as a matter of fact, if your problem is that clear, you can probably answer it yourself with a search. But if you’re stuck at a more vague point in the problem, like “why doesn’t this work?”, it might not be as easy to ask for help where you need it.
The tactic of progressively narrowing down the unknowns is the same when you’re trying to ask for help as it is when you’re trying to debug a problem on your own. Use any of the tools available to you—set debug breakpoints, insert var dumps, write unit tests—to pinpoint where the expected behaviour is breaking down. This might be enough to find the problem! And if not, you should at least have enough context to ask a clearly defined question. Work with the people trying to help you.
Finally, make sure you’re giving people enough information to answer your question. It’s often tough to guess from a description of a problem what’s actually going on – it helps if you can share links to your code or a gist. If an approach doesn’t work for you, explain what the problem or concern is with it – just saying “I tried that, didn’t work” to any suggestions people offer is a sure way to frustrate them and yourself.
Documenting the solutions you find after getting help is also a great way to foster a supportive, encouraging environment. Answering questions on Slack, pair programming, and providing support all take time, and feels much better to the person putting in that time if the knowledge you arrive at is shared publicly at the end of it. Any bug that one person faces and figures out should contribute to the overall knowledge pool accessible by the rest of the team.
Practice brings comfort
Learning how to manage unknowns is a skill developed over time. In a recent conversation we had internally, the team talked about how a principal engineer is expected to be able to “fight fires” by coming into any project and figuring out what needs to be done to get it finished, no matter what technology or tools it involves. This may or may not be a reasonable expectation, but my point is that the ability to work around what you don’t know is something that can be learned; starting with managing unknowns at the feature level until you’re comfortable looking at a codebase where everything is new to you.
Part of this is developing instincts and learning to trust your gut. It may never feel comfortable to estimate a task you have no idea how to do. I know from the times when I did sales engineering work that I’ll always feel a moment of panic after committing myself to a huge abstraction like “we can do this project in 130 developer days”. I get the same feeling when I start on a ticket and have to spend a couple of hours investigating an approach before I know if it’ll even be possible or not.
However, over time, through paying attention to the shape of what you know and don’t know, you can get to a point where your estimates are close most of the time, where your instincts on where to look for a bug are good, and where you can often give enough context to get a decent answer to your questions.
It’s amazing how many problems can be solved through better communication. Find out to work better with people from everywhere.