
Why we decided against GraphQL for local state management - threatofrain
https://tech.okcupid.com/why-we-decided-against-graphql-for-local-state-management/
======
pier25
State management is one of the reasons I moved away from React and Vue. You
need a lot of machinery and plumbing to do something that should be really
simple.

MobX is probably the best way I've found to manage reactive state with React,
Inferno, etc, but still, it's a huge piece of of software for just this
purpose.

I first moved to Mithril because it doesn't need reactivity. You solve the
same problem than React/Vue _et al_ in just 10kB. No need for an external
router or a state management library. Your state is just vanilla JS. Mithril
doesn't need to know when a particular piece of state has changed, it just
tries to re-render everything and the vdom takes care of the rest. The
performance is comparable to Vue 2 and React [1] but the DX is lightyears
ahead. It's a sushi chef knife though, you really gotta know what you're
doing[2].

Now I'm using Svelte because it's even better. It does have reactivity but the
compiler just figures out the dependency graph so you don't need to ship a
huge thing like MobX to do that at runtime. You also write a fraction of the
code compared to all the other frameworks I've used which is Svelte's best
feature. This compiler approach is a game changer IMO.

[1] [https://krausest.github.io/js-framework-
benchmark/current.ht...](https://krausest.github.io/js-framework-
benchmark/current.html)

[2] What I meant by this is that since your app is essentially vanilla JS
you're on your own to architecture the thing. If you don't know what you're
doing you will shoot yourself in the foot.

~~~
openfuture
> should be really simple

Ummm... no, state management is pretty much the only hard problem in
programming.

~~~
sidlls
Can you support that? This doesn't seem like anything approaching the truth in
the vast majority of web applications (where things like React are typically
used). Mostly, in my experience, front end development is made unnecessarily
complex by the developers involved.

~~~
rubber_duck
"Just code up 6 these screens, we already have everything working in sketch -
how long could it take"

Then you realize the "6 screens" actually turn in to a 50 step state machine
that shares state between screens and changes screen logic conditionally on
other screens, and the designer created sketches for the happy path.

And your "really simple straightforward state management" now has you going
through 10 steps and 3 screens before you can arrive your state 11 which you
are working on, you can't unit test the logic because your state is tightly
coupled to UI and the HTTP stack, you can't reason about state updates because
it's happening all over the place and is written by 3 other people
concurrently, and coming to the project 6 months later makes you quit on the
spot.

I've written plenty of WinForms to JQuery UI to know that "simple state
management" is anything but.

Redux has initial overhead but down the line it pays for it self in these
scenarios many times over. Going over requirements/flow with product owner and
then writing tests for a reducer specifying the expected states is incredibly
powerful in ironing out miscommunication in requirements and much faster than
sending iterations of UI app to testing.

Like the parent said - the hairy part of the app ends up being dealing with
the state machine - shuffling data over the HTTP is trivial,
CSS/layout/animation are not that hard if you know what you're doing and don't
need to support ancient browsers.

------
city41
I largely came to the same conclusion, including going back to Redux. I have
found using Apollo for client side state very cumbersome and even difficult.
You really do need to understand their cache well, and I also dislike having
to deal with things like __typename, which I feel is an implementation detail
that unfortunately gets foisted onto the end developer. Sometimes __typename
is a royal pain in the butt.

The article touches upon current Redux as well, such as when it says "If done
right, it can definitely be a breeze to work with", which I agree with. And
the "if done right" part has gotten a lot easier, as Redux has finally decided
it's ok to provide opinionated approaches that guide you towards that happy
path. I really do think if Redux hadn't been so concerned about being
opinionated way back when, it'd be far better received today. But better late
than never.

~~~
acemarke
> I really do think if Redux hadn't been so concerned about being opinionated
> way back when, it'd be far better received today

Can you clarify what you mean here?

From my perspective as a Redux maintainer, most of the concerns I've seen
expressed about Redux over the last few years really didn't focus on whether
it was "opinionated" or not. It's been a combination of:

\- Not understanding the original intent behind Redux's design and the
historical context that led to it being designed that way [0]

\- People being told they _had_ to use Redux with React, even when it really
wasn't a good fit for their use case

\- The "incidental complexity" of common Redux usage patterns [1], most of
which were due to the way the docs and tutorials showed things (writing `const
ADD_TODO = "ADD_TODO"`, separate files for actions/constants/reducers, etc).

\- Changes in the ecosystem leading to other tools whose use cases overlapped
with why you might have chosen to use Redux previously

All that said, yeah, we've made a concerted effort in the last year or so to
be much more opinionated about how you _ought_ to use Redux, based on how
we've seen people use it. Those opinions are built into our new official Redux
Toolkit package [0], which is now our recommended approach for writing Redux
logic, and the Redux Style Guide docs page [1], which lists our guidance on
best practices and patterns for using Redux.

I also just published a brand-new "Redux Essentials" core docs tutorial [2],
which teaches "how to use Redux, the right way", using our latest recommended
tools and practices like Redux Toolkit and the React-Redux hooks API.

We unfortunately can't wave a magic wand and get folks to update the seemingly
endless parade of Medium tutorials and Youtube videos that show the older
approaches to using Redux, but I'm hopeful that the emphasis on using RTK will
make it a lot easier for folks to learn and use Redux going forward.

[0] [https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-
ta...](https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-
part-1/)

[1] [https://blog.isquaredsoftware.com/2019/10/redux-starter-
kit-...](https://blog.isquaredsoftware.com/2019/10/redux-starter-
kit-1.0/#dealing-with-complexity)

[2] [https://redux-toolkit.js.org](https://redux-toolkit.js.org)

[3] [https://redux.js.org/style-guide/style-guide](https://redux.js.org/style-
guide/style-guide)

[4] [https://redux.js.org/tutorials/essentials/part-1-overview-
co...](https://redux.js.org/tutorials/essentials/part-1-overview-concepts)

~~~
city41
You certainly have more experience and context than me. But my experience with
Redux over the years is there was so many ways to do it leading to a lot of
uncertainty. Do you use a switch statement or something like redux-actions? Do
you use the duck pattern, where do all these things live in the codebase? What
package do you grab for async actions? Are actions 1:1 with DOM events, or are
they more like a state machine? How do you compose reducers? Should you
compose reducers?

I think this led to a lot of confusion and uncertainty with Redux. "I'm using
it, but I'm not sure I'm using it effectively." I think a lot of ineffective
implementations caused a lot of developers to get a really bad taste. I can
unfortunately say at my previous company, just mentioning Redux would make
just about every developer cringe. I hated that.

But I feel like a lot of what is making Redux more successful these days is
the more opinionated releases like the toolkit and the new docs. Since they've
only been around about a year now, I think it's reasonable to conclude that
before their existence, Redux didn't have a strong opinion a new developer
could lean on.

It's similar to React, which also tries to avoid opinions. I can appreciate
and understand that approach (for both React and Redux), but I do wonder would
React be better if there was a stronger opinion on things like CSS, routing,
state, etc?

I don't mean to criticize. I love Redux and am very grateful for it. This is
just how I experienced it over the years.

~~~
crooked-v
Having used Redux for some elaborate stuff (in particular, a web app that used
a couple of KB of info in Redux to generate an extremely dynamic UI, with
diff-style data changes via Websockets inserted in realtime), honestly, the
biggest problem I've seen with Redux use is just... people using it for things
when they shouldn't.

This is most glaring for the whole "do a GET and store it in Redux" thing,
where if there's no actual data mutation or derived data or anything else that
actually requires or makes use of a global scope, you should just be using a
memoized API call function (or a library that abstracts away the common use
cases of one, like SWR).

~~~
deckard1
> people using it for things when they shouldn't

I know people that advocate putting everything in redux. They are quite
serious about this. Then you end up with reselect everywhere and the whole
goddamn universe is memoized. No one seems to know how React renders (or re-
renders), so memoize everything! Yes! That's the ticket.

The overuse of Redux and the React hook brain damage stems from the tide
finally turning against OOP. Haskell did a number on the OOP paradigm. So
everyone is afraid of encapsulated state and localized logic. Then you end up
with React hooks. Instead of making React's object API better, they choose to
make functions worse. So everyone is pretending they are doing functional
programming when in reality they are just using functions that are bastardized
with this weird flavor of dynamic scoping and all the subtleties of that. But
I digress.

Today, there are a thousand different ways to do web development wrong and
practically no way to do it right. Starting with misconfiguring webpack and
working up the stack. It's a true complexity quagmire. But surely there is a
SaaS or open source toolkit (with adjacent commercial services!) coming soon
to help guide us out of the fog.

Just kidding. This hell of ours is by design.

~~~
crooked-v
> Instead of making React's object API better, they choose to make functions
> worse.

I'd be really curious to see how you'd make the object API reusably
composable, given that that's one of the basic reasons for hooks existing as
they do.

~~~
discreteevent
An over emphasis on re-use is what ruined a lot of oop systems also. Maximise
reuse, minimise use. It's a trade-off.

------
alextheparrot
Thinking about local state in the same way as external service calls just made
a part of my brain say “Yeah, that’s the right abstraction”. I completely
sympathise with the reasons it wasn’t worth the trouble from their
perspective, though. Being able to say “Yes, this improves X dimension but we
might have issues with other dimensions” shows a mature engineering org.

Tangentially related, they linked to RecoilJs which I wasn’t familiar with.
The presentation on the RecoilJs site finally helped me say “Ok, I get the
local state problem”. Worth a watch and reading the previous HN discussion on
it [0-1]

[0] [https://recoiljs.org/](https://recoiljs.org/)

[1]
[https://news.ycombinator.com/item?id=23181375](https://news.ycombinator.com/item?id=23181375)

------
Matthias247
I wish they would just revert their site to where it was 2 years ago instead
of doing anything new.

The new version just looks like yet another Tinder clone, and doesn't resemble
anymore what Okcupid was good at: Good profiles, which allowed to get an
initial impression about people beyond "I like their looks".

~~~
carabiner
I wish it was more like 6 years ago, or whenever the Match buyout was. It's
become hot people clickbait like all the swipe apps now.

The entire internet is being optimized to either outrage you or sexually
arouse you as quickly as possible.

~~~
sebmellen
A friend of mine at Google is considering moving to another team or leaving
because he's concerned about how addictive YouTube has become. Apparently it's
a real discussion internally: is YouTube doing more harm than good?

To me, it seems that we're in a precarious position. I wonder what happens
when we reach the limits of dopamine saturation, if there is such a thing.
Otherwise, it seems Huxley was right -- "man’s almost infinite appetite for
distractions" is a dangerous thing.

------
jasonhoch
I really appreciated the way this post was structured. It worked forwards, not
backwards. At the halfway point, I thought, "Oh, using the Apollo cache and
the @client directive is a reasonable way to store and access client-side
state," which is exactly what the OkCupid team thought at that point, too.
Then they stopped, thought ahead a bit farther, and came up with reasons why
it might not be the optimal choice.

Many posts are written about end results. "Look at this thing we built that is
cool and works well." Thanks for sharing the full story, OkCupid.

------
gavinray
As someone who works daily with GraphQL, it's neat to see other people talking
about this.

The tools for client-side state management with GraphQL are really powerful,
but require a lot more involvement than something like a standard state
management store, IE an action that calls your GQL endpoint and stores the
data in state.

    
    
      async function fetchUsersAction(state) {
        const users = await gql.getAllUsersQuery()
        state.users = users
        return state
      }
    

I generally set up a regular client-side GQL library (urql, Apollo) and use
this kind of pattern for store state.

This approach has worked well for me in a number of fairly decent-sized apps,
and it seems to be a pretty common one.

------
consolenaut
I'm doing a big Apollo/GraphQL piece for the BBC for a lot of the same reasons
OP lists, and have run into pretty much all the same issues with Apollo that
OP has.

Its rough because Apollo does so much for you, its wonderful, but there are so
many sharp edges and pitfalls - from the buggy devtools to the lack
of/incorrect docs, major unanswered github issues & constant API breaking
changes even on patch/minor version bumps, its been an uphill struggle all the
way. All that said, it still seems like the best tool for the job, Relay still
has a huge learning curve & has already had two major branches with no
refactor path between (Classic/Modern) & the numerous other implementations
all lack things Apollo gives you for free.

If your usecase is simple, using Apollo to query a GQL server with a well
defined schema doing little to no client state handling it can be pretty
straightforward, but the complexity ramps up crazy quick as soon as you start
messing around with caches or persistence or local state.

The Apollo folks seem to have a handle on things but hopefully I/we can start
contributing back, if not with feature work than with documentation

~~~
andrewingram
That Relay rewrite was over 3 years ago though, and it’s been pretty stable
since (the hooks API is coming “soon” but shouldn’t break compatibility). And
there was an upgrade path, there was an intermediate compat version which let
you incrementally upgrade.

The learning curve isn’t that really that steep, it’s just made artificially
so by the poor docs. It’s unfortunate that the Relay team doesn’t really
prioritise getting new users, because it’d motivate them to explain things
better. But there’s not actually that much to learn, you can be up and running
and productive with it pretty quickly.

~~~
consolenaut
True, and admittedly I've only cast a cursory glance over Relay to keep track
of where it is every now and again so maybe its unfair of me to write it off
quite so quickly. But I think you're also right about the learning curve being
made artificially steep by the poor docs, and when you're introducing this
stuff to a team who are already new to GraphQL, adding another framework on
top with even poorer docs than Apollo is a hard sell

------
gregkerzhner
One thing that drove me crazy about using Apollo for local state management is
that you have to manually fetch, update and save the data on every change. For
example, if you have a list of items and you need to add one, your mutation
would need to query the store for the list, add your new item, and them write
the mutation to the store.

This adds extra overhead on every single mutation as opposed to Redux, where
your the current state is automatically passed into your reducer, and you
don't need to worry about writing anything after you update - the store
handles that itself by updating the state to the result of the reducer.

------
wdb
Personally, I enjoy using React Context for some stage, and let data
handling/caching be handled by React Query and it works lovely. So much
simpler than Redux

~~~
VintageLight
Agreed. React Context wonderfully handles state that will only ever live
locally/"on the client".

I don't mind Redux for local state management, but it's a little overkill if
you aren't using it already to handle API state.

Using Apollo on the client side makes me want to pull my hair out though.

------
mikewhy
We're just in the process of switching to GraphQL for data fetching, pretty
shocked people would even consider trying to hack client-side state management
into it.

Redux still fills that role very well.

~~~
d0m
I don't particularly like Apollo, but the reasoning is that if you fetch data
with Apollo on the client-side, then that data is already available in their
cache. If you were to use Redux, you'd have to copy that same data in your
store.. so might as well use their cache instead. However, this is only for
fetched data, not all client-side state management.

Personally, I don't like the "write client-side resolvers mimicking the server
resolvers" approach. I'd much rather have a database that is synched with the
server and listens for new changes. Once you have your "offline-synched-db",
you get offline, optimistic-UI & real-time for free.

------
nojvek
In backend, most state is nicely stored in a database, in frontend, if you
don’t have good foundations for component state state vs app state vs server
state, then a lot of things become complicated for a decently sized app.

If you mix everything in one then you have a crazy ball of goo that’s
rendering the whole UI tree everytime something small happens. Sure vdom is
fast but you’ll still feel it for large apps because generating that vdom may
call expensive functions over and over.

Svelte is nice but I haven’t used it for a large project. I do swear by having
a good separation of those states. It has served me well for over a decade
building UIs in different frameworks.

When component state changes, only that component changes. E.g whether a
dropdown is opened.

When appState, changes the whole app tree is vdom diff rendered. Immutability
helps here. Props/context are threaded all the way down. E.g the current
light/dark theme

ServerState should be subscribed individually by components that need it, and
only the components looking at that state render. (E.g List of items from GET
call, when you update the item, an update only needs to happen in that one
place that keeps its data synced with server)

------
gregkerzhner
The problem with Apollo is that if you use it for server queries, you are
basically forced to use it for local state management as well. This is because
server state and local state is usually intermingled, so its not practical to
have a Redux store for local state and then use the Apollo cache for server
state.

This means that Apollo is essentially incompatible with Redux unless you are
willing to duplicate the data in the Apollo cache into your Redux store. Such
duplication is a waste of resources, and also defeats the point of using
Apollo to begin with, since you are circumventing most of its feature and just
using it as a plain GraphQL client.

I think Apollo is trying to do too much, and a much better architecture is not
to couple your GraphQL query infrastructure to your state management
infrastructure. This can be done by using a more low level GraphQL client and
then choosing one of the many amazing state management libraries out there in
combination. This way your GraphQL client does not dictate your state
management layer.

------
joshribakoff
I looked into Apollo for local state years ago, after trying to synchronize
remote & local state & running into race conditions, I quickly realized it is
better to implement GQL fetching inside something like Redux that is lower
level & gives more control over determinism & timings.

The holy grail of "fixing race conditions" and avoiding async bugs is RxJS in
my opinion, which is why I am working on what I call a "stream management
library", its a state manager where your "state" is represented as RxJS
streams [https://rx-store.github.io/rx-store/](https://rx-store.github.io/rx-
store/)

------
kevsim
We've been using Apollo's cache as our one and only source of state in the
issue tracker we're building [0], however, as of late we've started running
into all kinds of problems. Mainly performance related as the Apollo cache
flattens the object graph on insertion but then rebuilds the graph on read
(whether you need it to fully do so our not).

To remedy this, we're currently moving away from it. Either to Redux or just
plain useReducer (TBD).

0: [https://kitemaker.co](https://kitemaker.co)

------
bengale
> This gives us one of two options for our cached data: either make sure every
> query requests a uniquely identifying field of the data we are requesting
> (doesn't this defeat the purpose of requesting whatever fields we want?) or
> writing explicit typePolicies to tell our cache how to normalize our data.

This is the exact thought I had recently when fighting the Apollo cache.

------
k__
I found what AWS did with AppSync and DataStore really interesting.

------
claytongulick
I dunno. I was pretty frustrated by most of the state management solutions out
there, so rolled my own [1]. So far been really happy with it. Super simple
graph based notifications, does everything I need.

[1]
[https://github.com/claytongulick/applicationstate](https://github.com/claytongulick/applicationstate)

------
d0m
TL&DR: devs already knew redux so went with redux

------
claydavisss
I would definitely encourage all of my competitors to use GraphQL. Nothing
like getting a free six-month lead.

That's two months they spend learning GraphQL, two months introducing a
mystery-meat binding layer and learning that, and two months debugging it all
and pulling their hair out.

And no, using a giant third-party lock-in toolkit like Hasura or Apollo is not
a response.

~~~
vosper
Genuine question: What technologies / techniques are you using while your
competitors flounder around with GraphQL?

~~~
mschuster91
Tried and true server side rendering. Sure it will not look as snappy as a
PWA... but I _guarantee_ you that a seasoned team of Drupal developers can get
up and running _faster_ than a team of juniors fresh out of coding bootcamp,
or even a team of senior-ish Javascript frontend devs who haven't heard about
GraphQL yet, and much less have years of experience.

~~~
jklm
This feels like a strawman...I’m sure a seasoned team of GraphQL devs could
getting something running faster then a team of veteran devs who are trying to
use Drupal but have no experience.

~~~
mschuster91
No, it's not a strawman argument. Graphql was released in 2015, so even the
most senior devs you can find have only five years of experience (ignoring
people who have worked at FB before).

Drupal however has a history dating back to 2001!

~~~
vosper
5 years of experience in any frontend framework, including Drupal, is enough
time to learn how to stand something up pretty quickly. I’ve been doing web
apps for 15 years: the frameworks are not _that_ complicated.

And if we’re picking Drupal because of its age (and if not then why Drupal, of
all things? What’s the overlap with GraphQL?) why not go back further and
assert that someone who’s great with C and CGI could do even better?

------
egwynn
“OkCupid”, not “OkayCupid"

~~~
jtsiskin
Yes haha when I read the title I thought “how has this company not been sued
by OkCupid yet??”

