Deciding on the correct architecture

Editor at Sage
Sage Developer Blog
4 min readOct 13, 2020

--

by Didac Morales, mobile developer, Sage mobile center of excellence

This year we had the opportunity to lay the foundations for a new project within Sage taking advantage of our knowledge and experience as a Mobile Center of Excellence.

This is a new mobile app for Sage’s most recent acquisition, a people management product called CakeHR by Sage.

As always happens when we are going to start a project from scratch, we began the conversation/debate about which architecture would be best: MVC, MVP, MVVM, or VIPER. Whether to use CoreData or Realm as the database, etc.

In this article we won’t go deep into these methodologies, there are many articles written about the differences between them, for example, this one about architecture or this other about databases (all available in Medium).

Our experience tells us that there is no one solution for all projects, but one for each application. In other words, the best architecture is the one that best suits your project. So, we set out to analyze the requirements of the new CakeHr application and the API that it feeds on.

It is an application that contains little business logic, all the information to be displayed comes from the server, requiring several calls to the API in each view. With this scenario we will have to manage calls in the background, so we will need a good multithreading strategy. It will also require a database that can offer an offline mode as well as support for notifications, deep-linking, shortcuts, etc.

Our starting design pattern was an MVVM for its balance between the separation of business and presentation logic and added complexity of code.

The basic principles of this pattern are:

The view contains the presentation logic and is responsible for notifying the ViewModel of user interactions and state changes.

The ViewModel acts as a wrapper for the model and defines the user actions to be used by the view.

The model contains the business logic.

We also decided to add a router, or navigation manager, as other patterns like VIPER does to separate the routing logic from the View and thin the ViewControllers a bit more. Also added a repository to provide data from CoreData and API to the ViewModel. As you can see, we are building a hybrid pattern instead of following a closed one because it will better fit our needs.

When deciding which database to use in iOS, we bet on CoreData due to its native integration, its tracking and validation facilities, and its background context management.

For this project, we need a multithreading strategy that allows us to populate almost automatically every new or updated data the program will receive from the API. To build that strategy, we start decoding directly the JSON files received into CoreData managed objects using Codable protocol, introduced by Apple at WWDC 2017.

Then we built the ViewModels based on the NSFetchedResultsControllerDelegate provided by CoreData so that when the database is updated in the background, the ViewModel will have the changes without needs to fetch the database again.

And finally, we also want to make the UI reactive since we will have many calls to the API in the background and we want to update the views automatically. To do that, we also bet on the native solution and we decided on Combine over RxSwift for its better performance and future changes incoming. By adding Combine, we can expose the data on the ViewModel and propagate the changes received in the database to the UI automatically.

This is what the final pattern will look like:

To make the project fully testable we have followed a Protocol Oriented Dependency Injection strategy. As well as all the methodologies and best practices that as a Mobile Center of Excellence we have been designing and applying across the business.

Conclusion

As you can see, the necessary process to design the ideal architecture for a new application goes through specific analysis for each use case, the state of the art in application development, and the associated available resources.

Not always strictly following a design pattern is the best solution, in my experience most of the time, a hybrid solution will better fit a given project.

However, if you asked me what design pattern we have followed for this project, the answer would most likely be Reactive MVVM + Router + Repository.

--

--