Decouple Responsibility | raywenderlich.com


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/5443783-kotlin-coroutines-in-depth/lessons/9

so the purpose of this is purely for swapping out the schedulers during a test? or is there other reasons why? cheers!

Hey @eoin_a !

Decoupling code is a good practice overall, because it is easier to swap out the Coroutine code with something else, if it ever comes to that.

Having the ContextProvider is great for testing, as you can do even more complex tests, like integration tests, and you can use the provider to mock contexts, and enable coroutines.

But it is also good if you’re using the Strategy pattern, for your data sources. For example, you could have an interface named DataSource<T>, which provides a data type for you - like a user profile, or list od items, or settings, or similar.

Then you could have concrete implementations like so:

RemoteUserDataSource(val provider: CoroutineContextProvider) : DataSource<T> {
  ...
}

LocalUserDataSource(val provider: CoroutineContextProvider) : DataSource<T> {
  ...
}

Both of those sources have a provider, but one provider could use the IO Dispatcher, for the API calls, and the other could use a Default dispatcher, if it’s reading from the database, or from in-memory cache.

Since the provider is abstract, the internal works don’t know about the contexts, but once you decide to switch from one context/dispatcher/scheduler, to another, you can do so in an abstract way, using Providers.

It also gives you room to implement custom contexts and providers, in case you come up with a specific case you want to do that in, like having custom threading and lifecycle handling, error handling, or something else.

Hope this helps! :]

Hi @filbabic, thank you for this amazing Coroutines course. I’ve a question for this episode, why we still need an abstraction or wrapper such as CoroutineContextProvider instead of directly inject a CoroutineContext ?

Hey @rrsatudua!

By abstracting away the context in the provider, you can now mock the provider in tests, and return different contexts in every function, if needed.

But a bigger benefit would be that you don’t necessarily have to depend on a pure CoroutineContext, you can instead wrap complex contexts with error handlers, lifecycle, and other functionality, within the Provider.

If you don’t have such a use-case, it’s easier to just inject the context, so it also depends on what you’re trying to achieve!

Thanks,
Filip B.

1 Like

Hi @filbabic thanks for your explanation. :+1:

1 Like