I've never been a fan of VIPER. Furthermore, I've always agreed to a widely believed opinion that VIPER is an overkill for the most screens of any app.
There are tons of VIPER-related publications in the internet, but it turnes out that every team cooks VIPER in it's own way. I'm running through my recent recipe here.
I believe that technical and architecture 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 team, budgets, etc.
Everybody whispers: "Let the snake in"
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 of 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 to get into technical debt.
Letting the snake in
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 future and, for example, MVC for others.
I use VIPER for all the screens, no matter of their complexity.
In order to avoid writing a lot of boilerplate code I use an Xcode handcrafted template for codegen purposes + I've coded a tiny but helpful framework, that's responsibe 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, protocols generated. I can also add checkmark to create a corresponding Storyboard with ViewController inside, with 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, I started to receive a lot of profit and now I consider it to be an amazingly right decision.
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. 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 performs 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 custom camera module, that has:
- 1 Interactor
- 1 Presenter
- 4 implementations of ViewConrollers: photo, video, combined video + photo in the same screen, QRCode scanner
T.G.I. VIPER Otherwise it would be an incredible pain to juggle with these ViewController inplementations.
VIPER vs MVC finally explained
Module API Protocols that cover each module V, I, P, R components are like small packages for shit, that keep the whole shit organzied.
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.
- 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 mid-large size new project - definitely YES. Using VIPER on a small project with low budget is almost pointless.
Will I start using VIPER on a huge legacy non-VIPER project?
First of all, I will do my best to avoid old huge legacy.