I've never been a fan of VIPER. Furthermore, I've always agreed with a widely believed opinion that VIPER is overkill for most screens of any app.
There are tons of VIPER-related publications in the internet, but it turns out that every team cooks VIPER in its own way. I'm running through my recent recipe here.
I believe that technical and architectural decisions should be in sync with business needs and depend on the particular case of the project. Terms and deadlines, size of the project, size of the team, budgets, etc.
The project started in the middle of 2018 as a startup and was going to be rather huge and long-term. Now the app is having about one hundred screens in total.
We were moving fast from the very beginning. We often worked on those parts that were clear enough to be done right at the moment just to push the project forward. That frequently led to a totally upside-down-driven development when server API and business logic on the app side are ready and designs are not.
I've started as the only iOS developer on the project (nothing has changed, actually). But we had plans to enlarge the mobile iOS team in case of need.
I desperately needed as much decoupling as possible to handle these constant changes, keep the app stable, and not get into technical debt.
Should We Use VIPER for Every Screen?
Dealing with VIPER, there are two possible
- Keep the codebase consistent and use VIPER for all screens
- Use VIPER for complicated screens that may need to be extended in the future and, for example, MVC for others.
I use VIPER for all the screens, no matter their complexity.
In order to avoid writing a lot of boilerplate code, I use an Xcode handcrafted template for code generation purposes + I've coded a tiny but helpful framework, that's responsible for putting VIPER module components together.
With the help of these two guys, the whole process of module creation is:
- Xcode -> New File -> Module
- Add module to AppModules enum as a new case.
- Profit. The new module can be already presented.
I get all necessary module-specific files, classes, and protocols generated. I can also add a checkmark to create a corresponding Storyboard with ViewController inside, with the necessary storyboard ID assigned.
Frankly, I was feeling all that heavy overhead of VIPER during the time I was getting used to it. As soon as I got used to it, I started to receive a lot of profit and now I consider it to be an amazingly right decision.
Pros of Using VIPER
Reliable. Not about VIPER itself, but the way I build modules guarantees their correct instantiation. It allows to avoid common mistakes, caused by forgetting to pass some parameter or dependency. A great help when the amount of modules grows up to a hundred.
Slim UI. Being dumb as a tree, ViewController is usually amazingly slim, does not keep any state, and is used just as a middleman between Presenter and View, sometimes performing some animations.
RIP. Fat and unmaintainable ViewControllers.
You usually don't have problems with tests if you don't write tests, but at least you can do it.
Clean. Each module has an API which is defined as a set of Protocols covering its components. Very helpful for understanding how the module works.
Flexible. There are several levels of flexing the modules. Currently, posts feed module which is one of the most complicated has:
- 1 Interactor with 9 content settings, passed as a part of its config (different kind of feeds)
- 2 implementations of Presenters. Compact and extended option of posts presentation
- 6 implementations of ViewConrollers. 3 of them have much in common and share some base implementation, 3 of them are unique.
Another example is a custom camera module, that has:
- 1 Interactor
- 1 Presenter
- 4 implementations of ViewConrollers: photo, video, combined video + photo on the same screen, and QRCode scanner UI.
Thank God, it's VIPER. Otherwise, it would be an incredible pain to juggle with these ViewController implementations.
VIPER vs MVC Finally Explained
Module API Protocols that cover each module V, I, P, and R components are like small packages for shit, that keep the whole shit organized.
So, in other words, while we are applying a lot of changes constantly, VIPER is working like a strong basement for every screen, making the code structure still and extendable at the same time.
Cons of Using VIPER
- Boilerplate code that I've mentioned. Codegen partially solves the problem.
- N-times more files, protocols, etc. Frankly, I haven't reached the moment of uncomfortable build times or any other problems caused by a project size. Probably because my 6-core i9 is fast.
- Higher entry barrier. I've faced two cases when it wasn't easy for new developers to dive into VIPER at our project. BTW I've heard a legend that it is Russians who invented VIPER as a strong evidence of accidental complexity.
Will I Use It in the Next Project?
Strongly depends on the project, but I would love to.
If it's a mid-large size new project - then it makes a lot of sense. Using VIPER on a small project with a low budget is almost pointless.