It’s well known in the field of architecture that we shape our buildings, and afterward our buildings shape us. As all programmers eventually learn, this applies just as well to building software.
It’s important to design our code so that each piece is easily identifiable, has a specific and obvious purpose, and fits together with other pieces in a logical fashion. This is what we call software architecture. Good architecture is not what makes a product successful, but it does make a product maintainable and helps preserve the sanity of the people maintaining it!
In this article, we will introduce an approach to iOS application architecture called VIPER. VIPER has been used to build many large projects, but for the purposes of this article we will be showing you VIPER by building a to-do list app. You can follow along with the example project here on GitHub:
What is VIPER?
Testing was not always a major part of building iOS apps. As we embarked on a quest to improve our testing practices at Mutual Mobile, we found that writing tests for iOS apps was difficult. We decided that if we were going to improve the way we test our software, we would first need to come up with a better way to architect our apps. We call that method VIPER.
VIPER is an application of Clean Architecture to iOS apps. The word VIPER is a backronym for View, Interactor, Presenter, Entity, and Routing. Clean Architecture divides an app’s logical structure into distinct layers of responsibility. This makes it easier to isolate dependencies (e.g. your database) and to test the interactions at the boundaries between layers:
Most iOS apps are architected using MVC (model–view–controller). Using MVC as an application architecture can guide you to thinking every class is either a model, a view, or a controller. Since much of the application logic does not belong in a model or view, it usually ends up in the controller. This leads to an issue known as a Massive View Controller, where the view controllers end up doing too much. Slimming down these massive view controllers is not the only challenge faced by iOS developers seeking to improve the quality of their code, but it is a great place to start.
VIPER’s distinct layers help deal with this challenge by providing clear locations for application logic and navigation-related code. With VIPER applied, you’ll notice that the view controllers in our to-do list example are lean, mean, view controlling machines. You’ll also find that the code in the view controllers and all of the other classes is easy to understand, easier to test, and as a result, also easier to maintain.
Application Design Based on Use Cases
Apps are often implemented as a set of use cases. Use cases are also known as acceptance criteria, or behaviors, and describe what an app is meant to do. Maybe a list needs to be sortable by date, type, or name. That’s a use case. A use case is the layer of an application that is responsible for business logic. Use cases should be independent from the user interface implementation of them. They should also be small and well-defined. Deciding how to break down a complex app into smaller use cases is challenging and requires practice, but it’s a helpful way to limit the scope of each problem you are solving and each class that you are writing.
Building an app with VIPER involves implementing a set of components to fulfill each use case. Application logic is a major part of implementing a use case, but it’s not the only part. The use case also affects the user interface. Additionally, it’s important to consider how the use case fits together with other core components of an application, such as networking and data persistence. Components act like plugins to the use cases, and VIPER is a way of describing what the role of each of these components is and how they can interact with one another.
One of the use cases or requirements for our to-do list app was to group the to-dos in different ways based on a user’s selection. By separating the logic that organizes that data into a use case, we are able to keep the user interface code clean and easily wrap the use case in tests to make sure it continues to work the way we expect it to.
Main Parts of VIPER
The main parts of VIPER are:
- View: displays what it is told to by the Presenter and relays user input back to the Presenter.
- Interactor: contains the business logic as specified by a use case.
- Presenter: contains view logic for preparing content for display (as received from the Interactor) and for reacting to user inputs (by requesting new data from the Interactor).
- Entity: contains basic model objects used by the Interactor.
- Routing: contains navigation logic for describing which screens are shown in which order.
This separation also conforms to the Single Responsibility Principle. The Interactor is responsible to the business analyst, the Presenter represents the interaction designer, and the View is responsible to the visual designer.
Below is a diagram of the different components and how they are connected:
While the components of VIPER can be implemented in an application in any order, we’ve chosen to introduce the components in the order that we recommend implementing them. You’ll notice that this order is roughly consistent with the process of building an entire application, which starts with discussing what the product needs to do, followed by how a user will interact with it.
For the full VIPER demonstration, visit the original article at objc.io.