VIPER of many faces — Part 1

Mladen Despotovic
iOS App Development
8 min readAug 7, 2018
Courtesy of iStockPhoto

My favourite is Blue. Such a magnificent creature….

Still, although a great nature enthusiast, with all its creatures, I will not shame myself any further with my weak knowledge of zoology. I will talk about VIPER client architecture, of course.

This story is NOT another “Introduction to VIPER on iOS” or anywhere else at the moment. I believe we have loads of articles covering the topic. It is assumed, that you understand the concept and have some experience with it. It is also not about comparing it with any other architectural approach or architecture. I picked that one because it does represent a relatively good Clean Architecture approach and follows SOLID principles to something bearable. I wouldn’t even use the acronym myself, but I guess it makes easier for all of us to understand the topic.

This story is about presenting the VIPER in a more diverse way, showing its friendly face.

To do this, I will first deal with the few myths and after that with a few issues, I consider real problems and next time we shall look into a demo project, which would stand there as a possible solution/answer.

Myths and Issues

Myth 1: VIPER has a lot of classes

Does it? How many classes do you think it should have? Or better said: how much of Single Responsibility Principle you want to have in your code?

Perhaps all this is a bit of debatable. Even with SR principle, we can quickly end up debating about what is the responsibility of one particular class. For example, Microsoft in their definitions of MVVM sees the View Model as a Glue Code, as a middleman between business logic and a view. One could argue, that this responsibility is too broad: handling an event, presentation logic and transform model data into a view-friendly form should be considered as separate responsibilities.

Point is: whatever the architecture, if you want to make your code maintainable and reliable, then it will have to conform to the many paradigms of Clean Code and that includes SR, small classes, as little coupling as possible, OO Patterns, full monty… That all leads to “…a lot of classes..”.

Myth 2: Is rigid and has a lot of boilerplate code

I remember years ago, when I started with the VIPER commercially for the first time, taking over an existing project, it wasn’t the best experience. Not because of the VIPER itself, but because of the obvious struggle with the concept.

I actually saw, what I named here as a myth:

  • each module required a lot of boilerplate code
  • many times the classes were empty of created just to “follow the approach”
  • developers struggled to adopt requirements’ logic to accommodate it into VIPER specs, which of course didn’t work and lead to some weird combination of following it rigidly and breaking it at the same time.. And when I say “breaking”, I really mean it in terms of breaking the encapsulation of the module for one.
  • Presenters or Routers connecting too many objects bilaterally and making every structural change a real PITA…

We shall see later in our demo project, that it doesn’t have to be like that if you do it with this in mind:

  • What you need to follow, are the SOLID and other OOP principles VIPER was based on and according to that, you should create classes you see fit for the job.
  • Implement your boilerplate in your protocol extensions, abstract classes or even superclasses (if not too many!!!) as much as possible

Myth 3: Is hard to learn, fit only for Senior Devs

VIPER is as hard to learn as it is to learn SOLID, TDD and OOP Design Patterns. Wait… but that’s what we do anyway, don’t we?

OK, I could add FRP as well. But never mind, you got my point: if you ever wanted to become a real Senior Developer, then you have to learn aforementioned and in that case, you should code VIPER as easy as cutting your pizza and splashing it down with your craft beer of choice.

Yeah, but juniors… Ok, so, if your junior colleagues don’t dance VIPER style, then your codebase adopts to skillsets of juniors? If so, then yes, VIPER is fit only for Senior Devs. However, in most of the places I’ve ever worked at, we made sure juniors were coached by seniors through the code and not the opposite: adopting the code to fit the highest common skillset level…

Myth 4: Doesn’t go well with SDK dictated MVC infrastructure, like in iOS

I think I debunked that one again in my series Module Oriented Architecture, specifically in Part 6: Outsmarting the MVC. You also have frameworks like Uber RIBs, which tackle the issue as well, but I have to admit I personally think architecture should not be turned into instant framework solution, but that’s beside the point here.

Myth 5: Not fit for small projects or prototypes

Again, in series Module Oriented Architecture we could see the VIPER classes totally lean and small, because most of the boilerplate was implemented in protocol extensions.

If you follow such approach, described in Myth 2, then you can find it very easy to use and very fast to implement any kind of specific functionality even in small projects and prototypes.

Problem 1: Communication between the objects can get convoluted and complicated.

This is what I consider a real issue…

I already mentioned issues in the first project I worked on. I remember all sorts of combinations of delegates, closures, wiring, globals, all sorts of things you can imagine. Many modules were turned into a mess with loads of memory management issues and subsequently also race conditions.

But how did this happen? Were the problems coding skills? Poor understanding of VIPER, SOLID? None of this made sense…

I took me quite a long time, to find the culprit and it was hilarious, especially when I started to code according to this discovery to see, how simple and obvious the root cause was…

What was it then? The usual suspect: S from SOLID: Single Responsibility Principle!

Yes, the modules were simply too big, too comprehensive, doing too many things. Instead of providing the task, service, they provided the feature, many times related directly to a product feature.

This caused the following:

  • more responsibilities created more classes
  • more classes created more dependencies between them
  • more tasks and their classes required and created more dependencies to classes from other modules, creating even more potential memory issues and making the whole app more coupled and rigid, thus wasting one of the basic gains of VIPER: module encapsulated tasks and features
  • more classes and dependencies, harder to test, harder to catch a potential issue.
  • more tasks, more requirements for business logic classes beyond the usual VIPER 5, which brought even more confusion about how to connect them to others
  • more business logic classes, more bi-lateral communication between the classes which increases the risk of creating memory issues, especially when UI navigation with its own memory management is involved
  • or….
  • more responsibilities created more functions also in the VIPER 5 classes, breaking SR principle on the class level thus bringing all the known consenquences…

The consequences were grim, especially considering how simple and obvious the reason was.

Solution?

However, as much as simple the reason was, the solution was not that easy. We shall see 3 further short parts:

  • POC Project which will demonstrate a potential diversity of VIPER, deal with some of the myths above
  • we shall use the same project to demonstrate how can the Use Case of Clean Architecture be applied on the App layer and orchestrate the app and leaving modules lean and highly reusable. It will be a step further in Application Services, which we already introduced in the Module Architecture.
  • We shall see, how even within a very lean module, links between objects can still be a problem and we shall use the event-based approach to resolve it.

Our demo POC Project

Leaving here a bit of information about our demo project:

It’s almost a single view banking app, where we listed some Top Highlights and Last Payments on the first page.

Initial page

Highlights can be also extended by tapping any of them, but this will come in handy later when we shall add user analytics. Tapping continuously toggles extended and collapsed the display of the Top Highlights.

Expanded Top Highlights

In the lower part of the screen we show Last Payments and we can also see the details. Selecting the payment navigates to Payment Details:

Payment Details

Here is the schema of the used classes, just for the teaser…

We can already see few things, which point to our freedom of choice and rejecting rigidity and one and only VIPER module template:

  • we use View Models as well, because we want to keep our model objects clean, our Interactor to focus more or less on communication with the API and Presenter to serve the views without creating content for them
  • as already mentioned above, Presenters role is only presentational logic, where it responds unilateraly to the View Controller requesting the view model by calling the Interactor getting Model from it and mapping it into the View Model. If there would be more complicated views, then the last task would be most probably offset into a special View Model Factory, which would do the job for Presenter. But since our case is simple enough, we don’t create classes just “for the sake of the approach”
  • for the Highlights, we use 2-stage view model, where there is one type for each Highlight and one for all of them to keep the state of expand/collapse away from Presenter
  • we use embedded Table View Controller for Payments and we use it also as Table View Data Source, we don’t see the need for separate type for that
  • we have altogether 3 View Controllers and only one Presenter!!! 😱😱😱Aaaaaaaaaggggrrrhhh!!! Touching the Holy Grail of VIPER! Well,… no. A Presenter is still there, handles presentation logic and to be honest, the second view controller is merely an embedded one with a purposefully integrated with a parent view and a third is a simple detailed view of the data, which was already acquired by a presenter, hence the latter referencing the view models
  • Payment Details View Controller doesn’t have any separate view?!? No, so simple it doesn’t need it, self.view can do it, but we shall see the code in the next chapter.

Conclusion of the Introduction

We identified some potential VIPER pitfalls, debunked some myths and we presented a solution, which doesn’t follow the concept blindfoldingly, but rather showing the bridge between the VIPER and the reality.

Next chapter will present our POC Project, present the sequence diagram and the code.

Stay tuned!

--

--