Mobile Architecture — What design pattern I should follow?

Waseem Syed
Mac O’Clock
Published in
5 min readApr 15, 2020
Photo by Fotis Fotopoulos on Unsplash

All the developers at some point in time would have asked themselves — What is the best design pattern to build my application? Do I go with any of the design patterns like MVC, MVP, MVVM, VIPER, etc.? While all of the design patterns mentioned above have their pros and cons, any good design should follow the basic principles:

  • Modularity
  • Single Responsibility
  • Scalability
  • Testability

This blog talks about one such design that satisfies the four principles listed above and the benefits it offers to the developers with a simple example.

Modularity

Design

Any system can be broadly divided into four logical units:

  • View Controller is the core of the entire design and it has modules like dataSource, controller, and delegate. The controller is responsible for the basic setup. data source handles the business logic and the delegate handles the navigation logic.
  • Network Layer has two modules namely network manager and service client that handle all the network operations.
  • Presentation Layer provides the data to the screens and has modules like models, view models, and cell models. The view model is an observer in the controller which usually triggers a data reload based on the model injected into it. The view model consists of functions much à la the data source functions like numberOfSections ,numberOfRows , cellForRowAtIndexPath.
  • UI Layer: has the views and cells that render content.

Some of the benefits modularity offers to developers include:

  • Independent development: Modules can be developed independently and can be easily shared between different systems.
  • Easier to test: Since the system is broken down into smaller modules. Testing each module becomes a lot easier.

Single Responsibility

All the classes have a single responsibility. For example, the cells, whose only responsibility is to display data do not need to know where the data came from. The data source which handles business logic does not have to worry about what goes on in the delegate.

Example

Let’s take a look at a real example of how all this translates into code with a simple app that fetches data from the URL and displays it in a tableView.

  • The ViewController should only have a simple setUp and fetch data function. It owns the viewModel which in turn has a tableView reload function to reload the tableView every time there is a change in the ViewModel. The other components of ViewController, that are separated out and owned by the ViewController are DataSource and Delegate.
Controller
  • The Service and Network Clients are simply used to fetch data.
Service Layer and Network Client
Endpoint
  • The service call returns a data model to be injected as a dependency to the ViewModel.
Model
  • The ViewModel has functions that are exact replicas of the DataSource. It uses the model to create data to be supplied for data source functions. The data needed by the rows/cells in the function cellForRowAtIndexpath are supplied in the form of a cell model. PhotoCellModel in the below example.

Delegate just handles the navigation logic and assigns the responsibility of push or present DetailViewController to the ViewController.

Benefits:

  • Separation of concerns: A class is not impacted by what happens in another class.
  • Better readability and error detection: Since each class is responsible for only one task, reading the code and detecting errors becomes a lot easier.

Scalability

Since the modules are decoupled from the core logic and developed independently, most of them could be passed around different screens with slight changes.

Benefits:

  • Becomes much easier to extend functionality without having to change the entire system.
  • Shared modules limit the amount of duplicate code written and thereby make maintenance easy.

Testing

Since we divide the system into smaller components and use dependency injection to inject objects, it becomes a lot easier to add tests.

Testing EndPoint, Service, and Data Model: Using the mock class and mock JSON, we can test the entire Service layer, Endpoint, and Data models. The System Under Test (sut)in this case, is the Service PhotosService.

EndPoint, Service, and Data Model tests
  • Testing ViewModel and Row/Cell Models

The ViewModel holds clearly separates the presentation logic from the Controller and hence testing the ViewModel thoroughly is as good as testing the Views. The System Under Test (sut)in this case is the ViewModel PhotoViewModel.

View Model and Row/Cell Model Tests

Benefits:

  • Thanks to dependency injection, each class can be fully tested.
  • Classes can be tested independently without integrating into a system.
  • Makes it easier to mock classes and data.

Conclusion

The design we discussed so far can be applied to any app with slight modifications based on the requirements and complexity of the app. To summarize, a good design is one that:

  • Enables the developers to work independently.
  • Allows you to modify parts of your app easily.
  • Scales as the system grows.
  • Is easy to test.

Cheers!

--

--