Today we are starting a series of episodes to address one of the most common questions we get from people using the Composable Architecture, and that is: how do you share state amongst many features?
Now that question is surprisingly subtle. The Composable Architecture boasts having a “single source of truth”, and so shouldn’t that mean state is automatically shared? If you change one piece of state in the root store, doesn’t that mean every view sees that state immediately?
Well, that’s kind of true. In reality one tends to break a large, complex app into many features that can be run independently. In that situation, most, if not all, features do not have access to the entire app state. They only see a small portion of their state. And this is a good thing, as it encourages modularity and isolation.
But then the question is: how do you share the same piece of state amongst many independent, modularized features? We have a case study that demonstrates one way of attacking the problem, but to be honest we don’t really recommend people follow that style. It takes a lot of work, it’s easy to get wrong, and it’s easy to accidentally break the nice new observation tools we just recently released.
In various discussion forums we have told people that another way of handling shared state is via the dependency system. This allows you to immediately propagate a piece of state to all reducers, but we never created a case study to demonstrate this style, and it also has a lot of drawbacks.
And so we are finally ready to give some guidance on how to do this, and the solution is actually quite wonderful. It’s all made possible thanks to Swift’s new observation machinery, and it forces us to really grapple with what vague mantras like “single source of truth” really mean, and forces us to really understand the role of reference types and value types in our application.
And we have also gone above and beyond in these tools by providing two huge capabilities:
First, shared state is going to be completely testable. It can even be exhaustively tested. If that doesn’t sound impressive to you right now, then wait to you see how we implemented it. 🙂
And second, we are going to provide the tools necessary to persist state automatically. This means any changes to the state will be automatically saved externally and available on next launch of the application. And there will be multiple sharing strategies, such as user defaults, file storage, and more. This will look quite similar to how the @AppStorage
property wrapper works in SwiftUI, but it will be much better because it will be embedded directly in your Composable Architecture feature, and of course 100% testable.
We have a lot to cover, so let’s dig in!