Evernote Tech Blog

The Care and Feeding of Elephants

Elephants love mangoes – a look behind our Windows Phone 7 client

Introduction

A year ago I was working in the IT department of a large commodities trading company, managing a team of 11 people. I’d been developing software since my early teens, but I’d wanted to try my hand at managing.  I sold my two previous start-ups rather than growing companies, and management experience was something I felt I needed to change that.

Although I enjoyed managing, and didn’t totally suck, I still felt I needed to code to maintain my sanity.

So, in my spare time, I coded up an Evernote client for Windows Mobile 6.5.  My client did a few things that were missing from the official client, such as storing offline notes.  With absolutely perfect timing, I released it just as Microsoft unveiled their mobile strategy reboot, in the form of Windows Phone 7 (WP7).

Just as I was starting to realize that full-time management was not for me, and I began to explore doing another start-up, I got a call from Phil Libin, Evernote’s CEO.  Would I like to join Evernote to create their WP7 Evernote client?  Perfect timing – of course I would.  Last week we released the first version of that client.

This is the story of what worked, what didn’t work, what makes WP7 a great platform to develop for, and what some of the challenges were.  I’ll also explore the opportunities being opened by the next release of WP7, codenamed Mango.

A great development platform

Mature roots

In choosing to base WP7 on .NET and Silverlight, Microsoft immediately made the platform attractive to the massive existing community of .NET developers.

Although I had little experience with Silverlight, I did have many years of C# development under my belt, and it felt great to be able to re-use those skills.  Once you’ve experienced developing using technologies such as Language Integrated Query (LINQ), lambdas, and garbage collection it’s painful to have to give them up.

Silverlight has been out for several years, and although it has not seen massive uptake on the internet, it remains popular for intranet development within corporate environments.

Silverlight and the Model View ViewModel (MVVM) design pattern go hand-in-hand.  You declare what your UI looks like using an XML language called XAML, which is bound declaratively to your ViewModel code.  This means that you can test your ViewModel code stand-alone, without needing to involve the UI.  Silverlight also has a fantastic animation and visual state management system.

Superb tooling

As WP7 developers, we are spoiled.  Not only do we have a powerful, mature and rich IDE in Visual Studio, with great plugins such as Resharper, but we also get a fast emulator, and also a complete, standalone design tool in Expression Blend.

The emulator actually runs as a proper Virtual Machine, using the hardware virtualization features of your computer.  The upside to this is that you get snappy performance, but the downside is that you cannot develop inside a virtual machine, since the emulator will not run inside a virtual machine.

Blend lets you design, animate and tweak your app’s UI.  Although it was primarily created as a “high-end” tool for designers, there was such an outcry from developers, that Microsoft have made it available for free for WP7 developers.  It is a joy to work with, letting you focus on the look and feel of your UI, building storyboards and animations, without worrying about code.

Community

Great community

The existence of a strong community around WP7 development is far from unique to WP7, however perhaps because Windows Phone is something of an underdog right now, the community feels particularly tight.

Beyond the usual suspects such as Stack Overflow, and Microsoft’s own forum, there are sites such as Windows Phone Geek that provide a constant stream of high quality tips and tricks and articles.

Great components

Because it is such a new platform, it seems as though everyone and their dog is putting out new component frameworks, although it looks as though people are consolidating around WP7Contrib.

In the Evernote WP7 client I make use of:

Some challenges

Lack of Database

You know how everyone complains about the Google interview process, because they ask you about the implementation details of various hashing and sorting algorithms that you’ll never have to use in the real world?

Welcome to the world where knowing about those things counts.  The initial release of WP7 has no database technology exposed to developers.  What it does have, is isolated storage, and the ability to seek through files.

The ability to store notebooks offline, coupled with the possibility of having many thousands of notes, made the lack of a database a challenge.  A note belongs to a single notebook, and can have zero or more tags associated with it. You can view your notes by notebook and by tag, and the note list can be sorted in varying ways, including based title, timestamps, and geolocation.  A database would have been nice.

A number of people addressed this gap, and provided database technologies of varying levels of completeness and complexity.  I spent many weeks in late 2010/early 2011 trying them out, never finding one that really matched my requirements.  In the end I decided I’d had enough of spinning my wheels, and went with my own, simple mechanism.

Platform bugs

Normally it’s simple arrogance to think you’ve found a platform bug – chances are normally very high that it’s actually your code that is wrong.

But in the first release of any new platform such as Windows Phone 7, sometimes it is the platform!

Can’t set the focus on any of the controls on your page after setting the focus on a web browser control?   How about getting a crash when trying to restore your position to the third pivot item in a pivot?  Or unexpected error messages in your logs?  These are all things that have tripped me up, and turned out to be platform issues – totally understandable given the youth of the platform – just be a little more open to the idea that it isn’t your code that is causing the problem.

There are also features that you’d expect to be there, but simply aren’t – for example although you can stream data down from a web site, you can’t stream up meaning that if you want to send data to a web site it must all be in memory when you send it.  This poses a challenge if you are uploading extremely large files.

Finally, the platform itself seems to require things to run on the UI thread in surprising situations, such as some IsolatedStorage access, and networking (even if initiated off of the UI thread, and of course not using the WebClient class), which can have significant performance implications.

Smooth Scrolling

Given the emphasis on providing a snappy, responsive interface, it is surprising how hard it is to implement a really smooth scrolling experience when you have many items in a list, with images, and with some content potentially being dynamically downloaded.  Oh yes, did I mention there may be many thousands of items in the list ….

I started off using the built-in ListBox.  This provides UI virtualization through its use of a VirtualizingStackPanel, meaning that only the UI for the visible elements are instanciated.  It also provides data virtualization: if the list to which the ListBox is bound implements IList<T> then it only asks the list for the elements it needs right now, meaning that you can dynamically fetch elements from your data source as required.

Despite these benefits, I was drawn to using the LongListSelector from the WP7 Toolkit.  It has some cool features such as grouping, and hooks to tell you when your list data items are in use, and when they are no longer in use.   So it provides UI virtualization.  What it lacks however is data virtualization – the first thing it does is walk through every single one of the items in the list to which it is bound …

There are plenty of articles and techniques describing what to do to get smooth scrolling, such as downloading data in background threads and pausing downloads when scrolling … it is still very tricky to get right if you have many items, and everything is not sitting in memory.

In the next release of the WP7 client I’ve decided to go back to using the ListBox- the advantages of that special handling of IList<T> items, where it only requests the list items that it really needs is hard to beat.

Some challenges, overcome

Delay loading pivot items

The WP7 Evernote UI that you are initially presented with consists of a Pivot with several pivot items.  The initial pivot item that you see to begin with contains a list of all your notes.  Next are lists of your notebooks, tags and recent notes.

In order to improve the initial load experience, I delay load all Pivot Items other than the list of all notes.  The XAML content in the other pivot items is empty, but when the load event fires for those pivot items I then dynamically load a user control containing the UI elements for that pivot item, with appropriate loading animations so that it doesn’t look as though the UI has frozen.

Textbox run binding

In the list of notes, I wanted to display the timestamp in bold, followed by a snippet of text in another colour – all part of the same flow of text.

In order to create formatted text you can define a TextBlock, with child Run elements. Each Run defines formatting for the text within that Run.

Everything about XAML is about binding.  You define the UI using this declarative markup language, and bind properties of UI elements to properties of .NET objects, for example the Text of a TextBlock item to the Title of a Note .NET object.

To cut a very long story short, you can’t data-bind TextBlock Runs, meaning that I couldn’t simply bind the text of the first Run to the timestamp property of my note object, and the second to the snippet property of that object.

I ended up writing my very own binding mechanism, which was a lot of fun, seems to be pretty popular on Stack Overflow, but isn’t really where I want to be focusing my development time.

Wave file header

Recording from the Microphone in WP7 is pretty straight-forward, but if you want to actually do something with the recorded data stream, such as save it as a file, you are out of luck.  If you simply save the raw data stream, then that’s all you’ll have in the file.

In order for playback software to make sense of that data, there needs to be an appropriate header, which probably explains why the post on my blog, explaining how to add the WAV header is one of the most popular.

Isolated Storage performance

Although  I store the metadata (title, timestamps, etc) for all the notes, notebooks, tags, etc. in a single “database” file, the actual content is stored as individual files (the note body and associated “resource” data such as attached files and embedded images and audio clips).

I also cache the note content that I transform into HTML for viewing locally.  So for a note with a three embedded images there would be six files in isolated storage:

  • The note’s thumbnail for viewing in the list of notes
  • The note’s content
  • The note’s content transformed into HTML
  • Each of the three image files

The performance of opening a file from isolated storage degrades the more files there are in a single folder, so instead of storing the files for all notes in a single folder, with the note’s unique ID as the file name, I instead store the content in a subfolder, the name of which is derived from a two digit hash of the note’s unique ID.

One other issue I faced is that when a user signs out, I’m faced with the task of deleting several thousand files from isolated storage.  I don’t want to force the user to wait while this is happening – it could literally take hours (there is no ‘delete folder’ API call that does a recursive delete – you need to walk the directory tree and delete each file individually).

My solution was to store all the data under a root folder with a unique ID (Guid), and refer to that folder in the settings dictionary.  When you sign out, I clear that reference, and when you sign in again, you get a new unique ID (and corresponding folder).  I then have a background thread that deletes all files that are not under the current user ID – it can plug away in the background removing all traces of previous logins.

Looking forward to “Mango”

Wikipedia reliably informs me that Mangos are the most consumed fruit in the world, and while I’m not sure that the next release of Windows Phone, codenamed “Mango” will project Microsoft to quite that level of success with Windows Phone, it is clear that this is a major release, not only from a user perspective, but also from a developer perspective.

As well as addressing most, if not all of the issues I listed above, there are a number of features that will not only make our lives easier as developers, but also help us provide features and usability far beyond what we can provide right now.

Here are some of the things I’m very much looking forward to taking advantage of:

Database

Although this should be largely transparent to the user, as a developer the presence of native supported database will make a massive difference to me – I will take great pleasure in replacing several large chunks of code with a couple of lines of code: less code to support, less potential bugs.

Silverlight 4

Many of the issues I had to work around in the current version of Windows Phone are addressed in the move to Silverlight 4, such as not being able to data bind TextBlock Runs.  As a developer the experience will be a lot less frustrating, with things that you think should be easy actually being easy.

Integrated Search

One of the most puzzling things for users of the Evernote application on Windows Phone, is that when they press the Search hardware button when running the Evernote client, they get taken to Bing search rather than Evernote’s search.  Instead they must press the dedicated search button within the Evernote UI.

This situation may get a little less confusing with Mango, in that apps can indicate that they can handle specific kinds of search (products, movies, places and events).  The most obvious integration for Evernote will be places, since notes can be geotagged.  When you are looking for information to book a return trip to that fantastic holiday destination, perhaps you will also see the list of notes you created last time you were there.

Deep linking

In order to create an new note right now using Evernote, you first need to fire up the app, then press the “New Note” button.  This can be reduced to a single click using deep linking, whereby we’ll be able to create a tile that links to specific functionality (take a snapshot note), or specific content (a notebook or a note).

Tiles

We’ll also be looking to take advantage of the new live tile capabilities of Mango, perhaps to show that there is unsynced content, or the number of outstanding todo items.

Background Sync

The current release of Windows Phone has no capabilities to run apps in the background, and although the Mango release will open up some capabilities in this space, Microsoft are rightfully being frugal about how long apps can run for when running in the background.  Nevertheless, when your phone is plugged in, and within Wifi range, there is no real reason why you shouldn’t take full advantage of the abundant power and bandwidth to synch up your Evernote account in the background.

Conclusion

Windows Phone 7 has in many ways been a delight to program for, given the use of the .NET framework and C#, combined with the power of Silverlight.  Nevertheless, it has been challenging to create a data-centric app, with many thousands of interrelated entities, without fundamental OS features such as a database.

I am really excited about the potential of the next release of Windows Phone, codenamed Mango – it will open many more opportunities for us as developers and designers to make what we imagine, real, making it easier to bring those ideas to fruition.

Thanks

I’d like to say a special thanks to Reza Alizadeh from Microsoft, who helped us steer the product to release, and to Robby Ingebretsen who did wonders sprucing up our UI and adding that extra bit of magic.


  1. I’m a little jealous, but still — great work! :)

  2. Wow, thanks for all this information. It’s fascinating to see a little behind the scenes and gives me a bit more appreciation for what you’ve been up against to put Evernote on my phone.

    I think the most exciting thing about this post, though, is seeing your enthusiasm — it bodes well for the future of the app!

  3. Excellent post. I love the platform. It’s far better than android. Especially the emulator is really worth mentioning. Excellent performance and it comes with Hardware acceleration.

  4. Great post! Love Evernote’s technical stories. However, I have a question about Thrift. I know you’ve submitted a patch that helps to generate proper clients for Silverlight. Do you use exactly the same version (that attached to your blog post) for Evernote WP7 app? Have you contacted with Thrift development, are they going to integrated your changes into official version? Thanks!

  5. Hi Anton,

    I do use exactly the same version. I still need to submit the changes back to the Thrift folk – I’m currently focused on the next release of the WP7 client – big focus on load time performance, but submitting back the changes is high on my list.

    Regards,
    Damian

  6. Great post! I can empathize with a lot of this. What I’m surprised about is that you rolled your own storage solution. I also spent a good week evaluating various options, and sqlite turned out to be both performant and capable. The API is, granted, a little on the stone-age side, but I found it preferable to rolling my own. Did you also take a look at it, and if so, what made you decide against it?

  7. Hi Mike,

    When I was looking at the end of last year it was still quite new, and (as I recall) at that time the dev site didn’t have much activity, so I passed on it. I really liked it when I used it on previous developments, but I wasn’t sure that it was mature enough on WP7 at that point – maybe mistakenly.

    Damian

  8. Nice post!

    If you have any feedback on the WP7Contrib we would love to hear it.

    Did you use any WP7C components in the app ? If so which ones.

    Thanks

    Rich


Leave a Comment

* Required fields