Engineers for Designers: Getting to Know an Engineer

(This is the first in a 4 part series about engineers for designers. This series is based on a talk originally presented as part of Whitespace.)

Software engineers are special creatures, and as an engineer myself, I embrace the stereotypes. It takes a delicate touch to work with engineers, especially for people in less technical roles, such as design. Although everyone means well, differences in motivations and methods can lead to miscommunication and disagreements. The best way to move past these differences is to have empathy by putting oneself in another’s shoes. The purpose of this first post is to discuss the personality and role of an engineer so that designers (and others) can understand their background.

(Note that in the following post, I will be lazily using the terms “engineers” and “designers.” Although the discussion may extend to other related jobs, I am largely thinking specifically about software engineers and graphic designers for web applications.)

The Engineer’s Personality

I think it’s fair and not inconceivable that most people think of software engineers like “Vizzini” from The Princess Bride. Engineers can be pedantic when asked to justify some position, or even unprompted as they get into technical details. There will be a lot of big words and half-explained thoughts that can feel superfluous. Engineers are incredibly stubborn about their code and reluctant to concede that their approach could have been wrong or that it really is a bug and not a feature. Engineers can also be uncaring about the problems of users (or just about anyone else) and are instead deeply dedicated to the needs of their “system.” Most engineers are also introverted. They can be interesting and fun to talk to given a chance, but their default mode is not to engage with others.

This characterization becomes more problematic because engineers tend to see themselves more like “Neo” from The Matrix. Most obviously, engineers often can only see the code behind things. When presented with a toy, a software application, or a machine, engineers instinctively look for the logical or functional components behind it to understand how it works. Engineers also see themselves as the “one” designated to save the world by fighting the evils of messiness and complexity that are out there. This mandate is also a part of an engineer’s deep faith into their own ability and clarity of thought, even at the expense of others (see https://plus.google.com/102342595285863325267/posts/NWqidcgmvpn).

Like many things, the truth lies somewhere in the middle of these two characterizations. Understanding the opposite perspective, however, is the first step to overcoming differences and hopefully leading to more sympathetic communication.

The Engineer’s Job

Although the personalities may vary between engineers, engineers all share the same high level job: to build software by writing code. When people ask me what I do, I tell them that I write code. And usually not a lot. That’s it.

That response is intentionally glib for comedic effect, so I can break down a typical task into a few parts. The steps are:

1. Research
2. Architect
3. Build
4. Test

The exact tools to do this can vary. We often need to go backwards and redo steps, and some practices switch up the order of these. Like the scientific method we learned in school, not everyone does it exactly this way, but it’s often similar.

The first step is to research, which has a few major parts.

Research

Engineers need to research what they’re writing code for. Although engineers can appreciate code for its own sake, it’s better if it’s targeted to a specific purpose. If they have a product manager, there will often be a spec provided, which the engineer must understand and perhaps clarify. Without a product manager, the engineer will be responsible for either developing a concept internally or going out to do the research. In any case, there should be a reason to work.

Engineers also need to research what the existing context is for their new work. Tasks never exist in isolation from some use case or some code. In a large codebase, it’s important to know what components are already provided, what workflows need to be integrated, and how other code will be affected by the addition. This knowledge can – to some degree – be internalized with experience, but it is often a big point of learning.

Finally, engineers should research externally to see what other tools or processes can be used. One of the best parts of software is the broad ecosystem of services, libraries, and other open source code to be used. Many tasks have already been tackled by someone else, and it’s often easy enough to just snap in a library to do, for example, a specific transition, rather than try to create it oneself. We try not to reinvent the wheel because we are also lazy and the wheel is pretty great as it is.

The next step is to architect, which also has a few big parts.

Architect

After doing the research, it’s time to pick an approach. Sometimes, there are best practices and processes for tackling a particular problem. Often there isn’t a best approach, and we need to balance effort, robustness, complexity, and more to determine how to proceed before ever writing code.

One big concern is what affordances the code will allow. Not only should code address the problem at hand, it should also be flexible in anticipation of future changes. Being too flexible, however, is its own curse, and that can lead to unnecessary complexity. Complexity makes development more difficult altogether and needs to be carefully managed.

Finally, before we start coding, we need to know how it will affect other parts of the codebase and whether we need any prerequisites before starting. With new things, we need to figure out how it will fit into the existing system: this addition can require tweaks elsewhere. With changes to existing things, we need to figure out how it will affect dependent components: this can also require tweaks elsewhere. These tweaks can require action or consultation with other engineers as well, lest we break someone else’s code without warning.

Now that we have all of that out of the way, it’s time to start coding.

Build

Often, engineers need to backtrack to earlier steps as we encounter unanticipated problems. Perhaps a library doesn’t work quite right, or maybe we just didn’t think of something beforehand. Either way, we’re constantly re-evaluating as we go.

Although the code is the most concrete part of the job, most of us don’t spend that much time writing it. If we have prepared well, the actual typing goes relatively quickly because we know what needs to be done and understand the technology enough not to be bogged down in programming language problems.

There are some issues to address in the coding process perhaps with language features or code readability. If the coding itself takes a long time without going back to previous steps, it is time spent figuring out why the code isn’t working. And still not working. And still not working. Then we realize we had a minor typo and wasted the last 2 hours researching arcane documentation in crazy workarounds. Debugging requires both experience and holistic understanding, so it’s hard.

And even after we finish all of the coding, we’re still not done with our part because we still have to test.

Test

We have to ensure that the code meets specification or else it doesn’t matter how beautifully it was written. We have to look for edge cases where the code might crash. And even if we’re really confident that we did it all right, we should write unit tests to make sure that each logical part of our code works. And we also need to write integration tests to make sure that the flows as a whole always work. These are part of a regression suite so that even if the code works perfectly now, we can ensure that no change in the future will ever break our code.

Then, we can hand it back to designers or product managers for review.

The Engineer’s Biggest Concern

Hopefully that gives you a sense for what an engineer does and how various aspects manifest in their personality. I want to wrap up this section by emphasizing what I believe is an engineer’s biggest concern and motivation: stability.

When it comes to being a software developer, a lot of problems can be blamed on someone else. The designer made it look the way it does; the product manager wrote the spec; the business people had the requirement. The one thing that engineers have to own is stability. If the product breaks, that is on engineering. Being slow or under-delivering can all be justified by stability because if it isn’t stable, then it becomes the engineer’s fault.

A lot of the engineer’s concerns discussed above radiate from stability. Poor research can lead to misunderstandings that cause instability. Complexity puts the system outside of the engineer’s understanding to keep stable. Testing and re-testing frameworks ensure stability. It’s all about stability.

Next time, I will talk more about how engineers work with product and design as a part of a team.

Posted by: Kevin Leung, VP of Engineering