Taking Screenshots Like a Boss

Today I’d like to share a few tips and resources for taking and managing screenshots on Macs. We’ll start with the basics and move on to the more advanced tactics.

Take a screenshot of your entire screen

Command-Shift-3

Take a screenshot of a portion of your screen

Command-Shift-4 then highlight the area you want to capture

Take a screenshot of a specific window

Command-Shift-4 then press space then click on a window

Change the directory where your screenshots are saved

By default they’re saved to the desktop, but you can change the destination.

Take a screenshot of an entire webpage, part 1

For this I highly recommend the Blipshot Chrome extension by Automattician Davide ‘Fol’ Casali. It will automatically scroll down the page, take a screenshot of each section, and piece them together into a single screenshot that you can save to your computer.

Take a screenshot of an entire webpage, part 2

If you find yourself taking a lot of screenshots and are interested in a way to organize them, check out the Ember Mac app.

When you use its Chrome extension to take a screenshot, you can specify a category which will group those screenshots together:

Screen Shot 2015-12-07 at 1.41.45 PM.png

You can then browse your collections in the Ember Mac app.

The major downside to Ember though is the way it takes screenshots. Unlike Blipshot which will take a screenshot of the page as it currently stands, Ember seems to reload the page internally and then take a screenshot of that freshly reloaded page. So if you’re working with a JavaScript-heavy site, Ember’s screenshots won’t reflect any of the changes that have taken place since you loaded the page. Also, Ember doesn’t work with Flash websites.

My hacky workflow for managing screenshots is to use a combination of Ember and Blipshot. For capturing simple websites that I want to organize (where a screenshot of a freshly loaded page will do and it doesn’t use Flash) I use Ember. For sites where I want the screenshot to reflect the current state of the front-end or sites that use Flash, I take a screenshot with Blipshot, then drag it into the appropriate collection in the Ember app.

One question for you all

One thing that’s frustrating is taking screenshots on a Retina displays because all of the screenshots wind up 2x the size that they appear on the screen. Is there a simple way to take a screenshot on a Retina display and have not be 2x? When it’s important that the screenshot not be 2x, I load it in Pixelmator and shrink it to 50% of its original size. Kind of a pain though.

How Calypso’s A/B Test Module Works

Automattic recently open sourced Calypso, a JavaScript and REST-API powered interface that runs WordPress.com. I was fortunate to get to work on a few pieces of it, mainly its Analytics and A/B Test modules. In this post I’ll walk through how the A/B test module works because it might give you a few things to consider if you find yourself rolling your own A/B testing solution like we’ve done at Automattic.

Bucketing and Reporting

When it comes to A/B testing, there are two tools you need: one that buckets users and one that reports on the results of your tests. The bucketing tool lets you say “Show 50% of users a green button, show the other 50% the red button”. The analysis tool then lets you measure the impact of the green vs red button on other actions like signing up for an account, publishing a post, upgrading, etc.

The Calypso A/B Test module that I’ll be discussing in this post is our bucketing tool. We also have a separate internal tool for analyzing the results of the A/B tests, but that’s a topic for another post.

A/B Testing in Calypso

The A/B Test module’s README provides detailed instructions for how it works. You can also check out the module itself if you’re interested. I’ll give an overview here and elaborate on some of the decisions that went into it.

We have a file called active-tests.js that contains configuration information for all of the active tests we’re running in Calypso. For example, here’s one of the tests:

What this says is that we have a test called businessPluginsNudge that started on November 19th that has two variations: drake and nudge each of which are shown 50% of the time. Also, users that are inelligble to participate in the test should be shown the drake variation (more on what inelligible means below).

To assign a user to a test, there’s a function the A/B test module exports called abtest. It’s used like so:

The abtest function assigns the user to a variation and returns that variation. For this particular test, if the user is eligible then 50% of the time the function will return drake and the other 50% of the time it will return nudge. We can then use the variation to determine what the user sees.

The abtest function also sends the test name and the user’s variation back to us via an API endpoint so that we can record it and later use it to measure the impact on other events using our internal reporting tool.

Eligibility

Consider an A/B test that tests the wording of a button. If the new wording isn’t properly translated but a large percentage of the users don’t speak English, it can throw off the results of the test. For example, if the new wording underperforms, was it because the new wording was truly inferior or was it because a lot of non-English users saw the English wording and simply couldn’t read it?

To account for that and similar issues, we have this idea of eligibility. In certain situations we don’t want users to count towards the test. We need to show them something of course, but we don’t want to track it. That’s what the defaultVariation property is for in the test configuration. Inelligible users are shown that variation, but we don’t send the information about the test and the user’s variation back to our servers. By default in the A/B test module, only English language users are eligible for the tests so they will always be shown the variation specified by defaultVariation.

We also only want to include users that have local storage enabled because that’s where we save the user’s variation. We save the variation locally because we always want to show the user the same variation that they originally saw. Saving it to local storage keeps things fast. We could fetch it from the server, but we don’t want to slow down the UI while we wait for the response so we read it from local storage instead. A side effect of this is that we don’t handle situations where users change browsers, switch devices, or clear their local storage. That’s only a fraction of users though so it doesn’t impact the results very much.

One last point on eligibility: imagine you’re testing the wording on a particular button. You run one test where you show “Upgrade Now” and another “Upgrade Today” (this is a silly test, but just to give you an idea). Lets say “Upgrade Today” wins and you make that the default. Then you run another test comparing “Upgrade Today” to “Turbocharge Your Site”. If a user participated in the original test and saw the “Upgrade Now” variation, it could impact their behavior on this new test. To account for that, if a user has participated in a previous test with the same name as a new test, then he or she won’t be eligible for the new test. We only want to include users who are participating in the test for the first time because it will result numbers that better represent the impact of each variation.

Multiple active tests

In A/B testing parlance, there’s a concept known as multivariate tests. The idea is that if you have a test running on one page (green button, red button) and another test running on another page (“Upgrade Now”, “Upgrade Today”), the combination of the variations from those tests might be important. For example, what if green button + “Upgrade Today” leads to a higher conversion rate than the other combinations? There is that possibility, but we generally don’t worry about that to keep the analysis simpler.

Dealing with A/B tests that span multiple pages

There’s one final situation I want to note:

Imagine you have two pricing pages, one for your Silver Plan and one for your Gold Plan. On the Silver Plan‘s pricing page, you assign the user a variation and use that to adjust the page:

So far so good. Now imagine that you want to adjust the payment form on a different page if the user saw a particular variation for the Silver Plan.

If you call abtest( 'silverPlan' ) to grab the variation on the payment page, it will also assign the user to a variation for that test. Many of the users viewing the payment page though will be purchasing the Gold Plan and never have even seen the plan page for your Silver Plan. Assigning those users to a variation will distort the results of the test. To account for that, the A/B test module also exports a getABTestVariation function that just returns a user’s variation without assigning him to one:

This doesn’t come up in simple tests, but for complex tests that affect multiple parts of the user’s experience, it’s essential to be able to determine if a user is part of a variation without assigning him or her to one.

Wrapping Up

As you can see, there are a lot of subtle issues that can impact the results of your tests. Hopefully this gives you an idea of a few of the things to watch out for if you do roll your own A/B testing tools.

If you have any questions, suggestions on how to improve it, or just want to chat about A/B testing tools, don’t hesitate to drop me a note.

Johnny Lodden Thinks

“Johnny Lodden Thinks” aka just “Lodden Thinks” is fun little game you can play while you’re sitting around with friends or family.

The game is named Johnny Lodden Thinks because it originated when two pro poker players, Phil Laak and Antonio Esfandiari, began betting on what fellow pro Johnny Lodden‘s answers to their questions would be. YouTube has a clip:

Here’s how it works:

The game requires three people. Lets say I’ll be playing with my friends Adam and Ryan. One of us comes up with a question whose answer is a number. It then begins like this:

Me: Ryan, how many countries do you think border the Pacific Ocean? Think of the answer in your head. Don’t say it out loud. Let us know when you have a number.

Ryan: Ok, I have a number.

Once Ryan has a number, Adam and I start going back and forth saying what we think his guess is. After one of us says a number, the other player can say “less” or say a higher number. If the person says “less”, then we ask Ryan what his actual guess was and if it is less then the person who said “less” wins. Usually you’d bet money on it, but you don’t have to.

Me: I’ll start with 5.

Adam: I’ll go 10.

Me: 20.

Adam: 25.

Me: 26.

Adam: Less!

Me: Ryan, what was your answer?

Ryan: My guess was 20!

In this example Adam would win because I had last guessed 26, he said less, and Ryan’s original guess was 20. Had Ryan’s guess been 30, I would have won.

The key when guessing is not to start off too high. Had I initially guessed 100, Adam would have immediately said “less” and assuming Ryan’s answer was less than 100, won that round. Also, the real answer doesn’t matter, only what the person guessing thinks the answer is.

After each round ends you start again, usually with a different mix of people guessing and answering the question.

A question like “How many countries border the Pacific Ocean?” is just one example, but any question with a numeric answer will do. Usually folks wind up getting pretty creative (and often NSFW).

Here are a few more examples:

  • Ryan, what’s the population of England?
  • Ryan, how much money would you require to completely shave your head?
  • Ryan, if our other friend Joel had to obtain a live chicken and started his search right now, how long would it take him?
  • Ryan, if Joel was in the middle of an infinite field with no trees and no weapons, how long would it take him to catch a squirrel that initially starts 20 feet away from him?

… and so on. The more creative the better. :)

Give it a shot next time you’re sitting around with some friends and looking for something to do; I think you’ll really enjoy it.

A Ruby script to download a backup of your Heroku app’s Postgres database

A little over 5 years ago I shared a script that I had written to download a local backup of a Heroku app. Heroku’s CLI and its capabilities have changed a lot since then so I want to share an updated version for anyone who might find it useful.

You can check it out on Github: Heroku Postgres Backup Downloader.

For example, I have a cron job set up to generate a daily backup of Lean Domain Search that uses it:

$ ruby heroku-pgbackup-downloader.rb leandomainsearch "/Users/matt/Projects/LeanDomainSearch/Heroku Backups/"
Running backup script for leandomainsearch...
 Capturing a new backup...
  New backup id: b282
 Downloading new backup...
Done

Screen Shot 2015-11-27 at 9.16.28 AM.png

I’ve never had to use the backups and hopefully never will, but having them provides an extra layer of protection in case any of my sites are compromised and the data winds up corrupted or lost.

If you have a different backup strategy for your Heroku apps, I’d love to learn more – drop me a note or leave a comment below. Thanks!

How to subscribe to keyword mentions in HackerNews via RSS

If you’ve ever wanted to get notified via RSS every time a keyword is mentioned on HackerNews, there’s a neat service called HNApp that allows you to do just that. You can use it to follow mentions of your product or even just to follow discussions related to topics you’re interested in.

For example, I subscribe to a feed for the term “Strong AI”. This happens a few times a week and is almost always is part of an interesting discussion about the future of artificial intelligence.

If you search for “Strong AI” on HNApp, you’re presented with a list of recent discussions that include that phrase as well as links to subscribe via RSS or JSON:

Screen Shot 2015-11-25 at 10.11.08 PM.png

You can then plug the RSS URL into your favorite RSS reader and voilà, you’ll now be able to keep track of future discussions that use that term:

Screen Shot 2015-11-25 at 10.14.12 PM.png

I usually add the RSS URLs in the Feedly web app then use their iPhone app to read when I have downtime.

Here are a few other examples to get you thinking: WordPress, Calypso, Tesla, React.

HNApp searches occasionally time out so if you perform a search and it errors out, just try again later (RSS readers should automatically do this so there’s no issue there).

HNApp also supports following specific users which I use to learn from insightful commenters such as Patrick McKenzie, Ed Weiss, Jonathan Rockway, TokenAdult, and several others.

If you get use out of HNApp, give a shoutout to Nikita Gazarov on Twitter for the work he put into building it.

How to Add Terminal Aliases in Mac OS X Lion

One quick productivity hack is to add command line aliases to your Terminal in Mac OS X.

For example, I prefer typing c instead of clear to clear the terminal and I usually add all sorts of shortcuts for cd’ing into directories that I use often.

Here’s how to do it:

1) Navigate to your home directory:

cd ~

2) Open up .bash_profile using vi:

vi .bash_profile

3) Add an alias (press i):

alias c="clear"

4) Save the file (press Escape, type :wq, and hit Enter)

5) Restart Terminal

If you followed this example, you should now be able to just type c and Enter in Terminal to get the same affect as typing clear.

For more information, this post gives some additional examples of aliases you can add.

How to Change Your Default Terminal Prompt in Mac OS X

By default, when you open up a new Terminal window in Mac OS X the command prompt displays a relatively long name:

I prefer to shorten this to a simple dollar sign ($) in order to free up space.

To change your default command line prompt, follow these instructions:

1) Navigate to your home directory:

cd ~

2) Create a file called .bash_profile

vi .bash_profile

3) Add the following line (press i)

export PS1="$ "

4) Save the file (press Escape, type :wq and hit Enter)

5) Restart Terminal

You should now see something like this:

There are other ways you can configure the command prompt (for example, showing the current time), but I prefer to keep it simple.