Mobile Browser Quirks :/

What it’s like developing for mobile web

I have been working on the mobile web version of Pico lately and I have quickly stumbled upon many rendering quirks between different versions of Android and iOS.  I will show some examples of these and offer some suggestions for workarounds.

I am testing of four devices which should cover a large portion of the smartphone install base, though there are many others that aren’t addressed here.

Android 2.3.6 (Nexus One – Default browser)

Android 4.0 (HTC One S – Default browser, not chrome)

iOS4.2 (iPhone 3G)

iOS5.1 (iPhone 4)

Fixed Position

If you are making an app with a “native feel”, fixed position elements are essential.  Topbars and menu buttons are pretty standard in all native apps, and fixed position elements are the most direct way to accomplish that.  Well.. too bad they don’t really work that well.

First off, fixed position doesn’t work at all in iOS4.  The elements are rendered as static.  On Android 2, they work, but you have to have a to set the scale value in the meta tag.  Example: Doesn’t work in Android 2 (source), Works in Android 2 (source)

<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">

Secondly, on iOS5, tap events on fixed position elements don’t work if the page is scrolled.  Click events work however, so just use those.  Example (source). Stackoverflow (none of those solutions worked for me).

Also on iOS5, if the window is scrolled by anything other than the user (javascript scrollTo, refreshing the page when it is already scrolled, etc.).  Fixed position elements become unclickable.  What is apparently happening is the click area is being scrolled even though they are being drawn in the right place.  The point is, they won’t work until the user scrolls manually, then everything snaps into place. I also had limited success “rerendering” the fixed position elements after the scroll event.  i.e. removing them from the DOM and reinserting them (or in Backbone.js, calling render()).  Example (source).  In depth example.

Lastly, there is a rendering bug in iOS which causes fixed elements to be drawn in the wrong location some times.  In particular when dynamic content causes the page to scroll or when the keyboard pops up.  I unfortunately wasn’t able to recreate this in jsfiddle, but it does happen, I swear.  If the user scrolls the page, everything pops into place.

Transforms

Transforms are great.  You can apply all sorts of cool effects to any element on your page.  But, more importantly, even for simple effects, they are much faster to animate than normal css transitions because they are accelerated by hardware.  2d transforms work everywhere!  3d transforms have more limited support.

You can easily achieve the same animation effects (and a lot more) with transforms versus conventional CSS animations.  (e.g.left:100px ===> -webkit-tranformation: translate3d (100px, 0, 0) ).  See the difference here (source).  You will only see the difference on mobile browsers, and it is subtle with these simple elements; but if you are animating things with a lot of CSS, it will be slower without using transforms.

Note that if you are transforming an element that contains a fixed element, the fixed element will become static (though it will be transformed).  You need to transform the fixed and non-fixed elements separately.  This is not actually a mobile bug, it works the same way on desktops, but is still a little counterintuitive.  On Android2, it doesn’t work at all, so you’ll need to fall back to non-accelerated animations.  Examples: broken (source), working (source), Android2 version (source).

Another thing I noticed is that on Android, when I enabled 3d acceleration on an element dynamically, it caused the element to blink on screen.  That’s not a very common thing to do, but can be annoying.

Tap events

Tap events (touch start, touch move, and touch end) can be used to create cool low-level interactions like drag and drop.  However, their most common use case is to get rid of the delay from a click event.  On both Android and iOS, there is a 300ms delay after you click (presumably to make sure you’re not double clicking).  This can create a laggy user experience.  You can instead use touch end events (on mobile only) to perform actions.  See the difference here.

Don’t forget that tap events don’t work properly in fixed elements in iOS (mentioned above)

On Android, tap events can improperly cause a “click” action on elements below them.  This seems to only happen if the element moves when you tap it.  You can either have a filter element between the two that traps clicks, or just use a “click” event on the top element.  Example (source).

Scrolling Divs

Scrolling divs have many uses. Sometimes you want different elements on the page to scroll independently.  They can also be used to implement fixed topbars without using ‘positon:fixed’ elements.

Unfortunately, they don’t work on Android 2 or iOS4 (however, iScroll uses transformations to fake it).

On Android 4, javascript scrolling (i.e. element.scrollTop=x) does not work.  Example (source).  But really, if you want to do this, you should just use iScroll.

Conclusion

These are all quirks/bugs I found in about 2 weeks of mobile development.  I am sure there are many more out there.  This is very disappointing.  I feel like I am back in 1999 where no browser is standards compliant for even the most basic things and my code is riddled with IF statements checking the user agent.  Fundamental features like scrolling divs and fixed position elements seem to have poor support, while ironically, more modern features like animations and supported fairly well.  There are many third party libraries that try to absorb these eccentricities such as jQuery Mobile, Sencha, and iScroll.  These are all widely used, but the first two are fairly heavy-weight and impose many additional design decisions beyond abstracting layout differences.  I’d love to hear about other peoples experiences with mobile web development and the solutions they have come up with.

Advertisement
Posted in Programming | 4 Comments

Space age web development with Meteor!

TLDR; It’s an online dance party! Check it out. Source.

Danceynous

Danceynous (for Synchronous Dance Party) uses Meteor to make a real-time, interactive, YouTube playlist

Well, I can’t go a month without building a new side project, now, can I?  The release of Meteor last week made it doubly exciting.  I’ve spent about 30 hours working on Danceynous, and thanks to Meteor have come out with something pretty fun.

Danceynous is a social music playing app.  It is pretty similar to Turntable.fm, but aims to be a little more interactive.  Everyone can submit songs to a playlist and vote on them.  The playlist is reordered in real time as it plays, resulting in a fair amount of point battling.  The frontend and backend are powered by Meteor (with help from Backbone and jQuery).  The music is sourced from the YouTube player API.

There was a ton of buzz (in the developer community at least..) when they release the preview of Meteor last week.  I guess that shows how fed up people are with the state of javascript development.  I have been following Luna, Asana’s Javascript-based infrastructure for a little while now, hoping they would release it, but no dice.  I have been using Backbone for a few months now, and it is neat, but just not particularly life-changing.  Considering the whole thing is under 1300 lines of code, I wouldn’t expect it to be.

Meteor and Luna have a lot of similarities.  The idea is to unify the client-side app with the data being served on the server-side.  This way data transfer happens automatically instead of the client having to explicitly request data and the server having to explicitly serve it.  It turns out you need a lot of pieces to make this work well: Reactive front end with client side database caching, websocket emulation, client simulation on the back end.

In the end you get a much more clean and maintainable code base, with much less work needing to be done on the server side, and much less redundant coding.

I am going to briefly walk through the different pieces of Meteor that I used and talk about some of the challenges I faced and also what was remarkably easier compared to Rails+Backbone.

There are four pieces to Danceynous: Synchronized player, the real-time playlist, the chat room, and the YouTube search.  The first three are powered by Meteor; the last is purely client-side YouTube API.

The chat-room is incredibly straightforward; so much so, that I’m not even going to bother going into detail about it.  There is literally just a Chats collection with a bunch of message documents (‘documents’ are what MongoDB calls ‘records’) that get rendered as they are inserted into the collection.  Due to the natural reactivity of Meteor I don’t need to handle sockets myself to detect incoming messages.  My local database gets updated automatically, which triggers the render code, which inserts the new message.  MongoDB collections are stably sorted as well, so I don’t even have to do any “order-by” nonsense.

The real-time playlist is almost as easy as the chat.  There is a Songs collection.  Users can insert song documents into it.  Each song has a points attribute.  Players can increase and decrease the points on the song, which triggers resorting the list.  I use the $inc atomic method in Mongo to avoid any RMW race conditions.  Note that everything I have described so far is entirely coded on the client side.  A client creates a chat message; a client creates a song; a client adds points to a song.  Meteor, reacts to the client side changes and propagates them through the server to remote clients, updating their databases and triggering them to re-render.

The synchronized player is slightly more complicated.  The general idea is that each user has their local version of the song.  The videos are streamed directly from YouTube, so all the server can do is trigger the client to start loading the file and then hope for the best.  Users with slow connections may spend several seconds buffering, which puts them behind other users.  Users re-synchronize when a new song is loaded, which means the slow users may skip the last few seconds of the song.  There are two things that need to be done here.  We need to keep track of the time progressed through the song, so that someone who connects in the middle of the song can start at the appropriate time.  We also need a way to detect that a song has ended to trigger the synchronized loading of a new song (remember, the music playing happens entirely on the client side, so the server does not know how long the song is or when it ends).

To keep track of the time progression of the song, the client simply polls its local player periodically to check the time.  It then updates the song document with a time attribute (which is immediately propagated to the server). This time attribute is read by any new users who join the party and they start the song at that time.  The catch here is that since the time updating is done on the client side, we have potentially many users updating times that do not necessarily match.  One way to solve this is to pick one user as the “host”.  However, what do we do if the host disconnects?  We can pick a new host, but the problem is that it actually takes quite a long time to detect if a user disconnected (more on that later), which could cause problems.  If you have played Halo multiplayer, you have experienced this process (i.e. when screen goes black for 30 seconds after someone drops out, while they pick a new host).  I actually have all the clients attempt to update the time.  However, only the client who is farthest along actually gets through.  This is done by only updating the time if your  local time is greater than the server time.  The first client to reach time X will update the server.  All of the other, slower, clients will not perform any update.  Again, this is accomplished using atomic RMW Mongo commands to avoid race conditions.

We use a similar process for switching songs.  The first user to reach the end of the song updates the database to play a new song.  All the other, slower, clients receive this update and start playing the new song.  It is important to note that all of this is performed on the client side, with Meteor automatically syncing the clients with each other.  Think about how this would be done on a Backbone+Rails platform.  (Hint: it would involve a lot of POST /api/room/:id/current_time?time=t).

Of course, it wasn’t all gravy.  There are few things that I struggled with while using Meteor.  The first, that I alluded to earlier, is detecting user disconnect.  (This is important because I have a list of people currently in the room).  To be fair, this is a problem with all systems that use socket emulation.  The issue is that since the socket is emulated by long-polling the server, the server has a hard time detecting when the client actually disconnects, versus disconnecting as part of the periodic polling process.  The standard way to detect a disconnect is by having the client set a keepalive record in the database.  If the client disconnects, the keepalive record will expire and you can mark all owners of expired records as disconnected.  Unfortunately, since the long polling time is 25s, that is the minimum disconnect timeout.  I am using a 70s timeout right now to avoid false disconnects.

Another issue I had that is more Meteor specific is attaching things to DOM elements.  This is straightforward in conventional Javascript.  You just use a $(document).ready(dosomething) call.  However, since everything in Meteor is reactive, the document.ready paradigm does not apply.  When the “document” is ready, most of the HTML is not rendered yet.  In general, this is not an issue because you can just put everything in templates which are naturally reactive and will get called.  The template event system also handles event delegation in a fairly straightforward way.  There are some places, however, where this breaks down.

For example, the YouTube api needs to be passed an ID of a DOM element where it will put the flash player.  Passing the ID in the initialization does not work because the page isn’t rendered yet.  Even calling Meteor.flush() does not work if the the template that contains the ID depends on some record, as the records may not have arrived from the server yet.  Once the record arrives, the template is rendered, but I was not able to track down a way to detect the rendering and call a function to attach the player afterwards.  At first I used a timeout that was long enough that the page had rendered, but that was a terrible hack and caused me to give up a piece of my soul.  Ultimately, I put the ID in a section of the html where it did not depend on the presence of a record.  I then called Meteor.flush() to ensure that the tag was rendered.

A final issue I had with Meteor was that, in general, my code feels very unstructured.  Unlike Backbone, Meteor does not lend itself naturally to encapsulation.  This is due to much of the logic being in the Templating, and also the extensive use of global collections and session variables in order to enable the reactivity.  I am sure there is a way to write great, modular code with Meteor.  It just doesn’t come as naturally as it did with Backbone.

That sentence may be confusing since I said I am using Backbone on this project, but I am only using the Backbone router.  The Backbone Models and Views are superceded by Meteor reactive templates and Collections.

I have some other, more general, concerns about Meteor.  The first is client side performance.  The code ran fine on my Macbook Pro, but I am curious to see how well it runs on my 2.5 year old smartphone.  Also since Meteor is constantly pinging the server, how well does it perform on a flakey connection?  I imaging the user experience is better than a conventional framework because of the client side database that simulates a server response as it waits for the real response.

Also, as many people noticed last week, Meteor currently has no built-in way to effectively secure the database.  As in, I can open up firebug and type Users.remove({}) and delete all the users (please don’t do this.).  There are a few workarounds right now.  I can effectively disable the ‘remove’ function for certain collections.  I can use publishing (which I do) to restrict the records that users have access to (so you can only remove users who are in the room with you).  The conventional way to solve this problem would be to disable ‘insert’, ‘remove’, and ‘update’, and replace them with more restrictive functions that the server validates and then sends a response.  I am curious to see what the Meteor team comes up with and if they can manage to maintain the real-time feel on the client side and elegance on the server side.

Overall, I am very happy with how this project turned out.  I definitely see myself using Meteor for a serious project when it is more mature.

Posted in Uncategorized | 1 Comment

Introducing Freader

Freader.coTLDR: Freader is a social reading app.  I made it because Google killed Reader and I wanted a way to share and comment on stuff with my friends.  It’s open source! (GPLv3)

Last time, we talked about “Mom and Pop” startups that fill a niche need that large companies have trouble filling.  Now I want to tell you about one of my projects that does exactly that.

Freader is a simple social reading platform.  You have a private forum with your friends to share links, read articles, and comment on them.  I use it in two ways.  I have a Fread (or group) with my friends and we share interesting and funny links (aka cat videos..).  It’s like our own private Reddit.  It’s (slightly) different from Reddit because it is optimized for posting and commenting.  Almost everyone in the group posts and comments and people typically read every post.  The other use case is for work.  My cofounder and I do a lot of market research (aka read Techcrunch), and we used to email each other interesting websites and respond with comments.  This is a more structured way to handle that process.

As I mentioned, Freader is similar to Reddit.  It is also similar to Facebook groups.  However, what prompted me to make it was Google Reader.  I used to be a heavy user of Google Reader, especially the sharing features.  In November, Google decided that it didn’t make sense to have two social products and removed the sharing features in the interest of having folks share those articles on Google+.  Unfortunately G+ does not work very well for this purpose.  There is a lot of extra stuff in your stream (which requires a lot work to clean up), and it’s easy to miss things.  Also, it’s not optimized for reading.  You get a tiny, very narrow, space for the article.  Facebook has similar problems, though they are somewhat alleviated if you use a group for this.

Since there are very similar alternatives, I’m not expecting Freader to go gangbusters. However, I did feel the need to create it since I wasn’t satisfied with the alternatives, so I thought I would share it with others.  If people do use it, I intend to charge directly for it (for reasons mentioned in my last post) in some, hopefully unobtrusive, manner.

Now for the technology!

Freader is built on top of Rails 3.0.  It uses Backbone.js, jQuery, and the glorious Twitter Bootstrap on the front end (did you recognize the topbar?).  It is hosted on Heroku Bamboo.

This was my first Backbone.js project.  I previous worked on some Rails projects and I quickly realized the need for a javascript framework.  I like Backbone because it is very light weight and extensible.  It doesn’t force you to do things in a certain way like Rails does.  I also looked at Sproutcore (seemed a little too heavy weight for my first JS framework, but I intend to check it out) and Spine.js (seems very similar to Backbone, but the CoffeeScript really turned me off.  I have worked with fake languages that compile to real languages before and found it extremely painful.  If you’re curious, that was at Nvidia and ARM using internal languages that compile to Verilog).

I have released the source code under the GPLv3.  I had trouble finding real applications out there when I was learning Backbone and Rails, so hopefully someone will find this useful.  I also made a few simple extensions to Backbone.js.  Backbone doesn’t handle relations very well (like when a Post model includes Comments models).  So rather than use the large and complex backbone-relational.js (the source is almost as large as backbone itself!) I wrote a couple of helper functions.  I also created a simple solution for linking models to forms, the FormView class. I will do a separate post on these extensions.

Posted in Programming, Startups, Tech | Leave a comment

The Mom-and-Pop-Corner-Store Startup

The first law of the internet: Everything you love on the internet will eventually die a lonely death.  Remember when Facebook was a simple site that let you find and keep in touch with your old friends? or when Gmail was a streamlined web-mail client that didn’t trick you into opting into various social networks, chat, and phone services, or when Evite didn’t send you through 5 screens of ads when your RSVPed?

What happened to these services – and countless other web products that people loved and have now disappeared.  I’m not saying that people don’t love the new Facebook timeline, or the memory-hogging Gmail.  The point is that some people did like the old stuff, and if they want that experience again, where can they go? Nowhere – that’s where.

Why does this happen?  If a significant amount of people want a service, why doesn’t it persist?  Unsurprisingly, the answer is money.  The trend with web companies is to start with little to no money, and make a really simple product that people love (it has to be simple, because you have no money to build something complicated).  Then you get traction and thousands – or even millions – of people use your service.  Now you (and investors) get excited and you paint rosy pictures of ad revenue, lead generation, and affiliate sales.  You raise millions of dollars and expand.

As a side note, lets do a calculation here.  You raise a fairly modest sum of $3 Million and give the VC’s 30% of the company, for a roughly $10M post-money valuation (also not immodest).  VC’s want at least the potential for a 10-20x return, so you are shooting for a $100M exit if you don’t raise any more money (which you probably will).

Now you look back on your simple, fun-loving social network – or bookmarking tool – or news reader – and you realize, you need to do something different to make these returns.  Suddenly, it’s slightly less important that people love your company and more important that they spend time on your site and click ads and buy things.  At the beginning, your interests were very much aligned with your users.  You wanted them to use your widget, so you made the best damn widget you knew how to make.  Now, you want to make money, and it becomes more about dollars and less about widgets.

Now there is actually nothing wrong with this process.  It turns out it works really (really) well in lots of cases.  The web services are still useful, and people still like them, and everyone gets rich!  The problem is not every web service fits this model.   The ones that don’t tend to get massaged into larger services or disappear altogether.

Let me draw an analogy.  I love watermelon.  It’s delicious.  It’s sweet, it cools and hydrates you on a hot day, and it gives you a socially acceptable excuse to spit.  Now, these days I find that I get my watermelons from Safeway – or even Walmart – because I’m already there, it’s convenient and it’s pretty cheap.  However, I also can get watermelons from the farmer dudes selling them on the side of the road.  It may not be as cheap, it’s certainly less convenient (I don’t exactly live close to any farm roads), and they are hard to find.  However, those watermelons are so much better!  All these guys do is grow watermelons, and they sell more if the watermelons are more delicious – so believe me, they are good.  Well, lucky for me I have this option – as inconvenient as it may be – because the farmers have figured out how to make it work for them.

Unfortunately, on the web, it is pretty rare to see this.  We are often stuck with the Walmarts and Safeways of the internet.  They can usually do the job, but sometimes I miss that focused, special experience.  Well, just like the farms and mom-and-pop shops in the real world, there is a place for specialty web services.  However, like the corner stores, they require a different business model than the big corporate internets.  These services are not targeted at a mass audience, but at a niche group of devout followers.  They can afford to charge a little bit of a premium to provide this service.

Once they start charging for their service, something amazing happens.  Like the mom-and-pop stores, the foremost priority is once again making the customer happy.  Instead of finding ways to trick the user into spending money, they site can focus on maintaining itself in the way that the users want.

This sounds great, but a couple of things have to happen to make this work.  The sites have to raise little or no VC money.  If you are focusing on a niche market with a low value product, you can’t reach the valuation that you need if you raise millions of dollars. Also, the need has to be specific and difficult enough that it won’t be fulfilled by a larger site.  If the Safeway scientists engineer the worlds most perfect watermelon, the farmers are probably SOL.

The main issue, though, is you have to get people to pay for this stuff.  Unfortunately, users are conditioned against paying for things on the internet.  However, that doesn’t meant that they can’t afford it, or even that they mind paying for trivial, unnecessary things (heck, people pay $4 for a latte and $.99 for a fart app).  This is one of the great unsolved problems of the web today.  Many things have been tried to simplify the online payment process: having websites store your credit card number, paypal/google checkout accounts, even having your browser save your credit card information.  Unfortunately, none of these solutions are very good.

In the mean time, I still think there is ample space for mom-and-pop (also known as cash-flow) startups, and there are certainly lots of people out there wanting them, especially in the wake of killed products and startups.

There are a fair number of payment startups out there, so hopefully someone will solve this problem, because I could really use my fresh internet watermelon.

Posted in Startups | 1 Comment

The Bait-and-Switch aka How to Solve the Chicken-and-Egg Problem

Mobile payments is the classic chicken an egg problem.  How do you get vendors to support your service if people don’t have your app?  Why would people download your app if no one supports it?  This is one reason why many believe that mobile payment systems will be driven by large companies.  The main hurdle is market-based, not technology based.  However, let’s look at how Square is solving this problem.

It started with a simple idea that solved a real problem for a (relatively) small market.  Let businesses, too small or unsophisticated to accept credit cards, accept them using a smart phone and a free piece of hardware.  Fast-forward a billion dollars and they are doing $4M in transactions a day.  Sounds great, but now what?  I think you can do the math ($4M*2%*365 will not get them to the $10B valuation that will make KPCB happy).

Well, earlier this year, Square released Card Case, a (really well thought-out and executed) more conventional mobile payments solution.  Many of the merchants that supported square (especially those that used their point of sale system) have to do very little to now support Card Case.  Square does not have to spend time and money to convince them to invest resources in setting up a system relying on a startup which, frankly, could be gone in a year, because they have already done this to accept the Square device.  So now, when I sign up for Card Case, I see several merchants that already support Square, which means I might actually use it.  And Card Case is one step in the direction toward a capitalist-utopian future where we can buy things without having to lift a finger.  It also has the potential to greatly increase Square’s market because they now provide value to merchants who already accept credit cards.

What if Square had skipped straight to Card Case?  Well, then they would look like all of the other failed mobile payments systems, trying to solve both ends of the chicken/egg problem with a massive marketing campaign.  Not a cheap way to start a business.  This is not to say that Square has solved the problem.  They started with a small market and a small number of merchants, that gives them a small number of consumers to start with Card Case.  This will (hopefully) incentivize larger merchants to adopt the system, and therefore more consumers, and so-on.

Time will tell if this actually works.  But what I find interesting is that a company that many thought were addressing a niche market with a somewhat gimmicky device has suddenly created a very real presence in a very large and difficult market.  That is the bait-and-switch.

Posted in Startups, Tech | Leave a comment

I am alive.

Well, after about decade in the tech world, I figured it’s about time I have some semblance of a web presence.

I have been involved in two electric vehicle startups (as an early employee and as a cofounder).  I have been hanging out Stanford for the better part of the last five years doing research in multi-core processor design, TAing the Tech Venture Formation course there and being involved in the startup community in various ways.  I have also been involved in random things such as thisthis, and this.

Posted in About me | Leave a comment