Some time ago I started to play with AngularJS to create a simple side-project app.
During this work I realized that I don’t like the differences between how the application works depending on the environment where I deploy it (localhost - faster and Docker on VPS - slower).
The UX was quite poor for slower network connection and I decided to do something about that.
The user experience was increased by applying some simple rules like:
- always show user what is going on with the system,
- show the user some animation when he waits to give a feedback that the system did not hang,
- grey out or disable buttons you don’t want to allow if the previous one was not finished,
- always give the user ability to cancel the task,
- …
There are plenty of resources on the web about how to design UX.
I started to reproduce the slow network connection on my local machine very naively by putting
some TimeUnit.SECONDS.sleep(3)
or alike into the REST boundary code on the server-side.
You know - quick and dirty solution.
However, I thought it would be nice to have some more generic solution and I came up with trivial Servlet Filter implementation that simulates server-side operations taking a bit longer than you expect.
You can see the code here:
package com.piotrnowicki.utils.slowdownfilter;
import javax.servlet.*;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Filter which only aim is to slow down execution of the filtered
* resources. It is useful in cases you want to test how your
* application behaves in slow-network environment.
*
* @author Piotr Nowicki
*/
public class SlowDownFilter implements Filter {
private static final Logger LOGGER =
Logger.getLogger(SlowDownFilter.class.getName());
static final String DELAY_PARAM_NAME = "delay";
static final long DEFAULT_DELAY_IN_MS = 5000L;
long delayInMs;
@Override
public void init(FilterConfig config) throws ServletException {
delayInMs = fetchDelay(config.getInitParameter(DELAY_PARAM_NAME));
}
private long fetchDelay(String delayParam) {
try {
return Long.valueOf(delayParam);
} catch (NumberFormatException ex) {
String msg = String.format("Invalid value for delay [%s] ms. Running with default [%s] ms",
delayParam,
DEFAULT_DELAY_IN_MS);
LOGGER.log(Level.WARN, msg, ex);
return DEFAULT_DELAY_IN_MS;
}
}
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
try {
TimeUnit.MILLISECONDS.sleep(delayInMs);
} catch (InterruptedException e) {
LOGGER.log(Level.INFO, "Thread interrupted", e);
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
// Do nothing
}
}
It’s so naively simple that it actually does the job ;-)
You just plug it into your web.xml
and (optionally) define the delay in milliseconds as a init-param
:
<filter>
<filter-name>Slow Down Filter</filter-name>
<filter-class>com.piotrnowicki.slowdownfilter.SlowDownFilter</filter-class>
<init-param>
<param-name>delay</param-name>
<param-value>2000</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Slow Down Filter</filter-name>
<url-pattern>/resources/*</url-pattern>
</filter-mapping>
Simple, useful and forces you to correctly prepare your user interface for network slowdowns.