Perhaps many of you have heard, read or seen something about Model-View-ViewModel as an alternative to the most known MVC or MVP.
In this introduction, I will attempt to explain how and why to apply this software architectural pattern, and in a second post we are going to show how this Architecture interacts with the series of tools that Google introduce during the Google IO 2017: Android Architecture Components.
The more I’ve grown in experience as a software developer, the more I changed my belief about the so famous good practices of programming. I believe we all agree in this path. As your personality evolves, also your software development skills does. And to make that happen, you have to be informed and flexible about tendencies that might come up.
The presentation of Architecture Components as a library to speed up the MVVM architectural development was one of the most relevant for android lovers back in May, 2017. I felt overwhelmed at first but we gave it a try, we started studying it and applying some of it. Today we find ourselves in a real project, with a huge growth rate, applying all the practices that android sets as a path to a Clean Architecture, and using most of these components to build a solid, robust and easy maintainable product.
Let’s take a look.
Model-View -ViewModel is an architecture that emphasizes the “separations of concerns”, in another words, the abstraction between layers.
“It allows to separate the UI from the business logic”, this is what is mentioned by every architecture pattern we ever heard of. For example, one of MVP goals is to achieve this. However with MVVM you find a complete abstraction between the business logic and the UI.
Lets analyze the acronym letter by letter to help you to get the idea.
- ‘M’ for Model
Its data. As simple as that. Model equals data. The business logic of an app. But what do we do with the data? What consumes it? This layer, how does it abstract itself? Very simple. Data to be consumed purely and exclusively by ViewModel.
2. ‘V’ for View
This is a tough one. A good question for an interview with an android developer. What is the View of an app? An Activity? An xml? A fragment? All the previous ones?
If we watch MVP behavior, Activity/Fragment are considered part of the View. As good practice the View implements a contract for the Presenter to have an interface to write.
Advantages? It allows simple unit testing as a mock of the View. Very nice.
In MVVM, also Activity/Fragment are part of the View, its role is to check the data that ViewModel manipulates and to react with the variations in order to update the UI. So what is the difference with MVP? ViewModel does NOT know the View. The view is Unbekannt for the ViewModel. Anyone knows why this is best? I do. Decoupling. Keep reading.
3. ‘VM’ for ViewModel. Our star in the sky.
Theory says that it interacts with the model, and prepares the observables that are going to be observed by the View.
That’s it? No.
Lets dig a little deeper.
Concerning Android Components, the ViewModel objects scope is tied to theirs lifecycle owner. What does it means?
Let’s analyze this snippet.
Note: We use Dagger 2 to achieve dependency injection. Dagger is an static compile-time dependency injection framework. Its an adaptation from an old Square version, now developed and maintained by Google.
In a future post we are going to dig a little bit more into this framework, but know I want you to know that it is going to help us to reduce boilerplate and avoid strong dependencies between objects.
In order to keep our view model free of unnecessary external dependencies, we declare a ViewModelFactory and we inject parameters into its constructor.
ViewModelProviders is an utility class that provides ViewModels for a scope. We use the default ViewModelProvider for our Activity with two parameters:
It’s talking about the lifecycle owner that is creating the viewmodel.
The already mentioned factory injected with Dagger.
This ViewModel objects have as scope the lifecycle of its owner. This means that, when its owner’s lifecycle ends, they are ready to be collected as garbage.
This is a very interesting point to help android devs to stop struggling to achieve data retention over configuration changes and screen rotation.
Last but not least, one of the important implementation strategies of this layer is to decouple it from the View, as I said before, ViewModel should not be aware about the view who is interacting with, or any context reference. Ok, but why?
First, code reuse. The fact that the view model is framework independent, allows you to reuse it with any other view that needs to consume its data.
Second, isolation. Keeping your view model in isolation allows to implement unit testing much easier.
Lets see this with a simple example:
We are going to create a PropertyDescriptionViewModel, with a single responsibility: to provide a property Description to its consumers, and whether it has errors or not.
As you can see, we have the description wrapped up with a Live Data object (we are gonna get into this wonder later), and a Rx subject to observe the description errors.
Note: In RxJava, a subject is an observable that can also be an observer.
In our example, we are using this subject to call its onNext method with the description, and also we will subscribe to it so we can observe the changes and check for errors.
Now that we have a solid view model, let’s create our Unit Test.
What cases should we contemplate?
- With an empty description -> View Model must have error
- With a too short description -> View Model must have error
- With a too long description -> View Model must have error
- With a correct description -> View Model must have no error.
Lets take this into code.
First of all, we need to create a Test Rule, so our Live Data components could be executed on the main thread.
public TestRule executorRule = new InstantTaskExecutorRule();
Now, before we run any test method, we are gonna initialize the view model.
Perfect! The view model is ready to be used in our unit test.
The next step is to mock our description to achieve a correct description, one too long and one too short to test the view model errors.
Great! To close the unit test, we create the methods to test the 4 conditions we mention early.
Result? All five tests passed! — 145ms.
I don't want to sound repetitive, but a good architecture makes unit testing becomes really easy.
Now that we know a little bit more of MVVM, i would like to mention one extra layer in our arch that, IMHO, takes a very important role.
Why we should have a Repository pattern if we are working with MVVM you might say.
There isn’t an only road that leads to Rome.
The good programming practices lies in our structure flexibility to easily adapt to big changes.
In this layer, the repository works as a communication bridge between domain layer and business layer.
Who wants to access the data? You? Ok, ask for it to the repository. This is how this works, however popular our view model is, it must not go over a repository middleware. What do we achieve with this? Modularity, and SSOT. Single source of truth.
This is what our repository layer represents. We consume the domain data from an only source of trust. Where the data is fetched from? Nobody cares. In order to respect the single responsibility principle, retrieve the data you need from the repository and use it. End of story.
Code independent of framework, separated into layers, with their own responsibility, dependencies pointing inwards. I know this might sounds a little boring, but what we have here is a pretty SOLID approach.
MVVM minimize logic in UI, improves the layer abstraction provided by MVP, and with a Repository Pattern, we have a smooth road to a Clean Architecture.
You can combine lots of good programming practices to make your app architecture solid, robust and resistant over changes.
To be or not to be continued?
Of course! In a future post, we are going to talk a little more about Android tools that help us to accomplish this architecture pattern.
Would you like to know more? Do you need our help? Contact Us!
MVVM & Architecture Components. Lets Make a Blend was originally published in Quadion Technologies on Medium, where people are continuing the conversation by highlighting and responding to this story.