Mocast Postmortem
Frank 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 Design
Goal: 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 Fix
Instead 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 Binding
The Fix
?
Wrong: Manual Entity Binding
The 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

Mocast Postmortem

  • 1.
    Mocast Postmortem Frank A.Krueger Seattle Mobile .NET July 1, 2014
  • 2.
    What’s a Postmortem? Aftera 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
  • 3.
    What’s a Mocast? •Podcast player • Thumb-friendly UI • Emphasizes the full catalog • ADD-friendly UI
  • 4.
  • 5.
    Right: UI Design Goal:Make it iOS 7-y
  • 6.
    Right: UI Design Goal:Make it iOS 7-y Goal: Non-modal (no Now Playing screen, no Episode screen)
  • 7.
  • 8.
  • 9.
  • 11.
  • 12.
    Right: Reliance onBindings INotifyCollectionChanged INotifyPropertyChanged
  • 13.
    Right: Reliance onBindings • Producers: • ObservableCollection • ObservableQuery! • Consumers: • ObservableTableView
  • 14.
    Right: Reliance onBindings • 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”
  • 16.
    Right: iCloud Syncing •Mocast uses iCloud Key-Value store • Very simple API, very simple update model
  • 17.
  • 18.
    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 ();
  • 19.
  • 20.
    Wrong: The “EpisodeClass” • 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
  • 21.
    Wrong: The “EpisodeClass” Doesn’t Work :-(
  • 22.
  • 23.
    Wrong: The “EpisodeClass” I allowed the data source API to dictate my domain model :-(
  • 24.
    Wrong: The “EpisodeClass” The Fix
  • 25.
    Wrong: The “EpisodeClass” The Fix
  • 26.
    Wrong: Threaded ObservableQueries • Todo 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
  • 27.
    Wrong: Threaded ObservableQueries The Fix Insteadof: ! ObservableQuery (Func<T> source)! ! I should have: ! ObservableQuery (Func<Task<T>> asyncSource)
  • 28.
    Wrong: iCloud Sync •Wonderful because it’s simple • BUT very small storage size: • 1,000 keys • 1 MB data
  • 29.
    Wrong: iCloud Sync •Use CloudKit! The Fix
  • 30.
  • 31.
    Wrong: Manual EntityBinding The Fix ?
  • 32.
    Wrong: Manual EntityBinding The Fix There just aren’t many good declarative data binders out there: ! My Bind Library That Reactive Library MvvmCross BindableObject / Dependency Properties (haha)
  • 33.
    • Require re-architectingaround their pattern • Make for great demos, but have real-world issues: • async • reference cleanup • throttling • deep hierarchies • greedy events • … Wrong: Manual Entity Binding
  • 34.
    Thank you! • Mocastwill be available on iPhone/iPod in a couple weeks