MVC, MVP, MVVM, MVVM-C and VIPER are just the same idea in different clothes
Stop treating MVC, MVP, MVVM, MVVM-C, and VIPER like five distinct philosophies. They all solve the same problem: keeping the View (the UI) and the Model (the data/logic) from talking directly. Whether you call the middleman a Controller, Presenter, or View-Model, the core architecture is always just a View, a Model, and a translator.
What is actually happening in these patterns?
If you strip away the jargon, every one of these patterns is just arguing over how much power the "translator" should have and who else should help it.
MVC is the grandfather here, dating back to Smalltalk at Xerox PARC in the late 70s. It was designed to separate data from the screen, which was a huge deal back then. But in a modern mobile app, MVC often leads to "Massive View Controller" where one file becomes a 3,000-line monster because every single feature has to pass through that one door.
Here is how a simple "change profile picture" feature looks in MVC:
class ProfileController {
onPhotoPicked(image) {
model.setAvatar(image) // update the model
view.render(model.avatar) // tell the view to refresh
}
}
In this flow, the View tells the Controller a tap happened, the Controller updates the Model, and then the Controller tells the View to refresh. It's fine for tiny apps, but it scales poorly.
Moving toward MVP and MVVM
MVP (Model-View-Presenter) tries to fix the bloat by making the View completely passive. The View does nothing but draw pixels. When you tap a photo, the View tells the Presenter, the Presenter updates the Model, formats the data into something display-ready, and pushes it back to the View.
MVVM (Model-View-ViewModel) takes this further by using data binding. The View-Model doesn't explicitly tell the View to update; the View just "observes" the View-Model. When the data changes, the UI updates automatically.
When do we need MVVM-C or VIPER?
Once you hit a certain scale, even MVVM fails because the View-Model starts handling navigation logic (like "where do I go after this button click?"). That is where MVVM-C comes in, adding a Coordinator to handle the routing.
Then you have VIPER, which is essentially the "final boss" of separation. It breaks the translator layer into even smaller pieces:
- Presenter: Handles UI logic.
- Interactor: Handles business logic.
- Router: Handles navigation.
VIPER is great for massive teams where you want different people working on the logic versus the navigation, but it's overkill for most projects. If you've ever felt like you were writing ten files just to show one piece of text on a screen, you've experienced the "VIPER war story."
The choice isn't about which one is "best," but about how much boilerplate you're willing to tolerate to avoid a 3,000-line file. For most of my work, a lean MVVM approach handles the load without the overhead of VIPER.
All Replies (3)
Relieved to see this. I spent three months fighting VIPER boilerplate before realizing it's just a glorified version of UIKit. Maybe try TCA?
I want to try this tonight on my project. Does this logic actually hold up when using Combine or RxSwift?

Finally someone said it. I used VIPER for a month before switching back to MVVM-C and it saved me like 500 files...