Lets say that you go to your favorite pizza joint and order your favorite pizza: Hawaiian. You place your order and then wait patiently for the pizza to arrive. When it finally appears it is just cheese, sauce, ham, and pineapple in a pan. You look at the waiter and ask where the bread is. She replies, “oh, the kitchen didn’t have any flour, you should have told them to go get some.”
This is how I felt with my usage of NgRx. I was basically using it as an in-memory db where everything was properly normalized. I had projections off of my normalized state that combined different slices to create my view-models. It brought a nice structure to my app.
A problem that I quickly encountered is that the producers and consumers of data are disconnected. This is by design as there could be multiple producers (local and remote) and there isn’t any mechanism to associate an initial producer with a slice of state.
At first this was easy to solve. I just select the data and then fetch it like so:
store.select(x => x.soda); store.dispatch(new FetchSoda());
This became more cumbersome and error prone when I had projections that required 5+ fetches. Inevitably I would forget a fetch.
store.select(x => x.hawaiianPizza); store.dispatch(new FetchCheese()); store.dispatch(new FetchSauce()); store.dispatch(new FetchHam()); store.dispatch(new FetchPineapple());
Did you spot the missing fetch? Sometime the data would be there based on the previous actions I performed in the system and sometimes it wouldn’t. I felt like I was a customer who had to tell the chef which ingredients to use to fill my order. It was a poor separation of concern.
One solution was to add a layer of abstraction on top of the projections that also fetched their data as a side-effect on subscribe. Then I could add a cache check in the Effects that do the fetching to avoid excessive api hits. But what I really wanted was the simple act of subscription to flow back to the source streams that were combined into my projection and trigger them (RxJs style). I wanted a way to identify the producer responsible for initializing a slice of state when it was needed rather than repeating the logic in each projection.
I also didn’t like having a single global state because it made sharing components between projects awkward as different projects relied on different combinations of slices of state. I eventually solved that problem with a liberal application of interfaces (see here), but short of having a global message bus I didn’t really benefit from having all of my state in one tree.
So I setup a lite-weight, Reduxish style store which you could create an instance of for each bounded context. It allows you to specify which producers are hot (meaning that they are always pushing data) and cold (meaning that they will only activate upon subscription). I named it YARI (Yet Another Redux Implementation) because we probably have too many as it is. But here it is nonetheless: https://github.com/bygrace1986/yari
Erik is an agile software developer in Charlotte, NC. He enjoys working full-stack (CSS, JS, C#, SQL) as each layer presents new challenges. His experience involves a variety of applications ranging from developing brochure sites to high-performance streaming applications. He has worked in many domains including military, healthcare, finance, and energy.