Using composable architecture with a large graph of cached objects

I have been watching the tour video series and in general I am really intrigued by TCA. One big question I have though is around the best way to use it with a large graph based caching layer.

What I mean by graph based caching layer

For most of my career I’ve worked on “social” type apps. These apps include a remote graph of entities that are all interconnected together. Currently I’m working on a Mastodon app, so I’ll use that as an example.

Even just focusing on 2 entities, statuses and profiles, there are a ton of interconnected relationships. For instance the current user has various timelines, which are each a list of statuses. Those statuses each have a creator, which is a profile, and profiles have an inverse relationship of the statuses they’ve created. Profiles have a list of profile relationships for followers and following. A status has a list of profiles that have favorited and boosted. A status has a list of other statuses that are replies. And so on and so on.

Any given API endpoint could return a window into this graph, and different API responses will include overlapping data. For instance, getting the timeline will return the creator of each status, but not that creators followers. You could then tap into that profile, and load their details again from a dedicated get profile api. Then you could drill down further into their list of followers with its own API call and keep going from there. It’s pretty easy to get into a state where, for example, a profile name is loaded and displayed across several screens in a navigation stack.

In my experience, any time data gets out of sync in this scenario, users complain pretty quickly.

My current solution

The architecture that I’ve used for quit a while, for better or worse, is to cache all results from the API into CoreData and then drive the UI from the models. Loading a page will trigger a fetch from the API, the response updates the CoreData store, and then through notifications, KVO and more recently ObservedObject updates those changes get propagated to all the views that are displaying the updated models.

This has plenty of drawbacks (hence why TCA seems so appealing) but it works. Changes in one part of the app always updates everything that needs to know about the changes and when objects aren’t being referenced anymore, they are deallocated until they are needed again, at which point they get refetched from the local db.

Thinking through how this would work in TCA

I’m struggling a little bit to see how I would solve these same problems with TCA. I can see how a single screen might come together, but using the example from before (timeline > profile > followers) how would I model state so that fetching a profile on one of those screens propagates any changes to all other screens across the app?

I’ve seen an app that used React + Redux where they stored each entity in the root of the reducer state. For instance there would be an array of profiles and views always referenced those by ids, but I’m not even sure that would work in TCA (I don’t think child reducers get access to the root state).

I could imagine something where each reducer fetched and watched for changes independently using CoreData or something else. In this case your cache layer would be mostly independent from TCA state. But that doesn’t seem like it really fits.

1 Like