In our last series of episodes we discussed the idea of “deriving behavior”, which explored ways to break down large domains of application state and behavior into smaller domains. We showed ways of accomplishing this in vanilla SwiftUI and in the Composable Architecture. For the Composable Architecture in particular we saw some really cool applications of the .scope
operation, which allows you to transform a store that holds onto a big blob of data and behavior into smaller and smaller stores. We even showed how we use this tool in our word game isowords to allow tiny, leaf node views to work on only the domain they care about, which means they can also be extracted to their own modules, while still allowing them to be plugged into the whole app.
Scoping is a really powerful idea in the Composable Architecture, and so we should be using it liberally in our applications to break them down into smaller and smaller pieces.
However, all is not sunshine and rainbows in the Composable Architecture world. When you start building long chains of scoping and observations you run the risk of introducing performance problems if not done in the right way. Some of this can be solved in user land by being more vigilant with what parts of state need observing and what parts do not, and other things can be solved by the library itself. It turns out that some of the code in the Composable Architecture that handles scoping is not as efficient as it could be, and we want to take a moment to fix those problems.
Let’s start by first seeing what tools the Composable Architecture ships with that allows us to fine-tune the performance of our applications. To explore this we are going to pick back up the application we built at the beginning of the last series of episodes.