Tales of a Developer Advocate http://paul.kinlan.me Developer Relations @ Google posterous.com Thu, 09 Feb 2012 06:25:00 -0800 On Vendor Prefixes http://paul.kinlan.me/on-vendor-prefixes http://paul.kinlan.me/on-vendor-prefixes

There is a lot of chatter about Mozilla considering implementing some webkit specific prefixes - I encourage everyone to read "Platform/Layout/CSS compatibility"

My personal take on this is "great" and I am glad they have the guts to start the conversation, but in my eyes it should only happen IFF the vendor is going to choose to stop supporting their existing prefix and start supporting the other parties prefix as what they agree to be the way they want the standard to move. 

I know a lot of people who targeted mobile saw that the audience they needed to target were using almost exclusively a WebKit based browser and thus chose that as the platform to target.  If the mobile device you want to target or your customers want you to target is pretty much a single choice then web developers naturally gravitate to the browser that is most popular and for a long time in the case of iPhone etc, WebKit was (up until recently) your only web platform you had to develop for.

Remy Sharp's blog post is a good summary of the situation, but I don't agree with most of the proposed browser solutions.  

To Quote:
Browsers need to:
  • Fucking drop experimental prefixes. It's unacceptable and a disservice to the developers working with your browser. You need to give timelines to dropping these things.
  • Non-production ready browsers should support experimental prefixes, production ready releases should not. If it's Chrome 16 - the stable version - experimental support should not be baked in. The properties should be full available without the prefix.
On dropping vendor prefixes, yes but only if they commit to move to another one.  The whole gradient syntax winded me up no end - if at this point WebKit had chosen to name it consistently with the -moz implementation and prefixed it so then we could have started to completely drop the old syntax that IMO would have been better.  At the same time though we should be educating developers about the tooling available to make the vendor prefixing become a non-story (in most cases).

I had a little chuckle about "production ready browsers" - I don't think this is sensible or feasible given the update cycles of browser and that developers want what they have chosen to implement to look ace in the browsers that they have chosen to make it look awesome in.  If you have platform features that no other browser is going to support either now in the near future then we need to have a way to not have them in the base "namespace" - putting them in there is going to cause more problems.

Anyway, these are my thoughts and can be and sometimes are hogwash - my motto is "don't hate, advocate" - and as Remy says "As developers we need to better educate." to which I whole heartedly agree.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Wed, 08 Feb 2012 12:57:00 -0800 Getting your app to support Web Intents on Chrome http://paul.kinlan.me/getting-your-app-to-support-web-intents-on-ch http://paul.kinlan.me/getting-your-app-to-support-web-intents-on-ch

Chrome just got Web Intents support in Dev and Canary builds (18 onwards).  This is a huge milestone and I am very excited by this first step along the path of building a more connected web of apps.

A lot of developers have asked me how to get started as it seems some of the demos on http://demos.webintents.org don't register correctly.  I have a good answer for that - in short: Chrome doesn't yet detect the intent tag, instead applications currently can only register their support for an action such as "share" via the Chrome apps manifest.

The longer version is a little more complex:
  1. Consensus over the introduction of a new tag in to the spec has not yet been reached.
  2. Working with members of the DAP in the intents task force, it is clear that discovery of applications and services shouldn't only take place by detecting a tag on a web page.  What happens if the service you want to "Share" a video too is a TV connected to your local network? Or an external native application wants to be able to support a "Save" action.  To enable this important use case the User Agent should be able to determine the services it presents to users, and this is why this is allowed in the specification (3rd paragraph).
Bringing this closer to home, because the discovery and presentation of an app's capabilities can be managed by the User Agent, and Chrome has the concept of extensions and installed apps we can quickly enable the intents feature by letting developers declare their support for actions in the manifest.

So what does the declaration in the Chrome apps/extension system look like?  It is pretty easy, it is an entry into the manifest called "intents".  It looks like:

{
  "name": "Share to Gmail™",
  "version": "0.0.0.2",
  "icons" : {
    "16" : "favicon.ico"
  },
  "intents" : {
    "http://webintents.org/share" : {
       "type" : ["text/uri-list"],
       "title" : "Share to Gmail",
       "path" : "/launch.html"
    }
  }
}

It is that simple.  The intent section includes a dictionary of supported action (http://webintents.org/share) and in each action object there is an array of data types that the application or extension can handle, the friendly name to appear in the picker and a path to what should be opened when the user selects your app.  The client-side code remains exactly the same as it would in a normal web app.

In the long term we want applications to be able to declare their capabilities and services directly through their html and this will be done with the Intent tag.  However whilst the standardisation work continues we want to make sure that developers today can start building apps that can take advantage of the Web Intent system.

A lot more examples can be found on the Web Intents Github repository.

Expect a lot more posts about how to build applications that love each other with Web Intents.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Tue, 07 Feb 2012 08:19:12 -0800 Two years and counting at Google http://paul.kinlan.me/two-years-and-counting-at-google http://paul.kinlan.me/two-years-and-counting-at-google As of February 1st I have been at Google for two years! Yay!  It has been an amazing time and I am truly honored to work for such a company.

A year ago (+1 week) I wrote about my first year experiences, it was pretty crazy in my first year, not only did the scale of the work hit me overwhelm me, but so did the sheer number of excellent engineers and colleagues.  My overall feeling was one of awe.

My second year has taken that to the next level again!

One of the highlights of the year was that I got to speak at Google IO - Mobile Web App development: Zero to Hero, where myself and Mike Mahemoff (with the help of Eric Bidelman and Boris Smus) built an app that worked across 5 different form factors using one code base - the awesome thing about this is that we built LeviRoutes (a url routing framework) and FormfactorJS (a form factor detection library).

I got to travel a lot too - I am trying to count all the countries that I have been too; it is a lot - USA, France, Spain, Portugal, Romania, Belgium, Germany, Poland, Netherlands, Czech Republic.  Whilst I was traveling I did a lot of presentations which is a really good way to meet people that I wouldn't normally get the chance to meet. I also managed to get completely misquoted on TechCrunch too - I say misquoted, I didn't even say the words that they attributed to me.

The biggest thing for me was that Web Intents became a real living and breathing project and first native implementations have landed in Chrome, it has changed a lot since my first announcement late in 2010.  This is a huge change for users of the web and I am immensely proud to be working on the project and with some amazingly talented engineers (James Hawkins, Greg Billock, Rachel Blum, Ben Smith and many others) and helping to define the specifications.  We have big goals for Web Intents so stay tuned.

One of my resolutions last year was to be in Liverpool a little more and I managed to do that, it turns out that I unwittingly pre-announced another project (that I honestly had no idea was about to launch) I am glad it happened though, there are a huge swath of developers in the UK that are outside London and I don't think anyone reaches them properly and this gives me a chance to work with them.

So.  What is happening in the year to come?  It is hard to say, there are a lot of cool things happening, but I know two things for sure: we will keep working on making sure users' experience of the web is improved through technologies such as Web Intents and we will keep working with developers to build awesome sites and applications on the web and prove that the web is our future.

On to my third year! 

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Fri, 01 Jul 2011 12:05:49 -0700 Web Intents: A fresh look http://paul.kinlan.me/web-intents-a-fresh-look http://paul.kinlan.me/web-intents-a-fresh-look

We have a huge problem on the web today. If I built an image gallery application and I wanted to let users edit an image so that they can remove red-eye from a photo I either have to build an application that edits the images, or integrate with a 3rd party solution. Doing this is hard and stops you from building an awesome image gallery; and what happens if the user has a favorite service that they already use to remove red-eye? Simple, you have a frustrated user.

We have a solution!

In December 2010 I announced a project called Web Intents whose goal was to allow developers to build applications and services that could work with each other, but not need to explicitly know about each other – the concept has heavily inspired by the Intent system in Android, although the API bore no resemblance. It would allow you to build applications using just the functionality your cared about, and then delegate the other functionality to the users preferred choice of service.

After some conversations, I moved to try and support Web Introducer as a specification over Web Intents. For one reason or another this didn’t quite work out so I decided to plug away at revising the WebIntents work that I started back in November.

It turns out there is a lot of interest internally with the idea of Web Intents and how it can work in modern browsers. We set up a small crack team and after a flurry of work, speccing and prototyping how we think it might look we have put a prototype API on to Github. Have a play, it is really easy to get started.

So what changed?

A lot as it happens. It is not the same as the initial project that I experimented with, although the goals are the same. We have an objective to make the developer experience of the API so painless that most developers can start integrating with applications in 5 minute of reading the spec – in fact we want it so that most developers can just copy and past examples and it will work with their service. We have tried to drastically reduce the API surface and make it so there is literally only one or two lines of code you need to start an activity.

Service registration has been made even easier that my initial project through the use of a new tag, for example:

<intent
  action="http://webintents.org/share"
  type="text/uri-list"
  href="share.html"
/>

This small tag, that is included in the head of your application will signal to the browser the intention to handle a “share” action for a selection of URI’s (think “share this page”), and will register it in the system so that the user can choose it when a client application wants to provide “share” functionality in their app.

When the service is chosen by the user, and the service is loaded the intent data is passed to the open application and is available on the window.intent object.

For clients to initiate an Activity it is easy too. Simply declare an intent and start the Activity as follows:

var intent = new Intent();
intent.action = "http://webintents.org/share";
intent.type = "text/uri-list";
intent.data = "http://paul.kinlan.me";

window.navigator.startActivity(intent);

The system will take care of the service resolution for the action and compatible data formats and give the user the choice of using their favorite application to handle the “share” intent.

I have only just touched the surface of what you can do with the API. There are a lot of things that you can do with the API over and above what I have described in this 5 minute overview. A selection of examples can be found at http://examples.webintents.org/ where we show you how to build applications that solve some common use-cases. I particularly like the cloud kitten service provided by the “pick” example.

We are working with Mozilla to define a common approach to solving the challenges that web integrators face today. We are interested in hearing your thoughts and we are still thrashing out the API so bits of it might change but the intent is still the same.

My closing thoughts are: “This project will fundamentally change and improve the way we build applications on the web today for our users.”

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Wed, 22 Jun 2011 10:28:00 -0700 window.name http://paul.kinlan.me/windowname http://paul.kinlan.me/windowname

I have learnt a lot of the last couple of days about inter-window and inter-iframe communication. I documented some of my frustrations about Web Messaging API’s and an attempted work around.

For you to be able to pass data into a window (that isn’t on your domain) so that it is available before the onload event fires in the opened window, the only sane way I have found is to set the window name via window.open.

Client:

var w = window.open("list.html", "some data");

Service:

window.onload = function () {  alert(window.name); };

Now that we can pass data between the windows, you can quickly imagine that you stringify a JSON object on open and parse it in the opened window. Pretty simple.

The good news is that the work-around works in FF, WebKit and Opera as is, but not IE.

To get it working with IE, it takes a few of hacks so I thought it best to document them here.

When you open a window via window.open, the second parameter is the name, in IE it must only contain [A-Za-z0-9_], this means that you have to base64 encode the JSON object for it to be able to be sent across, but that is not enough because Base64 encoding can only use certain characters. Base64 will also likely include an == at the end, which is not an allowed character.

However, IE doesn’t include a btoa and atob function for managing base64, so you will also need to find a library to use.

To encode the data I used the following:

var winname = window.btoa(
  unescape(
    encodeURIComponent(JSON.stringify(obj))
  )).replace(/=/g, "_")
var w = window.open(e.target.href, winname);

To decode the data I used the following:

var obj = JSON.parse(window.atob(window.name.replace(/_/g, "=")));

Pretty hacky, but it seems to work.

As always, if anyone has a better suggestion, or there are any obvious flaws let me know.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Tue, 21 Jun 2011 02:10:53 -0700 WebMessaging is broken http://paul.kinlan.me/webmessaging-is-broken http://paul.kinlan.me/webmessaging-is-broken

I have been working on a rather cool project recently that initially used a lot of WebMessaging (postMessage etc) to talk between all the components. However, even though these API’s look simple and easy to grok there are some bizaare limitations and usage of them is frustrating to say the least.

Ignoring the fact that Chrome passes structured clones, and Firefox passes strings, that is a simple difference to resolve. It is not even the fact that WebKit supports MessageChannels and Entangled Ports and no one else seems too. These we can work around in sane ways.

The normal developers flow is as follows: open a window/iframe, get a reference to that window, send it a message, have the frame or window handle the message.

Client App:

var w = window.open("test.html");
w.postMessage({ data: "some more data"}, "*");

Service App: test.html

window.addEventListener("message", function(e) {
  // Do something with the data
}, false);

This would be pretty simple and intuitive, something that nearly every developer would be able to pick up in an instant. But this isn’t the case, if you want to send a window a message you have to wait for it to load – which might be a logical assumption, but given that if the page you are opening is outside the origin of the opener, you can’t easily tell when it loads. So the current solution is on the host page to postMessage back to the window.opener, and for the opener to handle the message.

Client App:

var w = window.open("test.html");
window.addEventListener("message", function(e) {
    if(e.data.state && e.data.state != "ready") return; // do nothing.
    // Send data
    e.source.postMessage({ data: "some more data"}, e.origin);
}, false);

Service App: test.html

window.addEventListener("load", function(e) {
    // tell the opener that it is ready to receive messages
    e.source.postMessage({ state: "ready" }, e.origin);
}, false);

window.addEventListener("message", function(e) {
    // Process data from opening window.
}, false);

This is bonkers! Developers just want it to work.

There is a hack that allows you pass data to a window so that it is available to the window as soon as the script starts executing. It is probably not safe nor is it likely to be secure. When you open a window, you can pass it data immediately using the name parameter on window.open()

window.open("test.html", "{ data: 'ABC123' }");

And then on the opening page, you can read it back.

var data = JSON.parse(window.name);

There are problems here though:

  • We have no real proof of where the data came from, we can check window.opener but that is not enough
  • We have to ensure that the window.name is cleared down as soon as we parse it, because it will be available for the life time of the application.

This is a quick hack, that allows the opened window to read the data that was passed to it as soon as it opened.

What are your thoughts? Have you come across these limitations? Have you solved them in any other interesting ways?

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Tue, 07 Jun 2011 04:19:58 -0700 Landing my first WebKit patch. OnPopState Lock and Load. http://paul.kinlan.me/landing-my-first-webkit-patch-onpopstate-lock http://paul.kinlan.me/landing-my-first-webkit-patch-onpopstate-lock

This is a story all about how my life got flipped turned upside down….. wait what?!?! I can’t start a blog post with The Fresh Prince.

Last week, when I was still in my 20’s, I wrote a blog post about HTML5 History API needing a new event. This came about because the LeviRoutes framework would work better if it could understand when state had been pushed via History.pushState. Whilst investigating pushState and adding some tests to the LeviRoutes framework I wanted to be able to simulate an “onpopstate” event.

Let’s just quickly digress with a little bit about HTML DOM events. HTML defines a rich series of events that are fired when a user clicks on something, the page loads or….. well let’s just say there are hundreds of events. Not only do the events get triggered when the user or system does something, but the developer can easily simulate events. If you want to click on a button via script. Simple:

var evt = document.createEvent("MouseEvent");
var anchor = document.getElementById(......);
evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false,

false, false, false, 0, null);

anchor.dispatchEvent(evt);

Why is this programatic dispatch important? You can build individual tests that are responsive to the events that would fire to user events without having to build a system that tries to automate the UI by say, managing the mouse pointer through hardware control.

Digressions aside, I was building tests that would test my HTML5 History handling logic without me having to physically invoke a History.pushState command. In summary, separating the physical navigation from my logic.

var evt = document.createEvent("PopStateEvent");
evt.initPopStateEvent("popstate".....);
window.dispatchEvent(evt);

This should have worked. Instead all I got was:

var evt = document.createEvent("PopStateEvent");
DOMException

Which if you read the Event specification is what occurs when an Event type is not implemented. I quickly jumped across to Firefox and tested the same code. It worked. So it must be a bug in WebKit.

Now, this is where my real story starts, and what I hope will demonstrate the power of Open Source software.

I was in a bind. I could raise a bug and hope someone might pick it up at some point in the future, or I could raise a bug and try to fix it myself. I chose the latter. I didn’t think it would be hard – after all the Event system is already in WebKit and PopStateEvent is already implemented, it is only the hookup with createEvent that didn’t.

Where do you start? I started by downloading the latest WebKit code and building it. In all this process took longer than the actual fix.

Once I had a build, I decided to create a very simple test case to prove that it is still broken. With this in hand, I had a quick peek at the Webkit code. Google Code search is your friend here, I just searched for “PopStateEvent” and it returned a list of important places to look.

Inspecting PopStateEvent.cpp and PopStateEvent.h, I could see that there was a create and initPopStateEvent methods so I was pretty sure I was in the roughly the correct place. I also knew that createEvent is on the document object in the DOM, so I did a quick search for createEvent and there was a file called “Document.cpp”, this looked promising. A quick search in Document.cpp highlighted the area where the events are created, and there was a suspicious lack of PopStateEvent.

Bingo!

I quickly raised a bug, on http://bugs.webkit.org/ detailing the error with a simple test case attached, and then went about fixing the code. Raising the bug seemed to take longer than the fix, which amounted to adding in a condition for the type of event, adding in a parameterless constructor and then calling it.

Pretty quick. My own test case passed, so I had a strong indication that it was fixed, but I knew if I submitted it without an automated test it would probably get rejected. The problem is that I had no idea how to build the automated tests or where to put them.

I had a quick scan through LayoutTests, and in the “fast” directory there is an “events” directory which seemed liked the logical place to start. I followed the examples of other tests, I created a simple test and an “expected” results file and then gave the test runner a go. Boom! it failed. It took a little bit of looking, I found that the results of the test run were stored in “/tmp/layout-test-results/results.html” and it gives you a visual diff of the actual output vs the expected – it was a single new line character that was causing the problem.

That was me done. I created the ChangeLog and attached it to the bug, set r to ? (this was an oddity that I had to learn about). After the first review there were a couple of changes I needed to make. The second review indicated that I updated the wrong ChangeLog and some other smallish issues. But after that it was ok and submitted.

And here it is: http://trac.webkit.org/changeset/88187, it is not a complex fix but it is one I am proud of, if all the ports include the fix then my code will be used by the eleventy billion users of WebKit (ok – I have no idea of the number of users, but I know it is very large number) and now I can get on with fixing my LeviRoutes framework ;)

In my eyes, this is one of the powers of Open Source. Rather than just report a bug and hope someone picks it up, and then wait for the next major release of the software to see if it is fixed, I have the power to go in and fix the problem, and if it stands up to muster I can get the solution published.

Beautiful!

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Tue, 31 May 2011 04:52:00 -0700 HTML5 History needs another event http://paul.kinlan.me/html5-history-needs-another-event http://paul.kinlan.me/html5-history-needs-another-event

I love the HTML5 History API, it makes developing applications with a consistent URL scheme across server and client super simple, however it doesn’t come without its problems.

When developing the LeviRoutes URL routing framework it became obvious that we need some changes to the specification as-is. The Mozilla documentation reports that onpopstate is called whenever the history object changes, unfortunately this is not the case, and is not the case with the spec either, the HTML5 Spec indicates: “The popstate event is fired in certain cases when navigating to a session history entry.”, which you can logically assume to be only on a forward, backwards navigation, not a replaceState or pushState.

This might sound odd. There is no mechanism to detect change in url afterit changes. You get notification via onpopstate when the user navigates forwards or backwards through your application, but not actually when it changes. This is apposed to onhashchange which does fire when the document fragment changes.

This causes us problems.

LeviRoutes listens to changes in your URL, it allows you to build applications that are responsive to the current URL, and are decoupled from navigation. So rather than have your code littered with “if(url == ”/“) { doA(); } if (url == ”/categories") { doB(); } you can now specify:

var app = routes();
app.get("/", doA);
app.get("/categories", doB);

Simple right?

It would be excellent if it was that simple, but it is not. We don’t know when the URL changes via pushState. This forces us o bind our logic in our controller to call the same code that LeviRoutes would call when it detects a change in URL via normal navigation.

Now I have to bastardise my code:

var app = routes();
app.get("/", doA);
app.get("/categories", doB);

.....
function gotoA () {
    history.pushState({}, "A", /);
    doA();
}
...

Pretty messy right?

I would love to see an event “onstatechanged” (or perhaps, onpushstate and onreplacestate) triggered when the user pushes or replaces state on to the history object so that I can capture the code and return to my simple routing logic.

var app = routes();
app.get("/", doA);
app.get("/categories", doB);

function gotoA () {
    history.pushState({}, "A", /);
}

I am not the only person asking for this: http://www.google.com/search?q=onpushstate

So, how am I going to solve this problem? I am going to wrap the History API and proxy pushState to call the natural pushState and also fire a new custom event. Hmph :\

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Tue, 17 May 2011 13:37:00 -0700 When are we going to see the death of SVG? http://paul.kinlan.me/when-are-we-going-to-see-the-death-of http://paul.kinlan.me/when-are-we-going-to-see-the-death-of

I have this bizarre mixed feelings about SVG, I loathe it and love it at the same time (according to urban dictionary the word is loave) and I hate myself for it - okay, hate is a strong word.

I constantly feel frustrated by its complexity, requirement for tooling (have you tried to create a path by hand) and half-arsed integration into the web of today.  I see the <svg> element much like I see the <object> tag, that is a boundary that rarely if ever should be crossed by mere mortals, a semi-permeable barrier where only through reverse osmosis can we wrangle some of the elements in our usermode. (to be read as, we can script it and hook it up in our app but that is about it).

The way I see it, once you get in to <svg> it is like a context switch, the HTML DOM and the SVG DOM will never really truly mingle.

But SVG has some serious awesomeness too - for one it is scaleable, two is vector based.... can you guess the third?  It has awesome graphical capabilities, you've seen the filters right and paths? There have been lots of project that I have worked on where I simply can't build what I want because it is not available in the "web" sans SVG.  I want to be able to apply filters with out importing a SVG declaration, I want to be able flow elements out along a path.

Why can't path be a css property?

p {
  path: "M 100 100 L 300 100 L 200 300 z";
}

Text inside the <p> will be rendered along the path.  But what if <p> was a block element like a <div>?  Even better all elements be they block or inline will be rendered along the path...... That is powerful!

For me this is better than what we have now. I don't want to have to have <p><svg>......</svg></p> when I want to do something awesome that SVG lets me do, that just doesn't scale.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Tue, 17 May 2011 12:36:59 -0700 App Cache and HTML5 History http://paul.kinlan.me/app-cache-and-html5-history http://paul.kinlan.me/app-cache-and-html5-history Whilst developing our latest app (https://github.com/PaulKinlan/ioreader) for a Google IO, we ran into several large is limitations with AppCache and HTML5 History that I wanted to share (and at somepoint hopefully solve).  

Putting the current discussion of the issues with AppCache aside for a couple of minutes, there is no provision in HTML5 History to include pages "pushStated" into the current App Cache Group

Consider this flow:  We have a multi paged app with pages A and B when rendered from the server sharing the same AppCache and thus in the same group.
  • User visits page A, it uses an app cache, so everything is cached.
  • User navigates from A to B, page B is added to the app cache group.
  • User goes offline
  • User refreshes A it is served from the Cache,  User refreshes B, it is served from the Cache.

Update the AppCache, A and B are re-downloaded and cached [see: Death by App Cache].

Now if we inject HTML5 History for the same flow:
  • User visits page A, it uses an app cache, so everything is cached.
  • User navigates from A to B (via pushState) .....  currently B is not added to the App Cache group.
  • User goes offline
  • User refreshes A it is served from the Cache,  User refreshes B, fail, because not in the Cache.
I believe that as URL's change if the master page is App Cached, the new URL's should be added to the App Cache group.  You are still in the same application, the state is just dynamically changed but in essence you are on a page that should be available offline.  The act of changing the URL client-side normally enforces you to generate the correct content on the server if the page was simple fetched. 

Death by App Cache: The problem that we also faced was as master entries are added to an App Cache group, when an update to the App Cache occurs, all those pages in the App Cache are refreshed, with more dynamic applications this could mean that 10's or 100's of pages are quickly downloaded by the App Cache software and thus can quickly cause a mini DDOS.

I am interested to hear your thoughts.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Sat, 14 May 2011 10:44:54 -0700 IO Question: How long did it take to develop the app? #io2011 http://paul.kinlan.me/io-question-how-long-did-it-take-to-develop-t http://paul.kinlan.me/io-question-how-long-did-it-take-to-develop-t One of the many question that we didn't get to answer in our talk - Mobile web development: Zero to Hero - is "How long did it take to develop the app?".  Luckily, we have an answer: The first commit of the project was on the 3rd of March, but that was mainly just a simple README file, the first commit of the server was 25th of March which is when we really started working on the code and began taking our ideas and basic concepts into a fully fledged solution

You might think that just over a months worth of work went into this (it was, in theory), but it is a little more complex than that.  We developed 2 frameworks, LeviRoutes and FormfactorJS and allowed us to push a lot of the common logic into a single controller.  Using FormfactorJS it was possible to assign engineers to each distinct UI and have them work on it in isolation.  FormfactorJS was used to specialize the base controller that was in every single page.  If you look in our "scripts" directory, you can see how we structured the project - controller.js is common across all interfaces, desktop/controller.js is then dynamically injected at run-time and using prototypal inheritance we added custom formfactor specific features (such as swipe detection in the case of tablet and mobile)

In total we had 4 engineers working on the project, each working on their own UI.  Each engineer spent roughly 20% of their time developing the parts of the UI that they were responsible for.

In all, it took just over a month of man effort to develop this application.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Fri, 13 May 2011 22:02:11 -0700 Google IO Q: Would one build a different HTML 5 app for keyboard devices and mobile (touch) devices? Why or why not? http://paul.kinlan.me/google-io-q-would-one-build-a-different-html http://paul.kinlan.me/google-io-q-would-one-build-a-different-html Another question that we didn't get to answer in our talk - Mobile web development: Zero to Hero - is basically the premis of the entire talk.  We believe that in a large number of cases that it is entirely possible to build applications using one semantic document structure, a large swathe of common core logic whilst specializing for a given formfactor.  

From our talk, you can see that the User Interface is optimised for smartphone, tablet, desktop and TV - we believe that there are qualitatively different user interaction patterns in each form that it is important that you optimise for the different experiences, but for the developer experience it is not easy (or possible in some cases) to keep having to build one new app for each category of device that you want to target.

Slides 30 to 41 describe how we came to solve this problem for our app.  The important code in our application is the base controller that describes all the common logic across all instances of our app, and then the form-factor specific desktop code or the smartphone code that is injected in using the FormfactorJS library via our UI detection code.

It must be noted, that a lot of tablet based apps work quite well on desktop devices, there are some unique differences that I can see from usage between the two.  For example, lots of touch based tablet apps are built with horizontal scrolling as the primary mechanism for finding new content (think the NPR app, where you scroll left and right to find new stories), whilst on the desktop, many users appear to prefer the vertical scrolling of columns of data.  This I believe is because it is more natural to swipe left and right with your finger, whilst it is easier to use your mouse scroll wheel on your desktop; this pattern for design was one that I explicitly made in the Desktop version of IO Reader.

What are your experiences of developing for multiple formfactors?  I would love to hear them, and your thoughts on runtime form-factor detection.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Fri, 13 May 2011 21:37:46 -0700 IO Question: How are you dealing with AppCache relatively small storage limits? http://paul.kinlan.me/io-question-how-are-you-dealing-with-appcache http://paul.kinlan.me/io-question-how-are-you-dealing-with-appcache We had an awesome question for our Google IO talk - Mobile Web Development: Zero to Hero - that we didn't get time to answer live.

How do we deal with the storage constraints imposed by modern browsers.  The answer is simple, App Cache is used mainly to store program code, that is just the CSS and JS (and also the page that requests the AppCache), our application never got that large.

We did make some basic optimisations, our production version ran compressed JS code - our build process minified the JS using uglifyJS.  We had the option to compress the CSS (but we chose not too for ease of development).  But in all honesty, our application never got that large.

If we struggled for space we would have moved into only AppCaching the form-factor specific code and assets, but it wasn't required.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Fri, 13 May 2011 21:27:15 -0700 Google IO Q: How can you use the Google Fonts API on mobile while optimizing performance? http://paul.kinlan.me/google-io-q-how-can-you-use-the-google-fonts http://paul.kinlan.me/google-io-q-how-can-you-use-the-google-fonts We had an awesome question by Pamela Fox for our Google IO talk - Mobile Web Development: Zero to Hero.  In summary the question is 
"How can you use the Google Fonts API on mobile while optimizing performance? (Both visual + # of requests)" - which is interesting because on the Desktop it is not something you particularly worry about, but in mobile it is one of the most important things you need to consider - bandwidth, latency and visual aesthetics.

From the Aesthetic point of view, we specifically chose two fonts that had been designed to work on the mobile context, that is Droid Sans and Lato.  So they looked pretty nice.

On the number of requests front, we used App Cache.  If you look at our source code for the project, you will see that the App Cache includes 3 remote objects, namely the request for the CSS of the fonts and then the two physical fonts.  The first load of the application will download 3 files, but all subsequent later runs of the app will use the data from the App Cache and thus will be blazingly fast.  A caveat to mention is that the number of files requested is directly proportional to the number of fonts in your CSS src.

To get the true URL of the fonts isn't amazingly easy, the Web Font API is designed to abstract away some of the detail.  We determined the URL of the fonts by delving in to the response of the request to the CSS file.

The AppCache and Web Font API work well together because the physical font file is determined at the time of download and since we won't change browser we know we are getting the correct font file and keeping it permanently cached (until the next App Cache update).

On the subject of ensuring that the file size is a small as possible, it is possible to download a subset of the font file by specify only the characters that you need for your page.  We didn't need this level of control purely because it is possible that a set of News articles will require the use of every single character in a given font (or a very large portion at least).

So, in summary that is how we optimised our font usage for the mobile context.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Fri, 13 May 2011 21:04:55 -0700 IO Question: WebSQL is dead or dieing, IndexedDB isn't there yet, what do you think about libraries like Lawnchair? http://paul.kinlan.me/io-question-websql-is-dead-or-dieing-indexedd http://paul.kinlan.me/io-question-websql-is-dead-or-dieing-indexedd A question in our IO Talk: Mobile Web Development: From Zero to Hero was with regards 

I will say this, I love LawnChair - I have used it a couple of times and it makes getting data in and out of your application very easy, it is based on the premis that you need to store objects against a key, and then get it out again, it allows you to use a richer querying syntax, but in many cases (as with our IO Reader app) you don't need anything more complex.

As to why I didn't use LawnChair (or any other wrapper) in IO Reader? I actually added the data caching layer later on in the project cycle, localStorage was supported well enough and I didn't want to introduce a new dependency in the code that late on.

As a developer that likes to get things done, I very rarely write code that will manipulate a given data source directly, instead I either use a project like LawnChair, or I use a simple wrapper that I have written that allows for flexible querying semantics on JSON based objects.

I am keen to hear your thoughts.  What are your favorite DataStore wrappers for Web apps?  Do you write to the bare metal?

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Sun, 03 Apr 2011 12:10:00 -0700 Badgemator .... it is all in the how you tell people about your app http://paul.kinlan.me/badgemator-it-is-all-in-the-how-you-tell-peop http://paul.kinlan.me/badgemator-it-is-all-in-the-how-you-tell-peop

Telling people about your web app in the Chrome Web Store is just as important as making your landing page rock. The more people that you can drive to your detail page the better your application will do, but you want to do it in a targeted way.

For this reason I created Badgemator – an app that creates badges for you to put on your website. It is about a month old, so why am I telling you now? Well the answer is simple, I posted it on twitter, and then forgot to post this blog – DOH!

It is an interesting project because it does a couple of cool things that make it super easy for you to use.

  • All you need is your Web Store URL – for example see http://badgemator.appspot.com/#https://chrome.google.com/webstore/detail/dhbgookgdfbbinnmmkbmjgolhikbbhpj to get started.
  • It is self contained – it base64 encodes your initial logo and css so that all you need to do is drop a single script tag into your HTML and BOOM, you have a great looking badge with no extra HTTP requests. Check out the source of Appmator and you will see there is a simple html tag that points to an embedded script.
  • It will only appear for Chrome users.
  • If installed on your app, it will detect if your app is installed using the window.chrome.app.isInstalled variable and not show it to users who already have your app running.
  • It will scan your listing page and pluck out all the important information including your Logo
  • The default style is “basic” to say the least, but you can style this up to look however ever you want, it could look like the Butter bar, or it could be some crazy 3d transform.

My good friend Mike Mahemoff suggested a neat use of URL fragments a while ago to enable quick sharing of links, hence you will see all my services support #URL at the end, so that if you wanted you could share it on Twitter and any reader would see the completed action – most of my service logic is on the client side.

I really need some more designs for default badges, so feel free to fork this project and make some changes to the CSS and I will incorporate it into the project and give you credit and links from the app.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Sat, 02 Apr 2011 23:17:00 -0700 The skinny on LeviRoute JS routing framework http://paul.kinlan.me/the-skinny-on-leviroute-js-routing-framework http://paul.kinlan.me/the-skinny-on-leviroute-js-routing-framework

If you follow me on Twitter – @Paul_Kinlan – you will know I yap on a lot about many of my projects on Github. This post is no exception, I want to introduce LeviRoutes, a client-side JS routing framework that is loosely based on a Rails like approach to URL handling.

There are plenty of frameworks that do this already so why did you create this? I hear you ask. Well it is pretty simple. I wanted a framework that would: * execute specific methods when the URL changed and matched a certain pattern; * is quick and easy to use; * listened for changes in the URL fragment; * worked with HTML5 History APIs; * worked on browsers that don’t support any of these features; * and most importantly doesn’t try to do anything else.

Thus LeviRoutes was born. It came about because I am working on a project that uses NodeJS with the Express framework, and the URL handling is very simple to access and I wanted to replicate this behavior in the browser, not just the server. My ultimate goal is for me to be able to share a lot of the logic that is on the server with the client and thus cut down the amount of code that I need to do.

The LeviRoutes project started with juat the ability to listen to changes in the HTML5 History by listening to the “onpopstate” event. When there is a “pop”, the matching code is invoked with the current window.location object. It later included a onhashchange event listener to listen to changes in the fragment and finally included a listener for the onload event. By listening to these three events.

Lets have a look at the simplest app that we can build with this.

var app = new routes();
app.get("/", function(req) { alert("On /"); });

Pretty simple right! Under the hood, the system is listening for when the URL is just “/” and nothing more, if your URL was “/index.html” the code would not be executed. If you wanted to watch for when the URL is “/index.html” you would need a route with that as the exact string.

Looking for just the root directory by itself is not very interesting, and neither are simple static URL’s. Thus the named parameters from Rails and other frameworks is built straight in, and this is the most interesting part.

It also supports named parameters for route syntax:

!#javascript
app.get("/:category", function(req) { alert("In " + req.params.category); });
app.get("/:category.:format", function(req) { alert("format: " + req.params.format); });

This is simple, yet powerful, LeviRoutes allows you to treat the URL as an input event to your controller, or as the controller.

Have a play, let me know what you think, and look out for my next post about FormFactorJS.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Thu, 03 Mar 2011 13:49:55 -0800 So what is happening with Web Intents? http://paul.kinlan.me/so-what-is-happening-with-web-intents http://paul.kinlan.me/so-what-is-happening-with-web-intents About 2 months ago I announced to the world a project called Web Intents (http://webintents.appspot.com/) as a way to allow client to client service discovery and communication over existing supported Web technologies, that is IFRAME's and SharedWorkers.  

There is a definite problem on the web that if you want to talk to an app, you have to integrate your client and service with 3rd party services.  This is bad for the user, your application imposes limits on the services you let the user interact with.  Web Intents was a step towards solving that problem; the problem of service discovery and communication.

Well, it is a very long story, but to cut it short I have still been working on Web Intents, but as luck would have it I found a very similar project called Web Introducer (http://web-send.org/introducer/) started by another Googler (Tyler Close - http://waterken.sourceforge.net/recent.html).  The overlaps between the two projects are clear and plainly obvious;  a lot of the harder security based challenges have been thought out in greater detail than I did for my version of the project. So I have decided that I will be focusing my effort on the Web Introducer project rather than support WebIntents further (although I am happy to answer any questions you have about it).

We are going to see some good stuff come from the Web Introducer project in the near future and I am looking forward to working on the project to push.  I am also really excited to start speaking to developers to see how we can get this intergrated in to your apps and services and start to provide a better experience for all users of the web.

I still think the WebIntents project did something great though.  It is a great use-case for SharedWorkers and messaging across your app without resorting to nasty localStorage hacks.  I will blog about this more in the near future.

Expect more posts from me soon about Web Introducer too.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Thu, 24 Feb 2011 01:12:00 -0800 I've seen the future of the web. It's in the background http://paul.kinlan.me/ive-seen-the-future-of-the-web-its-in-the-bac http://paul.kinlan.me/ive-seen-the-future-of-the-web-its-in-the-bac

* I will caveat this whole post with the a hefty disclaimer that this only works on the Dev Channel of Chrome and could change significantly over time.

Chrome introduced the notion of background pages to packaged apps and extensions. Background pages allow the app or extension to run without a UI surface – this is pretty cool because it allows for some really great use-cases that you don’t get with plain web applications; for example you can poll Twitter for updates that mention you and receive an alert via a Desktop Notification about the update.

Web-apps hosted on the open web have not had this ability, until now.

Chrome has recently brought this idea to the web with some added powers. Mainly:

  • Your web app can still run even when your app is closed,
  • Your web app can still run when the browser is closed,
  • Your web app can run after system start-up.

This is very powerful.

Actually let me re-phrase that. This is amazingly, unbelievably, stonkingly powerful. [definition: stonking]

So, how do you use them?

The good thing is it is really simple – a matter of two steps.

Step 1, this is currently only available to apps – not web sites. Apps in Chrome are defined using a manifest file. You as the developer must include a permission “background” to enable this feature. More on the permissions model can be found on code.google.com.

{
  "name" : "test",
  "version" : "0.0.0.1",
  "permissions" : ["background"],
  "app" : {
    "launch" : {
      "urls" : ["http://appmator.appspot.com/"],
      "web_url" : "http://appmator.appspot.com/"
    }
  }
}

Step 2, a little bit of Javascript magic…. actually, it is not magic, it is a simple call to window.open().

win = window.open("background.html#", "background", "background");

The detail is in the 3rd parameter which is reserved for specs. When Chrome is running with the “background” permission it will launch this page with no visible surface and track it in perpetuity.

By using window.open, it means that users and developers can toggle the state of the background running task by simply calling window.close, which will cause it to stop running. This also means that requesting window.open without a url, but with the background name will return a reference to the running window that can then be closed.

You can only open a url that is specified in the domain of the “urls” extents in the manifest – so for example you couldn’t open a background page to google.com if you didn’t verify you own that domain.

Now your app can run in the background. It will start up when the user logs into their machine, it will still be running when the user closes the visible browser (if you completely kill

POP QUIZ: How can my background page talk to my app pages?

ANSWER: SharedWorkers my hairy friend. Don’t use references to windows, that is so 2005.

In other exciting news, Appmator has been modified to support the “background” permission.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan
Wed, 23 Feb 2011 07:52:31 -0800 Dutch GTUG http://paul.kinlan.me/dutch-gtug http://paul.kinlan.me/dutch-gtug We recently announced that the Netherlands will be one of the countries that will have the Chrome Web Store available with integrated support for Dutch sellers.

On the 2nd of March 2011 starting at 7pm the Dutch GTUG will be holding an event at Google Amsterdam about HTML5 and the Chrome Web Store.  I will show you some new cool stuff in HTML5 and related technologies and talk to you about how you can use the Chrome Web Store to reach new users.

The event will start promptly at 7pm, so arrive a little earlier after 6:30pm.  I can’t wait to see you there, we have an Event Information page and a sign-up form.  If you want to come Sign Up Now as places are limited. I will be talking for an hour or so about HTML5 and the Chrome Web Store, showing you some really cool stuff and answering any questions that you have, followed by lighting talks - so if you have anything you want to demo, now is the chance.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1125163/me2.jpg http://posterous.com/users/4bmQV8rzpC01 Paul Kinlan Kinlan Paul Kinlan