Mobilization mvvm nikola header

Database-driven UI with MVVM and Realm

In this talk, I will show how to simplify an app’s architecture by letting the database drive the UI. We’ll explore powerful features of Realm such as change notifications and automatic updates to ensure we never have to manually update the UI again.


Introduction

My name is Nik, and I lead the .NET team at Realm. I want to cover the topic of simplicity and elegance in code. A few years ago, when I was in college, I made the most important decision of my life. I chose theoretical physics rather than computer science. It was the best decision ever because I got to explore the inner workings of the universe from subatomic particles all the way to black holes. What stuck with me most was how simple the laws of nature are, yet how complex it is to derive them.

For example, look at Schrödinger’s equation. It lays out the foundations of modern quantum mechanics, the field that deals with phenomena at a very small scale. Below that, on the other end of the spectrum is the Schwarzschild radius which tells us when an object becomes a black hole. You see a huge range of those equations, but they’re both really simple and elegant.

01-Mobilization-2017-REALM-Nikola-Irinchev-Schrodinger-eq

How is this relevant to us? If we can express the most complex of phenomena in the known universe in these really simple and elegant equations, then why do I need to write 120 lines of code just to update the label on my UI when some property changes on the backend?

Get more development news like this

I strongly believe that code elegance and simplicity are just as important to the success of your product as design.

What is MVVM?

MVVM was conceived by Microsoft architects in 2005 when they were trying to figure out a way to showcase the power of data binding in their cool new frameworks, WPF and Silverlight.

In its very essence, MVVM is an architectural pattern that defines a very strict chain of ownership and awareness of who knows what and who reports to whom. The three components are the Model, the View Model, and the View. The Model and the View Model are highly testable view-agnostic components, and a single UI component, the View, is separated from the rest, which front-end developers can work on individually.

Model

The Model is usually the most unambiguous and well-understood component in this pattern. Models contain all your business networking and persistence logic, and other things that are not directly related to your UI.

View

The View is responsible for defining the structure, the layout, the appearances, colors, animations, of your application. They should contain no business logic, no conversions. Ideally, they should contain no code at all.

For example, with XAML, which is Microsoft’s way of defining user interfaces, views are defined in an HTML-like syntax. With Cocoa or Swift, you may need to write some code for Interface Builder classes. Typically, views are not reusable outside of a single application unless they’re something very generic, such as a login screen or a settings screen may be reused across applications.

View Model

View models are something in between views and models. View models are responsible for massaging the models in a way that can be consumed by the view. For example, this can be done by combining data from several different models or converting data in the model to a view consumable format. For example, you can convert Boolean properties to colors or string paths to images. This is what the view model would look like in Swift:

public class PersonViewModel : INotifyPropertyChanged {
	public event PropertyChangedEventHandler PropertyChanged;

	private string firstName;
	public string FirstName
	{
		get { return this.firstName; }
		set { Set(value, ref this.firstName ); }
	}
	...
	private void Set<T>(T value, ref T field, [CallerMemberName] string propertyName = null)
	{
		field = value;
		PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
	}
}

View models can also contain commands that the view can invoke, such as when saving or deleting items, or changing the value in response to pressing a button. Those commands or events are later proxied to your models which are responsible for persisting the data or sending it to your services over the internet.

Unit Testing

The main selling points of your models are not so much their reusability, but their unit-testability. Because View Models do not depend on UI code, They should have no reference to UI frameworks, you can unitize them: you can invoke their commands from your unit tests, pretending you are the view and inspect how their properties change.

Lightweight Objects with Realm

Realm is a database that is mostly used on mobile. It is different from SQLite or Core Data or similar databases in that it is an object database.

The objects you work with in your application are the same objects that get persisted on disk. There is no intermediate layer, and there is no type conversion like in traditional SQL. As a result, objects in Realm are extremely lightweight. They never copy their data from disk to memory. Instead, internal functions and some metadata allow us to figure out the exact address at which the data is stored.

So, for example, when you access a firstName property on an object, you do not get some cache throughout data that’s an in-memory representation of this string. Instead, we look it up, look at this property, find the offset and the length of the property on disk, read it, and return it to you. When you access it the second time, Realm does this again, and you will get the most up-to-date version that is saved in the database.

There are two ways in which Realm simplifies MVVM code. First, it eliminates the need for the view model to make complicated decisions about what the view is going to need. For example, if I want to display a Person, I don’t need to fetch the entire Person. I can just fetch the Realm model and pass it to the UI. Secondly, is that since we no longer need pagination; we don’t need to hook up scrolling events and go into the view model to fetch new data all the time.

Realm is a Live Object Database

When there’s no intermediate layer between your objects and your database, Realm objects and collections can be notified whenever something changes from the disk, regardless of where it originated from. This makes Realm a live object database. This puts Realm objects at the intersection of models and view models and allows you to pass them directly to your view and have the view data bind to properties.

Data Binding

Suppose that you want to expose all the people in your database ordered by the first name property. You can create the Realm query and data bind to it. As new data comes into the database, regardless of where it originates, Realm will emit notifications and tell your list view that the order has changed, or that new objects have been inserted or deleted.

In .NET, there’s a single data binding engine that is a built-in mechanism for that. Realm objects are supported out of the box. In Swift or Java where there are many third party data binding libraries, you may need to manually handle the notifications, or you could use some of the third party data binding libraries. One of the most popular of these for Swift is Bond. Obviously, you can use ReactiveExtensions.

Simplified Data Updates Demonstration

Let’s see some of the steps involved with fetching data from the server in a non-Realm scenario. First, the user requests an update by pressing a button. This, in turn, triggers a REST API call which fetches information from your server, and you deserialize and process the returning data.

The views contain references to different View Models, and you have to find all that may potentially be affected by these changes - this is a difficult task. You have to keep a reference to all the View Models you created and then walk through them and find them. You can either diff them, or you can reload the data.

A talk called offline-first by Miguel Quinones illustrates why reloading data is an extremely poor user experience.

In a shared shopping list, for example, I only want what needs to be updated to be updated. Suppose you decide to diff the changes, you are still faced with the problem of notifying all your view models or the affected view models that something has changed, or notifying their parents that their underlying view models have changed. Only if everything has been wired correctly, your UI will update correctly.

If you use Realm, you eliminate that complexity. You just save to disk and let Realm handle the rest. Realm sits at the bottom of your application at the persistence layer. As a result, it knows when a property or collection has changed and will notify the Realm objects that are still alive. The MVVM benefits are free out of the box, and you lose nothing from using Realm.

new

Next Up: The Offline-first Approach to Mobile App Development

General link arrow white

About the content

This talk was delivered live in October 2017 at Mobilization. The video was transcribed by Realm and is published here with the permission of the conference organizers and speakers.

Nikola Irinchev

Nick has extensive experience with everything .NET - from architecting highly performant web servers to shipping cross platform mobile apps, you name it. Now he resides at Realm, delivering the best database in the world to .NET developers. When he’s not doing that, he speaks about cloud infrastructure and occasionally blogs about the hard problems he faces.

4 design patterns for a RESTless mobile integration »

close