1. Design Tips for
Dynamic UIs Under
Heavy Load
Patrick Lightbody
Founder, BrowserMob
patrick@browsermob.com
http://browsermob.com
2. Patrick & the ‘Mob
Open source contributor
- Apache Struts 2.0 (previously WebWork)
- Founder of OpenQA.org and SeleniumHQ.org
- Creator of Selenium Remote Control
Founder of BrowserMob
- On-demand load testing and monitoring services
- Uses real web browsers in various cloud
environments (EC2, GoGrid, Rackspace, etc)
http://browsermob.com
3. The Problem
AJAX => Faster (Perceived) Experience
- More logic on front-end with asynchronous calls
to server logic on back-end
But when the back-end is slow or error
prone, the experience tends to be worse
- Non AJAX => Full page load => spinning “e” for IE
Most complex UIs built in isolation
- Tested on localhost (no load, infinite bandwidth)
http://browsermob.com
4. Recent Example
Load test for a UK-based car insurance
provider
Frequent errors in which the the browser
was showing a registration form claiming
that field X was not filled out
A real head-scratcher... we were 110%
positive that field was being filled out by
the test
Finally figured it out: reproduced by hand
http://browsermob.com
5. UI Design
First Name Patrick First Name Patrick
Last Name Lightbody Last Name Lightbody
Company BrowserMob Company BrowserMob
Email Email Email is required
Home Phone 4158305488 Home Phone (415) 830-5488
Cell Phone Cell Phone
onchange
inject form data back in
Form Form
Representation Representation
(JSON) (JSON)
Web Server
http://browsermob.com
6. Typical Sequence
First Name Patrick
Last Name Lightbody
Company BrowserMob
Email
Home Phone
Cell Phone
http://browsermob.com
7. Typical Sequence
First Name Patrick
Last Name Lightbody
Company BrowserMob
Email patrick@browsermob
Home Phone
Cell Phone
http://browsermob.com
8. Typical Sequence
AJAX Request #1
First Name Patrick
Form
Last Name Lightbody Representation
(JSON)
Company BrowserMob
Email patrick@browsermob
Home Phone
Web Server
Cell Phone
http://browsermob.com
9. Typical Sequence
AJAX Request #1
First Name Patrick
Form
Last Name Lightbody Representation
(JSON)
Company BrowserMob
Email patrick@browsermob
Home Phone
Web Server
Cell Phone
http://browsermob.com
10. Typical Sequence
AJAX Request #1
First Name Patrick
Form
Last Name Lightbody Representation
(JSON)
Company BrowserMob
Email patrick@browsermob
Home Phone
Web Server
Cell Phone
http://browsermob.com
11. Typical Sequence
First Name Patrick
Last Name Lightbody
Company BrowserMob
Email patrick@browsermob
Home Phone
Cell Phone
http://browsermob.com
12. Typical Sequence
First Name Patrick
Last Name Lightbody
Company BrowserMob
Email patrick@browsermob
Home Phone 4158305488
Cell Phone
http://browsermob.com
13. Typical Sequence
AJAX Request #2
First Name Patrick
Form
Last Name Lightbody Representation
(JSON)
Company BrowserMob
Email patrick@browsermob
Home Phone 4158305488
Web Server
Cell Phone
http://browsermob.com
14. Typical Sequence
AJAX Request #2
First Name Patrick
Form
Last Name Lightbody Representation
(JSON)
Company BrowserMob
Email patrick@browsermob
Home Phone 4158305488
Web Server
Cell Phone
http://browsermob.com
15. Typical Sequence
First Name Patrick
Last Name Lightbody
Company BrowserMob
Email patrick@browsermob
Home Phone (415) 830-5488
Cell Phone
http://browsermob.com
16. Problem Sequence
First Name Patrick
Last Name Lightbody
Company BrowserMob
Email
Home Phone
Cell Phone
http://browsermob.com
17. Problem Sequence
First Name Patrick
Last Name Lightbody
Company BrowserMob
Email patrick@browsermob
Home Phone
Cell Phone
http://browsermob.com
18. Problem Sequence
First Name Patrick
AJAX Request #1
Last Name Lightbody Form
Representation
(JSON)
Company BrowserMob
Email patrick@browsermob
Home Phone
Web Server
Cell Phone
http://browsermob.com
19. Problem Sequence
First Name Patrick
Last Name Lightbody
Company BrowserMob
Email patrick@browsermob
Home Phone
Cell Phone
http://browsermob.com
20. Problem Sequence
First Name Patrick
Last Name Lightbody
Company BrowserMob
Email patrick@browsermob
Home Phone 4158305488
Cell Phone
http://browsermob.com
21. Problem Sequence
First Name Patrick
AJAX Request #2
Last Name Lightbody Form
Representation
(JSON)
Company BrowserMob
Email patrick@browsermob
Home Phone 4158305488
Web Server
Cell Phone
http://browsermob.com
22. Problem Sequence
First Name Patrick
AJAX Request #2
Last Name Lightbody Form
Representation
(JSON)
Company BrowserMob
Email patrick@browsermob
Home Phone 4158305488
Web Server
Cell Phone
http://browsermob.com
23. Problem Sequence
First Name Patrick
Last Name Lightbody
Company BrowserMob
Email patrick@browsermob
Home Phone (415) 830-5488
Cell Phone
http://browsermob.com
24. Problem Sequence
First Name Patrick
AJAX Request #1
Last Name Lightbody Form
Representation
(JSON)
Company BrowserMob
Email patrick@browsermob
Home Phone (415) 830-5488
Web Server
Cell Phone
http://browsermob.com
25. Problem Sequence
First Name Patrick
Last Name Lightbody
Whoops!
Company BrowserMob
Email patrick@browsermob No more Home Phone!
Home Phone (415) 830-5488
Cell Phone
http://browsermob.com
26. Reproducing
Re-create the slowdown/error in your code
- Can be turned on/off with a “test” flag in your app
Run load tests simultaneously with
browser tests
- Run a Selenium test on loop while using JMeter
Run your browser through a network
simulator
- Simulate bandwidth, latency, response codes, etc
http://browsermob.com
27. Mocking out Failure
Add simple if statement in the server code
that sleep for X seconds or throw an error
Attach a debugger, break on a line, and just
sit there before you resume execution
If you’re feeling especially adventurous,
make a generic “filter” for your app
- In Java this would be a “Servlet Filter”
- Could be made very advanced
http://browsermob.com
28. public void doFilter(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain)
throws IOException, ServletException {
String uri = req.getRequestURI();
Random r = new Random();
if (r.nextInt(100) > 80) {
res.sendError(500, "20% chance of failure!");
return;
}
// sleep between 0 and 5 seconds
Thread.sleep(r.nextInt(1000) * 5);
chain.doFilter(req, res);
}
http://browsermob.com
29. Selenium During Load
Hard to predict all ways in which things can
go wrong
- Easier to simulate the ways things should go right
Run a standard load test against the REST
interfaces
- Ideally, this should “realistically” slow them down
Simultaneously, play back Selenium scripts
- Check for functionality over performance
http://browsermob.com
30. Selenium as Load
Similar approach as before, but on steroids
Run hundreds or thousands of Selenium
scripts in parallel
- This means you need hundreds or thousands of
browsers!
- Checking performance and functionality
concurrently
Produces hyper-realistic load scenarios
and almost always uncovers unexpected
problems
http://browsermob.com
32. How It Works
Automatically provision
browsers from the cloud
http://browsermob.com
33. How It Works
Automatically provision
browsers from the cloud
http://browsermob.com
34. How It Works
4000 CPU Cores
3.5TB of RAM
Automatically provision
browsers from the cloud
http://browsermob.com
35. Network Simulators
Another approach is to run your browser
through a network simulator
Usually done via an HTTP proxy that can be
tuned to:
- Return fake error codes
- Simulate bandwidth & latency
- Drop packets
- Record network performance
http://browsermob.com
36. Charles Proxy
Charles Proxy
- “Web Debugging Proxy Application”
- Windows, OS X, and Linux
- Cost: $50 per user w/ bulk discounts
- http://www.charlesproxy.com
http://browsermob.com
37. BrowserMob Proxy
Announcing today: free, open source utility
Supports HTTP and HTTPS
Produces Firebug-like results for any
browser
Simulates different bandwidth, latency, and
error conditions
Available for download today!
- http://proxy.browsermob.com
http://browsermob.com
40. Design for Failure
Never forget: AJAX is still a network call
- Networks fail for a lot of different reasons
- Networks can be unpredictable (ie: request #1 can
take longer than request #2)
Add hooks to AJAX requests for the
unexpected
- Write your code to store request params & retry
Test for failure too!
http://browsermob.com
41. Be Careful w/ DOM
Only change the DOM state if it’s absolutely
necessary
- Avoid aggressive “synchronization” common in
some AJAX toolkits (ex: our form sync example)
Merge data together rather than replace
- Partial page loads (div.innerHTML = ...) is also bad
- Involves more work, but results in a much better
experience when things don’t work well
http://browsermob.com
42. Lock the UI
Don’t give the user a chance to change
things that might also get changed by you
- In our form example: disable the form elements!
- If necessary, use a modal dialog box to lock the
entire UI
But remember: have a recovery plan!
- Test for failure and ensure that the UI unlocks
when unexpected behavior occurs
http://browsermob.com
43. Inform the User
Always keep the user informed about what
is happening
Ideally give them an “escape hatch” if
things go terrible wrong
- Set thresholds for when to present the escape
hatch
- GMail is a good example of this
At minimum, simple “loading” indicator
http://browsermob.com