Tales of a Developer Advocate

Developer Relations @ Google

  • HTML5 History needs another event

    • 31 May 2011
    • 0 Responses
    •  views
    • Edit
    • Delete
    • Tags
    • Autopost

    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 :\

    • Tweet
  • When are we going to see the death of SVG?

    • 17 May 2011
    • 3 Responses
    •  views
    • Edit
    • Delete
    • Tags
    • Autopost

    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 {
      display: svg; /* http://www.w3.org/1999/08/WD-SVG-19990812/styling.html */
      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.
    • Tweet
  • App Cache and HTML5 History

    • 17 May 2011
    • 2 Responses
    •  views
    • Edit
    • Delete
    • Tags
    • Autopost
    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.
    • Tweet
  • IO Question: How long did it take to develop the app? #io2011

    • 14 May 2011
    • 0 Responses
    •  views
    • Edit
    • Delete
    • Tags
    • Autopost
    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.
    • Tweet
  • Google IO Q: Would one build a different HTML 5 app for keyboard devices and mobile (touch) devices? Why or why not?

    • 13 May 2011
    • 0 Responses
    •  views
    • Edit
    • Delete
    • Tags
    • Autopost
    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.
    • Tweet
  • IO Question: How are you dealing with AppCache relatively small storage limits?

    • 13 May 2011
    • 0 Responses
    •  views
    • Edit
    • Delete
    • Tags
    • Autopost
    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.
    • Tweet
  • Google IO Q: How can you use the Google Fonts API on mobile while optimizing performance?

    • 13 May 2011
    • 1 Response
    •  views
    • Edit
    • Delete
    • Tags
    • Autopost
    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.
    • Tweet
  • IO Question: WebSQL is dead or dieing, IndexedDB isn't there yet, what do you think about libraries like Lawnchair?

    • 13 May 2011
    • 0 Responses
    •  views
    • Edit
    • Delete
    • Tags
    • Autopost
    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?
    • Tweet
  • About

    I help developers build really cool products on the Web.

    I work for Google as a Developer Advocate in London, specializing in Chrome, HTML5 and the Chrome Web Store.

    231036 Views
  • Archive

    • 2012 (5)
      • February (5)
    • 2011 (30)
      • July (1)
      • June (4)
      • May (10)
      • April (4)
      • March (1)
      • February (5)
      • January (5)
    • 2010 (35)
      • December (15)
      • November (5)
      • October (2)
      • August (5)
      • July (8)
    • 2009 (1)
      • January (1)
    • 2008 (8)
      • December (1)
      • April (2)
      • March (3)
      • February (2)
    • 2007 (17)
      • December (1)
      • September (1)
      • August (5)
      • May (1)
      • March (2)
      • February (4)
      • January (3)
    • 2006 (153)
      • November (3)
      • October (7)
      • September (11)
      • August (9)
      • July (9)
      • June (14)
      • May (11)
      • April (32)
      • March (23)
      • February (26)
      • January (8)
    • 2005 (274)
      • December (7)
      • November (43)
      • October (63)
      • September (54)
      • August (66)
      • July (13)
      • June (10)
      • May (10)
      • April (6)
      • January (2)
    • 2004 (1)
      • August (1)

    Get Updates

    Subscribe via RSS
    TwitterFriendfeedLinkedIn