Mocast Postmortem

Post on 27-Aug-2014

714 views 0 download

Tags:

description

This is a presentation I gave at Seattle Mobile Developers meetup describing what went right and what went wrong in the development of Mocast - a new iPhone podcast listening app: http://mocast.io You can see purchase Mocast at: https://itunes.apple.com/us/app/mocast/id897185985?mt=8

Transcript of Mocast Postmortem

Mocast PostmortemFrank A. Krueger

Seattle Mobile .NET July 1, 2014

What’s a Postmortem?After a project finishes in a big production for a movie, video game, or large project. Everyone gets together to discuss in a meeting what went wrong and what could be done better. The issues brought up are almost always completely ignored by management and they continue to make the same incompetent mistakes they always have.

- Urban Dictionary

What’s a Mocast?

• Podcast player

• Thumb-friendly UI

• Emphasizes the full catalog

• ADD-friendly UI

What Went Right? !

What Went Wrong?

Right: UI Design

Goal: Make it iOS 7-y

Right: UI DesignGoal: Make it iOS 7-y

Goal: Non-modal (no Now Playing screen, no Episode screen)

Right: UI Design

Right: UI Design

Right: UI Design

Right: UI Design

Right: Reliance on Bindings

INotifyCollectionChanged

INotifyPropertyChanged

Right: Reliance on Bindings

• Producers:

• ObservableCollection

• ObservableQuery!

• Consumers:

• ObservableTableView

Right: Reliance on Bindings• A query that changes over time and

depends on other collections and queries

• Emits minimal CollectionChanged events

• Automatic Update Throttling

• General Purpose - you put anything into the “query”

Right: iCloud Syncing

• Mocast uses iCloud Key-Value store

• Very simple API, very simple update model

Right: iCloud Syncing

Right: Async Everywhere• Async is the greatest thing to happen to UI

development since Visual Basic!announceTask = AnnounceNewEpisodeAsync (episode, streaming); !beginSeeking = true; beginSeekingPosition = GetPlaybackPosition (ue); await BeginSeekingAsync (); if (announceTask != null) { await announceTask; announceTask = null; } player.Rate = BaseRate; !UpdatePositionData (); UpdatePlaybackInfo ();

Wrong

Wrong: The “Episode Class”• Oh my, I don’t have an Episode class!

• Instead, 3 classes comprise “Episode” based upon the source of data:

• UserEpisode has all the data a user can control (play position, tags, etc.) and is sync’d with iCloud

• DataEpisode has all the info from the podcast feed

• DownloadEpisode has information regarding its download status

• Each implements IEpisodeReference so they can be correlated

Wrong: The “Episode Class”

Doesn’t Work :-(

Wrong: The “Episode Class”

Wrong: The “Episode Class”

I allowed the data source API to dictate my domain model :-(

Wrong: The “Episode Class”The Fix

Wrong: The “Episode Class”The Fix

Wrong: Threaded ObservableQueries

• To do modern UI programming, you need to do as much / all work asynchronously

• My ObservableQuery started, naïvely, as thread-dumb

• Eventually, had to make the class itself thread-safe but did not require thread-safe queries so couldn’t automatically run them on separate threads

• Result: UI freezes under very heavy load

Wrong: Threaded ObservableQueries

The FixInstead of:

!ObservableQuery (Func<T> source)!

!I should have:

!ObservableQuery (Func<Task<T>> asyncSource)

Wrong: iCloud Sync

• Wonderful because it’s simple

• BUT very small storage size:

• 1,000 keys

• 1 MB data

Wrong: iCloud Sync

• Use CloudKit!

The Fix

Wrong: Manual Entity Binding

Wrong: Manual Entity BindingThe Fix

?

Wrong: Manual Entity BindingThe Fix

There just aren’t many good declarative data binders out there:

!My Bind Library

That Reactive Library MvvmCross

BindableObject / Dependency Properties (haha)

• Require re-architecting around their pattern

• Make for great demos, but have real-world issues:

• async

• reference cleanup

• throttling

• deep hierarchies

• greedy events

• …

Wrong: Manual Entity Binding

Thank you!

• Mocast will be available on iPhone/iPod in a couple weeks