Grasshopper

Patrick Perini
The App Cookbook
Published in
4 min readSep 3, 2015

Thursday, August 27th, 2015

Ingredient

@GrasswireNow. This was a unique ingredient because it was the only existing software product to be used as an ingredient. The @GrasswireNow Twitter account is where Grasswire, the startup Fortune dubbed “Wikipedia for news,” breaks their latest stories.

The Twitter account itself is a fantastic way to get live coverage of breaking news events, both by Grasswire’s staff (many of whom are volunteers) and by individuals currently experiencing the unfolding events. However, given the live-stream nature of Twitter feeds, many of these live accounts can get lost as new events occur and time passes.

Grasshopper acts as a hopper for these tweets and retweets, collating them into their corresponding stories, so that anyone can go back and read first-hand accounts of the occurrences tracked by @GrasswireNow.

Recipes

Stories

The root of Grasshopper is the story hopper, a collection of the stories sourced from @GrasswireNow. Each tile represents the “headline” tweet, which is the first tweet we’ve used to begin the story. This is often any tweet from @GrasswireNow which begins with “#BREAKING,” however if a substantial amount of time elapses between tweets (currently and expirimentally 3 hours), we’ll begin a new story. This keeps stories to a reasonable size and in context.

We also present a cover photo for each story. Since most of the story-inciting tweets are presented without image, this photo is set to the first image found within any of the story’s tweets.

We tested our final layout, along with several other prototypes, with a number of users. We considered card views, simpler tables, and several other variations, but in the end, our tile structure proved to be the right balance of attractiveness and navigability.

The collection view has a complex layout structure which accounts for a number of cases to prevent empty space on the screen.

switch stories.count {
case 1..3:
// all tiles' widths = view's width
// all tiles' heights = view's height / stories.count
case 4:
// first two tiles' widths = view's width
// remaining tiles' widths = view's width / 2
// all tiles' heights = view's height / 4
// all tiles' height is slight under view's height / 3,
// for 3 rows and scroll affordance
case _ where (stories.count % 2) == 0: // Even, > 4
// first two tiles' widths = view's width
// remaining tiles' widths = view's width / 2
case _ where (stories.count % 2) != 0: // Odd, > 4
// first three tiles' widths = view's width
// remaining tiles' widths = view's width / 2
}

Tweets

The details of a story are presented as a collection of their comprising tweets.

Typical tweet interactions like faving, retweets, and replies require a mastery of Twitter’s API, not to mention authentication via the “Sign in with Twitter” button. Anyone who’s ever worked with this API knows how complicated it can be, which is why the pros have teams of people on it full time.

So that we could get the app done in one day, the tweets in Grasshopper are shown as Twitter Embeded Tweets. By building an HTML document composed of all of the embedded Tweets, we took advantage of a lot of work that Twitter had already done.

Ant, the Collection Server

The tweets from @GrasswireNow are collected by our ever-busy server, Ant. Ant is a Coffeescript server running as a single Heroku worker instance. It listens for the tweets from just @GrasswireNow, like so:

# Tweet.client is an instance of Twitter's Node.js API client.
Tweet.client.stream "statuses/filter", {follow: '747682134'}, (stream) ->
stream.on "data", (tweetData) ->
processTweetData(tweetData)

Twitter’s Node.js library makes listening for tweets a trivial, 3-line process. The resultant tweet data is a JSON object, corresponding to the Twitter API’s standard tweet payloads.

Once received, we analyze the tweet data and sort it into stories, which are then stored in Parse and consumed by the iOS app.

Challenges

Twitter’s Nightmare API

As was briefly mentioned in the “Tweets” recipe, the Twitter API is large, complex, and riddled with pitfalls. Once a user has authenticated (a feat in and of itself, and a feature we had little interest in), a whole host of individual calls to handle user interactions like faving, retweeting, and replying need to be understood and integrated with a custom UI. Since, for our day-long prototype, we didn’t care about these interactions, we opted to use Twitter’s tweet embedding to save time. This is obviously not a permanent solution, and we expect to take a more nuanced approach should anyone be sufficiently interested in the app. It’s always better to do less work up front.

Chefs’ Notes

Having interest from the folks at Grasswire was easily one of the high points of the project.

We can’t wait to let them use Grasshopper, and we hope they’ll enjoy it.

--

--