Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Code Reuse with MVVM

Code Reuse with MVVM

My Xamarin Evolve 2013 talk.

Video available at: http://xamarin.com/evolve/2013#session-zm59b5yptf

Justin Spahr-Summers

April 16, 2013
Tweet

More Decks by Justin Spahr-Summers

Other Decks in Programming

Transcript

  1. ( And Halp clients )
    Code Reuse
    with MVVM
    1
    Dienstag, 16. April 13
    High-level talk, mostly focused on Apple (because that’s my forté), but most of the concepts here are generally applicable to all
    platforms (and that’s exactly the point).

    View Slide

  2. 2
    Dienstag, 16. April 13
    But first, let me introduce myself and the other guys who worked on this app.

    View Slide

  3. Who
    Justin Spahr-Summers - @jspahrsummers
    Paul Betts - @xpaulbettsx
    Josh Vera - @joshvera
    Josh Abernathy - @joshaber
    3
    Dienstag, 16. April 13
    I work on GitHub for Mac. I primarily write Objective-C code, but I also regularly code in Haskell as well. Paul works on GitHub for
    Windows (written in C#), Josh Vera works on an internal talks app written in Objective-C, and Josh Abernathy also works on
    GitHub for Mac.
    There’s quite a large diversity of experience between us, and I’ve included these guys on here because they all had something do
    with this presentation today.

    View Slide

  4. What
    Write unit tests for UI behavior
    Example: our native Halp apps
    Maximize code reuse across platforms,
    but keep 100% native UI
    4
    Dienstag, 16. April 13
    Halp is an internal app that we use at GitHub for user support (but more on that later).

    View Slide

  5. Why
    “Build software better, together.”
    At GitHub, we ask: “What is the best way to build software?”
    Philosophies, tools, practices
    5
    Dienstag, 16. April 13
    One of the questions _we_ work on every day is, “What’s the best way to build native user interfaces?”

    View Slide

  6. View Model
    Controller
    How
    ( According to  )
    6
    Dienstag, 16. April 13
    As recommended by Apple, Cocoa applications are typically designed using Model-View-Controller, shown here. The solid lines
    represent direct references; the dashed lines represent indirect references (like observation).

    View Slide

  7. View ViewModel Model
    How
    ( According to us )
    7
    Dienstag, 16. April 13
    At GitHub, we much prefer to use Model-View-ViewModel, shown here. If you haven’t been introduced to MVVM, here’s a quick
    explanation:
    The ViewModel replaces the role of the (View) Controller, but the VM doesn’t have a direct reference to the view like a controller
    would. Instead, the VM communicates to the V with a system of bindings. … For example, If you want to show a loading spinner,
    the view model might have a boolean property which indicates whether to show it. The view would observe that property for
    changes, and hide/show the spinner in response.

    View Slide

  8. Meh. So what?
    8
    Dienstag, 16. April 13
    This might just seem like a way to restate the MVC pattern, but the reversed relationship between the View and the ViewModel
    offers huge benefits.

    View Slide

  9. Benefits of MVVM
    ✓ View models are testable, no UI
    automation required
    ✓ View models can do model-like
    things (e.g., serialization)
    9
    Dienstag, 16. April 13
    Traditionally, view controllers rarely get unit tested in Cocoa, simply because it’s such a pain to write a controller that doesn’t
    depend on having a view (or, alternatively, to set up a valid view in unit tests). Since the VM doesn’t even know about view
    objects, they can be tested without a GUI at all!
    Serialization: for example, to save and restore the state of your UI, you can just save and restore your VM hierarchy. Doing this in
    MVC would require a separate set of “view state” objects – which are basically view models anyways!

    View Slide

  10. Also, portability!
    10
    Dienstag, 16. April 13
    I mentioned code sharing between platforms, so let’s take a look at how that works in MVC and MVVM. Naturally, we’ll assume
    the use of Xamarin for both.

    View Slide

  11. Model-View-Controller
    View Model
    Controller
    11
    Dienstag, 16. April 13
    The blue circle here is the code we can share across platforms.

    View Slide

  12. What’s Shared?
    Xamarin means we only have to write
    our models once, in .NET
    Any networking and domain logic
    is trivially cross-platform
    12
    Dienstag, 16. April 13

    View Slide

  13. What’s Unique?
    We want 100% native UI on each
    platform – no Qt, GTK+, or Java
    To do this, we need to create views
    specific to each platform
    13
    Dienstag, 16. April 13
    This makes sense and is perfectly appropriate. Sharing view code leads to lower-quality apps which cater to the lowest common
    denominator and ignore each platform’s individual UI conventions.

    View Slide

  14. What’s Unshared?
    Logic for when to fetch
    resources from the API
    UI behaviors
    (e.g., how to populate lists, or when to show spinners)
    14
    Dienstag, 16. April 13
    If we follow MVC, we’re also rewriting this logic for each platform (as part of our controller layer), even though it’s not platform-
    specific. This is code that _should_ be shared, but isn’t.
    Now, let’s contrast that with MVVM.

    View Slide

  15. Model-View-ViewModel
    View ViewModel Model
    15
    Dienstag, 16. April 13
    Interestingly, because the VM doesn’t reference the view (or any UI) directly, it becomes reusable across platforms. The VM
    describes only how the UI should update and respond to user actions – not how it should look. Multiple types of view can be
    created for one view model, and each can look completely different, but most of the underlying logic will remain the same.
    If we’re using Xamarin, we can now write most of our model _and view model_ code just once. The VM implements most of our
    UI behavior, like…

    View Slide

  16. View Models Handle…
    Loading content the UI needs
    Hiding and showing content
    Date, number, and string formatting
    Responding to the user
    16
    Dienstag, 16. April 13
    There are just some typical use cases, not a complete list.
    Loading: note that the view model is not actually responsible for the details of persistence, networking, etc. It’s only responsible
    for communicating with whatever that layer is, _based on_ what the UI needs to show at any point in time.

    View Slide

  17. Halp!
    17
    Dienstag, 16. April 13
    That’s most of the abstract stuff. I want to switch gears for a moment here and talk about our support tool, and the native clients
    we’re implementing using MVVM and Xamarin.

    View Slide

  18. 18
    Dienstag, 16. April 13
    This is the web app that we use for user support. It lets us triage our users’ emails and get them to the right people as quickly as
    possible. Supportocats and developers can reply to messages, bring other people into the discussion, cross-link to other internal
    resources, etc.
    Here, we’re looking at a discussion thread in the Technical inbox.

    View Slide

  19. 19
    Dienstag, 16. April 13
    GitHub is based in San Francisco, but about half of GitHub works remotely on a regular basis (I myself work from Seattle). Twice
    every year, all of the company meets in SF for GitHub Summit.
    Our last summit was earlier this year, and a few of us wanted to spend our Hack Day working on a native client for Halp. We
    decided to use Xamarin to share code between our different desired platforms, and reduce the development and maintenance
    effort that would otherwise be involved in each one. We started the iOS client that day, and a Mac client since.

    View Slide

  20. Mac App Goals
    Watch a specific inbox for new messages
    Display a message count in the menu bar
    View the messages in any inbox
    (but especially the watched one)
    20
    Dienstag, 16. April 13
    This is what we want to do for our Mac client.
    We’ve started on a prototype. It’s still very premature, so it doesn’t do much yet.

    View Slide

  21. iPhone App Goals
    View the messages in any inbox
    Read any message
    Triage messages by moving to another inbox
    21
    Dienstag, 16. April 13
    And this is what we want to do for our iPhone client. (An iPad client would be very similar as well.)
    This one’s a bit further along, but still pretty rough around the edges. All the data here is loaded from the API and cached locally
    by the app.

    View Slide

  22. (Demo)
    22
    Dienstag, 16. April 13

    View Slide

  23. Shared Behaviors
    Showing inboxes and messages
    Requesting and caching data
    Showing loading indicators
    23
    Dienstag, 16. April 13
    By no coincidence, these are the behaviors implemented by our cross-platform view models.
    Let’s take a look at the code. (ViewModels, MenubarController?, PopoverController?, TableSources)

    View Slide

  24. (Code)
    24
    Dienstag, 16. April 13

    View Slide

  25. Let’s get real.
    25
    Dienstag, 16. April 13
    Cocoa wasn’t really designed with MVVM in mind. Here are some minor obstacles you may encounter.

    View Slide

  26. View Controllers
    Layout, animations, device rotation,
    view transitions
    Seems like view controllers are
    actually part of the view layer!
    26
    Dienstag, 16. April 13
    OS X and iOS both have view (or window) controllers, which can make MVVM confusing at first glance. Once you look deeper,
    though, it’s not much of a problem at all.

    View Slide

  27. View Controllers
    NSViewController doesn’t do much
    UIViewController is quite powerful
    Between views and view controllers,
    use the easiest one
    27
    Dienstag, 16. April 13
    Basically, use the class that will make implementing your view layer easiest. On OS X, you’ll probably just want NSView, since
    NSViewController is relatively useless. On iOS, you’ll probably want UIViewController, so you can handle rotation, navigation, etc.
    No matter what you decide to use for your UI, you’ll still have a ViewModel.

    View Slide

  28. Data Binding
    Notifications are too general,
    and have global scope
    Key-Value Observing is difficult
    to use and comes with boilerplate
    28
    Dienstag, 16. April 13
    It’s hard to write the indirect relationship from the ViewModel to the View without a powerful system of bindings. Cocoa (and, by
    extension, Xamarin.Mac and Xamarin.iOS) offers a couple solutions, but they’re woefully inadequate.
    In addition to these individual problems, neither supports automatic transformation or filtering of bound values. Worse, both are
    specific to Cocoa, so our V <> VM bindings will look quite different from our VM <> M bindings (which should be cross-
    platform).

    View Slide

  29. Data Binding
    In Objective-C, we wrote a
    framework called ReactiveCocoa
    In C#, we have Reactive Extensions
    and our ReactiveUI framework
    29
    Dienstag, 16. April 13
    Reactive Extensions (or Rx) is an implementation of Functional Reactive Programming, which is unfortunately beyond the scope
    of this talk, but there are lots of great resources for learning more about it.
    ReactiveUI is an MVVM framework for .NET. One of its major features is an API for declarative data bindings, built on top of Rx.

    View Slide

  30. 30
    Dienstag, 16. April 13
    GitHub for Mac uses ReactiveCocoa to implement MVVM at a large scale. The app itself is written in Objective-C, but the lessons
    we’ve learned about MVVM are just as applicable to Xamarin.Mac and Xamarin.iOS.

    View Slide

  31. Linkage
    Rx – introtorx.com
    ReactiveUI – reactiveui.net
    github:mac – mac.github.com
    github:windows – windows.github.com
    31
    Dienstag, 16. April 13

    View Slide