Unlock This Episode
Our Free plan includes 1 subscriber-only episode of your choice, plus weekly updates from our newsletter.
Today we are going to begin a series of episodes on “designing dependencies.” We’ve talked about dependencies quite a bit on Point-Free in the past, starting over 2 years ago when we introduced the idea of dependency injection and how it can be made quite easy by packaging all of your dependencies up into one mega struct. And then earlier this year we showed how to bake that notion of dependency injection directly into the Composable Architecture so that each feature of your application precisely describes exactly what dependencies it needs to do its job, and then as you decompose your app into smaller and smaller components you simply describe how to slice up the entire world of dependencies into just the subset a particular component needs.
There are some really powerful ideas in those episodes, but what we haven’t done yet is discuss exactly how to design dependencies when you are writing code in this style. We’ve shown a few hints of how to do this, for example we strongly recommend forgoing classes, protocols and manager objects, and instead use simple data types. It can be a little uncomfortable to disband with those tools since they’ve been in our tool belt for so long, but there is a lot of power in doing so. So, we want to spend a little bit more time with this style of dependencies and show how to wrap some pretty complex functionality in simple data types instead of using protocols, and we’ll show that this unlocks some truly amazing functionality.
Our application currently has no error handling around API requests. Update the view model and view to show an alert when a weather request fails. Use the failed weather mock to verify that things look as they should.
When we added a delay to the happy path weather mock we found the user experience to be lacking. Update the view model and view to render a loading indicator when the weather request is in flight. Use the delayed happy path weather mock to verify that things look as they should.
Our first episode on dependencies, where we show that they can be wrangled quite quickly and effectively by introducing a global, mutable instance of a struct.
Today we’re going to control the world! Well, dependencies to the outside world, at least. We’ll define the “dependency injection” problem and show a lightweight solution that can be implemented in your code base with little work and no third party library.
Let’s have some fun with the “environment” form of dependency injection we previously explored. We’re going to extract out a few more dependencies, strengthen our mocks, and use our Overture library to make manipulating the environment friendlier.
We made dependencies a first class concern of the Composable Architecture by baking the notion of dependencies directly into the definition of its atomic unit: the reducer.
Stephen gave a talk on our
Environment-based approach to dependency injection at NSSpain 2018. He starts
with the basics and slowly builds up to controlling more and more complex dependencies.
In our first episode on side effects we first show that side effects that depend on the outside world can be controlled by passing the dependency as input.
Side effects: can’t live with ’em; can’t write a program without ’em. Let’s explore a few kinds of side effects we encounter every day, why they make code difficult to reason about and test, and how we can control them without losing composition.
Apple’s eponymous WWDC talk on protocol-oriented programming:
At the heart of Swift’s design are two incredibly powerful ideas: protocol-oriented programming and first class value semantics. Each of these concepts benefit predictability, performance, and productivity, but together they can change the way we think about programming. Find out how you can apply these ideas to improve the code you write.
An old article detailing many of the pitfalls of Swift protocols, and how often you can simplify your code by just using concrete datatypes and values. Chris walks the reader through an example of some networking API library code, and shows how abstracting the library with protocols does not give us any tangible benefits, but does increase the complexity of the code.