The ‘wiki’ pages I added some time ago are the best places to summarize topics and embed a list of related posts. So I added a page about VIPER and briefly had a look at my old posts.
On a side note, it’s funny how this approach looked kind of popular for a while, but never really caught on. Another example that programming is a pop culture. VIPER never made the Top 10. While it’s still an approach that does what it set out to do, the shorter ‘VIP’ tried to supplant it later, but the much less opinionated [view] coordinators really took the stage. (Crazy that Soroush’s post is from January 2015, which is 8 years ago.)
On Twitter, Manuel Schulze (@zet_manu shared the Swift package Resolver that does dependency injection in a very convenient way with little boilerplate thanks to property wrappers: Mr Dr Dominik Hauser replied, and that’s how it entered my Twitter timeline. I was curious why people use packages like this – I know the concept from Java, but have always found constructor injection and maybe a Service Locator here and there to suffice.
The folks at Swifting.io wrote a blog post about iOS software architectures. The comparison of VIPER and Clean Swift/VIP is very interesting: the VIP approach favors uni-directional flow, which I like very much. The article is worth a read for that alone!
They falsely consider MVC and MVVM to be software architecture approaches, though, and too point out that MVVM and MVC suffer from similar drawbacks.
As soon as you write a piece of software, you “architect” it. Can’t get around that; but if you do not do it consciously, the resulting structure may not be great. Taking ownership of the process is important to change the result and create maintainable software. When we write/architect software, we worry about two things:
Criticism targeting MVVM (Model–View–View-Model) from late last year essentially points out it’s not the silver bullet some take it for. Most of the stuff is missing the point. How are you supposed to make sense of it? What’s good advice for your project?
That’s a recent question from the comments put in my own words. A view model that encapsulates the display state sounds promising at first. But when you don’t have a simple view that displays one thing, how do you model that in code? How do you model a sequence of view controllers, for example a more complex checkout process?
They discuss general project architecture, using tools to generate module files, and how passing data from one Wireframe to another works in their app.
I haven’t used VIPER in an iOS app, yet, but I used the concept in the Word Counter. There, nothing’s disposed after setup, so I have all Wireframes and their components setup once upon launch. The authors use Wireframes as factories for view controllers.
A Note about Syncing Changes: Where to Handle Sync Events
Further down, under “How to deal with listening changes from backend?”, the authors show how synchronization changes take effect.
The SynchronizerService merges changes into the Core Data stack,
the Core Data Stack sends a notification,
the Interactor receives the notification,
and changes are then pushed through the Presenter to the View.
This works, but I find the decision to be weird. Now the Interactor prepares data when requested and pushes changes upon synchronization events.
Usually, the Presenter is created in such a way that it both presents data to the view and handles events from the view. You can split this into two objects, let’s say Presenter and EventHandler. Then it becomes clear that the EventHandler can deal with events both from UI interaction and from syncing. It’s the best fit to translate any event into a command for the Interactor so it does its job.
One of the commenters nailed it: any MV* variant focuses on architecting view components. Only VIPER takes the application as a whole into account. MVC by itself is an architectural pattern, but not an approach to app architecture in itself.
A UIViewController belongs into the user interface layer and is, in fact, a composite view itself. That’s confusing at first because of the name. This insight will liberate you from thinking that a view controller is sufficient to glue data to UIKit components. There’s room for a whole application between these two.
The VIPER example is exceptionally good. It takes VIPER’s heritage of Clean Architecture and Hexagonal into account and defines the Interactor through an output port. In that way Bohdan’s sample code is more east-oriented and cleaner than what you’d usually find on the topic:
protocolGreetingProvider{funcprovideGreetingData()}protocolGreetingOutput:class{funcreceiveGreetingData(greetingData:GreetingData)}classGreetingInteractor:GreetingProvider{weakvaroutput:GreetingOutput!funcprovideGreetingData(){letperson=Person(firstName:"David",lastName:"Blaine")// usually comes from data access layerletsubject=person.firstName+" "+person.lastNameletgreeting=GreetingData(greeting:"Hello",subject:subject)self.output.receiveGreetingData(greeting)}}
Usually, you’d model provideGreetingData() as a function that returns the data to the caller. This will cause trouble in async processes of course.
You see in the full example that the amount of types seem to explode. Don’t be afraid of that as long as you can assign each type a specific responsibility. Then it won’t turn into the mess everyone seems to be afraid of.
Having used VIPER in apps myself, I see a problem with the names, though. XYZInteractor and XYZPresenter aren’t much better than XYZController in terms of expressiveness. On top of that, a concrete Presenter is always modelled to act as event handler, too. Don’t let this fool you into thinking you absolutely have to do this yourself – there’s always room to separate writing from reading operations, or event handling from view population.
The test project I work on to develop a component of the Word Counter faster sets up a lot of service objects during launch. I shaved off 60 lines of AppDelegate by introducing bootstrapping as a thing to my code. This way you can prepare a list of Bootstrapping components and iterate over them to set up one after another.
Oy vey, now there’s a ton of AltConf 2015 talks online, too! So much to digest! In “250 Days Shipping With Swift and VIPER” by Brice Pollock, he shows how the folks at Coursera do some clever things with the VIPER iOS app architecture: they use a Router which handles internal URLs.
After working on the model of your app for a while, it can be hard to change your ways of thinking and see what should be coming next. How does an app come out of all this? Where does the user interface plug in? It helps to architect your app in layers and focus on the missing parts before figuring out the glue.
Ryan Quan of Brigade Engineering has published an article about using the VIPER iOS app software architecture. Their write-up is really good: message passing is illustrated with code samples – and they even use neat box graphs!
I use a VIPER-like approach in my apps, too, and I’d like to invite you to try it for yourself. VIPER is inspired by Clean Architecture and Hexagonal.
In a nutshell, you decouple the view controllers from event handling from data management. You introduce so-called “Wireframes” to set up a module or “stack” of objects to display a view controller with certain data. The Wireframes set up everything once. Afterwards, event handlers take over, called “Presenters”. They perform transitions between scenes. View controllers do not much more than setting up the view and reacting to IBActions.
This will make maintaining code easier because the view controllers are finally put on a diet. Figuring out how data has to flow differently takes some getting used to. I’m going to write about this in a future post.
UIStoryboardSegues are a blessing to add rudimentary navigation between view controllers in iOS projects. User interaction can trigger segues without any code. That’s all good and well to move back and forth between mostly static scenes in your Storyboard. Passing data around is not so easy, though, without making things more complicated.
Like I promised last weekend, I am going to write about the process of cleaning up the already rotten source code of Calendar Paste. In order to break massive view controllers into manageable pieces and un-tangle everything, I have to make sure that I don’t break the current implementation. Calendar Paste didn’t have any automated tests in place. To change this fact is my first priority.