Why I stopped using NGRX
First things first: This is not an attack against anyone. The creators, contributors and participants in the development of NGRX are amazing developers, well above my skills and knowledge. They’re doing a fantastic job with their library trying very hard to make it better and “fun”er. This is not personal.
A little about me
Since this is my first Medium post EVER, I’ll introduce my self. I’m a front-end developer since 2006. Started in asp.net web forms, way back in .NET 2.0. Yep- I’m that old. For the last few years I’ve been helping other teams in my company (most of them WPF developers by training) join the wonderful world of web development. Angular in particular. With more experienced teams, I help with architecture issues and Angular in depth. I’m still an active developer though, so I do have some projects of my own.
Let’s get down to business
Since my first encounter with NGRX two or more years ago, I’ve had a bad feeling about it. Something felt “not right”. Too many moving parts. Too much syntax. Too hard to follow or debug. Sooooo much code. But everybody was using it. EVERYBODY.
Right from the get-go, I’ve tried to convince the devs around me to K.I.S and just use a service with observables. You see, I think some of the principals of redux are great. A single source of truth, async, unidirectional state works for me mentally. That’s why I love using a service. It gives you all that with good old code without making you jump through countless syntax hoops. So lets go point by point- why I stopped using NGRX:
“A service is for small apps, NGRX is for big apps”
I’ve heard it a million times. We all have. But you know what? I’ve never heard a good explanation why. Why is it better for BIG apps? I wrote a not-so-big application about a year ago starting with NGRX because, well, that’s what you do in Angular, right? besides, even though I had some experience with it, I felt I had to use it and learn more about it. After some time, feeling all the frustrations that NGRX brings,
I just said “the hell with it” and switched to a service. It took me about 5 hours to turn all that NGRX code to a debuggable, readable, K.I.S-able code. In 5 hours, my app “lost” 80% of its code and about 50 files (NGRX and unit tests) For the exact same functionality. A colleague of mine did the same with his app. He bettered me with a ratio of 1/7. As I see it- there’s no reason to think that this ratio is not constant. To put it in perspective- if I have a very small 700 lines of code application with NGRX- it can probably be written with just one hundred lines with a service. That’s 600 lines difference. In a big 21,000 lines of code application, the difference could be more like 18,000 lines of code. Now, although the number of lines by itself is not the only consideration, it sure is a big one.
“But what about the time traveling debugger?!?”
well, although the redux dev tool is really awesome, it’s there to solve a problem created by redux in the first place! When using redux, you basically lose the option to follow your code in the IDE or browser debugger, much like event based code. You fire an event (“action”) and it’s received by someone, somewhere, at some point in time. A very difficult pattern to debug indeed. My point is, that with a simple service, you don’t lose the time traveling debugger, you gain your plain, good-ol’ debugger. The one you’ve been using for years and years.
But decoupling!!!!
Yeah, I know, decoupling… Does NGRX give us decoupling? Does it really? We use typescript in Angular. Not javascript. Our code is TYPED. That means that when we use actions and selectors in our components, we IMPORT them. We import them again in the files where we listen to those actions (effects and reducers). So, true, components are decoupled from the effects and reducers but coupled to the actions and selectors from the store module. The decoupling myth probably comes from the javascript implementation where the type of the action and the selectors are “magic strings”. Now let’s consider the service way- is there really a difference between service.updateUser(userData) and store.dispatch(new updateUser(userData))? Instead of knowing the services’ API, you have to know the actions.
But Entities!!!!
Entities are a great tool and a very welcome addition to the NGRX tool-set. When using a normalized, flattened store, entities really shine. Wait, a normalized, flattened store? Yes, in redux, as the documentation clearly states ( right here), your state should be as flat as possible and normalized. much like your relational database. That means, that after using JSON and objects with as many nested properties as your heart desires all over your application code, when it comes to the state, you’re expected to be a DBA. Of course, a lot of your code uses objects with hierarchy, so you must use your selectors to “build” them every time from the store. When using a simple service, just use the same objects you use all over. No need for complex “join” selectors just to create an object you already had in your code but broke apart for the sake of the state.
But everyone’s using it!
Now that’s a good, solid, important point. This library gained so much traction over the last two years that anyone wanting to build an Angular app NEEDS to know it, if just to understand the examples on GitHub or elsewhere on the web. It’s true that “joining the pack” has many advantages, like examples, documentation and community support. It’s just that for me- “everybody else does it” never played a major role in my decision making. At work or in life. I urge everyone reading this- think for your selves. Be critical. Is this library for you? Does it give you a good set of tools to accomplish your mission? Is this library working for you, or are you working for it?
After years of NGRX being on top, things are changing. In the 2019 ng-conf, quite a few talks where about checking whether NGRX is really needed, or is a service a good enough solution. The crack in the dam is getting bigger and more well-known community members are talking about a service with observables as a viable option for state management. Some Examples:
Dan Wahlin also wrote this great post about it.
Of-course I must mention the now infamous “for flux sake” video by christoffer noring & Aaron Frost that was taken down a few days after it was uploaded…
And the last one (I promise) by Jesse Sanders, not from ng-conf :
In conclusion
I think NGRX had a great run, helped many developers get in to reactive programming, know the redux pattern which is huge on the web right now, but, for most of us, most of the time, there are much simpler, quicker solutions for state management. A service with observable subjects is just one of them. Akita (from Netanel Basal) is another great one. I truly hope that in the future, we’ll get a state management system built in to the framework and that it’ll be easy and fast to write…