Realm is a popular database for mobile, already used in thousands of apps and deployed on over a billion devices. In this talk from Mobilization Conference, Marius will show how you can craft reactive applications (especially if you embrace persistence and state as a central part of your application architecture) by using the unique features of this database. He will also explore how this can be extended on multiple devices and the server-side with the recently launched Realm Mobile Platform and its synchronization capabilities.
The Reactive Manifesto (2:00)
What does it mean for apps to be “reactive”? Reactive apps should be:
-
Responsive: They should update a UI as soon as there’s new data, and they should not be blocking. A user should also be able to interact with it.
-
Resilient: They should work without an internet connection.
-
Elastic: We reach this goal by our concept of lazy objects and zero copies to be super efficient.
-
Well driven: Specifically for Realm, this is also true for the atomicity of the objects and transactions. You have a message-driven, event-driven concept.
You’ll find that you don’t need even ReactiveCocoa, RxSwift, RxJava, or ReactKits to build reactive apps.
The Realm Mobile Database (4:02)
The Realm Mobile Database is available for both iOS and Android. Since it launched, it had native platform language support in Java and Objective-C. Last year, we also launched bindings for React Native and Xamarin, so you can even use cross-platform development technologies to build your apps using Realm.
Our Realm core has also been completely open sourced as of the introduction of Realm Mobile Platform.
So what is the Realm Database, and what is it not? It is not an ORM. Rather, it is the database itself you work with. With Realm, you are directly interacting with the database. It’s an embedded NoSQL object oriented database. “Embedded” specifically means that it was built from scratch for mobile.
What does NoSQL mean? To directly avoid any misunderstandings, Realm has affixed schemas; it’s not schema-free, which would be too inefficient from our view on mobile over hardware constraints. Lastly, it’s object-oriented.
What does it look like? Let’s jump into some code.
import UIKit
import RealmSwift
class Person: Object {
dynamic var name = ""
dynamic var age = 0
let children = List<Person>()
let parents = LinkingObjects(fromType: Person.self, property: "children")
}
let person = Person()
person.name = "Craig"
person.age = 47
let realm = try! Realm()
try! realm.write {
realm.add(person)
}
You define your schema directly in code, and you don’t have anything like xcdatamodel or database schema persisted in your database.
This is in Swift, but it’s very similar across platforms. For Java, you would use notations. You derive from one common superclass, which for Swift is just called Object
, and then you have properties and atomic data types of the language here for the Person
object. You can define the types in Swift, as it’s a strongly typed language, by setting default values.
We have relations, which are also first class citizens. You don’t have to introduce any foreign key concepts which are not part of your schema, but are artificially introduced. You have relay links between your objects so children point to other Persons
, a specific array to be called in a list. You can also have backlinks based on that, where you link to another class. This is rough in this case, linking back to the Person
object here, and over the children attribute to get to the appearance of a person.
You could also do this in other cases; it’s possible to link back any one-to-many or many-to-many link. Based on this, you can create objects like you would with any other objects you define in an object-oriented language. To add them to the database, you make a write transaction and add them to the Realm. They will be in a specific Person table. It’s not completely un-ordered, so there is still the concept of table, even though it’s NoSQL.
Objects All the Way Down (10:56)
Even within your database, you’ll have objects all the way down. More specifically, Realm skips to copy; when you interact with objects, you interact directly with memory updater. All retrieved objects are just pointers to the data.
Implications
This has some far-ranging implications. Notifications that we have seen already when adding an object are only possible within a wide transaction. So, we have to do our transaction to add an object, and we would also need to do this to delete objects or to modify objects directly. Out of the scope of a write transaction, it’s best if we have value object.
I want to briefly go over the ACID principle for databases:
- Atomicity
- When you have a transaction that ever goes through or not, all or nothing.
- Consistency
- You go from one valued state to no valued state.
- Isolation
- When you execute multiple transactions in parallel, you can map those to a sequential order of these transactions.
- Durability
- Once something is committed, it will remain, and there’s no data loss at any time. When your app crashes or your device decides to kick your app out, the database has to be robust in such cases.
We achieve all of this by using a multi-version concurrency control algorithm. This sounds complicated, but it has implications for how you use Realm in a multi-failure or a multi-process environment.
Multiversion Concurrency Control (10:56)
When creating an algorithm, it will allow you to do several read transactions. These have been done implicitly in other databases, but with Realm, you do them more explicitly by pulling stuff out of the database and copying it.
In a naive database, you wouldn’t allow it to do any reads or writes because you would read out or there would be the possibility that you would read out corrupted or incompletely serialized data. Once the commit is through and your writes are actually in the file, then you would allow reads again. This is not the way we solve this problem.
Instead, the CC algorithm looks more like a Git without branches. It partially stores the history of what you did with your database. Once you do a write transaction, the data is forked so you can write a new version. The fork allows for retention of your old version, so you can still read from other threads and from other processors.
You have one thread, for example, where you’re making modifications to your database contents. Once the commit is through, other processes can help, and if you’re sending multi-network requests which all want to write something to the database, they can read from the data in the database. Once that commit is through, your UI thread can then update to the latest data.
If you spawn a lot of threads, they couldn’t be freed up as long as they are still a thread which is stuck in one particular version. For iOS and Cocoa specifically, there’s only a run loop on the main thread and not on the background threads. You would need to send them up yourself on the background threads. Based on that, we can have built-in notifications in the database.
Built-In Notifications (17:42)
Whenever something happens to your database, you can hook in and wait for specific events. These are possible on a wide range of granularities. File-wide observations seem to be pretty simple, even if you take a naive approach to implementing your database.
Beyond that, you can even have fine-grained notifications on collections so you can make queries for a specific subset, for instance all persons over the age of 30. Only if this specific collection is changed would get an update, and the update includes the specifics of what has changed within the collection.
That’s not even the finest level of granularity, it’s even possible to observe in the middle object properties. If I have one Person and I want to observe just the property “name”, then I would directly get an update if the name changes.
Deployment (20:45)
The Realm Mobile platform extends what you already have available on the client-side to the service side. Together with synchronization, this means that Realm can also work on the server-side and you connect it from the mobile side with just a few lines of code.
What does this change for the deployment options you have? On iOS and Android, and on the server-side, we now offer a OGS binding, and as you might expect, we didn’t go for the classic SAAS business model. Instead, we are giving you the server and you can deploy it yourself.
You can use it on your existing infrastructure or on your cloud of choice. You can easily use it on Ubuntu or on AWS, and there is also a developer edition which is available for free. You can run it with a simple app on iOS 10, for example.
Use Case: Device Backup
One use case is where we have one Realm client-side and one on the server-side, and it could be a device backup already; as simple as that. However, we can even extend this to offer far more than that.
Use Case: Cross-Device Sync
One scenario is where your app is supported on a phone and tablet, and you would use it at different times of day, say on a different device. You would always want the latest and greatest data available. By using Realm to give the user authenticated synchronization, you have that ability; you can connect multiple client-side Realms to the same server-side Realm.
As for conflicts, imagine I make a change on mobile and have been offline, and then in the evening I make another change on my tablet. The next day, I realize my phone wasn’t connected to the internet. Conflicts which may have happened in these cases will be automatically resolved. It won’t bother you, and there will be no loss of data.
Use Case: Real-Time Collaboration
When we launched our product, we had a blog post featuring our Canvas app, where we had two of our team members drawing something, and even showed a use case of internet connection loss.
Use Case: Replace Your Backend
We were thinking of using this as a replacement for whiteboards for all our meetings; when you’re working remotely as we do, it’s kind of hard to work conceptually together. Having a physical white board on a video call doesn’t allow everybody to collect or contribute in the same way. If you go a bit further and really want to go all in, you could even replace your existing backend with this technology. You can have multiple client-side databases. One of these could be private for your user, and another one could be shared across users, in a crew.
You can also use it for messaging, or it could be completely mobile and available to all users and read-only, so that users can get things like store locations, or something you want to push out to everybody that doesn’t update often.
Ban JSON From Your App (26:42)
If you really go all-in, you could ban JSON from your apps. If you’re developing on multiple platforms, JSON mapping isn’t a trivial problem. There are so many JSON frameworks for solving the problem in a type-safe language to map JSON to your objects. It must be clear this problem is not trivial, and doing it in a convenient and consistent way across all your mobile apps on all platforms is already helpful.
You have your model on your server-side, then you have to serialize that and POST something, and share data to do so. You have to serialize it to the string representation of JSON, and then you need to encode it for your HTTP request, and that would be sent to the server over HTTP, which is also not trivial in itself, and would be taken care of by Realm Mobile platform. On the server, you have to go all the way back.
Event Handling
Suppose we have an app we have built for a sports chain, and we have stores, coupons etc. In the app, you want to validate that specific components are valid, so you create a component. Once it is created, it will be sent to the server. There, it will trigger an event-handling framework, the event and the new code will pop up, and it will be processed.
You can do a validation check - maybe look it up in a global database which contains old components that are valid; this would be coming from a user-specific database where only the user can read and write, and then you would just do a modification to the object and say, “yes this component is valid.” This would be synchronized back to your client.
You could have notifications previously set-up on the specific property on your component object, and once you get the status change, you would get this in your app and could directly update your app from that. That is all just with handling your business object logic, so the only thing you do in your app logic is object-oriented programming.
Built-In Notifications
We can extend our list of built-in notifications by having the possibility on the server-side for observing all Realms. Suppose we have created a coupon object on the client-side. It will be part of the Realm on the client-side, and for the synchronization server, we have a divisive environment boundary. Because we did a wide transaction and made a modification, we can derive the actual change and only have to send over the buyer that there was an object created. This object will be made available on the server-side and on the server-side Realm. The event processing framework will listen for this specific Realm and will see the new coupon object.
You do this modification to the server-side Realm. This would be synchronized back to the client, so it’s very light-weight. However, there could be other effects. Say in a different scenario, there’s a customer on the app and one in the store; you could trigger that there’s a new object created here, there’s a customer who wants to use a coupon code, and this will be made available to a Realm which is shared with the seller and customer; they’ll be propagated through, and you could also see it in a different app.
Q&A (33:34)
Q: Can you tell us the cost of creating this small Realm for users in the example?
Marius: To keep separate Realms for thousands of users in one single instance, the Realm Object Server is already capable of handling 100,000 connections concurrently, as in open at the same time and interacting with data. You can have even more Realms than that. Each Realm will store the schema individually, so there’s a little overhead there, but this is not shared across all user-specific Realms, even if they would have the same schema, so you don’t need to set it up on the server-side at all. You only encode a schema within your object model on the client-side, so when you change something, you can do additive schema changes in your apps. It will then be propagated individually for each user and made available.
Q: Are you implementing this only in Java, or are you using a native code like C++?
Marius: The core of Realm is based in C++. For Java, we’re using JNI to make that available to Java, and there’s some API code, but yeah, it’s native framework.
Q: Is Realm testable?
Marius: We try really hard to test the Realm Mobile Platform, and it’s already been through the works. We did a lot of housing and testing on a scale to be confident enough to actually ship this product to our users and to our interested customers.
For the Realm Mobile Database, it’s possible to use Realm in memory and without having it synchronized on disk. This makes it possible to set up a database fixture very easily because you don’t have any overhead; you just open up your Realm in memory with your schema, and it will be bootstrapped for you (you don’t have to take care of setting the database up), and can create objects. Often, tests make modifications to that, and after will be just done, it won’t be any immature run. I think this helps a lot in testing, and that’s what we use for our own example apps.
Receive news and updates from Realm straight to your inbox