Darren asked me a question about my post on the Clean Swift iOS Architecture.
There are actually two parts to his question. So let me rephrase his question a bit:
- Sometimes your business logic is simply returning something from the underlying entity model layer. For example, fetching a list of available shipping methods from Core Data, over the network, or simply in a plist.
Should you go through the whole VIP cycle and have empty method implementation that just pass the same piece of data through the interactor and presenter and back to the view controller?
Or should you just return immediately from the interactor?
Going through the whole VIP cycle seems pretty dumb and unnecessary. Returning immediately allows you to quickly move on to another feature without writing all these boilerplate protocols and methods.
If you choose to return immediately, you can simply implement it as a property, or variable, or constant, instead of a method? It seems much simpler to do that. My example also implements
shippingMethodsas a property getter variable instead of a
As you can probably imagine, I asked myself these two questions A LOT when I was designing Clean Swift and using it for all my projects. I encountered almost every possible situation.
When I was converting Apple sample code to use Clean Swift, I often felt like going over my head. The sample codes are usually very simple. Apple shows you how to use their APIs instead of a complete app.
I wanted to make sure I didn’t create a bloated architecture that adds cruft instead of substance. My goal is always to find an architecture solution that can be applied to every project. I want the resulting architecture to work with a project. I don’t want an architecture that a project has to work with.
So, in the end, Uncle Bob has been right all this time. I believe I found something.
Now, to actually answer Darren’s question, I made a flowchart.
You’ll want to ask yourself the following 3 questions every time you implement a new feature or business rule:
- Is there business or presentation logic involved?
When there is any logic that needs to be implemented, you should do that in the interactor or presenter. It is preferred that you do this additional processing inside a method, rather than a property observer such as
didSet, or with a computed property getter.
Go with a full VIP cycle.
Is the response obtained asynchronously?
If you fetch the data asynchronously over the network, Core Data, or any blocking call, you simply don’t have the data until later. You could use a block, but be careful not to embed logic inside the block itself. You should extract the display logic to another method in the view controller, and call that method inside your block. But it is much simpler to stick to the gun.
Go with a full VIP cycle.
Is there a request model?
If your request object is not empty, that means you are passing some data as arguments to the interactor. You most likely have some hidden business logic that you aren’t even aware of. Maybe you want the shipping methods returned in a particular order? Examine your methods closely and see if you are properly handling it. Or, you may also find that you pass in data unnecessarily.
If request object is not empty, go with a full VIP cycle.
If request object is empty and you really don’t have any business rule, you can just use a property. You may still want to use a full VIP cycle because your app is likely to evolve. With the shipping method example in the CleanStore app, what if the store’s paid premium members can enjoy same-day delivery by Uber drivers? You suddenly need to check for membership before simply returning a list of all available methods. If you had done a full VIP cycle before, you can just fill in the blank in the empty methods. But if you didn’t, you’ll then need to turn the property into a method, and update a lot of tests.
In my interactor test example, I chose to just use a variable property for two reasons:
- I wanted to show you how to test a property a.k.a getter method.
It gave me a perfect leeway to show you how to change implementation while maintaining confidence in your code because it’s well covered with your tests. So yes, in a future post, I’ll tweak the shipping method business rule and convert it to a method AFTER we finish adding the tests back in.
This is a long answer to Darren’s question. But I feel it is important to explain some of the things I intentionally left out so far.
If you have questions about Clean Swift or testing, please leave a comment below. I’ll be happy to answer them because it means my readers are really reading and trying the stuff I write.