Mocast Postmortem

34
Mocast Postmortem Frank A. Krueger Seattle Mobile .NET July 1, 2014

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

Page 1: Mocast Postmortem

Mocast PostmortemFrank A. Krueger

Seattle Mobile .NET July 1, 2014

Page 2: Mocast Postmortem

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

Page 3: Mocast Postmortem

What’s a Mocast?

• Podcast player

• Thumb-friendly UI

• Emphasizes the full catalog

• ADD-friendly UI

Page 4: Mocast Postmortem

What Went Right? !

What Went Wrong?

Page 5: Mocast Postmortem

Right: UI Design

Goal: Make it iOS 7-y

Page 6: Mocast Postmortem

Right: UI DesignGoal: Make it iOS 7-y

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

Page 7: Mocast Postmortem

Right: UI Design

Page 8: Mocast Postmortem

Right: UI Design

Page 9: Mocast Postmortem

Right: UI Design

Page 10: Mocast Postmortem
Page 11: Mocast Postmortem

Right: UI Design

Page 12: Mocast Postmortem

Right: Reliance on Bindings

INotifyCollectionChanged

INotifyPropertyChanged

Page 13: Mocast Postmortem

Right: Reliance on Bindings

• Producers:

• ObservableCollection

• ObservableQuery!

• Consumers:

• ObservableTableView

Page 14: Mocast Postmortem

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”

Page 15: Mocast Postmortem
Page 16: Mocast Postmortem

Right: iCloud Syncing

• Mocast uses iCloud Key-Value store

• Very simple API, very simple update model

Page 17: Mocast Postmortem

Right: iCloud Syncing

Page 18: Mocast Postmortem

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 ();

Page 19: Mocast Postmortem

Wrong

Page 20: Mocast Postmortem

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

Page 21: Mocast Postmortem

Wrong: The “Episode Class”

Doesn’t Work :-(

Page 22: Mocast Postmortem

Wrong: The “Episode Class”

Page 23: Mocast Postmortem

Wrong: The “Episode Class”

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

Page 24: Mocast Postmortem

Wrong: The “Episode Class”The Fix

Page 25: Mocast Postmortem

Wrong: The “Episode Class”The Fix

Page 26: Mocast Postmortem

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

Page 27: Mocast Postmortem

Wrong: Threaded ObservableQueries

The FixInstead of:

!ObservableQuery (Func<T> source)!

!I should have:

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

Page 28: Mocast Postmortem

Wrong: iCloud Sync

• Wonderful because it’s simple

• BUT very small storage size:

• 1,000 keys

• 1 MB data

Page 29: Mocast Postmortem

Wrong: iCloud Sync

• Use CloudKit!

The Fix

Page 30: Mocast Postmortem

Wrong: Manual Entity Binding

Page 31: Mocast Postmortem

Wrong: Manual Entity BindingThe Fix

?

Page 32: Mocast Postmortem

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)

Page 33: Mocast Postmortem

• 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

Page 34: Mocast Postmortem

Thank you!

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