Xamarin Forms Architectural Guidance

With every project I keep learning something new, better ways to structure code. I always left the project feeling not quite right when I didn’t implement code in the best way I knew how. Project deadlines, bugs and more sometimes leaves a project with hacks and workarounds just to get the job done, hence the project was never “pure”. I never liked going back to a project because I had to deal with all of this.

I recently started on my spiritual journey to architectural purity (a.k.a I have completely lost my mind), in the pursuit of building a Xamarin Forms application with everything done to the best practice that I know of. A mobile project that I would be happy to extend.

I have come up with some completely crazy ideas but I thought I would share some of the patterns I found to be quite helpful in leaving a project clean and testable. I always try to find a better way to do something even if the current industry standard is ticking along just fine on the current practices.

Note: I am coming from the perspective of multiple developers on a large mobile application. I certainly understand this is overkill for a number of apps. I haven’t developed any new patterns here, its more of how to mix them the right way for Xamarin Forms.

Overview

When developing a project there are always some given architecture and project setups I base everything off. The patterns below are all based off the following setup.

  1. MVVM (Xamarin Forms was built with MVVM in mind)
  2. Use Portable Libraries (preferably .NET Standard). And for the reason why look at Portable vs Shared.
  3. 3 Tier Architecture – UI (the application) / Service (aggregate for repositories) / Repository (API’s or Local DB)
  4. Constructor Injection is the only way a class can gain access to an external class. In cases where constructor injection isn’t possible I use Static Initialization.

MVVM with Aggregate Service over Repository Layer

Xamarin Forms is designed with MVVM in mind and contains most of the building blocks. I like to have an MVVM approach with a services layer and repository layer. You will also notice I snuck in there a separate container for model and viewmodel state. I like to keep them in a separate object so you can serialize and log the entire state if needed, even replay states if you want to track history.

In a few quick notes about MVVM, I like my ViewModels as dumb as they come and my Models to hold state and operations that can be done. The ViewModel is just a relay in my opinion. A model doesn’t represent a model in a repository, nor a model in an API. The model is where the business logic lies. Any data transferred to and from them would be in a Data Transfer Object (DTO).

MVVM

A service can talk to multiple repositories and a model can talk to multiple services. I prefer to keep my View, ViewModel and Model and as 1-1-1 relationship however it is setup so that this can change if the need does arise, For example an AuthenticationModel to keep track of authentication is normally passed between models. Model’s keep state, services aggregate repositories.

Synchronization Service

A specific example of the aggregate service over the repository layer is the synchronization service. A common requirement of mobile applications is to have offline capabilities. This requires a local data store and an API to synchronize with. When the app is responding to user actions to store data, it should never concern itself with synchronization, most services should just pass straight through to the database repository layer. A separate synchronization service, which can be triggered by events or a timer can read the database and synchronize with the API.

Sync_Arch

Configuration Injection

Don’t load your configuration as static variables in your project. For one, its harder to switch out if you have a dev, uat and prod branch you have roll through. Second it makes it hard if you are all aboard the DevOps train and want your build service to change variables during its build and deployment process. Instead load a config (json or xml) file as part of your solution on initial load. The configuration container is the class where you would normally keep configuration values, except they will loaded at runtime into the container then pass throughout the app generally through constructor injection.

Configuration_Arch

The added bonus is that when you do unit testing you pass in the variable container in your test, no longer do you need to keep the hard coded static values in your project.

Proxy Pattern to Separate Dependencies

The main point of the Proxy Pattern is to ensure there is no dependency where one isn’t needed. Create an interface and class in your project that provides the functionality needed from the dependency and wire it up. For example I have created an INavigationContainer and implemented Push and Pop. The NavigationContainer accepts a Xamarin Forms NavigationPage as a constructor parameter and then implements the required functions as required. All that is concretely referenced in the other project is an interface. This has allowed me to keep Xamarin Forms dependencies out of projects it doesn’t belong in.

Proxy

 

Layered Dependency Injection

I don’t want a reference to the repository layer in my main project. The possibility that the main project can directly reference something it shouldn’t has always been a concern for those using DI, where they all need to be given the concrete reference at the start to put it in the container. You generally have 2 options if you don’t want to do this, the first being to place an attribute on the class you want to add to your container and then in your main project, load all assemblies in code and go through them to find any attributed classes. The second which I chose was just passing through the container through to each service. However in order to do this you need to Proxy your Dependency Injection Framework.

ContainerPass

Operation Separation

ViewModels and Models have operations generally called by a user interaction. They normally require commands being wrapped in everything from timeout handling to error handling and alerting the user to what is happening. This code becomes onerous and also hides the true operation inside a command inside a try/catch inside timeout handling and possibly more. Then normally each command will have to decide what to do with it once its complete. By separating out the operation, it can provide just the operation needed and return a result of whether to navigate or display something to the user.

Since the operation is completely separate, it can be tested on its own. The try/catch, timeouts and more you might normally wrap around this, you can create in a separate function that you pass the operation into.

operationseparation

Adapter Services

This is one is particularly useful for logging, when you might actually want multiple logging listeners. Consider this a simple mobile specific version of the Enterprise Logging Application Block.  It allows you to call a logging function only once and allow multiple listeners (or providers) to act on that information. Say you want to write to a local log file, output in the Debug window and send it to HockeyApp.

This all started because initially a project I used had one logging provider, then the business chose another one because the first one wasn’t that reliable and was also sun setting. Then the next one changed as the business went for another provide to consolidate their enterprise analytics. Three changes in 4 months where I had to rip out the crash reporting and analytics providers and switch them over. Who ever thought this actually happened.

Adapter

Summary

Hopefully this has provided you with a few good ideas on how to structure larger Xamarin Forms applications. I have used all of these in production applications to success and also what I based a lot of my Exrin Framework on.


Posted

in

by

Tags: