github halp app - minimizing platform-specific code with mvvm - justin spahr-summers

31
( 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).

Upload: xamarin

Post on 30-Apr-2015

55.185 views

Category:

Technology


2 download

DESCRIPTION

 

TRANSCRIPT

Page 1: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

( And Halp clients )

Code Reusewith MVVM

1Dienstag, 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).

Page 2: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

2Dienstag, 16. April 13

But first, let me introduce myself and the other guys who worked on this app.

Page 3: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

Who

Justin Spahr-Summers - @jspahrsummers

Paul Betts - @xpaulbettsx

Josh Vera - @joshvera

Josh Abernathy - @joshaber

3Dienstag, 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.

Page 4: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

What

Write unit tests for UI behavior

Example: our native Halp apps

Maximize code reuse across platforms,

but keep 100% native UI

4Dienstag, 16. April 13

Halp is an internal app that we use at GitHub for user support (but more on that later).

Page 5: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

Why

“Build software better, together.”

At GitHub, we ask: “What is the best way to build software?”

Philosophies, tools, practices

5Dienstag, 16. April 13

One of the questions _we_ work on every day is, “What’s the best way to build native user interfaces?”

Page 6: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

View Model

Controller

How( According to )

6Dienstag, 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).

Page 7: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

View ViewModel Model

How( According to us )

7Dienstag, 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.

Page 8: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

Meh. So what?

8Dienstag, 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.

Page 9: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

Benefits of MVVM

✓ View models are testable, no UI

automation required

✓ View models can do model-like

things (e.g., serialization)

9Dienstag, 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!

Page 10: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

Also, portability!

10Dienstag, 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.

Page 11: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

Model-View-Controller

View Model

Controller

11Dienstag, 16. April 13

The blue circle here is the code we can share across platforms.

Page 12: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

What’s Shared?

Xamarin means we only have to write

our models once, in .NET

Any networking and domain logic

is trivially cross-platform

12Dienstag, 16. April 13

Page 13: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

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

13Dienstag, 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.

Page 14: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

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)

14Dienstag, 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.

Page 15: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

Model-View-ViewModel

View ViewModel Model

15Dienstag, 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…

Page 16: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

View Models Handle…

Loading content the UI needs

Hiding and showing content

Date, number, and string formatting

Responding to the user

16Dienstag, 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.

Page 17: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

Halp!

17Dienstag, 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.

Page 18: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

18Dienstag, 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.

Page 19: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

19Dienstag, 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.

Page 20: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

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)

20Dienstag, 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.

Page 21: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

iPhone App Goals

View the messages in any inbox

Read any message

Triage messages by moving to another inbox

21Dienstag, 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.

Page 22: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

(Demo)

22Dienstag, 16. April 13

Page 23: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

Shared Behaviors

Showing inboxes and messages

Requesting and caching data

Showing loading indicators

23Dienstag, 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)

Page 24: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

(Code)

24Dienstag, 16. April 13

Page 25: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

Let’s get real.

25Dienstag, 16. April 13

Cocoa wasn’t really designed with MVVM in mind. Here are some minor obstacles you may encounter.

Page 26: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

View Controllers

Layout, animations, device rotation,

view transitions

Seems like view controllers are

actually part of the view layer!

26Dienstag, 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.

Page 27: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

View Controllers

NSViewController doesn’t do much

UIViewController is quite powerful

Between views and view controllers,

use the easiest one

27Dienstag, 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.

Page 28: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

Data Binding

Notifications are too general,

and have global scope

Key-Value Observing is difficult

to use and comes with boilerplate

28Dienstag, 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).

Page 29: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

Data Binding

In Objective-C, we wrote a

framework called ReactiveCocoa

In C#, we have Reactive Extensions

and our ReactiveUI framework

29Dienstag, 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.

Page 30: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

30Dienstag, 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.

Page 31: GitHub halp app - Minimizing platform-specific code with MVVM - Justin Spahr-Summers

LinkageRx – introtorx.com

ReactiveUI – reactiveui.net

github:mac – mac.github.com

github:windows – windows.github.com

31Dienstag, 16. April 13