10 ms·
Why we decided against GraphQL for local state management
- claydavisss 6y agoI 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.
- blablabla123 6y agoStarting to work with GraphQL is definitely "mysterious" and backend controllers must be implemented completely differently when it comes to caching. But I think performance- and complexity-wise it's definitely ahead of REST. I don't see any problem using Hasura for prototyping. It offers pagination, aggregation and other things that usually only matured REST APIs offer. So basically it's possible to post-pone the Web Application-Backend, see what queries make sense and later "hard code" that with the preferred framework. At least that's how I'm approaching a side-project right now and I'm really happy that I can focus on the open tasks and keep the mundane work for later.
- vosper 6y agoGenuine question: What technologies / techniques are you using while your competitors flounder around with GraphQL?
- claydavisss 6y agoREST and JSON because arbitrary querying is a huge YAGNI. That said, the presence of GraphQL is a great signal that a team is infested with architecture astronauts, so I suppose it has its uses.
- mschuster91 6y agoTried 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 6y agoThis 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 6y agoNo, 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 6y ago5 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?
- markl42 6y agoIt's undeniable that there's a learning curve to GraphQL - but at the end of the day, it's just adding another investment that developers may choose to make their lives easier in the long run. As in industry, we're okay with a frontend JS framework - React (or vue or angular) being part of the baseline set of investments you make when building a website. It's just considered the cost of doing business. (But that wasn't always the case! I for one don't miss using jQuery...) I imagine GraphQL will get to a similar place - where the investment is more well understood and accepted. (Of course common sense still applies - if a website is simple enough that it doesn't need a frontend js framework then don't use one - same goes for graphql, don't use it if you really don't need it)
- deleted 6y ago[deleted]
- egwynn 6y ago“OkCupid”, not “OkayCupid"
- jtsiskin 6y agoYes haha when I read the title I thought “how has this company not been sued by OkCupid yet??”
- alextheparrot 6y agoThinking 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
- gavinray 6y agoAs 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.
- Matthias247 6y agoI 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 6y agoI 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.
- syncbehind 6y ago> The entire internet is being optimized to either outrage you or sexually arouse you as quickly as possible. I absolutely hate how accurate this is. It feels more and more that the optimization and efficiencies are making the internet less useful but more addictive.
- droopyEyelids 6y agoOr both, as in the case of Netflix's new semi-child abuse documentary.
- sebmellen 6y agoA 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.
- throwaway4747l 6y agoI wish they'd restored their old blog posts doing a bunch of stats, that was fun. I don't know why they've been taken down.
- city41 6y agoI 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 6y ago> 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-tao-of-redux-part-1/ https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-ta... [1] https://blog.isquaredsoftware.com/2019/10/redux-starter-kit-1.0/#dealing-with-complexity https://blog.isquaredsoftware.com/2019/10/redux-starter-kit-... [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-concepts https://redux.js.org/tutorials/essentials/part-1-overview-co...
- k__ 6y agoI found what AWS did with AppSync and DataStore really interesting.
- jasonhoch 6y agoI 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.
- gregkerzhner 6y agoOne 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 6y agoPersonally, 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 6y agoAgreed. 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 6y agoWe'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 6y agoI 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.
- pier25 6y agoState 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.html https://krausest.github.io/js-framework-benchmark/current.ht... [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.
- pastrami_panda 6y agoThis might be obnoxious, but could you share some insights on what svelte is doing correct in your opinion? I've never worked with it but am curious to what is the secret sauce that made you feel like it was the correct abstraction.
- deleted 6y ago[deleted]
- darksaints 6y agoThat's almost exactly the path I've gone down, and svelte is something I've been seriously researching for a couple months now. I have a nagging problem that keeps coming back to me though. The declarative state model is the holy grail for UI design, but if you try to mix in any form of imperative logic, it all falls apart. All of a sudden you need to understand and plug into poorly documented and opaque component lifecycle APIs in order to insert your imperative code and have it work correctly. And that really messes up the nice clean solution, making it look more like a chimera of two state models. Some of that is fixed by libraries that create components native to your framework of choice, implementing the appropriate lifecycle hooks as necessary. But now you're relying on a library that adapts one library to another library, and now you've got a dependency sync problem on top of it all. It wouldn't be such a problem if there weren't so many extremely useful libraries that depend on imperative code. Personally, I've run into massive problems trying to use D3, Leaflet, and Bootstrap, as well as a handful of others. I'm sure there are thousands more. Not trying to take away from your point. When these declarative state models work well, it's a beautiful thing to behold. But there's always some point where the abstraction leaks. https://svelte.dev/tutorial/onmount https://svelte.dev/tutorial/onmount https://reactjs.org/docs/state-and-lifecycle.html https://reactjs.org/docs/state-and-lifecycle.html https://blog.logrocket.com/introduction-to-vue-lifecycle-hooks/ https://blog.logrocket.com/introduction-to-vue-lifecycle-hoo... https://mithril.js.org/lifecycle-methods.html https://mithril.js.org/lifecycle-methods.html
- bengale 6y ago> 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.
- consolenaut 6y agoI'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 6y agoThat 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 6y agoTrue, 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
- claytongulick 6y agoI 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 6y agoTL&DR: devs already knew redux so went with redux
- kevsim 6y agoWe'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
- nojvek 6y agoIn 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)
- joshribakoff 6y agoI 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/
- gregkerzhner 6y agoThe 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.