Speeding up Rails tests with Spring

I found Rails tests were running slow, these things helped.

Instrumenting application.rb

First, I added some logging to application.rb

  1. def logg(m)
  2.   puts "#{DateTime.now} #{m}"
  3. end
  4.  
  5. logg 'require boot'
  6. require File.expand_path('../boot', <strong>FILE</strong>)
  7. logg 'done'</code>

The main bottleneck was bundling (Bundler.require(:default, Rails.env)), which took around 12 seconds on OSX.

Goodbye Bundle?

10+ seconds delay for running a test is unacceptable, leading me to contemplate ditching Bundler. However, that’s a lot of manual overhead, requiring us to manually import stuff, and we’re using Ruby here because it’s supposed to cut out tedium like that.

Spring forward

The real answer is to avoid running application.rb every time using the (defaultly-installed) Spring. Spring should keep a master process around after the app has booted, so we don’t need to run application.rb every time. I thought Spring was already running, but with this kind of delay, I had to check it.

Opened a new terminal, started tailing /tmp/spring.log, and then made spring start using it in the main Ruby test running terminal:

  1. spring stop
  2. export SPRING_LOG=/tmp/spring.log
  3. tail -f /tmp/spring.log

This is perfect for diagnosis: I have the aforementioned application.rb logs in the main terminal and the other window shows me what Spring is up to.

Ran a test:

  1. truby test/models/user_test -n /username/ # truby is my alias for RAILS_ENV=test bundle exec ruby ...

And yes, I saw application.rb running through all the motions, 10 second bundle, etc. And no spring action.

Ran it again.

Same thing. We’re booting the whole app for every one of these tiny tests!

The thing is Spring only works for a select few commands – any rake command and just a few Rails commands (rails console, rails generate, rails runner). This caught me out as I was trying to run rails server and Spring again wasn’t running. I guess the thinking is you shouldn’t need to restart web server often in dev anyway – stuff is already auto-reloaded according to default config.

So the answer was to run tests through Spring. I’d previously stopped doing that due to difficulty running a single test method, but now it’s easy.

  1. rake test test/models/user_test /username/

In the above case, the second argument is an optional test method or regular expression. Unlike the direct invocation, no “-n” is needed if a regex is provided.

And, problem solved. I see Spring is cloning the booted process and the test runs in a fraction of a second.

Chrome’s new user switcher is a major design regression

I rely on profile switching completely for day-to-day use. I have my personal Google account, Google apps account, a sandbox account for testing in clean-slate, a company account, support account, account for Google Play, account with read-only access to some servers which can be authorised to analytics tools, etc. Consultants often have one or more accounts per client.

The old “switching between different browsers” doesn’t cut it, Chrome knew it when they introduced this feature, and with the latest update, it’s become barely usable.

The new user navigation switcher:

  • Shows text labels instead of the instantly recognisable, customisable, graphical ones. Welcome to 1990, have a nice day.
  • Requires an extra click to switch (“Switch profile”) after hitting on the current profile name.
  • Takes several seconds to open the switcher menu in its own dialog.
  • After clicking twice to open the switcher and waiting around for it to paint, it only shows 8 profiles (what?!), only the first 8 in alphabetical order, and won’t scroll for more. Turns out you have to manually expand it to see all profiles! Hidden core features ftw!
  • The big compromise was to show the old menu if you click with the second mouse button. Well guess what, many of us don’t have a second mouse button!
  • The old menu can also be launched with … a 2-finger tap on the trackpad. Yes, the only way to access this functionality is with an awkward 2-finger tap. It works 35% of the time for me, I’m trying to get some practice in so my average can hopefully get up to 50% (dream big). Keep in mind, this 2-finger tap is *the only way* I can access some of my profiles (those beyond the first 8).

Bottom line: Chrome had a great feature for years, which no other browser supports to this day. The architects of this feature have dropped the ball completely, given no explanation for these counter-intuitive design decisions, and hopefully Firefox or Edge will be there to pick up the slack.

All of the above issues are articulated in the bug tracker in very much the same way as the new design has no-one explaining the benefits. It’s hard to see anything good about the new design.

It’s not a case of wanting to stick to the old thing for the sake of not learning a new interface. It’s a case of a serious design regression in every dimension, one that hasn’t seen any rational justification from the designers.

Sometimes you can just tell when the designer doesn’t use their own feature.

Time spent in mobile apps considered harmful

TechCrunch reports on time spent in mobile apps. Saying users spend X time on these kinds of apps sounds like the best way to gauge engagement, but caution advised. This is a useful figure for apps like Facebook, whose revenue is closely tied to how many eyeball-seconds are spent in the app. But as others have pointed out, it’s flawed.

Consider the following app categories:

  • E-Commerce – as the above tweet mentions, a staggering amount can be spent with a few taps. Uber’s whole magic is precisely how effectively it gets out of the way.
  • Notifiers – how about getting recommendations from FourSquare when you walk past it, or seeing when your friend is nearby. Apps can be valuable even if they are mostly about poking you when something happens.
  • Audio – Few people outside of stock photo models specifically sit down to listen to music and podcasts. Audio apps are fundamentally about multitasking, which means users will do some basic management, hit play, and get out of the way. Whether they leave the app in the foreground or background is fairly arbitrary, so as long as these metrics are measuring eyes and not ears, it’s skewed.

“But we have ping pong tables”

As competition for developers heats up, companies are falling over themselves to attract the best talent. A common tactic is to offer perks, probably because someone heard Google offers free food and maybe because it sounds appealing to a manager who’s trying hard to channel their inner programmer.

Perks aren’t bad, but in my experience, the best workers don’t pay much attention to them. The best workers want to actually get work done. They care about the people they work with, their work environment, the technology and tools they can use, and the product they work on.

Of course, developers are motivated by extrinsic factors such as salary, health care, vacation time, etc. But if they are a sufficiently talented engineer to be worth hiring, they’ll also be smart enough to know the true value of a free gym membership.

Perks can make a difference, but they should be considered in the context of things developers actually care about.

Ping pong, for example, might add to the work environment for some developers. So it’s a small subset of a small subset of the overall things devs care about.

Free lunch, the real benefit is not money saving. Developers earning six figures are smart enough to know that. The benefit is saving them the hassle of arranging or queuing for lunch and being able to socialise with their team mates. They will probably end up working more instead of standing in a line somewhere, but that’s just fine for both parties.

For talented developers, it’s far more important to consider work-related perks like big displays and flexible operating system choice. Those things help developers kick ass all day long. They are more attractive to the kind of people who are able and motivated to get the job done.

(On ping pong tables specifically, they will backfire if they cause even the slightest noise disruption. Programmers need to work in quiet environments. Also, what makes you think programmers will like them more than other people you are trying to hire? It can come across as condescending to think it’s something programmers will value and others won’t.)

Google’s Many Marketplaces

Google’s Many Marketplaces

While Play is an “all-in-one” store for Google, there are numerous marketplaces or catalogues from Google, defined as resources where third parties may share content for other third parties to consume.

Here’s a crowdsourced list, courtesy Twitter. I’ve wikified it here; please add any others there.

The list could be useful for developers considering how to distribute their app or extend its reach.

For consumers

For businesses

For developers and online service providers

Android M Highlights

Google IO has now wrapped up. The conference went smoothly and overall there has been a decisive swing back in focus towards developers. Android remains the centerpiece, in terms of the keynote, schedule, and displays, and Android M is now here and available to developers.

Here are some highlights of Android M following IO. I haven’t yet tried it, though I’ll be flashing the giveaway N9 before long.

Mmmm … that name

If two makes a pattern, Google has now established the single-letter name convention for developer preview editions. I suppose this goes along with IO’s renewed focus on developers, in contrast to the actual OS release (which normally coincides with the new Nexus line, about 6 months later). Google gets to save the name reveal for the fanfare it really wants around that time. Any problems that happen along the way will be associated with M, not the eventual name. And finally, it also lets them defer a decision, which is usually a Good Thing, and especially when it involves other companies (Kit Kat).

Anyway … if it’s not marshmallowMarshMallow, I’ll be disappointed.

On-demand permissions! Finally

Android M joins iOS, Cyanogenmod, and the web in supporting on-demand permissions, a feature that had been experimented with previously but didn’t see the light of day until now. This is great news for both users and developers. Improved security and control for users, and meanwhile developers don’t have to get caned for providing rich, optional, features.

One recent example was Player FM supporting audio ducking, ie the ability to keep playing when a transient sound plays. Because phone calls are also transient sounds, we had to declare a permission to detect when the phone was ringing, which happens to include the ability to see the user’s phone number and those they call. All this for an optional setting. Not surprisingly, there were many queries about the new permission and I’m very pleased it can be optional with M.

App Linking

A developer can now tie its app and website together by, in crude terms, pointing each to the other. The net effect is users can click on a link without being presented with the tedious “Open with …” menu. It will open straight in the app if it’s installed. I believe these menus are one of the biggest UX problems for Android, as they appear far too often (basically, anytime an installed application has declared a regexp matching the link you just click). This doesn’t solve the problem completely, but is a major step in that direction.

It will also be a controversial feature, as it means any site can now block third-party apps from “presenting” or “hijacking” (depending which side you’re on) its links. By declaring its the one and only app to handle those URLs, other handlers are shut out. It’s true, at least in this initial M build, that users can modify those settings, but few will go to those lengths.

Custom Chrome Tabs

App linking is about jumping from one app to another. Custom tabs is about jumping from an app to the web. It’s actually a Chrome update, so once it lands in Chrome, it should work on older Android too.

Consider what happens when a link needs to open a web page? One solution is for the app to host its own webview, thus keeping the user from leaving their app and retaining their controls and branding. This unfortunately leads to a cottage industry in “optimising your website for Twitter/Pinterest/Facebook webviews”. The webview, being a sandboxed environment, is slow to load as caching isn’t possible, and nor does it inherit cookies or the user’s browser settings. So, not ideal.

Custom tabs aim to get the best of both worlds: custom controls and branding, but inside “actual Chrome”. Even the transition between browser and app can be configured, and pre-caching is also possible, ie telling Chrome to start loading something while the user is inside the app.

Direct Share

Direct share is a new standard for the popular pattern of sharing something with N friends. The technology is similar to the file picker introduced in Kitkat – where the file picker could let you choose a file from any of Dropbox, Google Drive, etc, the new share feature is effectively a “people picker” that lets you share with contacts or any participating social network. This is also about Google recognising Google Plus is not the only answer to social on Android.

Doze State

Doze is the apt name for a new state that kicks in when the phone is still for a long time. Apps go into background but notifications and alarms still work. It makes sense as a trade-off and will be brilliant if it even gets close to the “up to two times longer” standby lifetime.

Play Store:

Technically Play!=Android, but hey it’s the main distribution point, and there were some important updates. A-B testing of the description will be possible with the new experiments feature. Analytics on ad revenues and conversions will be available directly in Play. And there will be a new family-friendly Play store with some apps there being verified as family-friendly.

Image credit

API Pattern: Self-documenting REST Responses

Here is an example of a self-documenting REST response. Ideally every API call should let the developer append a param like help=true to get details such as calling context, documentation links, examples, and related/further calls that might be made. Of course, those additional URLs also include the help=true to ensure hypertext-powered API browser surfing is possible (Further calls might also be part of the response in some cases, following the HATEOAS model.)

javascript
< view plain text >
  1. {
  2.   type: 'post',
  3.   id: 123,
  4.   title: 'How to make pancakes',
  5.   ...
  6.   # other normal response stuff
  7.   ...
  8.   # some calling context help
  9.   caller: {
  10.     type: 'user',
  11.     id: 789,
  12.     name: 'happyjoy',
  13.     role: 'member'
  14.   },
  15.   # general docs link
  16.   docs: 'https://example.com/docs/posts#get',
  17.   # usage examples for this particular resource
  18.   examples: [
  19.     {
  20.        url: 'https://example.com/posts/123?help=true',
  21.        explanation: 'get post 123'
  22.     }
  23.     {
  24.        url: 'https://example.com/posts/123?metadata=true?help=true',
  25.        explanation: 'get only metadata for post 123 (omits the description)'
  26.     }<br />
  27.   ],
  28.   # calls related to this particular resource
  29.   related: [
  30.     {
  31.       comments: [
  32.         {
  33.           url: 'https://example.com/posts/123/comments?help=true',
  34.           explanation: 'get comments for this post'
  35.         }
  36.       ],
  37.       owner: [
  38.         {
  39.           url: 'https://example.com/users/5555?help=true',
  40.           explanation: 'get author details'
  41.         }
  42.       ]
  43.       editor: [
  44.         {
  45.           url: 'https://example.com/users/8888?help=true',
  46.           explanation: 'get editor details'
  47.         }
  48.       ]
  49.     }
  50.   ]
  51. }

Lightweight vs heavyweight frameworks. Or, “which kneecap do I want to be shot in”

Very sensible commentary on software frameworks and the dichotomous debates that afflict them.

“”” Using a lightweight, comprehensible framework is good, until you hit the limits of that framework and start pulling in lots more libraries to fill the gaps (the Sinatra/Cuba world). Using a heavyweight, complete library is good, until you start suffering from bugs caused by incomprehensible magic buried deep inside (the Rails world).

The underlying problem isn’t fashion, or bloat. It’s that software is very, very complex. Unless you’re doing hardcore embedded work in assembly language, you’re building a raft on an ocean of code you won’t read and can’t understand.

A friend of mine put it well once. He said that you should have deep understanding of systems one layer from yours (ie your frameworks), and at least a shallow understanding of things two or three layers away (operating systems, etc). “””

The last comment is similar to what I learned from the wisdom of Spolsky: Take control of one level below your primary level of abstraction.

https://news.ycombinator.com/item?id=9347318

Work-sample tests during interviews

Patio11:

“”” (W)e know — via copious academic studies — that work-sample tests are the best available method of predicting performance. Many companies in the software industry do not administer work-sample tests during job interviews. Instead, they have a disinterested person who you won’t work with make up a random question on the spot (seriously, this is not only a thing that exists in the world, it is the default hiring method in our industry). The disinterested engineer interviewing you then spends most of their time preening about their own intelligence while ignoring your answer, and returns a decision known to be primarily determined by demeanor, rapport, demographic similarity, and other things which all decisionmakers will profess that they are not assessing for. “””

Speeding up Rails asset loading in development: Tips and Gotchas

Rails can be so productive, but one big exception is asset serving in development. Loading HTML, scripts, stylesheets, images, fonts, etc can be slow, sometimes 10+ seconds per page if things go wrong.

Here are some tricks and gotchas to help improve asset speed in development. I’ve learned each of them the hard way, after messing around with settings in a rush to get things working.

Ensure caching is on

  1. # config/environments/development.rb:
  2. config.action_controller.perform_caching = true

Assets may compile slowly, but at least make them compile slowly only once, not every time. To ensure assets are cached, make sure caching is on.

Ensure the configured cache is working/running

Continuing the previous point, make sure caching is working. I normally use memcached via dalli gem, so I have a config line like this:

  1. # config/application.rb:
  2. config.cache_store = :dalli_store, 11211, { namespace: 'player', pool_size: 10 }

The important thing is to make sure memcached is running. I’ve left it off at times to guarantee cache is busted on each request, forgetting it’s off when I see slow page loads.

If you’re using the default file cache, make sure it’s writeable by the Rails process and there’s free disk space. Check files are being created.

Ensure browser caching is on

In a tool like Chrome devtools, it’s easy to flip HTTP caching on and off. With HTTP caching on – the default for browsers and their normal users – requests will include if-changed-since and last-modified. As with regular requests, Rails assets will serve faster if those things are turned on and that’s a good simulation of the production environment too. However, you will sometimes need to turn caching off to test changes; just be aware that this one can substantially speed up assets serving and developers probably turn it off too readily.

Turn debug off

  1. # config/environments/development.rb:
  2. config.assets.debug = false

This one’s another trade-off. It will munge your assets together, which usually means faster load times. e.g. if you have an application.js with //= require book and //= require author, you’ll end up with a single file with both. I’ve not been able to get Coffee/Sass mappings working under those conditions, so it makes debugging harder.

Inject styles and scripts dynamically

Web pages can easily update stylesheets and scripts just by adding a style or script tag. This is super-helpful during development because it means you don’t have to serve a whole new page from the server if you are just messing with styles or scripts. I use a keyboard shortcut to automatically refresh the stylesheet with a cache-busted update. (It could also be more fine-grained if debug is turned off).

javascript
< view plain text >
  1. Mousetrap.bind 's', U.reloadStylesheets
  2.  U.reloadStylesheets = ->
  3.    showDialog 'Loading stylesheet'
  4.    $('link[href^="/assets/application.css?body=1"]').remove()
  5.    $("<link rel='stylesheet' type='text/css' href='/assets/application.css?body=1&#{Math.floor(1e6*Math.ran
  6.  dom())}' />").appendTo('body')

There’s a more sophisticated, more automated, approach to injection here.

Libsass

Libsass is a fast rewrite of Sass in C. This makes every programmer happy except for Rubyists, who may feel bittersweet about Ruby Sass being obsoleted. But still, it’s happening and there is indeed a Ruby binding for it which should be much faster than the pure Ruby Sass. I’m talking 10x faster, potentially.

The main downside right now is compatibility. Not all features have been ported and not all of Compass will work presently, is my understanding, though I’ve also seen a report that Bourbon is now fully compatible, so that’s exciting progress. I do think the benefits will be too great and eventually Libsass will be The One for all things Sass.

So the advice here is to consider compiling with Libsass instead of Sass. Easier if you are starting a new project from scratch. I haven’t done this myself, though I noticed a while back Guardian did.

Avoid external dependencies

If you have scripts such as analyics or widgets, take steps to either not load them during development or defer loading so they don’t block anything. (Good advice for production anyway.) The last thing you want is a slow Twitter widget stopping your assets from even beginning to compile.

Consider parallel loading

Using a server like unicorn, you can configure parallel processing. This is another big trade-off. You’ll have trouble debugging and reading log files (though you can also separate log files per process).

Consider precompilation

You can, in some cases, precompile like you would in production. This is useful if you are writing and testing only back-end updates. However, a lot of the time, you should hopefully be writing tests for those and not actually testing in the browser much; in which case precompilation won’t be so useful after all.

Understand the fundamental asset model

Read this and this to really understand what’s going on. There’s a lot of quick fixes around (such as those herein) but it can all seem like magic and still leave problems if you’re not following it.