Workers of Clean Swift Architecture

Hello reader!



Earlier, we examined how the VIP cycle is arranged and how to make transitions between prices and data transfer. Now you need to figure out how to unload our Interactor from an overabundance of logic and take out part of it for reuse by other scenes. And Workers will help us with this. The topic is quite modest in volume, but important for mention.







Theory



Workers are auxiliary classes / structures (not to be confused with services or helpers) whose task is to take over part of Interactor ’s business logic. If the methods in Interactor are expanding, then it's time to take out the voluminous logic in Worker . In Clean Swift, they are used to work with the logic of data storage, with the network, with individual layers of the application, and so on. In other words, everything is voluminous, low-level and not related to the business logic of the application.



Workers are divided into two main types:



  1. Local that are used only inside the scene.
  2. Global that are available for any scene.


Local Workers are placed directly inside the scene and are named after her - SceneNameWorker . Global Workers are located in the root directory of Workers and are named according to their subject. Local Workers can also act as “decorators over global”, with extended logic for the needs of the scene.



If you use the separation of the project into layers ( Presentation , Business Logic , Persistency , Network Logic ), then the role of the connecting bridge between the Presentation layer and Business Logic can be assigned to Workers . Thus, we will unload Interactor , get more predictable behavior and ease of reuse.



Practice



The work of Workers we will consider on the example of working with the network. We will have two screens - on the first a list of users is displayed, and on the second a list of posts of this user. All data will be taken by API . We will divide this task into three Workers , two local and one global, which will act as an entry point for the other two. I will hide the implementation of the methods themselves in the article, and whoever wants to try out in practice, there will be a link to the finished project at the end of the article.







This project structure is not a reference for working with a network and does not reflect in any way how to work with it in Clean Swift . All this is done only for a good example of the role of local and global Workers .



To begin, create a global Worker - NetworkWorker . Place it in the Workers directory, at the same level as the Scenes directory. In the example below, there is a sendRequest (to: params: completion) method, which will be common to local Workers . He performs a routine task - forms a link from the parameters, sends a request and sends the result to completion .



struct NetworkWorker { // MARK: - Private Properties private let session = URLSession.shared // MARK: - Public Methods ///  Worker.    API /// /// - Parameters: /// - to: ,     /// - params:    /// - completion:     func sendRequest(to: URL, params: [String: String], completion: @escaping (Data?, Error?) -> Void) { // ... } }
      
      





For the first scene, we need to get an API list of all users. To do this, we create a local HomeWorker that will configure the parameters for loading users and call sendRequest (to: params: completion) in NetworkWorker with these parameters. Now in the scene Interactor we need to call fetchUsers (completion :) and send the received data for processing to Presenter .



When you click on a table cell with the username, we will make the transition and transfer the selected user to another scene.



 struct HomeWorker { // MARK: - Private Properties private let networkWorker = NetworkWorker() private let usersURL = URL(string: "https://jsonplaceholder.typicode.com/users") // MARK: - Public Methods ///  Worker.   API     /// /// - Parameter complete:     func fetchUsers(_ complete: @escaping ([User]?) -> Void) { // ... } }
      
      





On the page with user posts, we create PostsWorker , but only with the fetchPosts (userId: completed :) method. In it, we pass the ID of the user whose posts you want to download. In the method, we form the parameters and call sendRequest (to: params: completion) in NetworkWorker . And in the same way as before, we call the fetchPosts (userId: completed :) method in the scene's Interactor , passing the received data to Presenter .



 struct PostsWorker { // MARK: - Private Properties private let networkWorker = NetworkWorker() private let postsURL = URL(string: "https://jsonplaceholder.typicode.com/posts") // MARK: - Public Methods ///   API      /// /// - Parameters: /// - userId: ID ,     /// - completed:     func fetchPosts(userId: Int, _ completed: @escaping ([Post]?) -> Void) { // ... } }
      
      





Now our entire implementation has been moved to separate files that can be reused, without loading the business logic in Interactor .



Conclusion



Although Workers are very simple and do not reveal any hidden knowledge about architecture, their use is important in Clean Swift . When writing Workers , don't forget about protocols, structural patterns, and DI. Otherwise, you will quickly form a mess of Workers , where everything that could be taken out was taken out in pieces.



That's all. Thank you for reading to the end, below is a link to the full project.



Series of articles



  1. Understanding Clean Swift Architecture
  2. Router and Data Passing in Clean Swift Architecture
  3. Workers of Clean Swift architecture (you are here)
  4. Testing your application on the Clean Swift architecture
  5. An example of a simple online store architecture Clean Swift


Link to the project

Help in writing an article: Bastien



All Articles