We build a moderately complex application that has three external dependencies: network requests, network availability and location services. This gives us the perfect opportunity to concisely describe what a dependency is, how it makes our code more complex, and what we can do about it.
The technique of replacing protocols with simple data types goes far deeper than what we discuss above. Almost any protocol can be rewritten as a simple data type, and when you do so you can uncover a lot of interesting forms of composition that were previously hidden from us in the protocol world. To learn more watch our series of episodes on the “protocol witness” technique.
Well-designed dependencies and the Composable Architecture go hand-in-hand. If your dependencies are properly designed, then you will instantly unlock deep testing abilities of your application, including the ability to exhaustively assert the lifecycle of effects. To learn more watch our series of episodes on dependency management in the Composable Architecture.
We first talked about dependencies long, long ago in one of our first episodes. In these episodes we introduced the concept of modeling dependencies with simple data types instead of using protocols.
There are tricks we can employ to better design our test dependencies so that we can exhaustively describe what dependencies a feature needs to do its job. This comes with tons of benefits for tests, but also strengthens our SwiftUI previews and can even be handy for production code.