Because UX Engineering is a relatively new role and the responsibilities can widely shift depending on the company, it can be challenging to explain to folks what we actually do for a living.
What's a UX Engineer?
Generally speaking, a UXE (User Experience Engineer) is someone who uses design thinking and user behavioral data to implement solutions with code.
A UXE's skills can be considered a subset of frontend development in that they are focused more on the front of frontend and focus on translating design into code as close as possible.
While this role seems like a perfect fit for design systems, UXE's can flourish in any team that requires close collaboration between design and development.
Facilitating design alignment
Our design team includes representation from each of our business units, to make sure each product has voice within the system.
One of my main responsibilities is to ensure our customers have consistent experiences. This means that we need a shared, common understanding of how a component should look and function in any platform and product.
To help designers on our team understand which experiences are disparate amongst our products, we needed to establish (and commit to) explicit attributes within our design specs:
-
Anatomy
: How we reference each element -
States
: What happens during a user interaction -
Variants
: Alternative forms of the component -
Configurations
: Supported options that end-users can choose from -
Standard/Defaults
: What comes out of the box
Creating a template in Figma with corresponding visuals for each business unit has been a great way to get buy-in for alignment.
As a UXE, it is also my responsibility to help designers understand how previous implementation may not have matched the original spec, and to create a plan to get us to our desired outcome.
Establishing constraints
When designing a component, it can be easy (and fun) to hand-pick certain values. It's also easy to accidentally pick a wrong value from the system when building out a new component.
This is how we end up with scenarios where placeholder
typography in a textarea
could differ than what was established previously for a standard input
, when really design had intended them to share the same attributes.
UXE's typically work with designers to explain the impact of design decisions (or confirm this wasn't a mistake in the spec) so that situations like this don't happen.
It also means we sometimes need to act as negotiators in order to strengthen durable logic within our system.
Architecting scalable blueprints
Because we are responsible for making sure a component accurately reflects design specifications, it's crucial that a component supports the same logic, plus future considerations.
Anticipating how a designer would want to modify a component is critical.
Strong architecture ensures less code repetition, helps with open-source contribution, and provides a foundation that helps guide scalability discussions.
Blueprint decisions include:
- Defining the relationship between components
- Defining the relationship between parent and child components
- Determining if a variant is a separate component or defined through a prop
- Establishing what configurable aspects get exposed to an end user
- Creating and implementing design tokens
UXE's should constantly be asking:
How would someone want to implement this component?
The more time and care that can be invested at this stage, the less likely the team will need to implement a breaking change in the future.
Optimizing performance
While this article has emphasized making sure the component looks and behaves as expected, we also need to look at the bigger picture with how our decisions impact the rest of the design system ecosystem.
An optimized component includes evaluating:
- Bundle size
- Tree shaking
- CSS over SVG
- Asynchronous loading
- Strong types
You can have the most customizable component on the planet, but if it takes ages to load, no one will use it.
Promoting and enforcing accessibility
By the time a component is ready to be coded, the design should adhere to minimum accessibility requirements including:
- Typography
- Line length
- Contrast ratios
- Minimum tappable area
Beyond this, a UXE needs to consider other interactions that may not have been uncovered during the design-focused part of the team's workflow.
Typically, my accessibility checklist includes:
- High contrast mode
- Reduced motion styling
- Alt text/aria props
- Keyboard navigation
- Dark mode support
Incorporating these aspects into the component is only one part of how we help ensure accessible experiences. We also need to help end-users (product developers) understand what they need to consider during implementation.
I find it helpful to bake in as much accessibility logic possible to mitigate risk that user will forget to incorporate it. For example, if a user doesn't supply a value for a label
, you can make it a requirement that a user must provide an aria-label
value instead.
This not only helps ensure the experience is accessible, but also educates users on best practices.
Writing tests
Writing tests ensures that the logic behind the component is reflected accurately in visual snapshots.
Typically, you want to test against:
- Whether elements did or didn't render
- If certain classes were applied
- The render matches values from the design specs
At Intuit, we open-sourced proof, a test runner for Storybook!
Providing demos & documentation
After all the alignment conversations, architectural back-and-forths, and code iterations... we finally have something to show for it! 🎉
Providing a curated set of configurable examples and implementation documentation is the most visible part of a UXE's contribution to the project.
Iterative reviews
I believe in sharing early, and sharing often.
While working on a component, each pushed commit generates a new Storybook link that anyone can review and comment on within GitHub. The benefit of this is that feedback doesn't get lost in Slack, and we can keep track of change requests.
To standardize how teams provide component demos, we include Storybook as part of our Design Systems CLI.
Advocating for the community
As part of the design systems team, the UXE is also responsible for being an advocate for both product designers and developers.
This includes:
- Helping users onboard to the system
- Answering questions
- Making sure their voice is heard during sprint planning
- Addressing feedback
- Guiding users to the right team members
It's easy to get overwhelmed by this run-the-business type of work. Conducting office hours using Calendly is a great way to make sure you can stay connected to the community and guard your time (and sanity).
What success looks like
Because we have to switch gears so often and interact with so many people, it can be challenging for folks to get a full sense of the work involved.
A successful UXE is someone who:
- Goes with the flow and doesn't mind throwing away code to make something better
- Feels comfortable explaining technical constraints and requirements to non-technical audiences
- Tends to push back on one-off, unscalable designs
- Puts ego aside to listen to the community AND willing to collaborate on solutions
- Has intuition on how to add extra polish to an experience
I've found what's worked best is to include all disciplines in a JIRA board so that everyone is aware of what tasks need to be completed until we're ready to ship.
Wrapping up
Even though UX Engineering is still in its infancy, the need for this type of role has been around for ages.
I'm excited to see more of these opportunities pop up, and super happy I was able to make the role what it is for our team.
For additional reading, I definitely recommend checking out Emma Bostian's article on UX Engineering.
Hopefully you're now interested in hiring a UXE for your team, or you'll start applying as one!
--
Originally published at kellyharrop.com on February 10, 2021.
Top comments (0)