So, this is a pretty big missing part of the ergonomics story for the Composable Architecture. We need to figure out a way to use Effect.task
in our reducers because there are a ton of benefits:
It makes for simpler dependency clients that can just use
async
instead of returningEffect
values, which means that our dependencies don’t even need to depend on the Composable Architecture.
It makes for simpler live and mock instances of dependencies
It makes for simpler construction of effects in reducers, and we can chain multiple asynchronous tasks together by just awaiting one after another.
And finally it means we can even sometimes remove schedulers from our environment, especially if we don’t need to schedule time-based work.
But most importantly, we want to allow usage of Effect.task
in our reducers in a way that does not affect tests. Testing is by far the most important feature of the Composable Architecture, and we try our hardest to never add a feature to the library that hurts testability. We should strive to be able to write fully deterministic tests that run immediately.
And Effect.task
is really just the tip of the iceberg. There are a lot more ways we’d like to more deeply integrate the library with Swift’s concurrency tools, but let’s start with the problem of Effect.task
not being usable in reducers.
The main problem with using async/await directly in the reducer is that all new asynchronous contexts are spun up when effects execute in tests, and we are forced to wait for small amounts of times for those tasks to finish and feed their data back into the system.
Let’s see how we can fix this.