Apr 13 – Feb 14
Which? is a powerful brand in the UK, combining highly trusted product reviews with consumer advice and campaigning.
Their web site attracts millions of visits each month and helps drive their large subscription base. The project was a responsive rebuild of the Home Entertainment Reviews segment, beginning with TVs.
TV reviews are presented with high-impact use of 3D rotating images overlayed with tech highlights and the all-important Which? score and review breakdown. Review sections were loaded with pushstate for speed. We integrated with other review APIs such as Reevoo and Pluck.
Working with Rails for the first time and understanding more of the web stack was very empowering; when this contract ended I immediately sought out another using Rails. It has its weaknesses – the Asset Pipeline is a bit too tightly integrated with the front end for comfort – but the speed and ease that you can piece together and debug an app will be a revelation to any front end dev.
The event hub / aggregator pattern is fantastic for decoupling code modules but the emitted events are usually ‘fire and forget’ so if the event listeners want to feed back an error or status report to the event emitter, they can’t.
Adding promises solves this – if the event is published then each event listener will receive its own promise. Once the listener has performed any synchronous / async tasks that it needs to, it can choose to resolve or reject the promise it has received. If all event listeners report success using their promises, then a promise passed back to the emitter will resolve successfully. However if one or more of the listeners reject (fail) their promises, it will fail.
Because the event listeners are receiving promises, they can wait until async activities eg. ajax are complete before resolving their promise. Handy if decoupled modules need to save state or complete animations before feeding back to the event emitter.
The code is on Github, hope it helps someone!
It’s been a year and a day since my last post. Plenty has been going on in the last 12 months. I finally took the dive into mobile that I’d been putting off until the tools improved, with a rebuild at Which? in London.
Which? made some bold technology decisions to break with their legacy codebase. Previously using Java in the web app and API layers of the stack, they kept it for the API and adopted Ruby on Rails for the web application.
I’d heard great things about how fast you could build stuff with Rails. I didn’t come to front end development via a server side language so a framework like Rails, that gives an easier introduction to that layer, has great appeal. Without a doubt it’s enabling and makes you a better all-round developer.
Another big thing that learning Ruby has given me is the ability to write automated UI tests with Cucumber. I had heard about CucumberJS early last year but it looked a bit in-progress. Cucumber with Ruby looked more complete with better docs and plugins.
Regarding BDD and the practise of describing features using Given.. When.. Then syntax, that are readable by the business – I’d heard experienced consultants saying things like
“Feature files are a nice idea but I’ve never actually seen them used by a business in real-life”
I don’t buy that view – at Which? the features have been described by a business analyst in Jira then handed over to us to automate. We might make some minor tweaks in language not meaning, to make it possible to automate them.
The company, developers and QA then have a clear contract for what we’re building, and even better, we can code directly against it. When we fulfil the contract, the tests turn green.
BDD is of course an investment – in mocking up the data, working out robust ways to test the code, trying to make the tests run as fast as possible, and dealing with occasional (and sometimes inexplicable) fragile tests that work one minute then fail the next.
Finding a balance between unit and UI tests
You burn through a lot more unit tests because they’re more tightly tied to the implementation, which in any decently maintained codebase should be evolving constantly as it’s refactored. Parts of your code inevitably get thrown away, implementations change and the unit tests frequently turn red until you turn them green again or remove the redundant ones. The closer the tests are to the metal, the more ephemeral they are.
On the other hand, a UI test, once turned green should only turn red infrequently – if there’s a breakage in the interface, or if a refactor is significant enough to require the parts of the step definitions that touch the implementation, to need updating.
Again, am I saying don’t write unit tests? Absolutely not. They can guide the design of lower-level logic and help find flaws in it. And they can instantly expose regressions as you refactor.
I’m just questioning some commonly received wisdom that you should have orders of magnitude more unit tests than UI tests. All tests are an investment – the time spent writing and maintaining them gets paid back in fewer regressions and production bugs.
I’m totally sold on the BDD way of working now. You won’t always find it happens in a project – I’ve come across the odd very capable front end developer who didn’t see it as part of their role to write UI tests. Although it was in a technology stack that didn’t make it easy to write UI tests (hello Java).
Some QAs get nervous about developers doing it, but they shouldn’t. If the devs write UI tests for the web app that mock out services like authentication and APIs, then it frees up the QAs to write those true end-to-end tests using real copies of the services.
Writing tests and seeing them run green gives calm to the developer. You don’t get that sick feeling in the run-up to a release that you might have caused regressions with your last commit, but aren’t sure where. The better your tests, the more secure you feel. If you haven’t, try it!
If you want to use Jasmine to test something that’s inside a RequireJS module, for example a Backbone model, you need to find a way to load the Require module from your Jasmine spec, and pause the running of the test spec until the module is loaded and ready.
I need a few things loaded up front for my tests to run – Require itself, Backbone, jQuery, Underscore.
First of all I’ll load require.js from my jsTestDriver.conf.
Backbone is expressed as a dependency in my require.config, and will in turn pull in the other two libraries:
Now I can load the main RequireJS config file, and hence those dependencies, by loading an extra require.config snippet, which specifies where files can be found under the test server, and then loads the main config itself:
This extra require.config snippet is loaded directly by jsTestDriver.conf. The ‘serve’ directive below makes all files under the /app folder available to my test code under a ‘/test/app’ path. So for example /app/mymodel.js could be loaded by a Jasmine spec from the path /test/app/mymodel.js
Now if I run jsTestDriver, my dependencies are all loaded up, plus my require.config, but not my application. This matters as I should only need to load in the specific module I want to test. I can do this using a require call inside my test setup (beforeEach). Wrap it in a “runs” block then use a “waitsFor” block to halt things until it’s loaded.
These patterns took a while for me work out when I started testing Require / Backbone apps using Jasmine. Hope this helps somebody!
I quickly liked and later cursed the fact that Backbone gives you some structure yet lots of flexibility, especially around managing views.
At the start the flexibility makes picking things up conceptually easy. As you move beyond the most basic app you need to keep the creation and destruction of views under control, especially when you start nesting them. Backbone gives you very little to handle this, but Marionette plugs the gap nicely.
Terms used in Marionette
- A layout is a type of view that can hold other views
- The element within that layout that holds / wraps the nested view, is called a region. A region can hold one view at a time. It can reload the same view multiple times as required, or swap in different types of view.
- Marionette.Layout actually extends Backbone.View (not directly, but it does inherit from it). So as a layout is a type of view, you can actually nest a layout inside a region of another layout
Your template for the outer layout might be:
.. and your template for the view to be nested inside the region:
Why? I think the view should control its container element, it’s more maintainable. You know that everything relating to that view is in one place in your codebase and there are no fragments of the view contained in other templates.
The outer layout can use its regions to show views, when it has been rendered itself. Use the ‘show’ method of the layout’s region. When you call ‘show’ it automatically calls the render method on the subview.
The View definition for the nested view would contain a className attribute so the view container will be created dynamically when the view is rendered.
You can hook into the onRender and onShow events.
What’s the difference between onRender and onShow?
Remember that when the parent region’s ‘show’ method is called, it automatically calls render on the subview as well, so onRender will of course be triggered after that. At this point the view has been templated and a DOM fragment created. However it hasn’t yet been attached to the parent region so it’s still only in memory and not actually part of the page yet. If you put a breakpoint in the onRender and in your browser console looked for a parent of this.$el (the view’s container element):
it would return 0.
The onShow event fires after the view has been attached to its parent region. If you ran the same line in your console during the onShow event, it would return 1.
More reading on Layouts
Marionette provides structure in the biggest areas left vacant by Backbone. One of the best things about it is its creator Derick Bailey is a prolific blogger and documenter (and Stackoverflow lifesaver).
Check out his blog post – Managing Layouts and Nested Views with Backbone.Marionette and the Marionette docs on Layout.
“Speed is a feature” and I think the trend of templating the initial page render on the client negatively impacts performance, and also robustness and device independence.
Don’t get me wrong, Backbone, async updates and responsive web apps are all fantastic and I use them enthusiastically. But I think they should build on a solid first delivery of the page as markup – it will work more consistently on the ridiculously wide range of devices out there. You’re then taking fewer risks in the “hostile environment of the browser”. I think someone once called it Progressive Enhancement…
Twitter’s recent rebuild shows they came to the same conclusion.