Faking slow connections to improve user experience

Often, when developing sites locally, or even when you're on a fast connection to the live server, it's easy to forget that the experience in the real world can be different once latency and slow connections are added in.

For instance, that delete request over AJAX that removes a DOM element in microseconds on your local machine might take a second for someone in an area with poor connectivity. Does your app feed back to the user that the click or touch has been registered and that you're definitely doing something?

It's easy in Rails to make things happen remotely. Take a link like the following:

<%= link_to "Delete", some_item, method: :delete %>

This will send a delete request to the object. If you want this to happen over AJAX instead, it's very simple using remote: true:

<%= link_to "Delete", some_item, method: :delete, remote: true %>

Now you've made the same request with Javascript and your response can be a fragment of jQuery that removes the DOM element. If you're on a slow connection, the time it takes for that to happen can be significant enough that the user might think nothing happened and will attempt to click again. At best, this will raise an ActiveRecord not found error, at worst they might time that second click that they manage to delete another item. (There's a whole other conversation about confirmation vs undoability, but that's for another day.)

The first thing you can do is give feedback that the action has been registered. Rails allows you to easily disable a link or form button and (optionally), replace it with something else. So, let's tell the user we're working on their request:

<%= link_to "Delete", some_item, method: :delete, remote: true, data: {disable_with: "Deleting…"} %>

Now, when the delete link is clicked, it will be disabled (so clicking again does nothing) and we feedback to the user with a subtle interface change that we are performing their request.

So, maybe you're super awesome and always remember to think about things like this, but when working on a complex app, it's easy to miss areas where feedback and perceived responsiveness are not quite up to scratch, especially when they are non-issues for your super-fast, zero-latency, local-database, non-contended, SSD-toting, retina Mac.

I've started using a little helper that can be switched on and off to simulate, in a super basic way, what it's like to use your app with a slower connection, making it really obvious where the feeback mechanisms aren't what they should be.

In my application_controller.rb file I add the following:

before_action :sleepy if Rails.env.development?

  def sleepy
    sleep ENV["sleepy_time"] || 2

This adds a two second (or whatever you've put in the sleepy_time envoronment variable) delay to all requests.

Obviously, you could expand this out to be able to switch it on and off at will (it gets a little tedious simulating slow connections all the time), but as a way to test your application with a bit of a delay, it's super simple and will make it incredibly obvious where your interface needs to feed back more information to the user, or make use of non-remote Javascript to really tighten things up.