Duplicate protocols are going away

Some of you have raised the annoyance of having to declare the same methods in duplicate input and output protocols, in separate files.

I hear ya. You’ll love that they’re now gone in the latest update to the Clean Swift Xcode templates.

Read along to find out why those good, old reasons have become compromises that need to be re-evaluated and ultimately removed.

Naming…huh…

In the CreateOrder scene, the protocols in the VIP cycle are named:

  • CreateOrderViewControllerInput
  • CreateOrderViewControllerOutput
  • CreateOrderInteractorInput
  • CreateOrderInteractorOutput
  • CreateOrderPresenterInput
  • CreateOrderPresenterOutput

One reason I chose to name them this way was because I couldn’t find better names for them.

Take a look at the view controller-interactor boundary for the CreateOrder scene.

For the output of CreateOrderViewController, if we just have one protocol instead of two. I could name it CreateOrderViewControllerOutput. But then I found it weird for CreateOrderInteractor to conform to CreateOrderViewControllerOutput. On the other hand, if I name the protocol CreateOrderInteractorInput, CreateOrderViewController’s output would be typed to CreateOrderInteractorInput. Equally weird.

It was much nicer to have:

Now the naming weirdness is gone.

  • CreateOrderViewController conforms to CreateOrderViewControllerInput, and CreateOrderViewController’s output is typed to CreateOrderViewControllerOutput.
  • CreateOrderInteractor conforms to CreateOrderInteractorInput, and CreateOrderInteractor’s output is typed to CreateOrderInteractorOutput.
  • CreateOrderPresenter conforms to CreateOrderPresenterInput, and CreateOrderPresenter’s output is typed to CreateOrderPresenterOutput.

The VIP components don’t mention any other component by name in their respective files.

Redundant protocols…uh oh…

But the VIP components still need to be connected to one another to form the VIP cycle. So I experimented with two identical protocols and it worked!

And I could hide the ugliness in the configurator:

The connections, or plugging-in, are easily done using empty Swift extensions to add new protocol conformances:

  • CreateOrderViewController’s output is connected to CreateOrderInteractor’s input.
  • CreateOrderInteractor’s output is connected to CreateOrderPresenter’s input.
  • CreateOrderPresenter’s output is connected to the CreateOrderViewController’s input.

This means it’s a truly plugin architecture.

But the drawback is you have to declare the same method declarations twice for every use case. Once in the input protocol. Once in the output protocol. And they’re in two different files.

Plugin architecture…Hmm…

The original Clean Architecture, as described by Uncle Bob, facilitates a plugin architecture. That is, you connect the output of one module to the input of another module. These modules don’t talk to one another by concrete class types. Instead, they communicate by agreeing to an abstraction layer.

In Swift or Objective-C, this abstraction layer is modeled in the form of protocols. The VIP components connect to one another not by types, but by conforming to protocols.

You can swap out a module and swap in another with a completely different implementation. As long as both modules conform to the same abstraction layer, everything should still work. This is the premise of the Dependency Inversion Principle.

This plugin architecture sounds good in theory. But for an iOS app, you rarely, if ever, swap in another module for the VIP components. I’ve never had the need to do it.

In reality, each scene has its own VIP components, prefixed by the scene name. This cleanly separates the use cases for each scene. And it works spectacularly.

Less is more – Yay!

So, in the latest update of the Clean Swift Xcode templates, duplicate protocols are gone.

Three reasons:

  1. I found better names. The idea of the VIP cycle is already deeply ingrained in the DNA of anyone who uses Clean Swift. You know the view controller is for display logic, the interactor is for business logic, and the presenter is for presentation logic. It’s just intuition.
  2. Having to declare the same methods twice in two separate, redundant protocols for each use case is extra work without the plugin benefit. It gets in the way of a fluent workflow when implementing a new feature.
  3. The same inputs are always connected to the same outputs. Swapping modules in and out is not really practical for an iOS app. So the plugin benefit of the Clean Architecture is just in theory.

Instead of these statements that make you think twice:

  • Connect the VIP components:
    • Conform the view controller to the view controller input and presenter output protocols
    • Conform the interactor to the interactor input and the view controller output protocols
    • Conform the presenter to the presenter input and the interactor output protocols
  • Set up the VIP cycle:
    • Connect the view controller output variable to the interactor input
    • Connect the interactor output variable to the presenter input
    • Connect the presenter output variable to the view controller input

It’s much simpler and more intuitive this way:

  • Connect the VIP components:
    • Conform the view controller to the display logic protocol
    • Conform the interactor to the business logic protocol
    • Conform the presenter to the presentation logic protocol
  • Set up the VIP cycle:
    • Connect the view controller to the interactor
    • Connect the interactor to the presenter
    • Connect the presenter to the view controller

Clean Swift should illustrate these intentions, not the mechanics. Now the code reflects exactly that:

The components specify what they do, and the outputs are also renamed to the actual names of the components.

Because the configurator doesn’t need to do the plugging-in using extensions anymore, it makes it easier to remove the configurator altogether.

Let me know in the comments how you like this update.

If you haven’t subscribed yet, enter your email in the box below to download this update.

Raymond
I've been developing in iOS since the iPhone debuted, jumped on Swift when it was announced. Writing well-tested apps with a clean architecture has been my goal.

11 Comments

  1. Hi Ray, thanks for updating the templates.
    I still don’t get one thing:
    1. Interactor stores the data
    2. Presenter shows it.

    Let’s say that my interactor stores an array of data with 5 elements. And the presenter changes it to display an additional one (6 total). Now the tableView has to read the data from what the presenter gives, but in your examples the tableviews always read from the interactor, making the presenter kinda of useless. I mean the presenter cannot change the data at all because the interactor always stores the data that the VC reads.
    So what is the point of the presenter if it cannot change the data to be presented?

    I think this is still a bit messy part on the VIP.

    1. Hi Joao,

      The presenter formats the data but doesn’t present it. For example, it can formats a date from NSDate to String. The view controller then displays the date.

      Most of the time, the view controller reads the data in the view model sent by the presenter.

      However, I did illustrate a shortcut in the CleanStore sample app where the view controller reads the data directly from the interactor.

      This should only be done for the simplest case where formatting isn’t required. Even then, it’s still better and more consistent to stick to the full VIP cycle.

      I wrote some more detailed posts on this here and here.

    1. Can’t agree more, solved my VIPER issue…which, it full of input output protocol everywhere…nightmare. {Presentation}Logical is really a better naming.

  2. Cool, but I think it’s using in our project for a time. We first apply the Clear-Swift to our project, we started to use only one interface protocol for each boundary in the VrIP cycle.

  3. Hello Ray,
    I have a question, in the Presenter class there is this variable ‘viewController’. Why this must be a weak variable?
    Why the other injection variables in ViewController and Interactor aren’t weak too?
    Thanks!

    1. Hi Anny,

      The weak keyword for the viewController variable is necessary to break a potential retainer cycle. The VIP components have references to one another in a cycle. If they’re all strong references, the memory allocated for these components will never be released.

      1. Hello Raymond,

        I have an issue with this weak variable, I have this scenario in my Presenter Class when viewController var is becoming nil at some point. In that case It isn’t throwing any exception, just isn’t calling the DisplayLogic method that I want to call. This happens after displays the viewcontroller doing a PopToViewController in my navigationcontroller.
        I tried to set viewController as unowned variable (instead of weak), but I got this EXC_BAD_ACCESS error in the Presenter implementation method, when viewController.displaySomeThing is called.

        Can you help me? I need to understand what is happening and how to fix this.

        Thank you!

Leave a Comment

Your email address will not be published. Required fields are marked *