A deep discussion about coordinator, protocol, naming, and closure

Neil Smith is a subscriber to the Clean Swift list. He recently sent me an email asking about coordinator, protocol, naming, and closure.

After a few exchanges, I thought the discussion would be very beneficial to all of you. So I asked Neil if I could share it. He said yes. So here you have it.


Hi Raymond,

Thanks for everything you do at clean-swift.com. Your posts have really helped me clarify much confusion around architecture in iOS and swift.

I thought I’d share my take on clean swift: https://github.com/neilsmithdesign/clean-timer

I’ve got an ongoing large project underway where I’m trying to make use of clean principles (lots of learnings).

However, in the meantime, I’m putting together a demonstration of clean swift by recreating Apple’s standard OS clock app. In the github link is a work in progress app. I’ve made some variations to your theory which you might find interesting.

Coordinators instead of configurators

An object which plays a similar role to the configurator in your examples. Essentially, an object which is responsible for constructing and deconstructing VIP stacks and particular scenes. They also handle navigation via delegation (calls made from interactor as navigation is a business rule). I found having a coordinator useful for not having any memory cycle issues, regardless of the relationships that get established within the VIP architecture. As long as the coordinator owns the VIP stack, it can always take them out of memory.

Single protocols for boundary interfaces

I see in your email you have also updated to this. I’ve also used a protocol naming convention which hopefully reads logically at point of conformance (e.g. class StopwatchInteractor: ProcessesAStopwatchRequest { ... })

Callback closures from utility/worker objects

Simple but avoids further use of the delegate pattern/protocols when call/response is between two objects

I hope my work provides some useful insight for you (no matter how small) and keep up the great work at clean-swift.com

All the best,

Neil


Hi Neil,

Great work you’ve done there! It’s exciting to see more people take up the Clean Architecture principles in the iOS world. Massive view controllers are still way too common nowadays.

Coordinator

Did you get the coordinator idea from Soroush Khanlou? He’s been talking about coordinators for a while.

In Clean Swift, the configurator doesn’t actually own the VIP components. It simply sets up the VIP cycle by instantiating the components and setting the references. It doesn’t have any instance variables to hold references to them. When done, it gets out of the way.

But the latest template update removes the configurator altogether. You can read more about why here.

Routing, as I see it, has two phases: navigation and data passing. I don’t necessarily consider routing business logic.

Since Clean Architecture is more prevalent in web apps, I like to think about what routing really means in the web. If you think about web apps for a moment, what is routing? Take Rails for the sake of discussion. When the user clicks a link, the browser sends an HTTP request to the server. Apache or whatever receives the request and then dispatches it to the appropriate controller action using routes.rb. The routing, both navigation and data passing, is already done by the web server and Rails. By the time the request arrives at the app code (in the controller action), you only need to do the real business logic. Your app is not involved in the routing process.

Why would an iOS app be any different? So I like to put all routing logic in the router and keep only the real business logic in the interactor and worker.

Single protocol at the boundary

I think we’re on the same page here. 🙂

Naming is extremely important, IMHO. When I read a name in code, if I have to spend any mental capacity to think about what it means, that’s no good. It means I can’t be 100% focused on the task at hand.

I think I’ve achieved this with the new names:

  • View controller – Display logic
  • Interactor – Business logic
  • Presenter – Presentation logic

The actual names don’t really matter, as long as you don’t need to think twice when you see it in code. And you can always modify the templates to suit your personal taste.

Using closure instead of protocol at the boundary

We’ve also experimented with this in a super large client project. They’re alright. But I still prefer protocols because of the consistency.

When you use closure in this way, it usually means you’re trying to lump too much responsibilities in the interactor.

What you may try instead is to move some responsibilities to a worker. Establish the worker API with the closure syntax. This makes a lot of sense if the operation is asynchronous. But you can also standardize it with synchronous calls.

Your interactor can then call the worker using closure. Inside the code block, invoke your presenter when the results are available.

I found this to be much cleaner.

Keep me posted on your progress.

I think a lot of people will be able to benefit from this discussion. Do you mind if I share this?

Ray


Hi Raymond,

Thanks for your awesome response. Much appreciated. Please, be my guest, and feel free to share this discussion if you think your audience would benefit from it. Let me know if I can help 🙂 

These points are really useful. I’ve definitely benefited from trying to introduce clean architecture into one of my large projects; but there are things I’d change knowing what I know now.

To your points:

Coordinator

I’ve read a few of Soroush’s posts on coordinators. They’ve been thought provoking. Those, and also this talk from a developer called Steve Scott informed some of my thinking around coordinators (and here’s the code he’s used on github).

I’ve always viewed Coordinators, in my head, as sort of the ‘stage managers’. Like, in theatre, if a play transitions from one Act to another, their the ones responsible for running on stage, tearing down the current set/props and putting new ones in their place (a bit abstract but I hope you understand what I mean!)

Coordinators have been useful for having a clean “entry point” for new scenes in the app; and for managing the VIP objects. However, creating this object in this way definitely introduced some things which I’m not too happy about. For instance, simply navigating to the next scene involves too many calls in my opinion. Definitely code smell. So that’s something that I’d change. And has made me think that it’s circumventing segues for no particular reason – I’ll update my clean timer code soon, to include navigation code, so you can see what I mean.

I’ll certainly dive into your latest templates to see how I can refine things. I’ve never actually done any web/rails development so keen to leverage any best practices already out there.

Single protocol boundary

Agreed! Naming is so important. I do like the three naming conventions you’ve used (the three ‘logics’) as it makes it undeniably clear. One thing I’ve noticed about this pattern is that each scene has their own display/business/presentation logic protocols. Having lots of these is totally fine, however, it does feel like they’re primed for some kind of protocol inheritance to avoid simply writing out lots and lots of protocols. I’m just not quite what and how! Perhaps this is getting slightly ahead of myself, however, I’m wondering if thoughts like these have ever crossed your mind with respect to the protocol boundaries?

Closures

Interesting. So would the way in which the closure is used be reversed?

Not sure if you managed to take a look at clean timer on my Github page, however, I essentially use a closure for receiving back a time interval from the TimeController worker object. The interactor then decides what to do with this time interval (which is to package it up into a response and output it to the presenter). I got some inspiration for using the closure in this way (although it’s a pretty normal way to use a closure) from the folks at objc.io. They had a video talk with one of the developers at Kickstarter about how they use view models. I thought the way they constructed the view controller/view model relationship was really clean and a nice way to use closures/callbacks (code here)

Thanks again Raymond and great to connect. Look forward to more clean swift updates!

Also, later this year, I’m putting together a podcast focussing on how different iOS developers are writing code. So lots of conversations around design patterns, architecture, etc. I know we haven’t met before however, if I were to reach out later in the year, would you be willing to jump on a podcast? Would be great to chat.

Neil


Hi Neil,

You’re welcome, and it’s a good discussion. I enjoy it. It gives me more ideas on what to write next.

Coordinator

Do you have one coordinator for the entire app that handles the setup and teardown, and the routing between all scenes? This would be similar to the wireframe in VIPER, where it sets up everything in the app. Or do you have one coordinator per scene?

It feels like: Coordinator = Configurator + Router. Wouldn’t it be better to split it up?

Protocol

Protocol inheritance is deceptively tempting. But inheritance, of class or protocol, has a bunch of consequences:

  • Need to look at more than one protocol to find out if a method already exists
  • Inherit unused methods unnecessarily
  • Unintended behavior from parent methods
  • Refactoring becomes difficult with too many tangled dependencies when requirements change

Instead of inheritance, composition is better suited. However, in reality, when you find that you want to share code between multiple scenes. It’s is more naturally and appropriate to put the shared code in a shared worker. Then your interactors become just an entry point to the shared worker. The entry point is a lot simpler to write and it’s less important to be DRY. I would argue it may even be good to allow for custom before and after filters.

Closure

The way you described using closures is the way I was referring to earlier. I think that’s the most logical too.

Hey, a podcast will be fun. Count me in.

Ray


Hi Raymond,

Great points as always.

With Coordinators, I’ve been using mostly one per scene.

For protocols, that is very true. Lots of drawbacks for using inheritance. Especially when these ‘boundary’ protocols are ‘capabilities’ rather than ‘characteristics’. For example, with my CleanTimer example app, the StopwatchViewController outputs to the interactor via a protocol called ProcessesAStopwatchRequest. This naming style indicates some kind of specific capability of the object assigned to that output property on the view controller. So I can definitely see how composition would be suited here. There may be a scene which involves stopwatch functionality along with other features too. As such, providing an interactor which has each of these capabilities (i.e. conforms to several of these protocols including ProcessesAStopwatch) would allow for a nice, clean entry point.

Many thanks,

Neil


If you have questions too, email me.

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.

5 Comments

  1. Hi Raymond!

    How should one fit activity indicators and alert views with this architecture? I mean when a fire a request to the webservice I want to show an activity indicator while the response is being receive and parsed. How to I call the indicator? And if there is any problem with the data response, how to display an alert view? How to put the pieces together?

    1. Hi Fred,

      You can keep the mechanics of updating the activity indicator and displaying an alert in the view controller, but calculate the percentage done in the interactor and customize the message to display in the presenter. There is nothing to prevent you from invoking the presenter multiple times from the interactor.

      Hint: Invoke the presenter once immediately after the request is sent so you can start your activity indicator at 0%. Invoke the presenter again, multiple times, whenever the completion block is called by a worker which is doing the async work.

      1. I see… I was under the impression that I had to call the activity from the VC to the Interactor then to the presenter, but it makes a lot more sense to got from the Interactor to the presenter (testing for errors here) and finally calling the presenter to display the alertView and update the activity indicator. Thanks!!

        1. You’re welcome.

          Alternatively, you can also consider generating the activity indicator and/or alert as part of the presentation process. Then you can instantiate them in your presenter and pass them to your view controller whose only job is to get them onto the screen.

  2. Hi Raymond,

    with my pretty complex app, I’m on the way to refactor the UI in order to achieve a better user experience.

    This means that we need to go away from the current, pretty static and data-oriented way of navigation through all the various items and hierarchies, in order to achieve more flexibility in putting all the building bricks together.

    I experienced the concept of using coordinators as very helpful in this context. They brought a lot of clarity into the basic application structure, which I did not have up to now with clean swift VIP alone. As an example, the flow from setting up or initializing the app, down a hierarchy of UITabBarControllers down to the basic scenario VCs is working pretty well, when attaching coordinator delegates to those places where previously the router calls took place, and taking the router calls to the coordinator.

    However, I’m struggling with this questions: How can in general coordinators, VCs and routers be married so that the coordinator has the control of the major workflows, while the router cares about the details of these workflows, such as data transfer between scenes.

    Currently, it seems to me, that it might be an approach to use the coordinator delegate functions as replacement for the router calls, to call the router functions from the coordinator, and vice versa, so that the router knows the coordinator delegate functions as well, for instance, when returning from a subscene.

    What do you think?

    Hardy

Leave a Comment

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