Facebook Product Quirks, Part 1

As an Internet Professional who works with both Consumer & B2B Products, I’ve been keeping a growing list of issues with Facebook. I figured it was worth publicly sharing them — maybe others have thought this way.

Top 5 Product Quirks I Hate About Facebook , Part 1

1- Consumer Product : The messages that accompany a “Friend Request” are lost once you accept a Friendship

Let’s say someone sees your profile, realizes you know each other because of X/Y/Z to be a friend. Facebook has a great feature that gives them a chance to add a ‘qualifying message’ to their FriendRequest… you know, something like “Hey, Jonathan! It’s been years. My phone number is 555-123-4567. Call me!”

This is a great feature, right? Absolutely. There’s just a little problem though- once you become friends with that person, the message disappears. Since it’s not a real “message” ( in their world ), it doesn’t get archived in your message center history.

What Facebook should do: if a FriendRequest is accompanied with a message, turn it into a user-to-user message upon Accepting or Rejecting the request.

2- Consumer Product : When sending a FriendRequest to another User , the requesting first User doesn’t expose their Profile to the requestee

How many times have you gotten a FriendRequest, thought “Hmm, how do I know this person?”, and then clicked their profile ? I’d wager a lot. When you’re unsure of who someone is, it’s a normal reaction to check-them-out.

Here’s the problem – when Facebook first introduced their privacy settings, they gave users the option to make all ( or portions of ) their profiles “Friends Only”. It’s a great feature, but there’s a bit of a caveat — if this setting is turned on, the recipient of a FriendRequest can’t see the sender’s details. In many cases, the only information shown is a name & photo.

This user interaction is one of the most troubling and annoying to me – in order to find out exactly WHO sent me a FriendRequest, I need to accept their Friendship. This isn’t something that I really want to do — I don’t want to expose my activities, contact information, or network to someone that I don’t necessarily know or trust.

This is what it unfortunately looks like:

  1. The Friend Request Pane

Facebook - Friend Request Listing

  1. The requesting person’s profile. Who are they?!?!?

Facebook - FriendRequest - Profile

What Facebook should do: ProfilePermissions for “Friends” should apply to “outgoing FriendRequests”. There is an implicit intent to have a Friendship and share this information.

3- Consumer Product : Application Permission Dialogs show the name of the Application, not who is responsible for the Application.

All too often I see an interesting Post / Application and click on it to potentially add it to my own Profile.

Here’s an example – this Application promotes the song that was #1 on your birthday. “Hey, I want to find that out myself!”

Facebook - Application Newsfeed Item

When the Application requests an Authorization from me though, I see that I’m sharing my information with the App — which is great. What I don’t see, however, is exactly who I’m sharing my information with.

In an era where people get their Facebook accounts hacked, or viral apps pop out of nowhere only to get permissions they later abuse, I’m worried about who the developers/companies are. How do I know that “Some Random Application” is backed by solid, upstanding people – and not some foreign hackers that are trying to turn my account into a spamming node or mine it for personal info for identity theft?

Take a look at this screen and think about if you would feel comfortable granting whomever made this access :

Facebook - Application Auth Dialog

What Facebook should do: list the main developer/company/etc on the authorization page. Facebook makes a huge point about being based on “real names” – even going so far as to quarantine accounts that use ‘common’ names instead of legal ones ( if you haven’t read his tirades, Salman Rushdie wrote some great stuff on his own struggles here).

It’s also worth noting that this was a really awkward App to profile , because finding the install/auth screen was near impossible.

4- Business Product : Data about the origin of Linked content is nebulous or cryptic – and worthless for metrics

Links shared in Facebook aren’t direct links to content – they’re intercepted by a proxy at “http://facebook.com/l.php”. Basically, there’s a bit of javascript that rewrites an external link on a webpage into an internal link, which is used by Facebook to track performance and display within their own analytics suite. This is great and fine. “l.php” seems to take two parameters: a url encoded version of the destination, and a unique corresponding hash — which I think is a) just the a digest of the link with a ‘site secret’, and b) exists to ensure that the “l.php” script isn’t abused by non-facebook traffic. I could be wrong on both parts, but if the exact unique hash doesn’t appear with the corresponding link… Facebook throws a 404 instead of a redirect to the url parameter.

Because of the way this linking works, if you look within your own analytics suite you’ll see that ALL traffic from Facebook.com appears as if its from “l.php”. The only way to see how your referral traffic performs from Facebook is to use their own, limited, analytics program — and that can’t roll up into your existing analytics reporting tools AND only applies to “pages”.

If you embed a “Like” button on a page you can specify a “ref” label, into which Facebook will toss information back to your site with. However – this isn’t a default action, and applies to “Like” stories only, not organic shares. This is confusingly documented too – at a major publisher I was working with, earlier versions of the docs suggested that we would be able to note where on the site that button was placed, and we would then be able to access the information… nope.

What Facebook should do: append information about the outbound links into query strings on the redirect (e.g. “?fb:context=user.newsstream” ) or create intermediary dummy redirects that have that information and will appear in referral logs ( e.g. “/l.php” -> “/l/user.newstream.php” ), thereby letting publishers access that information within their own analytics programs. The information could even be coerced into the “utm_” namespace that Google uses, as Omniture can work with them by default — easily supporting two of the top analytics packages at once.

As a publisher your internal teams don’t need /much/ information (and they rarely have the time to sift though massive amounts), but it is invaluable to know some topline metrics — like the context of a link ( user newsfeed, profile page, app page, etc ) , and if there were images/non-default text shared, etc — the type of information that enables digital teams to better share and promote content on Facebook.

Additionally, the behavior of the “ref” tool should be on by default — affecting all links — and control for fine-tuning can be offered on a per-domain basis.

5- The internal Insights/Analytics app has a lot of data, but does little with it. There are some key metrics that could be shown now – and others that should be expanded upon.

Facebook is great about telling me how much content is shared, but is pretty bad at telling me HOW it is shared. As a publisher, I want to know WHERE the share is coming from and WHY – is it from within Facebook ? If so, is it as people “share” on each other’s walls or another mechanism? Is it happening from a “user to user” newsfeed story, or a “page to user” newsfeed ? Where did someone “Like” my story – on my website, on a newsfeed, on my brand’s profile page? As the Facebook Comments system is used more: I want to know if people are posting responses on Facebook , or on my own site. Most importantly, I want the ability to slice and dice all these bits of data on a “per post” or “per url” basis — it’ll help me figure out how to spend my internal resources in promoting stories. I need to figure out which types of stories do best as user-to-user vs brand-to-user, and which ones are being spread on Facebook vs those where offsite likes merely show an affinity for the stories.

For generic users this might sound silly, but as someone responsible for the digital growth of a brand this stuff is really, really, really important. As someone who is debating how much of a yearly budget to allocate to Facebook development, advertising, and internal staffing – this is information I really need to know. This is the type of information that tells me what I’m doing right, what I’m doing wrong, and guides my next steps. I want to know which Headlines performed the best in terms of “Likes” and which had the highest percentage of clickthroughs. Today, I only see the clickthrough data on my analytics suite and the aggregate of all activity on Facebook’s. This data is simply not substantial enough to base sound decisions on.

What Facebook should do: Surface the data. Repeat. Surface the data.

Give me granular details on the WHERE shares and comments come from; let me dive in and see things on a per-post basis.

“Like” buttons should support another tag called “placement” which tracks the context of the like on my site ( and makes the data available on Facebook’s site). For example: I want to know if the “Like” on my site happened from the button on the top of an article or the button on the bottom — or did the only like the “abstract” description , instead of the full article. I also want to know how social sharing is affected by A/B testing — did I get more likes using template A, B, or C on my website.

These are pretty basic things I want to know — but I can’t know them, because Facebook’s data collection and reporting just aren’t that great.

Posted in Social Media, Thoughts | Leave a comment

Python Fun : Upgrading to 2.7 on OSX ; Installing Mysql-Python on OSX against MAMP ( ruby gem too)

I needed to upgrade from Python 2.6 to 2.7 and ran into a few issues along the way. Learn from my encounters below.

Upgrading Python

Installing the new version of Python is really quick. Python.org publishes a .dmg installer that does just about everything for you. Let me repeat “Just about everything”.

You’ll need to do 2 things once you install the dmg, however the installer only mentions the first item below:

  1. Run “/Applications/Python 2.x/Update Shell Command”. This will update your .bash_profile to look in “/Library/Frameworks/Python.framework/Versions/2.x/bin” first.

  2. After you run the app above, in a NEW terminal window do the following:

  • Check to see you’re running the new python with python --version or which python
  • once you’re running the new python, re-install anything that installed an executable in bin. THIS INCLUDES SETUPTOOLS , PIP , and VIRTUALENV

It’s that second thing that caught me. I make use of virtualenv a lot, and while I was building new virtualenvs for some projects I realized that my installs were building against virtualenv and setuptools from the stock Apple install in “/Library/Python/2.6/site-packages” , and not the new Python.org install in “/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages”.

It’s worth nothing that if you install setuptools once you’ve upgraded to the Python.org distribution, it just installs into the “/Library/Frameworks/Python.framework” directory — leaving the stock Apple version untouched (basically, you can roll back at any time).

Installing Mysql-Python (or the ruby gem) against MAMP

I try to stay away from Mysql as much as I can [ i <3 PostgreSQL ], but occasionally I need to run it: when I took over at TheDailyBeast.com, they were midway through a relaunch on Rails , and I have a few consulting clients who are on Django.

I tried to run cinderella a while back ( http://www.atmos.org/cinderella/ ) but ran into too many issues. Instead of going with MacPorts or Homebrew, I’ve opted to just use MAMP ( http://www.mamp.info/en/index.html )

There’s a bit of a problem though – the persons who are responsible for the MAMP distribution decided to clear out all the mysql header files, which you need in order to build the Python and Ruby modules.

You have 2 basic options:

  1. Download the “MAMP_components” zip (155MB) , and extract the mysql source files. i often used to do this, but the Python module needed a compiled lib and I was lazy so…
  2. Download the tar.gz version of Mysql compiled for OSX from http://dev.mysql.com/downloads/mysql/

Whichever option you choose, the next steps are generally the same:

Copy The Files

Where to copy the files ?

mysql_config is your friend. at least the MAMP one is.

Make sure you can call the right mysql_config, and it’ll tell you where the files you copy should be stashed. Since we’re building against MAMP we need to make sure we’re referencing MAMP’s mysql_config

iPod:~jvanasco$ which myqsl_config /Applications/MAMP/Library/bin/mysql_config

iPod:~jvanasco$ mysql_config Usage: /Applications/MAMP/Library/bin/mysql_config [OPTIONS] Options: --cflags [-I/Applications/MAMP/Library/include/mysql -fno-omit-frame-pointer -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT -DDONT_DECLARE_CXA_PURE_VIRTUAL] --include [-I/Applications/MAMP/Library/include/mysql] --libs [-L/Applications/MAMP/Library/lib/mysql -lmysqlclient -lz -lm] --libs_r [-L/Applications/MAMP/Library/lib/mysql -lmysqlclient_r -lz -lm] --plugindir [/Applications/MAMP/Library/lib/mysql/plugin] --socket [/Applications/MAMP/tmp/mysql/mysql.sock] --port [3306] --version [5.1.44] --libmysqld-libs [-L/Applications/MAMP/Library/lib/mysql -lmysqld -ldl -lz -lm]

Include

Into /Applications/MAMP/include you need to place the mysql include files into a subdirectory called “mysql”

mkdir -P /Applications/MAMP/Library/include cp -Rp MySQL-Distribution/include /Applications/MAMP/Library/include/mysql

Lib

Into /Applications/MAMP/Library/lib you need to place the mysql lib files

mkdir -P /Applications/MAMP/Library/include cp -Rp MySQL-Distribution/lib /Applications/MAMP/Library/lib/mysql

Configure the Env / Installers

Note: if you’re installing for a virtualenv, this needs to be done after it’s been activated.

Set the archflags on the commandline:

export ARCHFLAGS="-arch $(uname -m)"

Python Module

I found that the only way to install the module is by downloading the source ( off sourceforge! ).

I edited site.cfg to have this line:

mysql_config = /Applications/MAMP/Library/bin/mysql_config

Basically, you just need to tell mysql to use the MAMP version of mysql_config to figure everything out itself.

the next steps are simply:

python setup.py build python setup.py install

If you get any errors, pay close attention to the first few lines.

If you see something like the following within the first 10-30 lines, it means the various files we placed in the step above are not where the installer wants them to be:

_mysql.c:36:23: error: my_config.h: No such file or directory _mysql.c:38:19: error: mysql.h: No such file or directory _mysql.c:39:26: error: mysqld_error.h: No such file or directory _mysql.c:40:20: error: errmsg.h: No such file or directory

If you look up a few lines, you might see something like this:

building 'mysql' extension gcc-4.0 -fno-strict-aliasing -fno-common -dynamic -g -O2 -DNDEBUG -g -O3 -arch i386 -Dversion_info=(1,2,3,'final',0) -D_version__=1.2.3 -I/Applications/MAMP/Library/include/mysql -I/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c _mysql.c -o build/temp.macosx-10.5-i386-2.7/_mysql.o -fno-omit-frame-pointer -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT -DDONT_DECLARE_CXA_PURE_VIRTUAL

note how we see “/Applications/MAMP/Library/include/mysql” in there. When I quickly followed some instructions online that had all the files in /include — and not in that subdir — this error popped up. Once I changed the directory structure to match what my mysql_config wanted, the package installed perfectly.

Ruby Gem

Assuming you’re using bundler:

bundle config build.mysql \ --with-mysql-include=/Applications/MAMP/Library/include/mysql/ \ --with-mysql-lib=/Applications/MAMP/Library/lib \ --with-mysql-config=/Applications/MAMP/Library/bin/mysql_config

and then before you do a bundle install , set the env vars

export ARCHFLAGS="-arch x86_64"

or

export ARCHFLAGS="-arch $(uname -m)"

Test it

If things install nicely, lets make sure it works…

$ipod:~ jvanasco$ python

import _mysql

Oh , crap:

Traceback (most recent call last): File "", line 1, in File "build/bdist.macosx-10.5-i386/egg/_mysql.py", line 7, in File "build/bdist.macosx-10.5-i386/egg/_mysql.py", line 6, in bootstrap ImportError: dlopen(/Users/jvanasco/.python-eggs/MySQL_python-1.2.3-py2.7-macosx-10.5-i386.egg-tmp/_mysql.so, 2): Library not loaded: libmysqlclient.18.dylib Referenced from: /Users/jvanasco/.python-eggs/MySQL_python-1.2.3-py2.7-macosx-10.5-i386.egg-tmp/_mysql.so Reason: image not found

Basically what’s happening is that as you run it, mysql_python drops a shared object in your userspace. That shared object is referencing the location that the Mysql.org distribution placed all the library files — which differs from where we placed them in MAMP.

There’s a quick fix — add this to your bash profile, or run it before starting mysql/your app:

export DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH:DYLD_LIBRARY_PATH=/Applications/MAMP/Library/lib/mysql"

Conclusion

There are too many posts on this subject matter to thank. A lot of people posted variations of this method – to which I’m very grateful – however no one addressed troubleshooting the Python process , which is why I posted this.

I also can’t stress the simple fact that if the MAMP distribution contained the header and built library files, none of this would be necessary.

Posted in Code - Python, Technology | Leave a comment

Facebook Developer Notes – Javascript SDK and Asynchronous Woes

I’m quickly prototyping something that needs to interact with Facebook’s API and got absolutely lost by all their documentation – which is plentiful, but poorly curated.

I lost a full day of time trying to figure out why my code wasn’t doing what I wanted it to do, trying to understand how it works so I could figure out what I was actually telling it to do. I eventually hit the “ah ha!” moment where I realized that by following the Facebook “getting started” guides, I was telling my code to do embarrassingly stupid things. This all tends to dance around the execution order , which isn’t really documented at all. Everything below should have been very obvious — and would have been obvious, had I not gone through the “getting started” guides, which really just throws you off track.

Here’s a collection of quick notes that I’ve made.

Documentation Organization

Facebook has made a lot of API changes over the past few years, and all the information is still up on their site… and out on the web. While they’re (thankfully) still supporting deprecated features, their documentation doesn’t always say what is the preferred method or not – and the countless 3rd party tutorials and StackOverflow activity don’t either. The “Getting Started” documentation and on-site + github code samples also doesn’t tie together with the API documentation well either. If you go through the tutorials and demos, you’ll see multiple ways to handle a login/registration button… yet none seem to resemble what is going on in the API. There’s simply no uniformity, consistency, or ‘official recommendations’.

I made the mistake of going through their demos and trying to “learn” their API. That did more damage than good. Just jump into the Javascript SDK API Reference Documentation itself. After 20 minutes reading the API docs themselves, I realized what was happening under the hood… and got everything I needed to do working perfectly within minutes.

Execution Order

The Javascript SDK operations in the following manner:

  1. Define what happens on window.fbAsyncInit – the function the SDK will call once Facebook’s javascript code is fully loaded. This requires, at the very least, calling the FB.init() routine. FB.init() registers your app against the API and allows you to actually do things.
  2. Load the SDK. this is the few lines of code that start “(function(d){ var js, id = ‘facebook-jssdk’;…” .
  3. Once loaded, the SDK will call “window.fbAsyncInit”
  4. window.fbAsyncInit will call FB.init() , enabling the API for you.

The important things to learn from this are :

  1. If you write any code that touches the FB namespace before the SDK is fully loaded (Step 3), you’ll get an error.
  2. If you write any code that touches the FB namespace before FB.init() is called (Step 4), you’ll get an error.
  3. You should assume that the entire FB namespace is off-limits until window.fbAsyncInit is executed.
  4. You should probably not touch anything in the FB namespace until you call FB.init().

This means that just about everything you want to do either needs to be:

  1. defined or run after FB.init()
  2. defined or run with some sort of callback mechanism, after FB.init()

That’s not hard to do, once you actually know that’s what you have to do.

Coding Style / Tips

The standard way the Facebook API is ‘instructed to integrated is to drop in a few lines of script. The problem is that the how&why this works isn’t documented well, and is not linked to properly on their site. Unless you’re trying to do exactly what the tutorials are for – or wanting to code specific Facebook API code on every page, you’ll probably get lost trying to get things to run in the order that you want.

Below I’ll mark up the Facebook SDK code and offer some of ideas on how to get coding faster than I did… I wasted a lot of time going through the Facebook docs, reading StackOverflow and reverse engineering a bunch of sites that had good UX integrations with Facebook to figure this out.

// before loading the Facebook SDK, load some utility functions that you will write
<script type="text/javascript" language="javascript" src="/js/fb_Utils.js"></script>
<div id="fb-root"></div>
<script>
    // when Facebook's SDK is loaded, it calls "window.fbAsyncInit"
    // the SDK load is the second block of code below
    window.fbAsyncInit = function() {
        FB.init({
            appId      : 'YOUR_APP_ID', // App ID
            channelUrl : '//WWW.YOUR_DOMAIN.COM/channel.html', // Channel File
            status     : true, 
            cookie     : true,
            xfbml      : true,
            oauth      : true 
        });
        // Additional initialization code here
        // ----------------------
        // ----------------------
        // the above is the fairly standard example from Facebook
        // now we'll do something custom 
        // we want to wrap all our facebook init stuff within a function that runs post async, but is cached across the site
        fb_Utils.initialize();
    };
    // this block actually loads the SDK
    (function(d){
       var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;}
       js = d.createElement('script'); js.id = id; js.async = true;
       js.src = "//connect.facebook.net/en_US/all.js";
       d.getElementsByTagName('head')[0].appendChild(js);
     }(document));
</script>

One of the move annoying things I encountered, is that Facebook has that little, forgettable, line in their examples that read:

// Additional initialization code here

You might have missed that line, or not understood its meaning. It’s very easy to do, as its quite forgettable.

That line could really be written better as :

// Additional initialization code here
// NEARLY EVERYTHING YOU WRITE AGAINST THE FACEBOOK API NEEDS TO BE INITIALIZED / DEFINED / RUN HERE.
// YOU EITHER NEED TO INCLUDE YOUR CODE IN HERE, OR SET IT TO RUN AFTER THIS BLOCK HAS EXECUTED ( VIA CALLBACKS, STACKS, ETC ).
// (sorry for yelling, but you get the point)

So, let’s explore some ways to make this happen…

In the code above I called fb_Utils.initialize() , which would have been defined in /js/fb_Utils.js (or any other file) as something like this:

// grab a console for quick logging
var console = window['console'];

// i originally ran into a bunch of issues where a function would have been called before the Facebook API inits. // the two ideas i had were to either: // 1) pass calls through a function that would ensure we already initialized, or use a callback to retry on intervals // 1) pass calls through a function that would ensure we already initialized, or pop calls into an array to try after initialization // seems like both those ideas are popular, with dozens of variations on each used across popular sites on the web // i'll showcase some of them below

var fb_Utils= { _initialized : false , isInitialized: function() { return this._initialized; } , // wrap all our facebook init stuff within a function that runs post async, but is cached across the site initialize : function(){ // if you wanted to , you could migrate into this section the following codeblock from your site template: // -- FB.init({ // -- appId : 'app_id' // -- ... // -- }); // i looked at a handful of sites, and people are split between calling the facebook init here, or on their templates // personally i'm calling it from my templates for now, but only because i have the entire section driven by variables

    // mark that we've run through the initialization routine
    this._initialized= true;

    // if we have anything to run after initialization, do it.
    while ( this._runOnInit.length ) { (this._runOnInit.pop())(); }
}
,
// i checked StackOverflow to see if anyone had tried a SetTimeout based callback before, and yes they did.
// link - http://facebook.stackoverflow.com/questions/3548493/how-to-detect-when-facebooks-fb-init-is-complete
// this works like a charm
// just wrap your facebook API commmands in a fb_Utils.ensureInit(function_here) , and they'll run once we've initialized
ensureInit :  function(callback) {
    if(!fb_Utils._initialized) {
        setTimeout(function() {fb_Utils.ensureInit(callback);}, 50);
    } else {
        if(callback) { callback(); }
    }
}
,
// our other option is to create an array of functions to run on init
_runOnInit: []
,
// we can then wrap items in fb_Utils.runOnInit(function_here) , and they
runOnInit: function(f) {
    if(this._initialized) {
        f();
    } else {
        this._runOnInit.push(f);
    }       
},
// a few of the Facebook demos use a function like this to illustrate the api
// here, we'll just wrap the FB.getLoginStatus call , along with our standard routines, into fb_Utils.handleLoginStatus()
// the benefit/point of this, is that you have this routine nicely compartmentalized, and can call it quickly across your site
handleLoginStatus : function(){
        FB.getLoginStatus(
            function(response){
                console.log('FB.getLoginStatus');
                console.log(response);
                if (response.authResponse) {
                    console.log('-authenticated');
                } else {
                    console.log('-not authenticated');
                }
            }
        );
    }
, 
// this is a silly debug tool , which we'll use below in an example
event_listener_tests : function(){  
    FB.Event.subscribe('auth.login', function(response){
      console.log('auth.login');
      console.log(response);
    });
    FB.Event.subscribe('auth.logout', function(response){
          console.log('auth.logout');
          console.log(response);
    });
    FB.Event.subscribe('auth.authResponseChange', function(response){
          console.log('auth.authResponseChange');
          console.log(response);
    });
    FB.Event.subscribe('auth.statusChange', function(response){
          console.log('auth.statusChange');
          console.log(response);
    });
}

}

So, with some fb_Utils code like the above, you might do the following to have all your code nicely asynchronous:

  1. Within the body of your html templates, you can call functions using ensureInit()

fb_Utils.ensureInit(fb_Utils.handleLoginStatus)
fb_Utils.ensureInit(function(){alert("I'm ensured, but not insured, to run sometime after initialization occurred.);})

  1. When you activate the SDK – probably in the document ‘head’ – you can decree which commands to run after initialization:
    window.fbAsyncInit = function() {
    // just for fun, imagine that FB.init() is located within the fb_Utils.initialize() function
    FB.init({});
    fb_Utils.runOnInit(fb_Utils.handleLoginStatus)
    fb_Utils.runOnInit(function(){alert("When the feeling is right, i'm gonna run all night. I'm going to run to you.");})
    fb_Utils.initialize();
    };
    

Concluding Thoughts

I’m not sure if I prefer the timeout based “ensureInit” or the stack based “runOnInit” concept more. Honestly, I don’t care. There’s probably a better method out there, but these both work well enough.

In terms of what kind of code should go into the fb_Utils and what should go in your site templates – that’s entirely a function of your site’s traffic patterns — and your decision of whether-or-not a routine is something that should be minimized for the initial page load or tossed onto every visitor.

Posted in Code - JavaScript, Social Media, Technology | Leave a comment

Fancy Blenders

I’m looking into the top blenders out there; there seems to be many pros & cons with the VitaMix and the BlendTec. Most notably I’ve found this:

VitaMix

  • Great Warranty – 7 years
  • The motor has issues for many people – like burning out or needing a rest period – its just not as “industrial” as many thing.
  • Most people need to use the stirring tool to blend
  • Not many bad reviews on the Amazon page, but many people on the BlendTec page mention “trading up” from it.

BlendTec

  • Warranty isn’t as great
  • Seems to blend faster for everyone.
  • The reviews are great, but some people have owned several units

Posted in Thoughts | Leave a comment

Net Neutrality

Net Neutrality is an increasingly popular topic for debate: Consumer advocates preaching about the freedom of choice; lobbyists preach about the freedom of markets; millions of people sit on the sidelines and wonder what they hell they’re talking about. While I can appreciate the arguments from each stakeholder, I’ve come to find both rather moot as internet tiering seems to be more a symptom of a larger economic problems than an actual issue itself. Net Neutrality isn’t a battle about the rights of internet consumers, its about the decline of innovation in the American economy.

Once upon a time ( in a land far far away), companies would compete for consumer dollars based on the strength of their products. The best /whatever/ were solid pieces of machinery that would last for years as the focus of innovation was to create better products. Most people are all too familiar with buying a modern day kitchen appliance that barely lasts a few years, while their parents regularly use products that are decades old.

At some point in time there was a cultural shift in America and we collectively decided to stop making purchases based on the strength of products, but instead on price. At the same time, corporations started to focus exclusively on maximizing their profits — and we all became familiar with planned obsolescence, offshore labor, and eventually offshore customer support as we increasingly complained about inferior goods.

The typical American Company no longer cared to innovate on the strength of their products, and instead focused on their financial statements — trying to make products as cheaply as possible. People began to not care they’d have to replace their blenders every year, because an unserviceable chinese made appliance was cheap enough to not care about how long it lasted. Unfortunately, we all learned the real costs involved on the third, fourth and fifth times we replaced any given appliance.

I doubt manufacturers consciously aimed to reduce quality at first, they simply didn’t care about it anymore; quality was an early casualty of minimizing costs. At some point though, marketers realized that they could position multiple lines of products — using a lower price point of disposable goods to inflate the prices of better made products, and encouraging consumers to trade-up to the higher priced model.

Over several decades, the general focus of what we innovate on — across our entire economy — has shift from what we make, to how we make and market it. American products are no longer as well made as they once were; in fact, many are not even made in America, they’re merely designed or managed within US borders, and manufactured outside.

Our capacity to innovate has shifted focus so much onto Costs and Marketing that an entire industry has grown around virtual goods. No, I’m not talking about the million dollar digital goods purchased in online games — I’m referring to the 1.2 quadrillion dollar “financial derivatives” market that nearly collapsed the US economy. Financial derivatives aren’t products that are linked to tangible goods, they’re essentially complex methods of valuing trading loan repayment obligations. An entire industry worth not millions, billions or trillions — but quadrillions — was created on the premise of selling different types of billing arrangements.

Financial Derivatives are merely an example of our shift from tangible products to intangible transaction-oriented ‘products’. US based Bank of America and Wells Fargo both recently lost class action lawsuits for creating illegal “billing products” in which their customers banking activity was processed in a way to maximize overdraft fees. While a customer’s deposits would be processed in a chronological order, their withdrawals would be reordered into a “largest to smallest” list. This created an abusive and aggressive situation in which multiple overdraft fees and penalty charges would occur. Instead of figuring out ways to lower fees or provide better service, Bank of America and Wells Fargo decided to innovate on how they bill their customers.

Telecommunication companies have operated in a similar manner. If you have a multi-year Cellular or Internet Service contract, you might note that your service has remained the exact same, while you have an increasing number of plans or service changes disclosed in your bills. It’s not uncommon to have an ‘unlimited’ plan suddenly capped at a very limited number; or learn that you now have your choice of 3 different ways to be billed for the exact same phone service. Instead of addressing the countless dropped calls or 2 week wait for customer service appointments, telecommunications companies have pushed their capacity to innovate into their billing department.

In modern times we use the term “billing products” to discuss these types of innovations, but historically this has been called “Rent Seeking (Activities)”. For those unfamiliar with the term, Rent Seeking is when an organization uses their resources to obtain an economic gain, without actually creating any wealth.

While the financial derivatives crisis has shown itself to be outrageous, the Net Neutrality issues is nothing other than perverse. For the first time in history, companies are actively lobbying for the ability to charge people for substantially worse service – and proud of it.

The argument for Tiered Internet Service isn’t one about free markets – in fact its the exact opposite , as its requires the manipulating of telecommunication resources – not to mention garnering government legal support. Instead of spending their energy on faster downloads, larger bandwidth, or cheaper costs… these companies are spending tens of millions of dollars to lobby the government for the ability to charge consumers more money for worse service. Instead of lowering their customer’s bills or improving their service through technological advances, companies like Comcast, Verizon and AT&T are spending time, energy and resources to argue for the ability to charge additional fees for improvements on a degraded service. Even in a purely capitalistic sense, this is a terrible idea — its an implicit sign to stockholders that these companies are technologically unable to compete for products, so must instead find new ways to bill.

I’m simply amazed that no one is discussing the situation around Net Neutrality from the larger economic context. Many people like to talk about the core of the American economy shifting from product to service based, but the service aspects have increasingly proven to be a midpoint on a larger shift — one in which Rent Seeking is a major component. The presence of Rent Seeking Activity has historically been one of the best indicators of substantial economic and governmental problems one can find, if you can find it. Today we’re in a cultural moment where this sort of activity isn’t happening behind-the-scenes , but its being publicly embraced and hailed as an ideal by its benefactors. Our economy has embraced a shift away from innovating on goods and creating better products that push our civilization forward, to one that is just trying to bill people differently. To me, this isn’t troubling, it’s terrifying.

Posted in Politics, Technology, Work | Leave a comment

GroupOn, You’re (probably) an Idiot.

GroupOn just turned down an acquisition offer from Google worth somewhere between 5 and 6 Billion dollars.

They believe they’re growing strong enough for an IPO of their own in light of their significant revenue (reportedly between 500MM and 2BN). Maybe they’re right… but I doubt it.

GroupOn did pioneer / popularize a certain style of “daily deep discount deals” – and to that they deserve much credit. As many people have pointed out — they’ve done a great job at revolutionizing local advertising and marketing.

But – and this is a huge but – just as much as GroupOn has “revolutionized” commerce, they’ve also exploited it. Merchants are flocking to the service for a chance to get in front of new customers, but what they receive isn’t necessarily what they expected.

GroupOn’s terms are roughly as follows: A merchant offers a 50% discount through GroupOn; and the revenue from the discount coupons are split 50/50 with GroupOn.
A merchant might offer a $10 store-credit for $5 , and receives $2.50 in return. I say roughly, because there are no set standards with GroupOn – the discounts vary, as do the revenue splits. From what I’ve been able to gather from a handful of merchants, a 50% discount is required to be ‘featured’, and some GroupOn sales team members will insist they receive 100% of the revenue, while others will split more evenly ( and perhaps slightly in favor of the merchant ). That being said, 50% seems to be a common baseline for the majority of offers.

For most small businesses, selling goods for 25% of their sticker price is a loss leader – both below the actual unit costs and the overhead / staffing. Merchants are eager for this to get new business.

In order to deal with these revenue splits, smarter merchants carefully position their offerings — creating “coupons” in packages or dollar amounts that will either result in an upsell ( ie: $10 credit at a store where everything is $15 — customers have to spend $5 more ) or a partial use of the non-carryover credit ( ie: $10 credit where everything is $7.50 — customers either give-up the $2.50, or upsell to a $15 purchase ).

Unfortunately, the type of customer that GroupOn fuels and caters to is the “lowest common denominator”. GroupOn is particularly attractive to people who want a great / cheap deal — bargain hunters. Industry reports claim these customers tend to not turn into repeat customers. While GroupOn itself claims that B2B merchant customers overwhelmingly are satisfied and want to return, independent reports show that almost half of merchants would definitely not do another campaign. Many merchants have also been public about how GroupOn’s deals have created havoc on their operations and balance sheets.

The end result of all this, is that Merchants use GroupOn because its a fad. In a down economy, small businesses need every chance they can to attract new customers; GroupOn has a large and growing userbase – they’re the easiest way to gain new exposure. Early into a relationship with GroupOn , merchants get a strained relationship with the sticker-shock of how much revenue they’re going to lose; as the deals progress, they learn of the stress on their businesses and staffs. Personally, I’ve been to one too many restaurants where the waitstaff rolls their eyes at the sight of GroupOns being used — knowing their tips will be scarce and the customers rude. I’ve unfortunately dealt with trying to use a GroupOn too – and finding out that the kitchen is out of my 1st, 2nd, 3rd, etc choices.

So yes, while GroupOn is growing – their future and the ability to foster repeat business is… unknown ( and probably depressing ).

Yes, in 2 years GroupOn could be worth tens of billions of dollars — but they could also be worth nothing. There are dozens of new competitors, each growing just as rapidly, and many with much more “Merchant Friendly” practices, policies, and consumers. One can’t help but wonder, if the economy was even only slightly better — would merchants still be so desperate to get in front of a bargain seeking crowd ?

On the flip-side of this argument — why would a Google / Facebook / AOL / Yahoo want to acquire GroupOn? There are no contracts that lock-in users, nor do they have no recurring customers — and too many merchants have found them to be antagonistic. The large internet companies have strong brands with hundreds of millions of customers — they could easily compete-with and overpower GroupOn with a more merchant-friendly endeavor , and their brands wouldn’t suffer from any anti-groupon sentiment.

Maybe I’m just ‘down’ on GroupOn — perhaps.

I can’t help but think of a VERY similar story a few years back… Friendster turned down an acquisition offer from Google that would have turned into over 1 Billion of post-ipo stock. The company began to falter shortly thereafter, as more and more competitors entered the market with more consumer-friendly products. After years of layoffs , shifts and downsizing, Friendster eventually sold for 100MM — a lower ( but still decent ) price… until your realize that they had raised/burned through 46MM… so they only had a 2x ROI vs what would have been 500x or more.

Everyone likes to reminisce about this as a ‘flop’ — but its only one in hindsight. Friendster was at the top of the market and dominating, and they had so much potential — they should have stayed there. But the market kept getting crowded, their relevance waned, then MySpace killed Friendster, and then Facebook killed MySpace, and then…

So yeah, GroupOn might be worth 20 Billion dollars one day — but they’re far more likely to only decrease in valuation. A $5BN sale would have been a huge accomplishment for a company to achieve in only 3 years. How / why it was turned down… that simply amazes me.

Posted in Social Media | 2 Comments

Crazy Few weeks, Part III

As of mid-October, I’m at IAC’s The Daily Beast for a bit !

An amazing opportunity was extended to me to jump on board and build out the Technology and Product departments of the leading news website. Professionally, it was an offer I couldn’t resist… and it was impossible to turn down on a personal level — the team in-place at The Beast is simply amazing and full of iconic experts in management, operations, editorial, and advertising.

This has been an interesting transition for me — coming from the agility of managing products and teams at growing startups / interactive agencies over the past few years, to functioning in the same role at an established organization with a clear structure in place. There’s a lot less time devoted to “setting of precedent” — and a lot more time spent on “making things awesome”.

I’m exceptionally excited about what we’re doing there to grow the brand and product over the next few months.

Posted in Personal, Work | Leave a comment

Crazy Few Weeks, Part II

I’m relieved to announce that FindMeOn’s main patent application has finally been published. Most of the concepts, images, and methods have been publicly shared over the past few years in documents and presentations – but we had opted to keep the application itself shielded by the USPTO to deal with the fact that competitors just kept on reimplementing our products and technologies.

The full contents of our application can be viewed here: http://www.freepatentsonline.com/y2010/0274815.html

There’s a PDF of the official USPTO version, which includes about 50 pages worth of images.

You’ll note a filing date of January 30th 2008 for our application, a “Priority Date” of January 30th 2007 for our ‘Provisional’ (which was the same content, images, etc)… and if you wanted to do some searching, you’ll find archives, screengrabs and reviews of the site with that functionality in 2006.

I find that’s important to note, because this unarguable proves how far advanced FindMeOn’s research , development and products were.

I’ve been saying for a few months that a certain technology giant’s 2010 social media strategy looks a whole lot like a patent I filed in 2007… and well, now the pictures and text are public.

Posted in FindMeOn, Personal, Start Ups, Technology | Leave a comment

Crazy Few Weeks, Part I

It’s been a crazy few weeks for me personally and professionally, as several projects that I’m involved in have been getting some traction.

Today Cityist.com had a wonderful feature on ArtWeLove titled A-SITE-WE-LOVE.

Their first paragraph pretty much nailed our business down:

Apart from robbing the MOMA, access to appealing, contemporary art is expensive and not to so easy to acquire (Actually, this would only be considered simple for James Bond). But to avoid jail time, because who actually looks good in orange, try this innovative way to obtain quality art. Enter ARTWELOVE, an up-and-coming art-shopping site that allows customers to purchase exclusive, high-quality paintings by contemporary artists. Amazingly, the quality and limited nature of these paintings well exceeds the low prices (works range from a modest $15 to $2,000). Each week, at least one limited edition work is released and ARTWELOVE.com features interesting interviews with each artist, so you can learn more about where each piece comes from.

They went on to say some rather nice things about the site, and eventually mentioned me!

The site was started by Laurence Lafforgue, an art lover who was concerned about the severe gap in the market for affordable, contemporary artwork, along with Jonathan Vanasco and The Barbarian Group. It was unveiled in 2010 and is a rising success. The art-loving team consistently asks contemporary artists to create exclusive pieces so that art appreciators have access to museum quality works without having to deplete their savings.

The full article is quite a bit longer, and flattering, so please read it!

Posted in ArtWeLove | Leave a comment

Lemons, Tea, and Me ( and you )

Last summer I went on the quest for the perfect ‘adult’ version of an Arnold Palmer — the tasty beverage made by mixing lemonade with iced tea.

I started my quest using Limoncello as the adult drink, and then began to branch out from there. At the same time, my friend Siena set out on a similar task using a vodka infused with Earl Grey tea.

These are some findings:

  1. A shot of Limoncello in a glass of iced tea is quite nice. It’s very refreshing if you’re using a tea with herbal notes – like a Pomengranate Green Tea; its even nicer if you float a bit of sparkling water on top. This is best when the iced tea is unsweetened.

  2. A shot of Sweet Tea Vodka in homemade Lemonade is best if the lemonade is unsweetened. This wasn’t as good with a splash of sparkling water. You can get Sweet Tea Vodka in a bunch of stores, its basically a tea version of Limoncello – about 30 proof and full of sugar.

  3. A shot of Earl Grey Tea infused vodka works well in a sweetened lemonade. I liked mine sweetened with honey. I also liked a bit of ginger in it too. This isn’t bought in stores — to make the vodka, you steep a couple tea bags in vokda for a few minutes; there’s a website with the exact recipe and timings to avoid bitterness.

  4. One of my favorite drinks was serving a San Pelligrino Limonata in a tall glass of ice, and topping it with a shot of Sweet Tea Vodka. The ice and bubbles cut the sweetness quite a bit.

  5. A shot that is 50% Sweet Tea Vodka and 50% Limoncello is a lot sweeter, and smoother, than 50% Earl Grey Vodka and 50% Limoncello.

  6. Unless you have tons of it, homemade Limoncello should be savored on its own. BTW, homemade Limoncello with lime is WAY better than the lemon variety.

  7. I’m missing some drinks we made. There were lots. 2 years worth of experimenting.

Posted in Recipes | Leave a comment