21 February 2013
Test Your Product with Strangers, not Friends

Pickmoto got started in earnest in April 2011. We left our previous positions, and decided to work on this project full-time. We believed then, as we believe now, that fantasy sports as it stands is a poor mobile experience, and that the time is right for someone to innovate on the concept of fantasy sports on mobile.

Prototyping

From April to June, we prototyped the original NFL app. The act of prototyping something brand new is a fascinating one, as you are constantly making assumptions about what your users will want. By June we had an MVP, and were ready to start showing it to people.

Early User Testing

We had a decent sized list of beta testers (~20) for our initial product, that was composed almost entirely of friends. Feedback was fantastic. They loved the app. We started dreaming about how to scale to the 10 million users we were sure would come in during NFL season.

Good Advice

As we are all first-time founders, we started asking our network of experienced entrepreneurs for advice. Ryan Mickle of Yardsale ended up giving us excellent advice: don’t test with friends. Test with strangers.

The Craigslist Sessions

We ended up putting ads on craigslist asking for (1) sports fans (2) with iPhones (3) who would like free coffee to just test our app. The feedback was immediate, visceral, and appalling. People didn’t understand how to use the app. You could see their eyes glazing over as they went through the tutorial screens. We still had lots of work to do.

Watch Their Eyes

The strangers we met with were also very nice people, but their actions betrayed their words. You could watch their eyes searching the screen, trying to figure out what to do. They would get confused and start apologizing. There was nothing to apologize for though: their confusion is our problem.

Finale

We never had a “perfect” meeting with a stranger from Craigslist, but those meetings were by far the most useful in terms of testing our on-boarding process and user experience flow. We want people to understand how to use our app within 30 seconds of starting the app. We made great strides with those sessions, and have made this a regular part of the testing process when releasing new apps.

7 September 2012
Silicon Valley is missing out on one huge market

This has been cross-posted from the Pickmoto blog.

I left my full-time job in April of this year to start Pickmoto with Ben and James.  I was finally going to apply my years of reading and absorption to try my hand at building a profitable business.  The last five months have been awesome, mostly consisting of designing, building, testing, and iterating the product that you’vehopefully downloaded onto your iPhone for NFL season.  I’ve learned so much since I left, but through it all, there is one thing that is becoming more and more prominent to me: Silicon Valley is not interested in sports startups.

Now, I want to quickly clarify that sports startups do exist.  BeRecruited,Sidelines, and OnSports are just a few of the various sports startups that exist in the area.  Culturally, however, sports are not taken seriously in Silicon Valley.  At any given meetup, conference, or talk I attend, 9 out of 10 people are self-proclaimed “not sports fans”. When we started asking other sports startups in the area about who we should potentially talk to down the line if we seek investment, they almost universally said that we’d be better off looking outside of Silicon Valley for investors, as the money here does not follow sports-related startups.  One person jokingly said that we should pivot to focus on triathlons and marathons, because that’s the only sport that most investors respect.

In general I’m fine with people who aren’t sports fans, or don’t want to invest in sports startups, but there is always one thing that bothers me about this fact:sports is a massive market to just ignore.  There is a ton of money in sports.  Most of the money and content is controlled by a few key players, who have become complacent, making the atmosphere ripe for disruption.  There are lots of opportunities to evolve and experiment with existing business models in sports, or make improvements to existing profitable sports-related business models.  From fantasy gaming, online content aggregation and distribution, real-time scoring, fan engagement (particularly in the stadiums), ticket sales, merchandise production and distribution… the list goes on.  There are arbitrage opportunities here to take advantage of, and for some reason, the Silicon Valley community is not interested.

Shall we talk about market size?  A vast majority of this country are self-described sports fans.  Being “not a sports fan” is downright sacrilegious in parts of Texas and Boston.  If we broach the subject of international sports consumers, I think it becomes clear how big the market actually is.  The sports business encompasses hundreds of millions (billions?) of actively engaged and passionate consumers, who spend countless hours consuming news, watching games, discussing games, and refining their fantasy leagues.  They are willing to pay a premium for a variety of services, if people would provide them more to pay for, or improve the existing services they’re already paying for.

As for us at Pickmoto, we see an opportunity to make real headway into a market that most of our peers are ignoring.  Our plan is to take the lessons of building successful businesses in Silicon Valley, and try to apply those lessons to the sports/tech market.  With our first app, we wanted to introduce a new way for fans to predict the most pressing, important question of any game: who is going to win.  We tried to create a game for sports fans that is as fun and competitive as games such as DrawSomething and Words With Friends.  Were we successful?  Well, it’s only been a week, so that questioned is unanswered, but we’ve been seeing massive interest from our users thus far.

What are your thoughts on this topic?  Why doesn’t Silicon Valley take more of an active interest in the sports market?

29 July 2012
Betable Hackathon Postmortem

I just finished the Betable hackathon this weekend, and it was quite a well done event.  As a refresher, Betable provides a platform for real-money gambling that can be integrated into any game or app. They recently received their gaming license from the UK, and this is their first hackathon.

For this hackathon, Ben (my co-founder at Pickmoto) and I worked out the game mechanics for a roulette game that can be played over Twitter.  The end result is a TweetChance, and you can sign-up at http://tweetchance.com.  The game works like this:

  • Go to TweetChance.com, and hit the “Get Started” button
  • Authorize with Betable (requires a Betable account)
  • Authorize with Twitter
  • Start playing on Twitter!

To play the game on Twitter, you write status updates that look like the following:

@tweet_chance bet {WAGER} on {NUMBERS}

For {WAGER}, you can input any number, however since I’m working in the Betable “sandbox” mode, the wager can’t be more than 1.00.  For {NUMBERS}, there are a variety of different bets you can make:

  • Single number bets: @tweet_chance bet 1 on 17
  • Multiple-number bets: @tweet_chance bet 1 on 13,19,27,33
  • Even/odd bets: @tweet_chance bet 1 on even
  • Red/black bets: @tweet_chance bet 1 on red

The bot I built (all in node.js, and hosted on Nodejitsu) monitors the @tweet_chance status updates, parses out the values, places the bet, and tweets the result back to you.

I came to this event representing Pickmoto, and I wasn’t disappointed. There were lots of interesting people present, and I even met a couple people who I think may be able to help Ben and I with our launch of Pickmoto for NFL season.  TweetChance didn’t place in the finals, but that’s not really why I came to this event — I wanted to explore the Betable platform, and meet cool people.  Check, and check.

All in all, this was a great event.  The Betable people present were really helpful, and very enthusiastic about what I built.  Their platform was very well done — they’ve taken the smart approach of limiting what types of games you can build on at the moment (Roulette, Keno, Slots, or a generic Paytable), but making sure that those games have been well thought-out, and easy to build on top of.  I’m sure more game types will be coming in time.

I do plan to keep working on TweetChance, but Pickmoto is my focus right now, so it’ll be slow and steady progress.  If you have any questions or comments on TweetChance, feel free to email me (ryan dot gerard at gmail dot com), or find me at @dreadpirateryan.

27 July 2012
Fixing the Testflight “Unable to download” error

If you’ve ever used Testflight to help track and manage the testing of your app, you may have run across the following error:

  1. User tried to download your app
  2. The app downloads, but fails to install, giving the generic error “Unable to Download Application”

I don’t know exactly why this error pops-up for some users, but I can now tell you how to fix it:

  1. Connect the users phone to a computer that has Xcode installed
  2. Open up the Organizer
  3. Select “Provisioning Profiles” underneath the users device
  4. Delete all provisioning profiles related to your app

After deleting the old provisioning profiles, your app should install smoothly.

17 July 2012
In-app Purchase Testing for iOS

I’ve recently been working on integrating in-app purchasing for the upcoming iPhone app for Pickmoto.  The general documents you have to follow are pretty well done in explaining to you how to use StoreKit and go through the process of making an in-app purchase, and the iTunes Connect documents do an excellent job of walking you through the steps to accept payments.

That being said, in order to test in-app purchases, there are a couple of important steps that aren’t made clear, and should be bolded and underlined.  These are steps I discovered through trial and error, and reading some excellent StackOverflow posts:

1) In iTunes Connect, when you create a new test user for testing in-app purchases, do NOT sign-in using this account on your device from Settings -> Store.

In order to test purchasing, you must be logged out of your device, and you must be running a debug build of your app. When you sign-out of your default user in Settings -> Store, you may feel inclined to then sign-in using your test user account.  DO NOT DO THIS.  It will completely mess up the test user, and cause in-app purchases to fail.  I can’t tell you why, I can only tell you what happens: you get the dreaded “Cannot connect to iTunes Store” error.  Instead, sign-in with the test user account at the point of purchase.

2) The iOS Paid Applications contract must be completely filled out before your products are available.

Until this contract is completely filled out, the SKProductsRequest response will always return an empty products list.

3) It is possible to test in-app purchasing before you submit your app for review, and before the new in-app purchase has been reviewed.

The information I found out on the net seems to be unclear on the subject, so I want to set the record straight.  I’m working on an unreleased app, have submitted neither my app nor my in-app purchase for review, and am able to test in the sandbox environment.

If you continue to have problems, please go through this checklist.  It’s a life saver.

9 July 2012
Encoding auth information for iOS apps

In the event that you ever have to POST authentication information that needs to be encoded, I thought I’d write a little bit on the subject to help speed you along.  If you’re creating an iOS app, you’re likely using the NSURLRequest object for your requests.  A typical POST request looks something like this:

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.domain.com/auth"]];
[request setHTTPMethod:@"POST"];

NSString *postString = [NSString stringWithFormat:@"email=%@&password=%@", email, pass];
[request setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];

The code above creates a POST request, and encodes the email/password information in UTF-8.  Now, before you copy and past this code, you should know that it’s not good enough.  Your non-ascii characters will be UTF-8 encoded, but the data also needs to be URI encoded.  HTML form data needs to be percent-escaped for most web servers out there.  The variety of non-ascii characters people use for passwords makes this step necessary right out of the gate, but one shouldn’t forget email addresses as well.

Let me give you an example of why this is necessary: the email address ryan.gerard+demo@gmail.com is a valid email address.  Gmail takes the ‘+demo’ text and automatically labels the email with ‘test’ once it hits your inbox.  If a user signed-up to your service using this email address, and it wasn’t URI encoded before being sent to the server, then once it hits the server the string would likely look like this: “ryan.gerard demo@gmail.com”.  Since the ‘+’ is not percent-escaped, the webserver turns the character into a space.

The plus sign is not the only character you have to watch out for.  The allowable characters for an email address are much larger than you may think.  According to RFC 6531, the following characters are valid and legal for use in an email address: !#$%&’*+-/=?^_`{|}~.  Now, despite what the RFC says, not all email clients will actually allow these characters to be used when creating email addresses, but you shouldn’t assume that these characters won’t appear in email addresses from users.

Now, to the code!  Here is a snippet of obj-c code that will correctly UTF-8 and URI encode the email/pass data being sent to your webserver.  For non-ARC code, just remove the “__bridge” inserts:

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.domain.com/auth"]];
[request setHTTPMethod:@"POST"];

NSString *encodedEmail = (__bridge NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef)email, NULL, (__bridge CFStringRef) @"
!#$%&’*+-/=?^_`{|}~”, kCFStringEncodingUTF8);

NSString *encodedPass = (__bridge NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef)password, NULL, (__bridge CFStringRef) @"!#$%&'*+-/=?^_`{|}~", kCFStringEncodingUTF8);

NSString *postString = [NSString stringWithFormat:@"email=%@&password=%@", encodedEmail, encodedPass];
[request setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];

Now, some of you may wonder why I chose to use CFURLCreateStringByAddingPercentEscapes instead of just using NSString’s method stringByAddingPercentEscapesUsingEncoding.  Characters like ampersands and plus signs won’t be processed by that NSString function, because they’re valid URL characters.  If you really want to percent-escape all characters, you should use CFURLCreateStringByAddingPercentEscapes.

10 May 2012
MongoDB MapReduce doesn’t always reduce

Today I decided to dive into the mapreduce functionality provided by MongoDB.  I have some batch processing jobs involving a decently large amount of data, and overall it was a pleasant experience implementing those jobs.  Mongo uses a javascript interpreter to run your map and reduce functions, so as long as you have some JS under your belt, you’re good to go.

While writing unit tests for some of this new functionality today that utilized mapreduce, I noticed something odd: the collection that the mapreduce output in my unit tests had a slightly different schema than the collection output when my real server ran the same jobs.

The map reduce looked similar to this:

var map = function() {
        emit(this.team, { count : 1 } );
}

var reduce = function(key, values) {
        var result = {totalgames: 0};
        for(var item in values) {
                result.totalgames += values[item].count;
        }
        return result;
}

db.games.mapReduce(map, reduce, { out : "teamrecords" });

This is a pretty straight forward map reduce: I’m emitting a signal for each game that records a count of 1 for the team, which acts as the key.  The reduce is then adding up all the counts.  When I ran this against real data on the server, the teamrecords collection correctly had data that looked like this:

{ “_id” : “ari”, “value” : { “totalgames” : 11 } }

When I ran my unit tests, the collection had data that looked like this:

{ “_id” : “ari”, “value” : { “count” : 11 } }

After thumping my head against the table for about an hour, I figured it out: in my unit test, I only had one value emitted for the key “ari”.  Since there was only one value emitted for that key, the reduce function never ran, and the value emitted was put into the collection directly.

This functionality does make sense — there’s nothing to reduce, so why run the reduction step?  That being said, I was expecting the reduce function to run, and having it not run resulted in a different key being saved in my collection.  It seems like a minor optimization made by mongodb that could potentially result in large errors.

10 May 2012 0 Comments
“I’ve built my career by 20+ years of looking people in the eyes, making promises and then delivering against what I said I would do. You don’t build trust, friendship and human bonds on Skype. - Mark Suster”
10 May 2012
iPhone Spotlight View

I’ve recently been working on some tutorial screens for a new app, and have created something I think is rather neat.  It’s a view that provides a spotlight effect over whatever aspect of the screen you want to highlight.  

For tutorial screens, a view like this allows you to isolate specific things you want the user to pay attention to, such as login buttons, point boxes, and notification bars.  The label next to the spotlight acts as a button, so that when the user presses the button, the spotlight can animate to the next section of the screen you want to highlight.

The code has all been open sourced on github.  Feel free to email me with questions.  Here is a screenshot of the spotlight overlay on a plain white view.

Spotlight Screenshot

28 March 2012
Effective unit testing of node.js with futures

Recently I had the idea to attempt unit testing of my node.js codebase.  There are some decent resources out there that cover this concept, and this blog post is a summary of my own thoughts and findings while implementing unit testing for node.js.

Lets start with the basic issue: testing asynchronous code is not straight forward. For most unit testing (and testing in general), you assume items will move in a linear fashion: follow steps 1-3, and you should see some expected result. Because node.js forces you to work in a more async fashion, you may not necessarily know when something is complete, which forces us to look for other ways to find out when that something is complete.

I’ve written below a contrived and simple node.js app, using express and mongodb, with a login mechanism.  We want to unit test the login mechanism.  The app may look something like this:

// login.js
var
    express = require('express'),
    app = express.createServer(),

    // Database Config
    mongo = require('mongojs'),
    mongoStore = require('connect-mongodb'),
    db = mongo.connect('dbname',['users']);

// Configuration
app.configure(function(){
    ...
});

app.listen(3000);

app.post('/login', function(req, res){
    var email = req.body.email, password = req.body.password;
    db.users.find({'email':email,'password':password}).forEach(function(err, user) {
        res.send('Found user ' + user);
    });
});

As you can see, it’s pretty straight forward: a POST request containing an email address and password are searched for in the mongodb instance.  If that user exists, then return that user object.

Now, lets take a step back for a moment and start building a simple unit test for this mechanism.  To do this, I’ve been using nodeunit, which provides a reliable and simple framework for executing tests, and reporting results.  Here is an example of how we’d like to write the test:

// login-unit.js
var login = require('login.js');
exports.testLogin = function(test){
    test.notEqual(login.loginUser('email', 'pass'), null, "The user was null!");
    test.done();
};

Clearly our application code can’t yet support this unit test.  The login logic needs some refactoring so that it’s externally accessible:

// login.js
var
    express = require('express'),
    app = express.createServer(),

    // Database Config
    mongo = require('mongojs'),
    mongoStore = require('connect-mongodb'),
    db = mongo.connect('dbname',['users']);

// Configuration
app.configure(function(){
    ...
});

app.listen(3000);

function loginUserPrivate(email, pass) {
    db.users.find({'email':email,'password':password}).forEach(function(err, user) {
        return user;
    });
}

app.post('/login', function(req, res){
    var email = req.body.email, password = req.body.password;

    var user = loginUserPrivate(email, password);
    res.send('Found user ' + user);
});

module.exports = {
    loginUser: function(email, pass) {
        return loginUserPrivate(email, pass);
    }
}

As you can see, we’ve added an export function for the login code, so that the unit test can access it.  However, there is a problem.  Due to the asynchronous nature of node.js, that user value from the private function is not being returned correctly.  The private function will return immediately, and not wait for the db call to finish.  To fix this, we will use futures, which are also commonly called promises, or deferred objects.  To learn more about this concept, this article sums up the concept well.

I’m currently using this futures module, but there are other modules out there, and I encourage you to experiment.  If we refactor the application code to use futures, it will look like this:

// login.js
var
    express = require('express'),
    app = express.createServer(),

    // Future object
    Future = require('future'),

    // Database Config
    mongo = require('mongojs'),
    mongoStore = require('connect-mongodb'),
    db = mongo.connect('dbname',['users']);

// Configuration
app.configure(function(){
    ...
});

app.listen(3000);

function loginUserPrivate(email, pass) {
    var future = new Future();     db.users.find({'email':email,'password':password}).forEach(function(err, user) {
        future.deliver(err, user);
    });
    return future;
}

app.post('/login', function(req, res){
    var email = req.body.email, password = req.body.password;

    var future = loginUserPrivate(email, password);

    future.when (function (error, user) {
        res.send('Found user ' + user);
    });
});

module.exports = {
    loginUser: function(email, pass) {
        return loginUserPrivate(email, pass);
    }
}

The changes above show one way to get around the async nature of node.js for testing purposes.  The private login function will return a future object immediately to the caller.  The caller will then essentially subscribe to an event (with future.when()) telling it when the object has data.  The caller can then access this data from the callback function.

We can refactor the unit test code to also use futures, and thereby effectively test out the login functionality:

// login-unit.js var login = require('login.js'),
    Future = require('future'),

exports.testLogin = function(test){
    var future = login.loginUser('email', 'pass');
    future.when (function (error, user) {
        test.notEqual(user, null, "The user was null!");
        test.done()
    });
};

Some of you may wonder why we need to use futures / promises at all.  Indeed, we could just send in a callback function as an extra parameter to the login function that would get called when the async call is finished.  However, there are other benefits to using futures: chaining of objects and default timeouts are just two of the benefits that come with using a futures object.

To recap, what I’ve been trying to show today is that using futures/promises/deferred objects are effective ways to unit test node.js code, despite it’s asynchronous nature. The future objects returned from the private login method allow you to essentially subscribe to an event that tells you when the async call is finished, and passes back the result of that async call.  In addition, I believe the above code is more structured and less brittle.

Now that I have a method to unit test my node.js code, I can happily move forward and have some degree of certainty that my code is working correctly.