MVVM (Model-View-ViewModel) is a usual pattern of choice when it comes to XAML development. It is used in WPF, Silverlight, Windows Phone, UWP and Xamarin.Forms. MVVM was first introduced by John Gossman in this blog post back in 2005. I strongly recommend reading this blog post as it gives couple of interesting facts about early days of this pattern. Also, take a look at this post written by John few months afterwards about advantages and disadvantages of using MVVM.
Every developer has his own opinions about how MVVM should be implemented. During my career, I saw different ways to implement and understand this pattern. In this post I describe myths that I have found most common.
1. XAML apps should always implement MVVM pattern
This is the myth that I found most common. MVVM is a great pattern, but patterns are ready to use solutions for a specific situation/problem. I mean that using a design pattern should be a conscious choice. You should not blindly follow other developers/projects, because there may be no point of using some pattern just because everybody are doing that – it can do more harm in the end.
MVVM can be an overkill for small apps or apps that will have short life. However what is a definition of “small apps”? I think it really depends on your personal experience. In my opinion, “small apps” are apps that only have few pages and don’t actually have any complicated business logic. In that case, it is ok for doing everything in code behind. Moreover, if you are working alone or need to develop your app fast, then maybe MVVM will just disturb you during work.
On the other hand, if your code behind will get too complicated then this may be a sign that you need MVVM after all. This pattern is a better choice for bigger applications and for projects where development team has few members. MVVM will allow you to easily split work across different team members and still have consistent application.
2. Code behind should remain empty
MVVM is not about removing everything from code behind. If you move everything from your code behind to your view model, then your view model will become your code behind. There is no point in moving garbage from one place to another just to have empty code behind.
MVVM is about separation of concerns, so code behind will not disappear completely but it will become smaller. Code behind should have code that is touching only UI parts of your application. What do I mean exactly? In code behind there should be code that is changing colors, size or visibility of UI controls. Doing that from view model is much harder, because you will need to write additional level of abstraction. If you are spending too much doing some UI related code in your VM (or don’t know how actually do this), then maybe it should be done in code behind?
View models are abstract representations of views, so they should keep state of view and execute logic in response of user actions. VM shouldn’t access any UI related part of your application. Having UI related code in your VM is tightly coupling VM with View. This may lead to problems if for example you have one VM that is shared in Android/iOS using Xamarin.Native.
3. Navigation should be implemented only in view models
If app has simple navigation logic, then in my opinion it’s ok to implement it in code behind. By “simple navigation” I mean a navigation that has no business rules. For example, user clicks on some button and it’s immediately navigated to next view. Simple as that.
Doing navigation in code behind also makes sense because XAML platforms favours view-first approach. Implementing navigation in view model requires creating some kind of a navigation service that will abstract that away. This may be an unpopular opinion, but I think that doing navigation in code behind is just easier to understand and maintain.
Of course you can use some MVVM framework that will provide out of the box navigation service for you. However, choosing MVVM framework is completely separate topic about which I could write another blog post. From my experience, MVVM frameworks are great if you only stick to what certain framework has to offer. If you need to do something that is not supported by certain framework, then you have a problem.
For example I have found implementing tab navigation in code behind much easier to implement than, for example, doing this using MvvmCross. When I was implementing my first view presenter using MvvmCross I was excited about this feature, because it was feeling really nice. However over time I have found myself that abstracting away navigation in that way was hurting readability of code. Something that could be done easily in code behind, suddenly required tons of additional code for just to be just consistent with MVVM pattern.
4. Every property in VM should call PropertyChanged
PropertyChanged should be called only if your VM actually needs to notify View about change in certain property. If property is not used by View, then what’s the point of calling PropertyChanged? Even if property is used by VM you don’t need to call PropertyChanged if you are for example setting property only once in constructor.
In my opinion, we should have as little code as possibile. If some code is not needed then it should be removed, just to keep things clean and simple.
5. Every collection in VM should be of type ObservableCollection
ObservableCollection is good choice if your app needs possibility for adding/removing items from list dynamically (for example swiping to delete item). In any other case, I think that List or even ReadOnlyCollection would be better choice. ObservableCollection is for me a clear indication that there is implemented functionality for dynamic items management on the list. In my opinion we should use as basic types as possibile in code for better readability and to be clear about our intentions.
6. Every VM should be reusable in different views
This is something I heard very often back in WPF and WP days. In practice, I’ve never implemented view model that was used by different views inside same application. Every view has its own responsibility and it’s very rare case that different views will share same functionality.
7. VMs should be always covered by unit tests.
Well written VM is not implementing any business logic, so there is almost no code that require unit testing. VMs are just passing execution to the underlying services, so you may think of VMs like a “glue” for your app. This kind of code is not well suited for unit testing.
If you really want to cover view model with unit tests, you may find yourself mocking everything. When you mock everything, you may realize that you actually not testing anything but your mocks. Also, watch out for leaking method flow logic from your VM into your unit tests! According to TDD, unit tests should be written before writing code – that is a good practice. However this is done the opposite way most of the time. In that case you may find yourself testing execution flow for every method in your view model. You will be testing execution flow and not actually testing any business logic.
It’s better to cover the core functionality of your app with unit tests. There is no point of covering some trivial code like one-line navigation to another view model. However what is the core functionality? It really depends on specific case. Usually this is some business logic, but what if your app is just CRUD-like app? Then maybe there will be no code that is worth to cover with unit tests. Think about what value unit tests will bring for you.
Consider writing UI tests instead of unit tests. In some scenarios UI tests will bring more value for you than unit tests.
8. Layers of app should be in separate projects
I’m a fan of having one project in solution that its used by platform projects (Android/iOS/Windows). In this project I keep my XAML views, business logic, database access, network resources access, etc. I put separate layers of app in separate folders in a project. For me this approach is much more simpler to maintain and understand.
I once work on Xamarin.Forms app that had over 15 projects in solution, but the app was pretty simple – it had about 10 views. I was struggling all the time to find what I was looking for. Also creating new classes was a challange – I’ve never really know in which project I should create them. This is the perfect example of overengineering things.
What do you think? Do you agree or not with my list of MVVM myths? Maybe you found some other myths? Let me know in comments!