Facebook Login, My Old Nemesis

An Alternative Login with Facebook Implementation

So every app of sufficient complexity has one feature that always seems to break in odd ways. You tweak it, duct tape it, adjust it, but it just breaks, breaks, breaks. When this happens enough, you tear it down and rebuild the silly thing from scratch. This is what happened with my Facebook login implementation for babynamester.com

Facebook-My-Nemesis

I used to have an implementation based on this: https://developers.facebook.com/docs/facebook-login/getting-started-web/

This default implementation runs on event listeners. For whatever reason, this version of Facebook login proved to be really fragile for me. After many hours trying to shore it up, I spent some quality time with the Facebook API documentation and built the version below instead.

My version works by passing callbacks to the FB.login function to perform an app login on success.

1. Create a Facebook app

Just follow the instructions here under section 1 of this page: https://developers.facebook.com/docs/facebook-login/getting-started-web/

2. Initialize the Facebook SDK on your page

Next, make sure your page initializes with Facebook’s API correctly. There’s no need to nest any of the javascript in a document ready function.

<div id="fb-root"></div>

<script type="text/javascript">
(function(d){
   var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
   if (d.getElementById(id)) {return;}
   js = d.createElement('script'); js.id = id; js.async = true;
   js.src = "//connect.facebook.net/en_US/all.js";
   ref.parentNode.insertBefore(js, ref);
}(document));
  
window.fbAsyncInit = function() {
   FB.init({
      appId      : '123456789123456789', // replace this with your appId
      channelUrl : '//'+window.location.hostname+'/channel.php', // Path to your Channel File
      status     : true, // check login status
      cookie     : true, // enable cookies to allow the server to access the session
      xfbml      : true  // parse XFBML
   });
}
</script>

3. Write a function to handle success

Let’s skip to the end before circling back. After we have a successful Facebook login, we’ll need to tell our app that we’ve validated a Facebook login for a specific user and create the appropriate session. At this stage we’ll have a Facebook user object to work with, ‘me’. We’ll see how we get that in step 4 below – just go with it for now.

Let’s make sure this object is valid (i.e. has an id). If it is, I hit an endpoint in the app to get a signature for that id. This is to prevent people from spoofing my app’s facebook login form and creating bogus accounts and sessions in the app. Once we get the signature (‘key’) back from the app’s endpoint, we enter the id, the signature, and some basic user information (found on the user object) into the login with facebook form and submit it. The form submits to an action that will validate the id against the signature. If it checks out, it will see if a user exists in the app. If not, we create one. And then either way we create a session.

The code I’m showing you is everything in the view layer. I leave the signature endpoint and login endpoint to your imagination. Those will be specific to your app anyway. This code also does not need to be in a wait for document ready.

<script type="text/javascript">

// this is the function to login to our app once the Facebook login
// is successful and we have a Facebook user object
function login_with_facebook(me) {
   // this is the endpoint in my app that I get a validation signature from
   url = '/facebook/jskey';

   if ('id' in me && me.id) {
      $.post(url, { 
         'id': me.id 
      }, function(response) {
         // use the user object data and jskey signature to post the #fb_form form
         if (me.name) {
            $('#fb_form input.fb_name').val(me.name);
         }
         if (me.id) {
            $('#fb_form input.fb_id').val(me.id);
         }
         if (me.gender) {
            $('fb_form input.fb_gender').val(me.gender);
         }

         var data = jQuery.parseJSON(response);
         $('#fb_form input.fb_key').val(data['key']);
         $('#fb_form').submit();
      });
   }
}
</script>

4. Hook up a login button or link and a logout link

Finally, we create a button or a link with the class ‘login_with_facebook’ somewhere on our page and another link with the ‘fb_logout’ class. To make it functional, we use this code.

<script type="text/javascript">
$(document).ready(function() {
   $('.login_with_facebook').click(function(e){
      e.preventDefault();

      // Get the login status, perform actions accordingly
      FB.getLoginStatus(function(response) {
         if (response.status === 'connected') {
            // user is logged into Facebook and has already authorized your
            // app. request a user object and call our app login function
            // with it
            FB.api('/me', function(me) {
               if ('id' in me) {
                  login_with_facebook(me);
               }
            });
         }
         else if (response.status === 'not_authorized') {
            // user is logged into Facebook, but has not authorized your app.
            // Facebook login, passing in a callback to fetch the user object
            // and perform an app login on success
            FB.login(function(response) {
               if (response.authResponse) {
                  FB.api('/me', function(me){
                     login_with_facebook(me);
                  });
               }
            });
         } else {
            // not logged in to Facebook. We do a Facebook login, passing in
            // a callback that fetches the user object and fires an app login
            // on success. The same actions as the previous case, but I'm
            // keeping them separate to more clearly show the three possible 
            // states you can be in relation to Facebook. You also may want
            // to handle these cases differently.
            FB.login(function(response) {
               if (response.authResponse) {
                  FB.api('/me', function(me){
                     login_with_facebook(me);
                  });
               }
            });
         }
      });
   });

   // who said breaking up is hard to do?
   $('a.fb_logout').click(function(e){
      // preventing default to make sure our logout request fires and
      // then redirects to where the link points
      e.preventDefault();
      FB.logout();
      window.location = $(this).attr('href');
   });
});

</script>

5. Knit it into your web app
The parts that I haven’t shown you are on the backend of my app. You’ll need to figure out what makes sense for your app. Specifically, the parts of my app I’m not showing you are:
1. the /facebook/jskey endpoint that creates a signature for an id. For best security, the signature for a given id should change over time.
2. the endpoint that the form submits to. This endpoint validates the id against the signature. If valid, it checks to see if the user exists yet for that Facebook id in our app. If so, it just creates a session and redirects back to the page. If not, it will also create a new user.

Also, I leave my #fb_form form, login button, and logout link html to your imagination.

We’re not handling failure with much sophistication, just ignoring it. In the places where failure is detected, you could easily add some code to flash the user a helpful message if you desire.

That’s it, I hope you find this useful.

Developer Diary: Taming Doctrine’s 2000 Flushes

I’ve just started a new side project that will involve finding some creative solutions to tough problems. I thought it would be neat to share what I learn as I go, so here goes…

For my project I decided to use the Doctrine 2 ORM to manage my data layer. We also use this at work, so the biggest reason I chose this was to be able to learn more about Doctrine to help me in my job. But this decision also makes sense for my project because my entity relationships will likely be fairly straightforward for the most part and using an ORM will allow me to make a lot of progress very quickly without (I hope) causing me lots of trouble later on.

One of the odd little things about Doctrine is how it handles persistence. The rules are a bit complex and non-intuitive. Here’s a summary:

  • Changes are saved when you call flush() on the entity manager, and at no other time.
  • Objects that were already in the database that you made changes to will be updated at this time with no special instructions.
  • New objects will not be saved by default.
  • If you want a new object saved, you need to persist() it.
  • If something would have saved and you don’t want it to, you need to detach() it.
  • Objects that are linked to each other through association fields can cause problems when one part is created or deleted and one isn’t – this can cause you to error out nastily and close your entity manager.
  • You can avoid this by creating cascade rules in your model classes, but this can lead to updates happening that you didn’t intend if you aren’t careful!

Clear as mud, right? We kind of have a love and hate (sometimes hate and hate) relationship with Doctrine at work because the hardest 20% of things we need to do with it tend to be very hard and annoying. One of the annoying things is that when a function needs to update an object, it’s not always obvious if we should flush. If we flush, maybe we’re committing a temporary change that shouldn’t be committed. Or maybe our data is still in an inconsistent state and the entity manager will crash. If we don’t flush, maybe we’re creating a burden on the controller layer to remember to do it for us (which isn’t what our controller layer should care about). We’ve sometimes resorted to having a flush flag parameter to a function to tell it whether to flush or not. This is complexity that we’re better off without!

It tends to be easier to solve these problems by adding way more flushes than we strictly need, which is not good for performance. The data in my side project is simple, but there’s a lot of it, so I wanted to mitigate this problem. This is my first stab at a solution:

First of all, I’m not using Doctrine’s entity manager directly. I’ve created an abstraction layer called the Data Manager which my code calls to perform all entity manager actions. This not only gives me better options to tame Doctrine’s rough spots, but gives me a fighting chance to yank Doctrine out and replace it if I decide it’s causing me significant problems.

<?php

class BB_Manager_Data
{
     static protected $instance = null;
     static protected $em = null;
     ...

If I want to go old school and just flush, I have a function for that. If I just call it with no preliminaries, it’s just a pass through. But I’ve borrowed the idea of SQL transactions to handle chunks of related changes. If I call startTransaction(), the flush() function will do nothing. When I call commit(), flush() is reenabled, and then called. This makes the idea of transactions more explicit and allows me to be more flexible about how I commit changes without cluttering my method signatures. Here’s what the first version of my code looked like:

static protected $disableFlush = false;

static public function startTransaction()
{
     self::$disableFlush = true;
}

static public function commit()
{
     self::$disableFlush = false;
     self::flush();
}

static public function flush()
{
     if (!self::$disableFlush) {
          $em = self::getEntityManager();
          $em->flush();
     }
}

Ah, but Doctrine supports transactions! It’s just a matter of calling $em->getConnection()->beginTransaction(); to start and $em->getConnection()->commit(); to complete or $em->getConnection()->rollback(); to cancel. Until commit() is called, the flushes won’t actually flush. So another version of the above would be:

static public function startTransaction()
{
     $em = self::getEntityManager();
     $em->getConnection()->beginTransaction();
}

static public function commit()
{
     $em = self::getEntityManager();
     $em->getConnection()->commit();
}

static public function flush()
{
     $em = self::getEntityManager();
     $em->flush();
}

Or you could just use Doctrine’s transactional functions outside of an abstraction layer.

Which of these versions is better depends on how Doctrine implements its transactional functionality (which I don’t know yet) and what your particular needs are. My initial version may actually be more performant in some cases if Doctrine’s transactions are just pass-throughs to your DBMS’s transactions. But it may be a micro-optimization or none at all. I may dig a little further or do some A/B tests to gather some information about that.

I think the transactional capabilities are an underutilized tool in Doctrine 2′s toolbag that can provide useful flexibility, group related changes, and minimize database writes. And the transactional paradigm (whatever the implementation) goes well with many use cases to help tame those flushes and optimize database writes.

 

The Product as a Promise (On Executing Well, part 1 of 2)

The year was 2002. Three men had a revolutionary idea for a new type of web site. This would be a new way to connect with existing friends and make new friends in a safe online “social network”. Not just anyone could join, you needed to be invited by an existing user. This could change the way people interacted over the Internet or even fundamentally alter how casual communication worked in the 21st century.

The idea had some initial success, and the company was funded in 2003 with a $12 million dollar investment from a capital investor firm. The site had enough mainstream popularity that Google made a buyout offer (which was declined). In fact, the company was featured in articles in magazines such as Time, Vanity Fair, and Entertainment Weekly and was generating a surprising amount of public buzz. Yet the company was doomed to fail to achieve its promise, their mantle stolen by a company with a better implementation of the same idea.

Any guesses? The company that was overtaken was Friendster. The company that overtook them was MySpace. Of course, both companies where bettered and beaten by Facebook. If you watched the movie The Social Network about the founding of Facebook without any other context, you would hardly know that any other similar site had ever existed before Mark Zuckerberg graced our world with his troubled, lonely genius.

What’s the point? Innovation is good, but execution matters more. This is the central premise that I want to explore in this two part series. In this first part part of the series, I want to focus on the product as a promise and how that plays out for the user and ultimately for the success or failure of the product.

The Product as a Promise

Software marketing seems to live and die by the bulleted list. Look on the back of any box of shrinkwrapped software (even games) and you’re sure to find a list of features that the software will deliver. Look on any web site for software, or a sign-up page for a Software as a Service (SaaS) product, and you’ll see the same thing. Sometimes you’ll even see a grid that includes competing products, showcasing which features they conspicuously lack. This high stakes game of bingo is played by product owners and marketers for the hearts and dollars of potential customers. But it misses the point.

That bulleted list is read by the customer as a promise, and every feature in that list creates an expectation by the customer that the software will deliver. The product owner might think of a feature as secondary or an afterthought, but the customer will be unlikely to do so. If that feature isn’t complete, well-executed, and intuitive, the customer will – rightly – view that as a broken promise. And broken promises are personal.

A Case Study: The Everything Software for Everybody

It was an amazing product for its time. Lotus Notes made hay in the nineties as extremely innovative business collaboration software. It sported and still sports an impressive list of features: email client, address book, calendar & meeting scheduler, instant messaging, word processor, database features, etc, etc. IBM bought Lotus in 1995 primarily to acquire this software, and this was haled as a tremendous strategic move.

How the mighty had fallen. By 2005, Lotus Notes had gone from dominating it’s corner of the the market with an over 60% market share to being dominated by Microsoft Exchange.

When I worked at IBM (circa 2004-2006), they made use drink the company Kool-Aid and use Lotus Notes for everything. At the time I observed that I’d never seen any application capable of doing more things less well than Lotus Notes. It was a constant hindrance to our day to day work lives and a horrendous user experience. More recently, competing products like Google Mail and Microsoft Sharepoint have gobbled up even more of its market share. There are few products that attract the same level of antipathy as Lotus Notes.

So what happened?

I’m not really familiar with every version of Lotus Notes from the early nineties to the present, but allow me to connect the dots. While growing their laundry list of features, Lotus Notes failed to keep up with users’ increasingly high expectations for the user experience. Some of the features were considered secondary and where implemented in an incomplete or slipshod way. Over time their user base took this personally and left.

It doesn’t matter how long that feature list is if those features are clunky and hard to use for most users. People will go elsewhere. And the best software is easier to use than it’s ever been. In short, the bar has been raised, and Lotus Notes did not keep up. The same thing has happened with many formerly successful products – I didn’t switch from Firefox to Chrome, for example, because Chrome had better features. It was faster and easier to use. That’s also why many people still prefer Microsoft Office products over fully featured free alternatives like Open Office.

Principle 1 – Poor execution leads to a poor customer experience every time, regardless of how innovative your product is or how many features it has.

Principle 2 – The bar for an acceptable level of execution has risen over time and will probably continue to rise. Products that fail to keep up will be abandoned.

The quality I’m trying to explain in common to these successful products is “execution”. Execution is the product’s ability to fulfill the explicit and implicit promises of a product, delivering a user experience that is reliable, intuitive, and pleasant. This includes the quality of the product, the completeness of the features, and the success of the UX design and implementation.

The Anti-Pattern: The Homer Mobile

Lotus Notes reminds me of the Homer Mobile. Do you remember that episode of the Simpsons? Homer Simpson, through an unlikely series of events which I won’t bother to relate here, was put in charge of designing his dream car for a major car company. The feature list:

  • Large beverage holders
  • Bowling mascot on the hood
  • Horns that play La Cucaracha
  • Sound-proof bubble for the kids
  • Huge motor
  • Big Fins
  • Power like a gorilla, yet soft and yielding like a nerf ball

And this was the result:

 

Needless to say, the product tanked, taking the company down with it. Silly Homer.

So what can we glean from this parable? By just stacking the product punch list with a list of (from Homer’s perspective) great ideas, Homer did a few things wrong. First, he bit off too large of a scope for a new product, undermining their ability to execute. Secondly, he didn’t consider what the set of core features were right for his product and whether they complemented each other. Finally, he never tested his ideas with a potential user base to determine whether there would be a demand.

Principle 3 – Be aware of what promises you are making the customer and make sure they are the right ones.

Principle 4 – Limit your promises to the most valuable ones you can fulfill. A more focused product that executes is a better start than a sprawling, half-baked product.

This may seem like a silly example, but I’ve worked on Homer Mobiles in my career. Maybe you have, too. It can be a little frustrating to be a software developer on a product that seems to be adrift without clear direction or achievable goals. It certainly doesn’t lead to competitive success in my experience. So if you are a product owner, don’t be a Homer.

Cleaning House at Apple

Steve Jobs understood this. After returning to Apple in 1998, he reduced their product line from 350 products to 10. Jobs understood that each product is a promise, and he limited what promises Apple made to just a handful – with the goal of nailing each and every one.

In his own words: “People think focus means saying yes to the thing you’ve got to focus on. But that’s not what it means at all. It means saying no to the hundred other good ideas that there are. You have to pick carefully. I’m actually as proud of the things we haven’t done as the things I have done. Innovation is saying ‘no’ to 1,000 things.”

Execution and Iteration

Ah, but what about iteration? Can’t you have a lot of basic, clunky features and iterate towards more complete and polished features. Isn’t that Agile?

Well, maybe sometimes, and I’ll explore the idea more in the next part of this series. But allow me to assert that it’s usually better to try to iterate by scope as much as possible. Start by delivering a fully realized product with a narrow initial scope and fill out the feature set over time. Don’t start with a huge set of poorly realized features and try to fill out the quality and the positive user experience over time. Your user base may not wait for you to keep your promises.

As someone working on a new product that’s currently in beta, I have to admit that polish and intuitive user experience is by necessity an outcome of iteration and benefiting from a good feedback loop. But that should, in my opinion, be a priority in a young product. The grace you receive for being new expires very quickly. If you don’t provide a product that has fully realized features and a positive user experience, you may find that a Zuckerberg will beat you to the punch. The first one in has a head start, but a successful product needs to execute and fulfill its promises to the customer.