iosswiftsingle-responsibility-principleofflineappsviper-architecture

iOS Offline first app single responsibility issue


I am switching to offline firs app from my already made online app.

This is how online works:

I have VIPER interactor which requests data from service. Service knows how to request data from API layer. So then I have callbacks with result or error and process it in integrator and then update local storage if needed. Nothing super hard here.

So all elements, Interactor, Service and API are single responsibility objects and do only one task:

Interactor handles if blocks logic to handle result or error and trigger presenter to display data

Service calls for API

API calls Alomofire to do rest of work with requests.

So now in offline first app I added RequestService where I store all my requests and then send it using Timer and in case connection is online.

So now I need to overload single responsibility somewhere to check next things.

So first off all I need to check reachability:

if noConnection() {
loadLocalDataToShow()
}

Next I need to make sure all requests has been sent:

if requestsService.pendingRequests > 0 {
loadLocalDataToShow()
}

So there are two approaches as I thinks:

  1. Make global check. Like providing API layer to do these checks for me and return some enum Result(localData) or Result(serverData) after Alamofire returned for me with result or if no connection.

  2. Or second one make interactor to do these checks like this:

    func getData(completion ...) {

    Service.getData() result in {
    
    if requestService.pendingRequests > 0 {
        completion(loadLocalData())
    }
    
    if result.connectionError {
        completion(loadLocalData())
    }
    
    completion(result) //result it's returned data like array of some entities or whatever requested from the API and fetched directly from server via JSON
    
    }
    
    }
    

so now we will have kind of all of the same check for all interactions which requested data, but seems we have not broken single responsibility or maybe I am on a wrong way?


Solution

  • TL;DR: IMHO, I'd go with second one, and it won't be breaking SRP.

    VIPER Interactors tend to have multiple services, so it's perfectly fine to have something like OnlineRequestService and OfflineRequestService in the interactor, and act accordingly.

    Hence, you won't be breaking SRP if you decide which data/service to use in the interactor itself.

    To elaborate more, let's say that there was an initial requirement for user, that they may use the app online/offline. How would you plan your architecture? I would create the services mentioned in the upper part, and let the interactor decide which service to use.

    Interactor in VIPER is responsible for making requests, and it may go with different Services, such as CoreDataService, NetworkService, even UserDefaultsService. We cannot say that interactor is doing only one task, but it doesn't necessarily mean that it has more than one responsibility. Its responsibility is to take care of the flow between the data and the presenter, and if there needs to be a decision between which data (online/offline) to use, it would reside in the interactor's responsibility.

    If it still doesn't feel right, you may create an additional interactor, but who/what would decide which interactor to use?

    Hope this helps.