For this week, I want to give a clear example of the type of architecture that I’m trying to push on the projects I work on. Some of you probably already know VIPER. It tends to become a classical architecture in iOS development and in other platforms like Android. VIPER goes for :
- V : View
- I: Interactor
- P: Presenter
- E: Entitie
- R: Router
It was inspired by the Onion Architecture or Clean Architecture pushed by Robert Cecil Martin, more known as Uncle Bob.
On the image The Clean Architecture, you can see an example of what it looks like. You see “skins”, or layers, that go from external to internal, crossing boundaries in one way and going right to the center where you find Entities.
Entities are the core of your app. They are not only models that do not move, they are also rules that make the hearth of your business. In a way, Entities define clearly the intent of your business. For example, an app about exchanging messages between teenagers (a so called social media) should have an entity called Teenager* and another entity called Message. Because the core of this app is sharing messages between them.
A Discussion between 2 teenagers for this app is then a Use Case. Another Use Case could be a “Wall” of discussions exchanged between other teenagers. Use Cases are the core functionalities built on top of the Entities. They use Entities to give the users of the app options on how to interact with them. Those options are defined by the Business (the guys who are leading the company and who define the goals of the app/company. They own the ship).
Then Uses Cases are presented, controlled, fed by external components thru the presence/development of adapters. an Adapter can be a simple Presenter/Controller, linked to a UI or a manager responsible for the connection to a database, or an interface in front of a WebService. Adapters will make you independent from external things like framework, UI, API, suppliers, freelancers, etc.
At the end of the line, you will find all the external components, like UI, Webservices, API, Databases, Framework, etc. All those things that should be independent from your core business. I like to call them Externals.
So the “order” of layers in a Clean Architecture scheme is simple :
Externals > Adapters > Use Cases > Entities
And as you can see, it goes in only one direction.
As said in the beginning of this post, VIPER uses/is based on this concept.
The major problem is that VIPER is generally applied for a specific functionality…
and you end up with nice small silos for every functionality of your app. On paper this looks nice but if a silo is a functionality then what if a silo shares an entity with another silo, what if a silo shares a functionality with another silo ? Is this allowed, is this rational, can I make it ?
The ambiguous thing in VIPER lies on Entity: Entities, in the mind of many developers, are generally seen as or mixed with Models and this is bad to me as it breaks the Clean Architecture scheme. It also creates this tension that VIPER is over-engineered and that you will have a new entity for every functionality. This is not how VIPER should be applied and thus Entity should be ejected from VIPER (but then the name is unpronounceable and pretty difficult to put in a discussion or in an interview), so for now I will exchange VIPER for VIP’R.
Does it means that Entities are bad things ? Of course not. Entities should be defined outside of a VIP’R. Entities are your core business, they define what your application is working on and for.
So now, what do I propose pragmatically to make it work. Below you will find a schema of the kind of architecture I’m working on :
It could look, on a first approach, like a huge over engineered thing. On this I agree :-). But let’s have a closer look at it.
Let’s start with a simple description (I will go in details later):
The layer on the top is for external stuff (External Layer) : here you have a View. This View depends on a Controller and is also presented to a Coordinator/Router thru an interface (ViewProtocol) and it also has a dependency to a ViewModel.
Then, you have the Adapter layer which contains a Controller, a Presenter and a Coordinator/Router. This layer is in relation with Interactors thru the use of interfaces that reverse dependencies between all those classes.
And at the bottom of this, you have the Interactor Layer, where you will find the Use Cases, your business rules and some models to present/convert Entities to something useful for the Use Case. As you see, between this layer and the layer on top, it’s all about interfaces. No one knows anything about the other. An Interactor can be in relation with an Entity (thru dependency relation) if needed or with another Adapter (thru an interface relation). This way you can share things between the functionality you are doing and the rest of the app, but your functionality remains clearly decoupled.
Let’s go more into details (as the devil generally lies in details).
About the Adapter Layer: I’m pretty sure some of you are already saying that this Coordinator/Router thing should not interact with the View. I agree with that, but to me, Coordinator is all about playing with the UI and thus it should know about it’s current View and potentially interact with it. Another thing is about those 2 things : Presenter and Controller… Why 2 classes ? Well, because it makes them easier to handle, to test and to read. The Controller is for things/events that come from the View, the Presenter is for things/events that come from the Interactor. One could decide to mix them together and I will agree with One :-). One could decide that Coordinator/Router should only know about how to go from one screen to another and that only Presenter/Controller should know about the View and I will also agree with One. It’s all a question of decision from and for the team :-).
Now about the Interactor Layer: I will not talk about the 2 interfaces (InteractorProtocol and PresenterProtocol). They are application of the Dependendency Inversion Principle (DIP) that you all know. Considering the ModelProtocol maybe some of you are thinking: “Why the hell is he using that ?”. Well first because I made an article about how to protect yourself from model (here) and because I don’t want my Presenter/Controller to know about the Entities that the Model potentially uses. This is where most of developers call this Model and Entity and this is where it all starts to break Clean Architecture… Why, because this Model will generally cross all the layer and potentially be used by the View and then you have a general mess with everyone starting to be dependent from the Model in all the layers…
And I will end on that : “If you want to apply VIPER to your project, then please, stop calling your Entity and Entity and maintain it in the Adapter Layer. If this is really an Entity, then extract it from your functionality and create a Model to map it to your functionality”.
You can find an example of a Swift implementation of “VIP’R” on my github : Clean Architecture in SWIFT.
If you compile it and run some tests, you will see that I have a 100% code coverage on all the important elements of this example, i.e. : Presenter, Controller, Coordinator, Model, Interactor.
*: I could have called this entity a User, but then it will have created confusion with the users of the app by themselves.