You have to love Apple. They really want HTML5 to be big. They managed to come up with a way to force major companies to invest boat loads of money in HTML5. Last year Apple began requiring third-party app developers to sell any available content inside their apps instead of linking out to browser based items on a website. Apple wanted their 30 percent of all sales bad…or did they? They must have known that the companies behind the most popular native iOS eReader apps would never agree to pay a 30 percent fee on every eBook they sell. So why did they do it? I think they have something in development that needs HTML5 to be widely adopted before it is ready to launch. Think about it, they just bought the Justin Timberlake-backed HTML5 firm called Particle.
A direct result of the changes Apple made to their app store is the beautifully designed Kobo Instant Reader app. The HTML5 app was on Kobo’s bucket list but got pushed to the top when they found out their iOS apps earning potential was about to hit the fan. Kobo decided to partner with Appnovation Technologies to develop and launch their Instant Reader cloud application. It was created using HTML5 and the SproutCore framework. SproutCore was the secret sauce behind Apple’s MobileMe, iWork and iCloud applications.
Kobo Instant Reader is fantastic. It might just be my favorite HTML5 app of the year. Reviews on the Chrome Web Store have been very positive as well with people writing things like “Really easy to use and has a nice, clean interface.“, “Great app, I can access my library on any computer (across operating systems) with minimal effort and everything gets synced!“, and “Absolutely brilliant. Best reading app out there!“.
I was so thrilled with this HTML5 app that I wanted to know more about how it was developed. Tyler Keating, Appnovation Developer on Kobo App, Lead Developer & Architect of SproutCore, Core Team Member on SproutCore and Dave Porter, Appnovation Developer on Kobo App, Core Team Member of SproutCore were gracious enough to answer a few of my questions.
The open source framework SproutCore is amazing and your team did a wonderful job using it to build the Kobo web app. Were there any major challenges that the SproutCore framework posed during the development process?
Tyler: In terms of challenges created by SproutCore, there were very few as the framework has been stable for years. We did encounter some minor bugs and deficiencies, but were able to patch them and submit them for inclusion back into the framework very quickly. Therefore, the real challenge was to get new developers experienced with the framework in order for them to contribute effectively. There is a lot in SproutCore, even our most experienced developers still find new features occasionally, and so it takes some time for new developers to reach the level required to contribute to a project as large as Kobo.
Implementing offline storage is one of the more difficult tasks developers face when creating web apps. I would imagine that the size of the users’ books would be an issue when creating your e-reading application. How were you able to overcome this?
Tyler: We did a lot of experimentation with the different client storage solutions and yes, it was a challenge. Some Kobo books are more than 10MB in size, which required us to split the data amongst several rows when using WebSQL and recombine it later. And some browsers require the user’s permission before storing data on the client, which adds another design consideration. As well, the browser doesn’t provide a means of determining how much storage is available and so at any time a store request may fail based on a number of factors beyond our control. On top of all that, loading a 10MB+ book into memory is not an option and so we had to work very carefully to load and unload data only as necessary.
One benefit of all this work though is that we built WebSQL and IndexedDB interfaces that we should be able to open source back into the SproutCore framework to aid the next developers doing the same.
Dave: That’ll be a great example of SproutCore at its best: insulating developers from the complexities of evolving, or even competing, standards and letting them get on with the business of building features. It’s best practices, baked in.
Performance is such a huge issue in app development these days. Congratulations on creating one of the best performing web apps I have seen. How were you able to accomplish this?
Dave: Thanks! SproutCore understands that its goal is to build applications, rather than web pages, and is highly optimized for that use case. You have to know what you’re doing, though.
Tyler: Performance in a SproutCore application can come cheaply, but it requires understanding the framework to ensure that you are doing things right. One of the first big wins we got by using the framework was the combination of SproutCore’s sparse array with its list views and its scroll view. We were able to request subsets of a long list of data and only request additional data if it is required for display.
Dave: Sparse arrays are crucial for any application that’s going to ever display lots of information, a little at a time.
Tyler: On top of this, the list view is aggressively optimized so that only the visible elements are in the DOM, those elements are re-used for new content and they never change position in the DOM tree. This allows us to scroll through lists of potentially thousands of books without a hiccup or having to resort to the “Web 2.0” method of paging.
Tyler: Another aspect of performance is the load time, which SproutCore is often criticized for.
Dave: To be fair, developers face SproutCore’s worst-case load time scenario: with rapidly-changing source code, SproutCore’s excellent caching solutions are ineffective. It’s by no means slow enough to impact developer efficiency, but it’s enough to earn SproutCore a reputation as slow-loading. But the story for users – who aren’t tweaking the code every time they visit the site – is much, much better.
We also mitigated a lot of the load time issue by using SproutCore modules, which are a very simple means to separate out units of code into a module that can be deferred until needed. Depending on the purpose of the code, it may never be loaded into the application, thus avoiding adding to the initial download and parse time or it may be loaded as a string and parsed only when needed, thus avoiding adding to the initial parse time.
But on top of that, we consider developer performance to be just as an important an issue. It makes no difference if a library claims “micro” size or “ease-of-use” if a team using it loses the ability to iterate when the application reaches even a minor level of complexity. What we found was that by doing things right, using the framework, using statecharts, using computed properties and bindings, using the build tools, etc., that each additional iteration was straightforward and developers are almost never blocked. And because we re-used so much from SproutCore, we spent the majority of our time on implementing features and improving the user experience.
Finally, we also used the built in SC.Benchmark to find slow spots so that we could revisit them every few sprints and keep the performance aspect from getting out of hand.
I understand that you used the HTML5 postMessage feature. Why did you use it and how did you enhance the default security that comes with it?
Tyler: Because Kobo has several other applications, they’ve built some common resources for sign in and purchasing through their webstore. In order for us to use these assets in our app, we worked with Kobo to implement postMessage so that we could load these resources inside an iframe and they could indicate the state back to our application. Security was not actually an issue with our scenario, because each resource is self-contained and the frames share the same domain as our app.
How did you go about making sure that the Kobo web app used as little memory as possible?
Tyler: It is probably safe to say that memory debugging is one of the most difficult aspects of web (or any other) application development and we spent some time understanding how memory is used. As was mentioned above, a lot of care was taken to only load data as necessary and to unload it as well, which saved us large amounts of memory and to compartmentalize code into modules so that they aren’t even in memory unless necessary. During the deep memory debugging we were also able to reduce some of SproutCore’s internal memory use with improvements to the framework, that we shared back with the community.
However, the application plus framework alone take up a lot of memory, so we did take the time to blacklist any code from the framework that we weren’t using and refactored the application wherever we felt that the tech debt was getting high.
What was the process of testing the cross-browser compatibility of your web app like?
Tyler: Both Kobo and Appnovation had QA team members that tested the app on various browsers and devices. This process was made difficult, because we simultaneously developed the app to work on desktop, tablet and smartphone as well as a Windows 8 version that shared the core code. Although unit testing was able to keep core components bug free, in such a scenario the UI is most susceptible to regressions. For example, a change to a style for the large screen design (Instant Reader is fully responsive) could inadvertently break a style for the responsive smartphone mode.
Dave: SproutCore as a framework is 100% unit-tested, and it comes with all the tools you need to implement tests for your own application as well. We’ve begun that process on the Instant Reader, and once an application is fully covered, then most of your cross-browser debugging is just a matter of running the test suite in each of your target browsers. I highly recommend automated testing to anyone starting a project in any environment where it’s available.