Steve Jobs on Ping and Facebook:
Facebook wanted “onerous terms that we could not agree to.”
but when I read this, in another time I was reading about other Onerous silly terms:
Steve Jobs on Ping and Facebook:
Facebook wanted “onerous terms that we could not agree to.”
but when I read this, in another time I was reading about other Onerous silly terms:
Facebook announced a lot of bold moves at f8 yesterday. It was exciting to see Bret Taylor (who I had the pleasure to work with at Google) do such a great job on stage, and with the platform. There are many implications that will ripple out from this news, and here are some of my thoughts:
Act One: Security
At JSConf, Doug Crockford came out in his talk, asking to do an ECMAScript 4 to HTML5. Stop it. Block it. Go back to the table and fix the Web security model.
He must have had a giggle when he saw the new Facebook “Like” button. It allows anyone to throw a Facebook like on any page. I quickly put it up on Ajaxian:
<iframe src="http://www.facebook.com/plugins/like.php?href=<?php echo urlencode(get_permalink()); ?>&layout=standard&show-faces=true&width=450&action=like&colorscheme=dark" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:450px; height:30px; padding-top:8px"></iframe>
Note how you pass in the href
of what you want to like. I am getting the URL for each post and plugging it in. However, you could put any URL in there, as folks quickly discovered. Isn’t it fun to have a like button on content that actually likes some XXX porn. You like innocuous content X, and your wife looks at your stream to see that you are into a dirty movie.
As soon as you iframe in the world of Facebook, the page in question gets the power to get content into your graph and stream. Ouch. Not good.
The UI should at the very least see if it is liking a URL that isn’t the same as the main window.location
. If it is exactly the same page, when you hover on “Like” it could say “this exact page”. If it is on the same domain it could say “a page on this site”, and if it isn’t on the domain…. ALERT ALERT ALERT. Since Facebook knows who you are, why not even let me set what I want to do here?
It is also frustrating that I couldn’t easily change the look and feel. Neither “light” or “dark” themes work on Ajaxian for example. I hope that power user features are added, so you can set the colors for various elements without having to go low level and do everything from scratch.
Act Two: Owning My Data
When I look at how we add the “Like” in the browser, we see the code smell of an iframe to an external site. We see this in other forms too, such as script tags pointing to Google to get a Google Map. This feels utterly wrong to me. Instead of a code snippet that points to a particular service, I want to declare what I want to see.
In the case of “like”, let me just say something such as:
<div class="data-like"></div>
Then some JavaScript could come in and augment this to be the iframe, OR the right thing could happen. The browser itself could take over and understand the semantic meaning here.
Imagine if around the Web we had:
<div class="map loc:xxx,yyy"></div>
Rather than the Google Maps, Bing Maps, Yahoo! Maps snippets. If a cool new maps startup came along, I could change my maps provider in my browser, and ALL maps would be shown using the provider of my choice. Much better.
I want to see the same for “Like” and other social data. The browser could then know what services to ping with the like. For example, perform a “like” on Facebook, a retweet on Twitter, and a bookmark. That data could be stored locally, and I am assured that I can always have it.
This leads me to Michael Hanson, principal engineer at Mozilla Labs. Mike and I didn’t even get a chance to really overlap at Mozilla, but I met him before I left. He is a killer engineer, and someone who is going to have a profound effect on the state of identity for us all.
His early work, in alpha-ish stage, is around the notion of contacts in the browser. This add-on is fantastic. Contacts are consumed from Yahoo!, Facebook, Google, etc (a la Palm webOS Synergy) and people are first class citizens (e.g. person:[email protected]
, person:http://facebook.com/btaylor
). With type=”email” you can auto complete of your friends. He already uses the new Facebook Graph API which is a dream to use compared to the old REST/FQL. I hope it is more solid too. Anyway, these are just a few of Mike’s features. Firefox is about to get very social.
So, the browser should be the universal like machine. Not Facebook. Not a service owned by a company. You. Your browser. You own your data.
Facebook continues to change your privacy policy, and the EFF just spoke out again: Facebook Further Reduces Your Control Over Personal Information. Some claim that ad companies do this and more already, tying it together sneakily on the backend…. but changing your privacy and making it OPT-OUT is terrible.
Act Three: Performance
Alex Sexton pointed out the performance side of a like button:
From what i can tell, a single facebook like button requires at least 12 unique requests and ~1 second of load time.
The button adds ~161 new http requests to this page on Levis which is ~4sec
Compare the difference in when onload kicks in via iframe compared to via JS.
Time for Steve Souders to do a P3P? :)
Again, if the browser handled the notion of like, we wouldn’t have this issue. Also, what if instead of a million iframes, we all loaded one set of JavaScript from Facebook, and there was a JavaScript function that would let us put the like content into a div. To optimize, we could pass in the set of URLs to ONE JavaScript function and get one set of metadata back. Then we have a function that adds the right HTML to a div. No matter how many like buttons you have. One request.
We could go the OpenLike route, but we don’t want a huge list of buttons and another resource to deal with. Let the browser do it. We don’t need to see a world of this. It is broken. Time to wake up:
Chris Messina has some words on the subject too:
When all likes lead to Facebook, and liking requires a Facebook account, and Facebook gets to hoard all of the metadata and likes around the interactions between people and content, it depletes the ecosystem of potential and chaos — those attributes which make the technology industry so interesting and competitive. It’s one thing for semantic and identity layers to emerge on the web, but it’s something else entirely for the all of the interactions on those layers to be piped through a single provider (and not just because that provider becomes a single point of failure).
I give Facebook credit for launching a compelling product, but it’s dishonest to think that the Facebook Open Graph Protocol benefits anyone more than Facebook — as it exists in its current incarnation, with Facebook accounts as the only valid participants.
As I and others have said before, your identity is too important to be owned by any one company.
Facebook Uploads
Sorry, we cannot support uploads sent via email. Upload photos from your iPhone with our free application, Facebook for iPhone:
http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=284882215&mt=8
This is the message that I now get when I try to use the Facebook feature of emailing photos to my account. For a long time, I have emailed an alias on my domain which forwards on to both Flickr and Facebook, get to get photo into both places at once.
My blog brings in these photos from Facebook using Fotobook. Now I can longer use this workflow. Instead, Facebook wants me to stop using the “open” import mechanism of SMTP, and instead wants to force me into the mobile walled garden of the Facebook app on the iPhone. Now, don’t get me wrong, the Facebook iPhone app is fantastically produced by Joe Hewitt, and I have no beef with it at all. I just don’t like being forced into one workflow which will then only work with that one provider. Facebook, by taking away a feature, changed the entire game.
Open protocols give us the ability to develop our own patterns, and tweak the implementation over time. When blogger (and others) allowed us to abstract the implementation behind DNS records, it felt better (as well as being able to export the data out).
Facebook Connect
There are advantages to the walled garden though. I have been really worried about seeing Facebook Connect buttons shown up around the Web. The UX for FB Connect is very nice indeed, which is why I was so worried. The majority of people won’t choose the Open platform purely because “they should”. Open needs to compete on its own rite.
This is why I was so pleased to see Open Connect:
We need to do this quickly, as people will only put “one” of these on, and it should be the open meta platform.
I think that there is a place for the browser to help out here too, as I have mentioned before. If you login to the browser once, and we agree on the protocols, the browser can do the handshake for us. A great UI….. none at all.
Time to “make the Web better” instead of how Facebook tries to “make a better Web”.
When I heard that Facebook had released a more FriendFeed like version I was excited. Maybe this would bring me back into the Facebook world that I have pretty much left alone as a destination (now using FriendFeed and Twitter more, even though that means I am in tech-friend land).
At first glance I liked it. The river of news flow, the un-boxiness. Good stuff.
I quickly ran into flaws though. I wanted to upload my video on monkey balls (not what you think) and I got a “hey you need to allow popups”. Really? Isn’t this going backwards? The video upload experience has always been top notch on Facebook, why ruin it now?
Then in the popup it completed but with no way to save the info. I opened up Firebug and found this:
If I didn’t despise the phrase “FAIL” and “EPIC FAIL” I would have used those terms. To get the video up there, I had to go back in time and go to the old site, but this unfortunately took any changes with it.
The second frustration is the way that actual useful content has been striped from the mini-feed.
Take a look at this:
See the Dion has activitiy on FriendFeed
post? Are you kidding me? My river of news now has millions of those which tell me NOTHING. I want the opposite. Given a choice I would rather see “Dion said that Facebook has some rough edges with its new version” with no mention of the FB brand other than the icon say.
Overall I like the new look, but there are definitely things I want to see ironed out. You?
If Ryan and I were in marketing then we would be talking about “making your iPhone applications BREAAAAATHE” or something ;)
Ryan has a wrapper that lets you run iPhone applications inside of the AIR container:
This implementation just uses the mx:HTML tag with the location set to http://iphone.facebook.com with some extra code to handle the custom chrome and the option to make it transparent. Ideally I could take all of the source code for the iPhone application and have all of those files locally installed with the application but going through that code was more time than I had. You’ll also notice that it just refreshes the entire page. My plan is to go through the iPhone facebook code more and call the function that loads the feed information and just refresh that. I’d also like to be able to detect when a new feed item comes in and bubble that up so I can show a notification but detecting changes to the DOM isn’t easily done with AIR so I need to check with the engineering team. I’m going to have some followup posts this week discussing little parts of the application and I’ll also post the source code later this week (I just need to clean it up).
This is a natural fit for certain applications such as Facebook. Doesn’t this application now look a little like Adium sitting over there?
This, once again, gets me back to Face IM. Similar form factor, just add a few more abilities than you get with the iPhone client (which is optimized for having a crappy keyboard etc).
Ryan, we should get together and hack on this bad boy sometime!
When I built the Facebook Auto Expand Greasemonkey script I had to find out the function that kicks off the expansion, and I wanted it to be the right one.
Firebug can help out there, but as I looked through I was surprised by something:
Facebook doesn’t seem to minify/compress their JavaScript!
Since they push ~60 billion pages a month, I was a touch surprised. With this nugget I decided to grab the <head> of Facebook and iGoogle to compare.
The obvious differences as you look at them side by side (below):
Maybe it is time to run some YSlow?
My Facebook HEAD
<head> <title>Facebook | Home</title> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <meta name="robots" content="noodp" /> <meta name="description" content="Facebook is a social utility that connects people with friends and others who work, study and live around them. People use Facebook to keep up with friends, upload an unlimited number of photos, share links and videos, and learn more about the people they meet." /> <script type="text/javascript">var cc=new Image();cc.onload=function(){cc.hit=(typeof(Env)=="undefined");};cc.src="http://static.ak.facebook.com/images/global_menu_space.gif?12:37897";Env={method:"GET",dev:0,start:(new Date( )).getTime(),cache:(((typeof(cc)!="undefined")&&cc.hit)||0),ps_limit:5,ps_ratio:4,pkgv:1};</script><link rel="stylesheet" href="http://static.ak.facebook.com/css/base.css?12:62201" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/apps_menu.css?12:43718" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/typeahead.css?12:19905" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/wallpro.css?12:57950" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/dialog.css?12:39930" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/attachments.css?12:59060" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/captcha/captcha.css?12:60350" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/dialogpro.css?12:61009" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/editor.css?12:52799" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/components.css?12:53705" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/sharer.css?12:55903" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/share_media.css?12:60984" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/typeaheadpro.css?12:58664" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/inbox/css/inbox.css?12:62108" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/homeslice.css?12:58781" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/info.css?12:56012" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/profile.css?12:60600" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/feed.css?12:61849" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/feed_ad.css?12:43135" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/status.css?12:39712" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/gifts/gift.css?12:36833" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/mobilepro.css?12:60047" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/sms.css?12:59681" type="text/css"/> <link rel="stylesheet" href="http://static.ak.facebook.com/css/sprite/icons.css?12:56618" type="text/css"/><!--[if lte IE 6]><style type="text/css" media="screen">/* <![CDATA[ */ @import url(http://static.ak.facebook.com/css/ie6.css?12:62634); /* ]]> */</style><![endif]--> <!--[if gte IE 7]><style type="text/css" media="screen">/* <![CDATA[ */ @import url(http://static.ak.facebook.com/css/ie7.css?12:62093); /* ]]> */</style><![endif]--> <script type="text/javascript" src="http://static.ak.facebook.com/js/base.js?12:62634"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/extended.js?12:59503"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/string.js?12:59850"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/async.js?12:61542"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/deprecated.js?12:58595"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/apps_menu.js?12:55974"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/typeahead_ns.js?12:60552"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/suggest.js?12:52414"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/dynamic_dialog.js?12:51503"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/captcha.js?12:52414"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/recaptcha_ajax.js?12:60350"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/typeaheadpro.js?12:61630"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/dialogpro.js?12:62226"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/fbml.js?12:62093"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/swfobject.js?12:55357"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/editor.js?12:58199"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/timezone.js?12:52149"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/share.js?12:61979"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/home.js?12:47671"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/polls/polls.js?12:48801"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/pools.js?12:36733"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/editregion.js?12:56446"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/statuspro.js?12:52414"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/profile.js?12:62148"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/rooster.js?12:40867"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/poke.js?12:62143"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/privacy.js?12:57099"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/addfriend.js?12:62209"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/mobile.js?12:61909"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/search_typeaheadpro.js?12:59982"></script> <script type="text/javascript" src="http://static.ak.facebook.com/js/animation.js?12:62119"></script><link rel="search" type="application/opensearchdescription+xml" href="http://static.ak.facebook.com/opensearch_desc.xml?12:27839" title="Facebook" /> <link rel="shortcut icon" href="http://static.ak.facebook.com/favicon.ico" /> </head>
My iGoogle HEAD
<head><meta http-equiv="content-type" content="text/html; charset=UTF-8"><meta name="description" content="iGoogle is your personalized Google page. Add news, photos, weather, and stuff from across the web to your page."> <link rel="shortcut icon" href=" http://www.google.com/favicon.ico" type="image/x-icon"/> <link rel="icon" href="http://www.google.com/favicon.ico" type="image/x-icon"/> <title>iGoogle</title> <script>var _IG_time_epoch = (new Date()).getTime();var IGoogleTranslation = {};</script> <script src="/ig/extern_js/f/CgJlbhICdXMrMAE4ACw/93yMfLuYD4A.js"></script> <script>var domain = document.location.hostname;var google_pos = domain.indexOf('.google.');if (google_pos > -1) {domain = domain.substring(google_pos);document.cookie = "TZ=" + (new Date()).getTimezoneOffset()+ ';path=/;domain=' + domain;}_et="Tr8WCSVW";_source="";_setp_url="/ig/setp";_gmail_json_url="/ig/gmailjson";_magic_tabs_url="/ig/filltab";_prefid="";_uli=true;_pnlo=false;_mpnlo=false;_pl=false;_mod=true;_pid="";_old_html = false;_use_old_feed_styles = false;_cbp=true;_authpath="";_upc();var _pl_data = {};</script> <script><!-- function save_chkbox_value(hidden_elem_name, checked) {var hidden_elem = document.getElementById(hidden_elem_name);hidden_elem.value = checked ? "1" : "0";}function module_loader_closure(el, rm) {return function() {_IG_RemoveModuleEventHandler(rm.id,'unzip',arguments.callee);el.src=rm.base_iframe_url;};}function RemoteModule(spec_url, id, render_inline, base_iframe_url,caching_disabled, is_zipped) {this.spec_url = spec_url;this.id = id;this.render_inline = render_inline;this.base_iframe_url = base_iframe_url;this.caching_disabled = caching_disabled;this.old_width = 0;this.wants_scaling = false; this.is_inlined = function() { return this.base_iframe_url == ""; };this.is_zipped = is_zipped;};var remote_modules = [];_IG_RegisterOnloadHandler(function() {for (var i=0;i<remote_modules.length;i++){var rm=remote_modules[i];var el=_gel("remote_iframe_"+rm.id);if(el){if (rm.is_zipped && true) {_IG_AddModuleEventHandler(rm.id, 'unzip',module_loader_closure(el, rm));} else {el.src=rm.base_iframe_url;}}}});function ifpc_resizeIframe(iframe_id, height) {var el = document.getElementById(iframe_id);if (el) {el.style.height = height + "px";}}_IFPC.registerService('resize_iframe', ifpc_resizeIframe);function _ig_gmid_(iframe_id) {return(iframe_id.split("_")[2]);}function _setModTitle(title, module_id) {var title_element = _gel("m_" + module_id + "_title");if (title_element) {title_element.innerHTML = _hesc(title);}}function ifpc_setTitle(iframe_id, title) {if (typeof(iframe_id) == undefined|| !iframe_id || iframe_id == "undefined") {return;}_setModTitle(title, _ig_gmid_(iframe_id));}_IFPC.registerService('set_title', ifpc_setTitle);function _IG_SetTitle(title, specified_module_id) {if (typeof(specified_module_id) == "undefined"|| !specified_module_id || specified_module_id == "undefined") {throw new Error("Inline modules must specify their "+ "__MODULE_ID__ when using _IG_SetTitle");} else {_setModTitle(title, specified_module_id);}}function ifpc_setPref(iframe_id, var_args) {var module_id = _ig_gmid_(iframe_id);var prefs = new _IG_Prefs(module_id);var keyValues = new Array();for (var n = 1; n < arguments.length; n += 2) {keyValues.push(arguments[n], arguments[n + 1]);}prefs.set.apply(prefs, keyValues);}_IFPC.registerService('set_pref', ifpc_setPref);function share_gadget_safe(msg, url, width, mod_id, send_label,cancel_label) {_share_gadget(_hesc(msg), _hesc(url), _hesc(width), _hesc(mod_id),_hesc(send_label), _hesc(cancel_label));}_IFPC.registerService('share_gadget', share_gadget_safe);var isPubSubEventRouterLoaded = false;function setupPubSubEventRouter() {if (!isPubSubEventRouterLoaded) {document.write("\x3cdiv id\x3d\x22remote_pubsub_event_router\x22 name\x3d\x22remote_pubsub_event_router\x22 style\x3d\x22border:0;padding:0;margin:0;width:100%\x22\x3e\x3ciframe id\x3d\x22remote_iframe_pubsub_event_router\x22 name\x3d\x22remote_iframe_pubsub_event_router\x22 style\x3d\x22border:0;padding:0;margin:0;width:0;height:0;overflow:hidden\x22 frameborder\x3d0 scrolling\x3dfalse src\x3d\x22http://pubsub.gmodules.com/ig/modules/pubsub_event_router.html\x22\x3e\x3c/iframe\x3e\x3c/div\x3e");isPubSubEventRouterLoaded = true;}}// --> </script> <script src="/ig/f/CSyPjYmOhjg/lib/libminimessage.js"></script> <style>.modbox .el {display:;}.modbox .csl, .modbox .es {display:none;}.modbox_e .el {display:none;}.modbox_e .csl, .modbox .es {display:;}.dm {position:relative;width:1px;height:1px;}.fres {width:expression(_gel("ffresults").offsetWidth+"px");overflow:hidden;}.panelo {}.panelc {}.mod {}.unmod {}form {display:inline;}.c {clear:both;}.fbox {margin-top:1px;margin-right:6px;display:block;overflow:hidden;width:12px;height:12px;background-image: url('/ig/images/max_dark_blue.gif');background-repeat: no-repeat;cursor:hand;cursor:pointer;}.fmaxbox, .fmaxbox_reverse_directionality {background-image:url('/ig/images/max_dark_blue.gif');}.fminbox, .fminbox_reverse_directionality {background-image:url('/ig/images/min_dark_blue.gif');}a.fmaxbox:hover, a.fmaxbox_reverse_directionality:hover {background-image:url('/ig/images/max_dark_blue_highlight.gif');}a.fminbox:hover, a.fminbox_reverse_directionality:hover {background-image:url('/ig/images/min_dark_blue_highlight.gif');}a.ddbox {background-image:url(/ig/images/arrow_blue.gif);}a.ddbox:hover {background-image:url(/ig/images/arrow_blue_highlight.gif);}a.delbox {background-image:url(/ig/images/x_blue.gif);}a.delbox:hover {background-image:url(/ig/images/x_blue_highlight.gif);}a.minbox {background-image:url(/ig/images/min_blue.gif);}a.minbox:hover {background-image:url(/ig/images/min_blue_highlight.gif);}a.maxbox {background-image:url(/ig/images/max_blue.gif);}a.maxbox:hover {background-image:url(/ig/images/max_blue_highlight.gif);}.f_tbl {font-size:12px;margin-right:2px;margin-left:2px;padding-top:4px;padding-bottom:4px;}.fr_tbl {margin-right:2px;margin-left:2px;padding-top:4px;padding-bottom:4px;}.fb {font-size:12px;padding:2px;padding-top:4px;border: 1px solid #d1d3d4;border-top:none;overflow:auto;}.sftl {border: 1px solid #d1d3d4;border-bottom:none;}.sftl_reverse_directionality {border: 1px solid #d1d3d4;border-bottom:none;clear: right;text-align: right;}.uftl {border:1px solid white;border-bottom:none;}.uftl_reverse_directionality {border:1px solid white;border-bottom:none;clear: right;text-align: right;}.remote_module_textbox {box-sizing:border-box;-moz-box-sizing:border-box;padding:1px;padding-left:4px;margin:2px;margin-left:3px;width: 95%;}* html .remote_module_textbox {width: 91%;}.remote_module_select {box-sizing:border-box;-moz-box-sizing:border-box;padding:0px;width:95%;margin:2px;margin-left:3px;}</style><link rel="stylesheet" type="text/css" href="/ig/f/hDk4Fm4iv7I/ig.css"/><style></style><style>#gbar{float:left;height:22px} #gbarl{border-top:1px solid #c9d7f1;font-size:0;height:1px;position:absolute;right:0;top:24px;width:110%} #gbar a{color:#00c} #gbar .gbard{background:#fff;border:1px solid;border-color:#c9d7f1 #36c #36c #a2bae7;display:none;font-size:13px;position:absolute;top:24px;z-index:1000} #gbar .gbard a{display:block;padding:.2em .5em;text-decoration:none;white-space:nowrap} #gbar .gbard a:hover{background:#36c;color:#fff} #gbar td{font-size:13px;padding-right:1em} #guser{font-size:13px;padding-bottom:7px !important;padding-top:0} #gbarc{font-size:0;height:1px} #guser,#gbarc{background-color:#fff}#guser{color:#000;margin-bottom:0px}#guser a:link,#guser a:visited,#guser a:hover{color:#00c}#gbarl{border-top:0;border-bottom:1px solid #c9d7f1}#guser{padding-right:10px ! important;}</style> <script>window.gbar={};(function(){function o(a,b,c){var e="on"+b;if(a.addEventListener){a.addEventListener(b,c,false)}else if(a.attachEvent){a.attachEvent(e,c)}else{var d=a[e];a[e]=function(){var f=d.apply(this,arguments),g=c.apply(this,arguments);return f==undefined?g:(g==undefined?f:g&&f)}}};var h=window.gbar,m=["affdom","channel","client","hl","hs","ie","lr","ned","oe","og","rls","rlz"];function i(a){return escape(unescape(a.replace(/\+/g," "))).replace(/\+/g,"%2B")}function j(a){return a=="c"||a=="o"||a=="m"}h.getHtml=function(a){var b;for(var c=0;c<a.length;c++){if(a[c][2]==""){b=a[c][0]}}var e=j(b)?" target=_blank":"",d="<td nowrap>",f="<table border=0 cellpadding=0 cellspacing=0 style=margin-left:"+h.getPad(true)+"px><tr>"+d;for(var c=0;c<a.length;c++){if(a[c][0]==b){f+=a[c][1].bold()+d}else{f+="<a href=";if(a[c][3]==3){f+='# onclick="this.blur();return gbar.toggle(event)" style=text-decoration:none'+e+"><u>"+a[c][1]+"</u> <span style=font-size:11px>▼</span></a><tr><td colspan="+c+"><td><iframe class=gbard id=gbarif style=border:0;z-index:999></iframe><div class=gbard id=gbardd onclick=gbar.stopB(event)>";d=""}else{f+=n(b,a[c][0],a[c][2])+e+" onclick=gbar.close(event)>"+a[c][1]+"</a>"+d}}}f+="</div></table>";return f};h.getPad=function(a){var b=-1,c=a?10:4,e=document.body.currentStyle,d=document.defaultView;if(e){b=a?e.marginLeft:e.marginTop}else if(d){b=a?d.getComputedStyle(document.body,"").marginLeft:d.getComputedStyle(document.body,"").marginTop}b=parseInt(b,10);return b>=0&&b<c?c-b:1};function n(a,b,c){var e=window.location.search.substring(1),d=e.match("q=([^&]*)"),f=e.match("near=([^&]*)"),g=c+(c.match("[?]")?"&":"?");g+="tab="+a+b;if(j(b)&&window.location.protocol=="https:"){g=g.replace("http:","https:")}if(!j(b)&&!j(a)){for(var k=0;k<m.length;k++){var l=e.match("("+m[k]+")=([^&]*)");if(l){g+="&"+l[1]+"="+i(l[2])}}if(d&&f&&a=="l"&&b!="l"){g+="&q="+i(d[1])+"+"+i(f[0])}else if(d){g+="&q="+i(d[1])}}return g}h.toggle=function(a){h.stopB(a);var b=document.getElementById("gbardd"),c=document.getElementById("gbarif");if(b&&c){b.style.display=b.style.display=="block"?"none":"block";c.width=b.offsetWidth;c.height=b.offsetHeight;c.style.display=b.style.display}return false};h.close=function(a){var b=document.getElementById("gbardd");if(b&&b.style.display=="block"){h.toggle(a)}};h.stopB=function(a){if(!a){a=window.event}a.cancelBubble=true};o(document,"click",h.close);})();</script> </head>
For some reason it has always bugged me to only have a few applications show in the left bar, with the “more >>” link that you have to hover/click on to get the full list.
So, I wrote the simplest of Greasemonkey scripts to automatically expand the more link whenever I go to a Facebook page.
Now I have all of my gems (Pet Monkeys and co…) in plain sight. I am glad I am doing the important things while I wait for my flight from London back home to the US. Yup, “back home” to the US :)
At the end of Dave Morin’s Facebook talk at FOWA he kindly did the usual, and accepted questions from the audience. For all of the other talks that I participated in, the questions were fired off by fellow developers and were generally technical.
This time around, it was time for the reporters. They popped out of nowhere to ask the usual silly questions that you KNOW the guy can’t answer. I get them all the time for Google. “When is the Google Deathstar coming out”. What are they thinking? Do they think that I will slip and think “hmm, I guess we released the Deathstar so I can start talking about it up on stage here!”
Anyway, one of the rants hidden in a question was about how the platform competes with third party applications. It is as though it is so novel that Facebook has some apps and features like the Wall, Videos, Photos, …. and that they may overlap with applications that others have developed. This is not new guys:
So, everyone does it. I think the key points from the platform vendors side are:
The “niche” is key. You KNOW that Facebook is going to make its profile page better, which will include a better wall (sorry SuperWall) or better friend grouping (sorry TopFriends). As a third party developer you know the risk.
If you go into something generic, and it becomes popular, expect the platform vendor to do something in that space.
If you go into something niche, then you are probably safer. If you make a killer application for lawyers, then you will probably be safe.
If you decide that you want to target everyone and build a generic app, you just have to know that either:
In general, make a product rather than a feature.
But wait, isn’t Facebook a little different? The virality model is such that the big guys like RockMe have an advantage in that they can watch out for anything popular, and quickly jump in and use their overall platform to promote their quickly-hacked-up solution.
You come up with the next cool mini-app, and then they clone it and advertise the hell out of their clone on their most popular applications.
That is life. It isn’t new. Big players are able to do that on the other platforms too.
Again, you have to assume competition and use your unique assets to counter it… or sell out to the big guy! :)
My favourite talk at the FOWA was Matt Biddulph talking about his experience with Dopplr which is a fantastic little service (and I was shown today that the colors change EVEN on the favicon.ico when you are in a different location!!!).
Matt’s talk was high level, but he managed to keep it interesting and it wasn’t about pimping Dopplr.
He also released identity matcher, a new open source project that allows you to import social graphs! Now we can all work together on this instead of reinventing the wheel:
This code, extracted from the Rails codebase of dopplr.com, extends your User model with methods to pull in social network information from sites such as GMail, Twitter, Flickr, Facebook and any site supporting appropriate Microformats.
This is an alpha-quality plugin. It was extracted from our codebase at the start of October 2007 and may still contain dopplr-specific code (although we tried to avoid that).
The code is just one file with a few includes and you can now matches_identities
in your Rails model. Of course, you can abstract out the Rails stuff and just have a library to do the matching. Very nice indeed.
Now I just want the option to say “if someone shares their stuff with me on Dopplr, and they are friends with me via another service (e.g. Facebook, Twitter) just go ahead and share back automatically!”
Being able to talk about what you are working on is a good thing. Sometimes the whole “we don’t pre-announce” world that big companies can get involved in is a real pain.
It is great to see In the works as a section of “What’s New” at Facebook:
Sort out your friends.
We
My posts, status updates, link blog, and anything else I do on the web is here:
I am honoured to be working with my long time friend and collaborator Ben Galbraith on helping to set the direction of the industry.