Xamarin Application Architecture

In this post, I will talk about strategies for developing a cross-platform Xamarin application with focus on code sharing, increasing testability, and reducing overall development and maintenance efforts.

The application architecture is itself problem specific, but there are certain design patterns that can guide the overall structure of the application. The ones I mostly work with are Model-View-Controller, Model-View-Presenter, and Model-View-ViewModel.

MVC should be adopted for small applications or proof of concept. Since, Android and iOS both natively support MVC, it will mean less roadblocks, and faster implementation.

MVVM reduces platform specific code, and most of the logic is shared across platforms using PCLs. There are great MVVM frameworks out there that work really well with Xamarin, such as MVVM Cross, and the official Xamarin Forms.

MVVM Cross is a data driven pattern, and the presentation logic is quiet centralised. This means any upgrades to the library or to the system, can break custom navigation and screen transitions within the application. As Android and iOS platforms are constantly upgraded, with newer restrictions around security and permissions (background tasks / app permissions), and as user interface (gestures / notifications / newer design guidelines) are greatly improved, support for these can be costly in both time and effort. That being said, it is still a very powerful platform, and most applications can be written with it, with great results.

Xamarin.Forms is a UI first framework, and allows .Net developers to use their existing XAML skills for developing mobile applications. However, this platform is still maturing and needs to reach a more stable stage. Even though native controls can now be used in XAML, but one looses advantage of data binding, and the extra effort required to maintain proper navigation in the application, and catering for various screen types, out does the benefit for now.

MVP is another pattern that works really well with Xamarin cross-platform applications. It is a variant of the MVC pattern and allows full use of platform native capabilities, with great control over the UI of the application. It is the pattern of choice for native development and we will look more into it below.

MVP has 3 major components

Model: This is data that we want to show in our views. Apart from data classes, this carries responsibility for retrieving, storing, validating advanced data sets, and advanced functions such as syncing and conflict resolution, cache maintenance, offline capabilities.

View: This module is responsible for showing data to user and responding to user gestures and actions. It should only be dependent upon the presenter and native platform capabilities for styling.

Presenter: Presenter is the layer below the view and is responsible for providing data the view can use. It relies on the model layer to retrieve data, and can also publish other events to UI, such as loading data state, timeout and error state.

The golden rule of mobile development is to keep the UI layer as dumb as possible. That means UI only needs to know about its data, view transitions and animations, and publishing interaction events, such as gestures, button clicks. As mentioned view is completely dependent upon presenter, and presenter is dependent upon the view for human interaction. However, to promote unit testing for each of the modules, presenter and view need to be decoupled.

To achieve this, we can define a contract between presenter and the view. For a login screen the view’s contract can be:

and the presenter contract can be

The presenter should be platform independent so that it can be shared across different mobile platforms. This means, it does not respond to UI life-cycle methods, unless explicitly told so.

The controllers in iOS and Activities in Android are never directly created using constructor, which means that we cannot use dependency injection to provide a presenter to our view. In this scenario I like to use an anti-pattern called ‘Service Locator’.

Service locator is considered anti-pattern because of the complexities of managing dependencies, and dependency’s child dependencies. This is highly error prone, but in case of multi-threaded programs, where start of the application can run many different initialisation threads, double instance of a service can be created. This pattern works well in simple scenarios and this is exactly what we are trying to solve. A dependency service can be used to locate the presenter implementation inside the view.

If the scenario was anymore complex, it certainly means, that View has been assigned more work than it needs to perform and is against MVP principles. A sample of this is shown below

As shown above the AppDelegate in the application loads all the presenters in the application. When the view loads, it uses the service locator instance to retrieve its presenter.

By abstracting the presenter from the view gives us many advantages.

  • One presenter will not work on all devices. Such as finger print functionality for login can only be used on devices that have the required hardware. In this case inheritance can be used to create versions that can handle extra features, while having no functionality in base presenters.
  • By abstracting the creation of the presenter outside the view, allows to make our UI really passive, and thus we are able to test UI independent of any other module.
  • This method allows to create presenters that can help automate UI testing, performing common testing scenarios automatically. This can also be used for automatic product demos.

 

The above implementation of MVP suffers from one disadvantage. It ignores the asynchronous nature of the mobile applications. Both Android and iOS are quite capable devices. Even a simple Notes application performs a lot of activities when loading. These can be logging in the user, loading the notes from the cache, syncing down any notes created on other device, syncing up any notes created during offline mode, resolving conflicts, showing progress to the user, restoring state to what it was when the application was last closed. These activities can take from few milliseconds to few seconds. The longer the application takes to boot up, the higher the chance that the user will stop using the application, and will eventually remove it from the device.

Enterprise applications are much more complex. In a perfect world, they are developed using mobile-first approach. However, not all companies can follow this and instead of the application interacting with a unified set of APIs, it ends up interacting with multiple legacy systems, combine the result and then provide it to the UI layer. This means that the application load time can be really high especially if there is stale data on the device.

In such a scenario, instead of defining contracts between the presenter and view, a more reactive approach can be used. This allows us to build application with a user centric approach. This means we think of how the user is going to interact with application, and what does the user see while waiting for data to be available in the application. The code below shows this for a login screen.

The above code shows the asynchronous nature of the View, and it follows a push approach, reacting to events when raised by the presenter. This further decouple the bond between the view and the presenter allowing for easier testing, and also helps to identify real life scenarios within the app, such as data being delayed or no connectivity.

Thus, we see how MVP aims at building a very user centric app, with a very passive and light UI layer. Both iOS and Android platforms are competing to enhance user experience. In future, we can see apps that will react and adapt to user habits using machine learning. This also means that they will have to work in a stricter environment, like stricter guidelines for UI, background tasks, app permissions, reduced background tasks, and change in application notification patterns. MVP will definitely allow to handle these changes, without affecting user experience.

Mobile-first development with Xamarin

 

Modern application users have high expectations for applications, even for in-house enterprise apps.  IT leaders realising this have adopted a mobile-first development approach, which ensures great user experience, reduce overall development and maintenance cost. In this post I will provide an example of a mobile-first development project for an enterprise application.

 Business case

A retailer is using Windows CE devices for performing daily tasks in it stores and is planning to move to the latest Android / iOS devices. Each particular task is performed using a single independent application, developed with different technologies (.Net Compact, C++), and each application communicates with many different back-end services and systems.

Apart from maintaining applications on variant technologies, the company also spent heavily on training employees to use these applications.

The road ahead is to develop these applications for Android powered devices.

Road ahead

The application was initially to be developed only for Android, with a future scope of developing a similar iOS application.

The company relied a lot on the daily activities performed through these applications, which meant that these should be powerful and simple enough for end users, minimising training and update costs.

Xamarin was chosen as the development platform, for the fact that it will prove beneficial for porting later to iOS, single code base with C# language (fully matured async patterns, better type-safety, front and back-end teams work more collaboratively), and also, it can realise the full potential of the native platforms (native UI, Geo-location, Notifications).

Mobile-first approach

Mobile-first approach in enterprise means allowing user to perform complex tasks, with ease. This means interactive and intuitive UI, build around the use-case of solving a problem from a user perspective. This also means developing new infrastructure and services that cater for specific use cases in the application.

Consider a case when the store manager of a hardware store wishes to order new stock for an item. This previously involved getting following information:

  • Current store stock
  • Stock availability for delivery
  • Back store capacity
  • Shelf capacity
  • Upcoming sales
  • Pending deliveries
  • Pending customer orders
  • Wasted / discarded stock
  • Understanding of stores’ sale patterns (daily / seasonal / monthly)

 

Some of the services interact with the in-store server, some will require the central server, and a manual review of previous orders, while some of the tasks are completely dependent on a person’s experience. The final task is to manually calculate the final stock to be ordered.

With the new system, a scheduled task interacts with all of the above services, uses machine learning (items bought together/ customer ordered / quantity etc.) to find out sale patterns, cache results daily and in case an order needs to be placed, pushes a notification to the user who has the authority to submit orders.

On the application side, the user can interact with the notification, review the order and submit or cancel with just 3 clicks.

Thus, focusing on the user-first mobile app, made a complex task very easy and efficient for the user.

Additional use case: An item in a store is to be recalled, or is towards the end of its life and needs to be discarded. Since the new web service caches all of the data every day, a new service can be added, that identifies such products and utilises the existing notification module to notify the user.

The mobile-first development can turn a ‘pull’ experience into a ‘push’ experience – making use of mobile platform features like push notifications. With powerful services in place, new functionality is easily added greatly improving store operations.

Code-sharing

The application was designed using Model View Presenter (MVP) architecture. In this pattern the presenter layer acts as the supervising controller for the view. The view itself is quite passive and is responsible for displaying the data provided to it by the presenter and to route UI interactions to the presenter. This allows for moving most of the logic into the presentation layer. The presentation layer is shared across platforms reducing platform specific code. Test coverage is also greatly improved as most of the presentation code is shared.

Use of Xamarin combined with MVP architecture allowed for more than 95% of the code to be shared across different platform, with emphasis on Unit and automation testing. This is evident from the fact that the whole project was delivered in under 9 months and the iOS application was started in the 7th month, and delivered with the Android app.

The components of the application were broken into individual packages, so that they could be used for all future enterprise or customer facing applications.

An excerpt from the OrderService shows how a sync component (LiveDataService) written to work with a live database could be used for a consumer application as well. In below case, it will notify user of current promotional stock.

It is also worth noting here that the use of Xamarin allowed for sharing components between mobile and back-end systems (as separate NuGet packages). This was the case with custom synchronisation framework, model classes, ORM components, utility libraries etc.