« Beeminder home

Beeminder Blog

Assumption of Mary; Asunción de la Virgen (c 1670), Juan Martín Cabezalero, Museo del Prado

Last week Leah Libresco blogged about beeminding rituals. This week we’re continuing the Catholic theme with a guest post by veritable Renaissance man, Pedro Paulo Oliveira Jr. [1] Pedro Paulo has a popular iPhone app for praying the rosary and has used the Beeminder API to include beeminding one’s praying as part of the app. It’s the holy grail, so to speak, of making one’s app sticky! In this post Pedro Paulo describes how it works, first for users of the app, and then for iOS developers who may want to similarly integrate Beeminder. There’s also an insightful philosophical/behavioral-economic detour about intrinsic, extrinsic, and transcendent motivation. (See also the open source Beeminder iPhone app.)

App development is a very rewarding activity. I’m not talking about the monetary aspect, although it maybe rewarding on that front too, but the impact you can have in other people’s lives. With more than 5 million people using our apps I feel we have the responsibility to constantly improve their experience.

Our popular Electronic Rosary app helps people to pray the Rosary with voice guidance, beautiful images, and variable pacing. It’s especially useful in places or situations where you’d have trouble keeping count or need a companion.

“In 2011, instead of praying a special devotion, I wrote code that would help me pray better in the future.”

Actually I developed it for myself. Praying the rosary while commuting, I’d constantly lose track of the Hail Marys. I wrote the first version in 9 days, during a time of the year numerous Catholics live the devotion of the novena to the Immaculate Conception. In 2011, instead of praying a special devotion, I wrote code that would help me pray better in the future. Noticing that the experience had been positive I donated the code to the company I work for so they could build it into a product and make it available to other people. Now more than 10k users pray the rosary daily using Electronic Rosary for iOS.

One feature users asked for constantly was a mechanism to help them to pray this devotion every day. In iOS, we can set daily notifications but the downside of notifications is guessing correctly what time to display the notification. That’s where Beeminder comes in.

I was introduced to Beeminder by Leah Libresco’s Unequally Yoked. I strongly recommend it. Even if you don’t agree with everything the author says you can’t dispute her honesty and intelligence in exposing ideas. Leah has used Beeminder for multiple purposes from getting to sleep on time to writing a book (Arriving at Amen).

Motivation, Spiritual Practice, and Beeminding Your Way to the Rosary

In the previous post, Leah Libresco asks and answers a question. It’s a very interesting consideration but I’d like to dissent somewhat.

Prayer is supposed to come from the heart, so is there something weird about graphing it and setting up my own penalties if I don’t measure up? My answer is, yes, it’s a bit weird, but so is most of my prayer life. I’m a convert (…)

My answer is no, it’s not weird. It’s the way, with variations, a fair share of people successfully lead a life of prayer. Romans 7:18-19 illuminates why it’s not weird: “For I do not do the good I want, but I do the evil I do not want.”

“As Leah Libresco describes, it can happen the other way around, using extrinsic motivation (Beeminder) as a tool to reach a transcendent goal.”

A model of motivation I first heard from IESE Business School, expands the extrinsic, intrinsic model to accept a third category: transcendent. The transcendent in this case would be the “prayer is supposed to come from the heart”, the intrinsic “I need to pray more, as I understand it is important for my spiritual life,” and Beeminder (or other tools Catholics have used for centuries, ring a bell?) the extrinsic. Therefore, in this layered framework, each level supports the adjacent in order to achieve an ultimate goal.

Inserting a poetic touch, I cannot resist the temptation to quote Henri Guillaumet which Antoine de Saint-Exupery describes in the book “Wind, Sand and Stars”:

Tu résistais aux tentations. « Dans la neige, me disais-tu, on perd tout instinct de conservation. Après deux, trois, quatre jours de marche, on ne souhaite plus que le sommeil. Je le souhaitais. Mais je me disais: ‘Ma femme, si elle croit que je vis, crois que je marche. Les camarades croient que je marche. Ils ont tous confiance en moi. Et je suis un salaud si je ne marche pas’. »
 
You resisted temptation. “Amid snow,” you told me, “a man loses his instinct of self-preservation. After two or three or four days of tramping, all you think about is sleep. I would long for it; but then I would say to myself, ‘If my wife still believes I am alive, she must believe that I am on my feet. The boys all think I am on my feet. They have faith in me. And I am a skunk if I don’t go on’.”

Guillaumet used his transcendent drive (“the concern about the future of his wife”) to enable his intrinsic motivation (“find an elevated place to die, so his body could be located and insurance claim easier”) to empower the extrinsic (“take one step after another so he could rest”), in order to overcome the urge to sleep in the snow. However, on numerous occasions, as Leah Libresco described, it happens the other way around, using extrinsic motivation (Beeminder) as a tool to reach a transcendent goal.

How Beeminder Works in Electronic Rosary

If you plan to use Electronic Rosary to beemind your praying habits, here’s what you do.

In the sliding menu, select the Beeminder icon.

Sliding menu to open Beeminder

If you have not authorized the app to access your Beeminder account yet, you’ll be redirected to Beeminder’s website to get the appropriate permission. After granting access you’ll be redirected to Electronic Rosary.

The next step is to select among your goals which one the app will update at the end of the rosary.

Goal Select Screen

Now we are ready to go. For every rosary you finish, the app will send a +1 to your Beeminder goal and you’ll see a popup confirmation.


 

——— Non-Nerds: Jump To The End ———


 

Now I’d like to share how easy is to integrate Beeminder with any iOS app.

iOS SDK and Beeminder: A Brief How-To

The Beeminder API documentation covers the first step of registering your app.

Authentication

To get the user’s goals and to add a datapoint to a particular goal you must first authenticate using OAuth2. In the iOS SDK it’s easy to do that without any external library:

static NSString * BackendBaseURL = @"https://www.beeminder.com/";
static NSString * OAuth2Path     = @"apps/authorize";
static NSString * ClientId       = @"client_id=mysupersecretwithbeeminder";
static NSString * RedirectURI    = @"redirect_uri=iterco://beeminder-callback";
static NSString * ResponseType   = @"response_type=token";

- (void) beginOAuth
{
  if([[NSUserDefaults standardUserDefaults]
      stringForKey:@"beeminder_token"] == nil)
  {
    NSString * auth = [BackendBaseURL stringByAppendingFormat: @"%@?%@&%@&%@",
                                                               OAuth2Path,
                                                               ClientId,
                                                               RedirectURI,
                                                               ResponseType];
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:auth]];
  }
}

It will redirect you to Safari where the user will authorize Beeminder to let your app have access to your account. No login credentials are entered in your app.

The redirect_uri you should set at CFBundleURLSchemes in the Info.plist of your project.

Safari will redirect you back to your app and you’ll listen for it in your App Delegate and store the access_token to access Beeminder on behalf of the user:

-(BOOL) application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
  NSLog(@"%@",url);
  if([url.host isEqualToString:@"beeminder-callback"]) {
    NSArray * comp = [url.query componentsSeparatedByString:@"&"];
    for(NSString * st in comp) {
      NSArray * twoComp = [st componentsSeparatedByString:@"="];
      if(twoComp.count == 2) {
        if([twoComp[0] isEqualToString:@"access_token"]) {
          [[NSUserDefaults standardUserDefaults] setObject:twoComp[1] 
                                                 forKey:@"beeminder_token"];
          [[NSUserDefaults standardUserDefaults] synchronize];
        } else 
        if([twoComp[1] isEqualToString:@"username"]) {
          [[NSUserDefaults standardUserDefaults] setObject:twoComp[1] 
                                                 forKey:@"beeminder_username"];
          [[NSUserDefaults standardUserDefaults] synchronize]; 
        }
      }
    }       
  }
  return YES;
}

Requesting the Goals

Since Beeminder’s API is pure JSON I suggest a library like AFNetworking to make things easier.

- (void) refreshGoalsWithCompletion: (void (^)(BOOL, NSInteger))completion
{
  id success = ^(AFHTTPRequestOperation * operation, id JSON) {
    NSMutableArray *l_goals = [NSMutableArray arrayWithCapacity:[JSON count]];
    for(NSDictionary * goal in JSON) { [l_goals addObject:goal]; }
    _goals = [l_goals copy];
    completion(YES, 200);
  };
  id failure = ^(AFHTTPRequestOperation *operation, NSError *error) {
    completion(NO, [operation.response statusCode]);
  };
  NSDictionary *params = @{ @"access_token" : [self getToken] };
  [_client getPath:@"/api/v1/users/me/goals.json"
           parameters:params success:success failure:failure];
}

In the above function _client is a variable of our helper class initialized as:

_client = [AFHTTPClient clientWithBaseURL:
	[NSURL URLWithString:@"https://www.beeminder.com/"]];
[_client registerHTTPOperationClass:[AFJSONRequestOperation class]];
[AFNetworkActivityIndicatorManager sharedManager].enabled = YES;

Adding Datapoints

The last step after the user selects which goal will be updated when he prayed the rosary is to add a datapoint.

- (void) addOneUnitToGoal:(void (^)(BOOL, NSInteger))completion
{
  id success = ^(AFHTTPRequestOperation * operation, id JSON) {
    completion(YES, 200);
  };
  id failure = ^(AFHTTPRequestOperation *operation, NSError *error) {
    completion(NO, [operation.response statusCode]);
  };
  NSDictionary *params = @{
    @"access_token": [self getToken],
    @"comment": @"Added by Electronic Rosary by Netfilter",
    @"value": @"1"
  };

  NSString * path = [NSString stringWithFormat:
                     @"/api/v1/users/me/goals/%@/datapoints.json",
                     [self getSelectedGoal]];
  [_client postPath:path parameters:params success:success failure:failure];
}

We’ll be releasing in the next few weeks the full code of the helper class to integrate Beeminder in your iOS app (we need to refactor the code decouple it from our libraries, although a work in progress is already available).


 

Thank You, Leah and Beeminder!

To thank both Beeminder and Leah Libresco, I’ll be making Electronic Rosary [2] free for download for the next five days. Maybe you can use it to pray for me once in a while. :)

Electronic Rosary logo


 

Footnotes

[1] Pedro Paulo graduated with a degree in Computer Engineering from PUC-Rio. He also graduated, years later, with a PhD in Medicine from USP. He spends most of his time at Netfilter but some days he teaches, advises students, and does medical research (Alzheimer’s and Autism) at the hospital. In his spare time he reads, plays soccer, and organizes volunteer work sometimes involving improvised medicine. And fun fact: he was one of the first Lua programmers.

[2] There are versions of Electronic Rosary for Windows Phone and Android as well, but they are far less polished than the iOS version.


 

Tags: