00:00:11.160
Okay, so today we're going to talk about small details and their big impact.
00:00:16.320
The general topic area here is that it takes a lot of little details to get a product to work well. It's actually pretty hard to give a talk on any of those details because, on their own, they're pretty boring.
00:00:29.679
So, we decided to put together a talk that includes a few vignettes that hopefully motivate you to think about the small stuff in your own applications, and also give you a sense of what we think about while working on our product.
00:00:42.239
First of all, I am Yehuda Katz, often known as ycats. I work on a lot of open source projects, perhaps too many, but I absolutely enjoy it.
00:00:54.079
And you probably know me from some of those projects. My name is Liz, and I'm known as infinite math on Twitter. I used to be a cartoonist for about ten years before getting into engineering.
00:01:06.400
I have published about five graphic novels and just started getting into programming a year and a half ago, and I've been working at Tilda on Skylight for about three months.
00:01:18.040
Let’s talk about the concept: Death by a Thousand Cuts or that big things come in small packages. Every day you make a choice—sure, your app works and it does its job, so your users are technically getting what they paid for—but you can do better. We can all do better.
00:01:36.520
User experience is a story, like a movie; you know exactly how you want it to go from beginning to end. The user signs up, logs in, and interacts with your landing page. But what if they click on something unexpected? What if they take a wrong turn?
00:01:51.680
They can easily end up in a 'Choose Your Own Adventure' style scenario that you never planned for. Suddenly, they might find themselves on the Vampire Express to Terror Island. Weird things happen, and users end up in unexpected places. It's your job to ensure they're guided through seamlessly without them realizing it was a weird place to begin with.
00:02:25.000
You don’t want your user experience to resemble that scene from Dune, where Patrick Stewart carries a pug into a laser battle for some reason. You want it to feel more like Gandalf riding in on a bunch of eagles to save Frodo and Sam at the peak of Mount Doom.
00:02:48.920
Sure, it may not make a lot of sense if you think hard about it, but while you're in the moment, you think, 'Yeah, of course, this is what happens.' That’s a good user experience.
00:03:13.440
Today, we’re going to talk about four different vignettes, and the first one involves what seems like a very small problem.
00:03:20.280
But before diving into that, I want to take a moment to explain what Skylight is, to give you context.
00:03:27.680
This is Skylight; a few months ago, when you logged in, you would see a list of your endpoints sorted by something we call Agony.
00:03:38.840
Agony basically indicates things we think are probably good for you to work on. If you have an endpoint that doesn't get hit often, we don't care as much if it's slow, but if you have an endpoint that gets hit a lot, any slowness matters.
00:03:51.680
So we try to combine those into an intuitive experience. We also have these little red icons that mean there are some database or memory problems, with further details provided. This is the experience you should definitely check out at our booth.
00:04:05.360
On this page, you can see a bunch of numbers, but the Agony index used to be invisible; it just formed the way the default list was sorted. This was frustrating for users, as they could understand Agony but had no way to click and sort by it.
00:04:18.320
We realized we needed to make that more visible. In the column labeled RPM, for example, users were confused by what it meant. RPM stands for Requests Per Minute, something learned quickly, but those unfamiliar with the term often found it unclear.
00:04:36.480
People kept saying that there were too many values like 0.01 or 0.03, which seemed to have the same significance. Initially, we determined that if users didn’t care about the difference, we might as well display everything as 'less than one' instead.
00:04:49.680
However, that only created a slew of 'less than one' values. This problem took a long time to figure out, which I want to discuss further.
00:05:06.479
Our great designer recognized that saying 'RPM' was the core issue. He suggested we change it to 'popularity.' That's great, but when we looked at how to visualize it, he proposed using a filled bar to represent the popularity of each endpoint, where not very popular ones would have an empty bar.
00:05:24.120
We looked at this design and felt it encapsulated what we wanted to convey, so we decided to ship it. Skylight uses feature flags to gradually roll out changes; we tested this on our app, and while 'popularity' was indeed better, it wasn’t what we truly desired.
00:05:36.760
Now, let’s explore why that happened. Initially, we assumed we were dealing with a normal distribution—a bell curve pattern. In essence, most data points cluster around the mean, with fewer points falling at the extremes. For instance, a ten-foot tall person is as rare as a zero-foot tall person.
00:05:54.760
While that distribution clears up a lot of issues in the physical world, many things actually conform to a log-normal distribution, which doesn’t mimic the bell curve taught in school and can be counter-intuitive.
00:06:10.840
This distribution appears in various contexts, such as income distribution, survival rates, city population sizes, and commute distances, all exhibiting this surprising similarity. If you look at your Skylight endpoints, you might notice these patterns.
00:06:26.640
It’s common enough that a performance company literally named itself log-normal to highlight the discrepancy between this and the traditional bell curve. Our designer had the wrong intuition, thinking we were analyzing a bell curve when we were really working with something else.
00:06:38.880
The first solution that comes to mind when encountering this issue is to rescale the numbers using a logarithmic scale. However, this poses an issue because users tend to think that if a bar is twice as big, it signifies twice as much popularity.
00:06:51.360
The concept of pre-attentive visual processing explains how people instinctively react to visual stimuli, making it important for the designers to consider how users perceive size while processing information quickly.
00:07:08.839
Our designer, for instance, initially used a bar on the left that was filled red. It was easy to identify because the visual element was strong, while the right side took longer to recognize; it lacked a distinct feature like a filled versus empty variable.
00:07:22.760
The keywords are visible, weakness versus strength. Users had the expectation that doubling the size of the ink would correspond to double the popularity, leading to confusion and inaccurate interpretations.
00:07:36.120
Additionally, when employing a slippery metric like popularity, it’s important to consider if that truly conveys much meaning. This icon provides general-aspect meaning, which is flexible and difficult to misinterpret.
00:07:56.760
For Skylight, as a Rails profiler primarily targeted at developers, we gave our users the option to log in using GitHub, allowing for a quick and simpler sign-in process.
00:08:10.760
The users would click 'Sign in with GitHub,' which leads them to a page where they authorize the app, after which they are seamlessly returned to the platform.
00:08:28.880
While most users enjoy this seamless experience, we still wanted to address the less-than-happy paths.
00:08:41.959
What is the happy path? It’s when the user connects their existing Skylight account to GitHub by first signing in with their email and password, heading to the settings page, and clicking 'Connect to GitHub.'
00:08:54.239
They would then see the connected account information, including their GitHub username, and could sign in with GitHub moving forward.
00:09:05.840
A common issue identified is that users often forget whether they originally signed up with an email/password combination or GitHub. To reduce confusion, we now display the connection information on the account settings page.
00:09:30.480
If the GitHub account they authenticate with is already linked to a different Skylight account, we will notify them with a message at the top of the screen.
00:09:45.039
What happens in edge cases, specifically for users who have an existing Skylight account that isn’t yet connected to GitHub yet? When they click 'Sign in with GitHub,' we redirect them to an interstitial page.
00:10:01.759
That page contains a pre-populated email form with the email from their GitHub account, guiding them to enter their password upon signing in.
00:10:18.320
Once signed in, we automatically connect their account to GitHub, allowing them to sign in with GitHub easily.
00:10:35.160
As for users who already have a Skylight account when clicking 'Sign up with GitHub,' we don't want to treat them as new users.
00:10:52.840
Even if they clicked sign-up, we still log them in as if they signed in, but we make sure to confirm their identity. After all, it's conceivable that they intend to sign up, but their coworker might be logged into GitHub on their computer.
00:11:12.560
If that's the case, we casually inform them who they're signed in as, with a helpful welcome message at the top of the screen. If they aren't that user, they can sign out and sign in with their own GitHub account.
00:11:36.520
For cases where a Skylight account is linked to a GitHub email, clicking 'Sign up with GitHub' leads to an interstitial page with an error message stating that the email is already taken.
00:11:53.720
In this scenario, they would need to sign out of GitHub and sign in with their account.
00:12:05.680
Implementing OAuth was a challenge. GitHub's configuration allows a single redirect URL, and it doesn’t differentiate between a user signing up or signing in.
00:12:20.040
We had to find ways to support all these different user pathways while still maintaining clarity.
00:12:34.160
Interstitials are generally viewed as detrimental; we all hate those pop-ups enticing us to download an app when we're on our phones.
00:12:50.440
Thus, we made a decision to include them upon realizing we were choosing between an awful experience for a few users or a slightly awkward one for many.
00:13:11.600
It's essential we don't divert users intending to sign up into someone else's account—nobody wants that.
00:13:26.799
Meanwhile, we aimed to minimize the typical frustrating experience of interstitial pages. Anything to ease the burden on users was our guiding principle.
00:13:41.760
If GitHub provides an email address, we want to expedite logging into their existing account by auto-filling that field. If they need to enter their password, then focusing on that field should be a priority.
00:13:55.519
Let’s transition and talk about Rust. At Skylight, we utilize Rust, often mistaken for a trendy choice.
00:14:06.720
When we began using Rust, it wasn’t the hyped technology, and many had apprehensions about it being a new and scary language.
00:14:23.680
However, we had solid reasoning behind using it. The primary challenge was collecting data efficiently from your application for analysis.
00:14:39.920
The key was instrumenting the application without impacting its performance.
00:15:01.720
If an agent slows down the application it's supposed to analyze, we have already failed.
00:15:14.720
Thus, it’s vital for everyone creating these tools to prioritize maintaining performance.
00:15:28.799
The natural inclination is to simply write the agent in Ruby, given it's safe and included in the Rails environment by default.
00:15:47.520
Ruby is useful for collecting baseline information, such as rendering times; however, it tends to slow down when grabbing fine-grained information.
00:16:05.920
In particular, we needed to capture detailed data on memory allocations within your application, requiring connection to every allocation.
00:16:21.360
Just as valid an option would be coding in C. However, placing performance-critical code into your application raises concerns.
00:16:36.280
The risk of errors causing application crashes is high. Even seasoned C programmers can struggle with reliability and security.
00:16:53.480
C++ poses a similar issue, raising fears about long-term maintenance and unexpected crashes losing users.
00:17:10.000
We suspected executing many components in C or C++ could create potential user anger and damage our relationships.
00:17:21.520
Around this time, Patrick Walton from the Rust team published a blog post indicating that garbage collection isn’t necessary, as Rust’s ownership model suffices.
00:17:39.720
I discovered this in October and initiated the task of rewriting the critical sections of our application, focusing on serialization of traces and sending to the server.
00:17:58.480
After a couple of weeks, I saw good progress and ended up shipping a functional segment written in Rust.
00:18:14.520
We didn’t undertake a complete rewrite of the agent. Most functionality should remain in the Ruby layer, but transitioning performance-critical aspects to Rust has proven beneficial.
00:18:30.480
Since implementing Rust, there have been no crashes in the agent attributable to our code, showcasing the stability and safety that Rust provides.
00:18:42.769
This stable nature is a remarkable feature of Rust, where a compilation event confirms that the code is sound, mirroring the security risks present in Ruby and C.
00:19:02.240
The Rust 1.0 blog post underscored stability through various factors: memory safety without garbage collection, concurrency without data races, and abstraction without overhead.
00:19:15.760
Each of these attributes feels like contradictions, yet work within straightforward primitives.
00:19:30.720
Ultimately, Rust empowered us to develop code that's efficient without the dread of crashing, a crucial value during our operations.
00:19:46.160
We could ship our allocation tracing feature confidently when many thought it unfeasible.
00:20:03.520
Now, Godfrey is delivering a talk on Helix, a binding layer between Rust and Ruby, which is indeed exciting, so be sure to check it out.
00:20:19.679
Next, let's talk about names—names hold profound significance.
00:20:31.920
Correctly addressing someone by name fosters respect, and when someone introduces themselves, people usually attempt to pronounce it right.
00:20:52.720
But names can vary; individuals might prefer names that differ from their government IDs. Nonetheless, official documents must reflect their legal names.
00:21:06.840
Changing names may stem from innocuous reasons or serious circumstances where addressing someone by their legal name poses safety risks.
00:21:18.480
Thus, beyond just respect, valuing your customers should drive you to address them by their chosen name.
00:21:36.840
For me, being called Elizabeth instantly signals a sales pitch, prompting me to hang up. Services that automatically use full names can feel disconnected.
00:21:52.240
When emails awkwardly address me as 'Greetings, Elizabeth Bailey,' I feel the same disconnect, making the service appear robotic.
00:22:09.360
No one wants faceless communications from a corporation, especially when your team cares deeply about the product.
00:22:26.720
Thus, how do we address names at Skylight? Initially, we collected first and last names and addressed emails using only their first names.
00:22:43.520
This worked sufficiently in many situations but didn't accommodate those with alternative names, as over half of our company utilizes names not on their IDs.
00:23:04.240
Many of our Skylight email subscribers rely on these updates about our projects and conference participation. We cannot risk alienating customers by using incorrect names.
00:23:20.640
Thus, we transitioned from first and last names to full names and nicknames; all email communications will now utilize the nickname while still keeping full names secure for billing.
00:23:43.680
For existing customers, we concatenated their first and last names for their full name in database records and assigned their first name as the nickname.
00:24:04.520
To track and confirm chosen nicknames, we added a Boolean field called 'nickname confirmed,' marking existing users as false until verified.
00:24:21.840
This improvement is critical, but also lies in how we manage these names in the user interface.
00:24:35.920
Upon signing up, we ask what name users prefer, asking permission to call them so.
00:24:50.360
If they accept, we confirm their nickname. Otherwise, they can input a different one they'd like to be addressed by.
00:25:11.480
If someone doesn’t initially input a nickname or refuses to enter one, we keep track and make it clear later that they can opt for a new nickname.
00:25:33.520
After saving and confirming a nickname, another minor wording change is that we say 'we will call you' versus 'can we call you?' for a subtle but thoughtful distinction.
00:25:51.560
If a user hasn't confirmed yet, we show them the nickname and ask if they're alright with that name, allowing input during the signup process.
00:26:10.240
This feature benefits users who create accounts via GitHub as well. If they don’t confirm initially, an additional layer through the settings page exists to remedy that oversight.
00:26:27.920
Developing this user interface introduced challenges, as portions of it are built with Rails views while most run on Ember.
00:26:44.640
The signup page is currently a Rails view. When I first began programming, I primarily learned Ruby on Rails before diving into Ember.
00:27:08.240
At the time, I found myself paired up with Rocky, with both of us new to Skylight.
00:27:21.520
Neither of us had built anything in plain JavaScript, but our perspectives complemented one another in navigating this challenge.
00:27:42.760
We needed to implement functionality to debounce typing, giving users time while entering their name to avoid showing inputs until completion.
00:27:59.840
Without debounce, the user would see each character as they typed, leading to an unpleasant experience.
00:28:18.080
Debounce seemed straightforward but, surprisingly, is not native to JavaScript. We ended up creating our own jQuery debounce plugin.
00:28:36.560
On top of that, certain methods like trim are not universally accessible across all browsers, prompting us to polyfill JavaScript's string.trim.
00:28:56.520
It's critical to remove surrounding whitespace for accurate input presentation. Many applications neglect this, leading to frustrating experiences.
00:29:13.440
Overall, we prioritize getting users the correct name upfront, allowing for easy adjustments whenever needed.
00:29:34.360
In closing, while developing applications, little details truly matter.
00:29:46.320
Focused attention on the small components can fade in the busyness of technical work, like selecting libraries, structuring migrations, or other components.
00:30:07.679
You're ultimately crafting an experience for your users.
00:30:24.720
As Liz mentioned, creating an app resembles constructing a movie—it's essential to focus on creating an enjoyable user experience.
00:30:45.440
Making an amazing movie requires fastidious attention to every detail. Pixar's animators will dedicate days to perfecting a single second.
00:31:02.560
There's a marked difference between applications developed with care and those where the intricate details haven't been considered.
00:31:20.480
You can easily downplay aspects like choosing names, but these elements significantly affect the overall experience.
00:31:37.440
Take time to determine what happens when a user presses 'Sign up' with GitHub—indeed, the user experience should differ based on context, and such nuances matter.
00:31:55.440
As users, we notice these distinctions between applications—those that are attentive to detail inevitably succeed.
00:32:09.760
We are grateful to provide this glimpse into our daily routines at Skylight—spending time on the little things results in positive impacts.
00:32:23.440
Our periodic development journal shares insights created by our engineers, highlighting their experiences working on Skylight.
00:32:38.080
If you’re interested, please sign up for our emails, as they provide valuable insights—just remember, you can do so for free.
00:32:54.880
We initially anticipated only a few sign-ups but were happily surprised to see hundreds engaged in our journals.
00:33:10.080
Sharing work experiences enhances the community atmosphere. Don't underestimate the impact that discussing these insights can have.
00:33:25.840
Thank you all!