A little bit of background. What is Clean Architecture?
The idea of the Clean Architecture of systems has one main objective, namely separation of concerns. This goal is achieved by dividing software into distinct modules. An app’s logical structure, thus, is split into layers with different fields of responsibility. We can distinguish two groups of layers: those responsible for use cases and those responsible for interfaces.
A use case describes what an app is supposed to do. Use cases contain the business logic of a project. But an application is complete only when besides a business logic layer, it includes a user interface.
Apps designed in Clean Architecture have a few things in common:
- independence of frameworks, which means they rather use frameworks as tools, than have to adjust their systems to the constraints of a particular one;
- testability meaning that a given layer of code can be tested without a user’s interface, Database, Web Server or any other external element;
- independence of UI - business rules of an application remain intact regardless of any modifications done to the interface layers;
- business rules not bound to any database;
- independence of any external agency.
As Uncle Bob Martin explains in his speech, when you code in frameworks like Ruby on Rails, what you first see is that it’s a Ruby on Rails app. Quite different than in Clean Architecture when you see the actual architecture of an app and what it’s supposed to do. See the full speech below:
The underlying principle of the Clean Architecture is called the Dependency Rule. After reading about so many examples of independence in the paragraph above, it might seem a bit confusing, so let’s take a closer look at the very idea.
Imagine that you design an app. The source code of the software is divided into several layers. The innermost ones are responsible for your app’s business rules. They are surrounded by mechanisms such as UI (user interface), databases, devices, gateways, presenters, controllers etc. in the outer layers. According to the dependency rule, the source code dependencies can only point inwards. No part of the code in the innermost layers can know anything about the code in the outer layers. Particularly, no name of something declared in the outer layer can be mentioned by the source code of the inner layer. This prohibition includes functions, classes, variables or any named software entity. To sum up, the Dependency Rule enables the separation of concerns between several parts of the code.
VIPER. What does it stand for?
As a Clean Architecture design pattern for developing iOS apps, VIPER relies on the separation of concerns. The name itself is an acronym of View, Interactor, Presenter, Entity and Routing. This sole fact showcases the clear division of an app’s source code into classes. They are arranged in compliance with the single responsibility rule, which states that no class of the source code goes beyond its sole purpose.
Different than many other iOS apps, architected according to the MVC (model-view-controller), VIPER divides the code into more layers. Thanks to this, apps based on this pattern are more likely to avoid the issue commonly known as the massive view controller, occurring when excessive amount of an application logic ends up in the controller. VIPER does away with this problem. Let us take a look on the particular components of its architecture.
The interface layer constituted by UIKit files, view controller class and other stuff. View is passive and fully dependent on the Presenter which provides it with the content to display. It never asks for it, nor does it do anything business-logic-related. It’s basically the view controller and nothing else.
This is the module responsible for fetching the data from the model layer (does this, communicating directly with DataManager), performing calculations and return them to be viewed through Presenter. Interactor represents a single use case of an app and contains its business logic. Its implementation is completely independent of the User Interface. It can sort or prepare data, but only for the data management layer.
Is formed by the logic driving the User’s Interface. This layer gathers input from user interactions and updates the UI as well as sends requests to an Interactor. It also prepares data for display in View and may do type conversion if Interactor requires specific data format.
They are model objects manipulated by the Interactor. Entities are a representation of data downloaded or received from cache They are never passed to the presentation layer.
This is the navigation layer guiding an app to an appropriate screen. Every time a user is tapping a button, selecting an option or just going back in the navigation stack hierarchy, this is the Router module that’s responsible. The responsibility for routing is shared between the Presenter and the wireframe, which is kind of against the Single Responsibility principle. A wireframe object owns the UINavigationController, UIWindow and UIViewController. Its responsibility is to create a View and install it in a window. As it is the Presenter that contains the logic to react to use inputs, it knows when to navigate to another screen and to which one. Coupled with the wireframe which knows how to navigate, it forms a route from one screen to the next.
Thanks to the single responsibility principle, every element in the VIPER architecture has its own unique role. Responsibilities are separated and limited to the possible minimum. This makes changes in the source code of an app easier. When modifying one class of a code, we are pretty sure it will not affect the other layers. Programming apps in VIPER makes testing much easier than the MVC approach, prevents from code duplication and, simply, helps you keep your code clean.
- Pair programming in a software house: yes or no?
- Starting with Rails - how to set up a development environment
- Wanna see how we roll? Here is the Prograils playbook!
Photo by Anders Jildén on Unsplash