This is going to be one of those once upon a time articles so buckle up and prepare for a story.
When I wrote my first lines of code I wasn’t quite convinced that I would be able to do that for a living. For me it was something that people with extraordinary math and logical abilities could handle. Nevertheless I pressed on. I went through a bootcamp, got some projects in my portfolio and managed to land an internship at a small digital agency.
At this point I found everything in the software world amazing so I was more than eager to face any challenge that came my way. However, nothing grabbed my interest as much as AJAX and Single Page Applications did. This was way back when the first version of Angular (AngularJS) was the framework to use. This tool revealed the true power of the web to me.
I could create shapes, forms, animations and interactions with code. The ability to add and remove elements from the DOM dynamically, to send and receive data in real-time based on user input - it blew me away.
Ever since I started programming professionally I’ve loved the connection with the people on the receiving end of the product. I love to see how they use the tool, how they interact with it. I enjoyed getting feedback and discovering new ways to make the product even better. We have certain constraints put on us so we need to do everything we can with the options that we have available to provide good UX.
But "With great power comes great responsibility" - as uncle Ben says. This complexity introduces a lot of potential problems which we need to deeply consider when building rich front-end applications.
Being an UI engineer comes with its own set of problems. Working on the first thing that the user sees about a product means that you don't have much room for mistakes. Your work is what the users interact with. Even though they are using the whole technical stack under the hood - the UI is the gateway through which they are doing it. Let's discuss some of the challenges that UI engineers face.
It's Not Just About Style
Yes, working on the UI you need to have an understanding of what looks good and what doesn't. However, having a pretty interface doesn't make it usable. It's not just about having the proper colours, animations and shades but about providing consistency and intuitiveness.
Don't take me wrong - it's important for a product to please the eye. But it's critical for it to be intuitive first and use styling only as a way to make it even better. There are numerous applications that look stunning but are hard to use because the creators paid more attention to looks rather than usability. As UI engineers we don't want to be in this boat.
We need to provide a seamless and consistent user experience. Every person that uses our product goes through a subconscious phase of exploration. The way that we position elements on the screen teaches the user what they can expect. In other words - if we put a primary button on the right we need to stick to that decision throughout the app. We can't change our design philosophy every month because that frustrates the users.
Give Feedback to the User
We touched on that in the previous point but it's important to reiterate on how critical giving proper feedback is. Often times our products work in unreliable conditions. We need to send and receive data across the network which opens a lot of possibilities for something to fail. Now the user doesn't have to know about everything that is going. They need to know whether their action is successful or not and if they have to do anything about it.
When things work as expected and the status is green then subtle marks are okay. The real problems are when something fails. I find that sending a generic message in the lines of "Ops, something failed!" is a really bad thing to do. The user can't know if it's because of their input, because of the network or a failure on our side. So more specific messages with a call to action to the user are clearer - "Looks like our servers are getting hammered. Could you please send this request again in a couple of minutes?".
If they do some action which takes time because it goes on a queue or something it's worth to keep track of it and give feedback about the progress. If they expect to see something on the page but instead it is empty they would most likely try submitting again and queue another action. It's better to signal that their request is still being processed.
Also as UI Engineers we can bend time and space a bit. We can show data in the UI before it is actually persisted in the storage or do changes that we expect to eventually become consistent. With tools like Redux it's easy to keep track of what action we're handling and do some UX shenanigans to make our app seem faster - optimistic updates, loading screens, transitions.
Guiding the Experience
We need to guide our users through the different actions that they can take. We can't just put a giant form in front of the user - we need to make the process interactive, enjoyable and safe. The users know what they want to achieve but if they haven't interacted with your product they are probably not sure how to do it.
By styling the UI and using certain layouts we can guide them to what action they should take. Having a lot of elements on the screen leads to noise so we can blur or darken the rest of the UI when the user is focusing on something important.
Let's get back to the form for a second. Maybe we can split it in multiple steps that get stored in local storage in case they leave the site halfway through. Putting a progress bar shows the person how far in the process they are and lets them know long it will take. We can also give them immediate feedback when they are filling the fields so they know that the data they've put is valid.
We can prompt them when they are closing the tab to make sure that they don't close the app on accident. Those are just some simple considerations - in reality it depends a lot on the aim of the product and the audience.
Most applications are about some form of data presentation - text, images or something else. It's critical to provide consistency when someone is reading or updating the data that they are storing with us. Imagine updating some record, then going to another screen and seeing old data. This is quite tricky because it depends on components that are not in the UI layer. Maybe the user's request is stuck in a queue (again) or for some other reason hasn't been processed yet.
Imagine that you update your profile image and open a list of posts that displays your name and photo. Shockingly it still shows your old profile picture even though you updated it. As a developer you're not immediately worried because you know that the app may use a third party service for them. As a user you most likely let out a four-letter word and go back to update the image again. With modern tools it's quite easy to keep track of state in the UI. We can bend time a little and add the new image to it before we get confirmation that it is stored.
Again - data consistency is a challenging problem in distributed systems as a whole and it's deffinitely not up to UI engineers to solve it. However we can still go the extra mile for the sake of UX.
I truly love working on the front-end because I feel that my work provides immediate value for the users. Dan Abramov also has a really good article on the Elements of UI Engineering.
But as time went on I understood that while the UI was the closest part of the application to the user, this didn’t mean that the other pieces in the puzzle produced less value. If the interface creates the main part of the user’s impression no program can be complete if a single piece is not working properly.
I decided to take everything I’ve learned so far in the software industry and all the product knowledge I’ve acquired while working for startups and once again move to a more full-stack role. A position in which I’d be able to touch multiple parts of the stack at once and make sure that our users get the best experience possible.
While I still hold affinity for polished user interfaces, I now deeply admire well designed distributed systems.
Highly Available services that make sure that even if there is a missing piece from the picture our users will still be able to reach their data.
Secure systems that protect the users from harming themselves.
Scalable products that can seamlessly scale and potentially serve millions of people without breaking a sweat.
A good UI is just the start. In order to create a truly amazing product you need to apply the same principles and responsibilities all across the stack. The whole organisation, every team should look at their work this way.
I’m running a small newsletter. Join 300+ others to get my thoughts and musings on software engineering and philosophy every now and then. No news, tutorials, ads or spam.