Recently I took part in a meetup about architecture and general role of an architect. Most of the participants were backend related.
I thought that in mobile world we tend to underestimate the value of mobile app architecture. I think one of the reasons why we do so, is that we don’t see any advantage of designing mobile app. Let’s be clear: I am not talking about UI/UX design. I am talking about code.
If I asked you to draw diagram of your app, what would you draw? Would it be? Testable? Would someone else understand it pretty quickly?
This article won’t be a strict, technical one. It will be more of sharing my thoughts. I am going to ask questions but I would like you to answer them. I would like to do it in a such way, so you can make decisions that you fully understand.
When googling “architecture design in mobile”, the first thing shows is layer separation architecture.
Does the image above ring any bells? MVVM comes to your mind?
Having 3 layers in the app sounds like a good idea, but that’s only the starting point. The bigger your app gets, the more you need to think about design.
Why is that important?
One of the reasons why having a clean architecture design in mobile is a good idea is testing. It’s much easier to cover your app with Unit/Integration tests when everything is separated. But you are probably aware of it already.
To this point, I didn’t write anything that you weren’t aware of. To visualise what I am trying to highlight with this article let’s take a look at few examples.
Disclaimer: in this article I assume you are aware of MVVM pattern; you know how it looks and how it works.
Is it JUST an API call?
Let’s assume, you are building new awesome app and your app will consume data coming from remote API. Knowing that much, how will you do it?
The answer is a typical one: it depends. Let’s see the our options.
1. F*** it, I am calling it from ViewModel
This is the first thing that came into my mind that I saw several times in my career. Is it wrong? I don’t think so. Will I do it like this? No. I won’t do it like this because I like to have API calls in a separate layer that I can cover with tests.
Initially, I wrote that there are cases when you could do it like this. I’ve changed my mind. There is no excuse to make your ViewModel cluttered. I definitely won’t recommend doing it like this. The difference between this approach and the next one is so small that you shouldn’t even consider doing it like this.
2. … maybe I should create additional layer that will take care of my API calls
Looks slightly better, right? We have centralised service responsible for making API calls only. We should be fine to cover this service with tests. This looks fine and I would follow such path in a small app. But what if…
3. I need more!
… I need more. I would like to get the data from the API and cache it. Doesn’t matter where. I just want to have it somewhere. Should I do it in API service? If I did so, then I would break single responsibility principle. Not good. Then maybe I should create another “service” that would be repository for my data.
Again, it’s testable and cleaner.
Now imagine that we would everything in ViewModel. How big will it be? Will it be easy to maintain it?
Each of the solutions above have its pros and cons. In order to pick one, you need to see the value of using the chosen approach and understand potential risks. Let’s move to another example.
How will we talk?
Let’s assume that you are building an app that has multiple Views (with ViewModels behind) on a single page.
Given those are on the same page user can logout in 3rd ViewModel and rest should be updated.
I feel this example is not the best one but I hope you get my point. Those ViewModels need to communicate. How to achieve it?
1. Singletons FTW
One of the ways to communicate between those services would to create a stateful service (singleton) that will be the same in each instance. Then each ViewModel will subscribe to exposed event and voilá we are done. We have communication established. Personally I don’t like it because it might happen that FirstViewModel and SecondViewModel will use LoginService only to consume the event raised by the service.
What’s more, from my experience having singletons in the app might result in a headache when their states become hard to maintain (stated being updated by different consumers).
2. Send me a message
Another potential solutions is to use some messaging center (or whatever we call it).
With this approach, interested parties can publish events in that center and everyone interested can subscribe to it. In Xamarin.Forms there is something like MessagingCenter coming out of the box. It’s a static and you can consumer it anywhere you want. Meaning you can publish any event from anyplace in your app. I hope you already see the risk here.
3. Parents will help me with that
Another approach would be that those 3 ViewModels need to be hosted. Probably there is something like parent ViewModel that could help us with.
With this approach ParentViewModel will observe its child and if one gets updated it will notify others.
With examples above I wanted to show that there are many ways to achieve expected result. Which way you choose it’s up to you. It’s you, the developer, who is responsible for the code. That’s why I think it’s really important to always think about mobile architecture.
Don’t get me wrong. I am not saying that you should have big design up front, it does not work like this. I am a fan of KISS principal and I think you should not overcomplicate things from the start. Begin with something small but easy to extend. Something that you could cover with tests. Later, when the app grows, you could easily adjust it to your desired architecture.
I strongly encourage you to always spend 5 minutes thinking before you start coding. You will see it’s beneficial.
Diagrams used in this article
Beside the fact that C4 is awesome for process documentation, I really enjoy creating the diagrams and I use it often during my work. If you are interested about them, you should start by visiting C4 model website and with Github