4 ms·
GraphQL is an abysmal technology. In terms of destructive power to the software industry it's almost on the level of OOP. The one positive seems to be that eng
by exfalso 2y ago
GraphQL is an abysmal technology.
In terms of destructive power to the software industry it's almost on the level of OOP. The one positive seems to be that engineers are catching on to this fact at a much faster rate(5-10 years instead of 10-20). However, unfortunately, GraphQL sits in a position of the software stack that's very difficult to swap out, so even when engineers do realize the damage, they are stuck with it unless they change jobs. Extremely frustrating. Yes I'm one of those stuck engineers.
And then you have articles like this still touting it as some kind of rainbow miracle.
I'm not even going to list the countless issues you will be encountering by committing to this tech, or the fact that the mitigation of those issues will result in essentially gravitating back to REST with several unnecessary and convoluted translation layers. Instead, I invite you to research how Meta, the company behind the technology, is using the technology in practice. Just open Facebook and look at the /graphql queries, or read some articles by Meta engineers.
- threatofrain 2y agoCould you explain a little more about the Meta part and how they're using it?
- exfalso 2y agoThey don't have a "hard" persistence layer, it's all in-memory, which is the only reason they can have any sort of performance. In terms of the actual queries, you'll find a bunch of prefetch calls and dumping of all data related to your user. So much for "fetch what you need". What you will also find is, surprise surprise, not actually a whole lot of graphql queries. Instead, a bunch of plain REST-ish queries, custom WS, and some graphql.
- lyall 2y agoI'm not sure exactly what GP is referring to, but it might be things like this? > Facebook report they maintain an allow-list of queries extracted from from their source code at build time, to fix this. I've not seen any other GraphQL site do this https://x.com/AdamChainz/status/1392162996844212232 https://x.com/AdamChainz/status/1392162996844212232 Which references this article: https://intercoolerjs.org/2016/02/17/api-churn-vs-security.html https://intercoolerjs.org/2016/02/17/api-churn-vs-security.h...
- Scaevolus 2y agoIt was beautiful before they did this. You could introspect the entire Instagram API surface and write queries to scrape precisely what you wanted.
- hobofan 2y agoThis, to me, doesn't sound believable, as conceptually, it such a trivial problem, that I don't believe Meta can not handle it. Maybe in 2016 when that article was written that was the case, but even then I doubt it. Yes, for your average small team that hasn't figured out how to do resource- and subresource-level permissions, this will be tricky. That will also be tricky regardless of whether you are using GraphQL or REST (though with REST, the "solution" is often to write permission checks on a more coarse level and hope that they align correctly with the data you are querying). However with the advent of Zanzibar and derivative solution and policy languages (Rego for OPA or Polar for Oso), it has gotten quite easy to do (sub)resource permissions without that being a huge burden on complexity and your codebase.
- Kwpolska 2y agoIt is trivial to verify Meta is doing this. If you go to Facebook or Instagram and look at the network traffic, you might find requests to /api/graphql, with a lot of weird values in the request payload, but no GraphQL query text — one of the fields is an ID of the query from the allowlist, and GraphQL becomes a glorified RPC mechanism.
- hobofan 2y agoI'm not disputing that Meta is doing build-time query->query ID replacement. I'm disputing the that they are doing that(/have to do that) because it's the only way to satisfy security requirements. It makes sense for many more reasons to do that, e.g. to validate/automatically optimize your database schema and indices. Especially if your base database is quite schemaless (such as the TAO system, which they used for a long time), that can be crucial for performance.
- tmountain 2y agoMy experience has been that it falls into the category of making easy things hard. I had a previous team that adopted it, and it turned into a huge time sink. These days, I'm just using PostgREST, and life feels easy again.
- anon22981 2y agoCould you or someone else expand on the destructiveness of OOP to the industry?
- exfalso 2y agoIt is not as easy to see as with GraphQL because the term is overloaded/ill defined, and there is a large number of ways to interpret how OOP should be used. Probably why it took so long to realize the issues and move away from the concepts. Sidenote: with GraphQL you will also see a lot of people who are scratching their heads saying "Surely I must be doing something wrong, it can't be this bad. I just don't understand what that something is.". When the users of your tech have difficulty even articulating what the issues are, that's when you know you hit the anti-design jackpot. In terms of whether a shift away from OOP has happened, you can look at how modern languages/language features are designed, and how "best practice" has changed: they are explicitly moving towards data-centric design with FP concepts(e.g. ADTs, "plain" functions, ironically similar to C), and moving away from dynamic dispatch. And when they do implement dynamic dispatch, there are warning signs around it, it's not considered good practice (see e.g. trait objects in Rust). Encapsulation/visibility is now treated as an orthogonal concept (as it should be), the whole getters/setters visitor-pattern/proxy-pattern/etc nonsense is essentially binned, they're not even mentioned anymore outside legacy codebases and Java shops. In terms of what the issues are, it's inheritance/subtyping and dynamic dispatch, IMHO the two hallmarks of OOP. (I know, purists will point to a different kind of definition, but in my experience this is how OOP is used in practice). There are some additional oddities like "design patterns" and "encapsulation" and whatnot, but I would consider these as secondary fallout issues, stemming from the two major problems and a zealous shoehorn-y attitude. This attitude BTW is characteristic of hype waves. Ok so what are the issues with inheritance? From a type-theoretic point of view it's variance. When you have a (parametric) polymorphic type and you shove a type into it with subtyping relations, you'll get problems. The classic example is the array of Animals/Dogs/Cats case. At the time of the OOP hype's peak, advocates kept bringing up this example as if it was a tool to understand OOP better. But instead, it's a great tool to understand how subtyping can lead to intractable reasoning about variance for no good reason. "Composition over inheritance" is now commonly understood as a good preemptive tactic. (Composition is not an OOP concept.) From a data-structure point of view the issue is fields. Can/should a subtype access the parent's fields? How about multiple inheritance? Throw in the private/protected/public trio and you'll get pieces of code so hairy that you'll just end up writing wrappers around it instead of trying to understand it. Sidenote: I do want to note that there is a single use case of inheritance I know of which actually makes sense, but it's very specific to C++. It's "plain" (non-virtual) inheritance for the purpose of composing memory layouts while still allowing pointer aliasing. Row polymorphism (see e.g. TypeScript) is also useful, but it's difficult to argue that it's an OOP concept. Ok, what are the issues with dynamic dispatch? From a code design point of view the issue is, for lack of a better expression, missing alternatives. OOP-supporting languages "solved away" ADT-style dispatch (enum data structures+pattern matching) which has a very natural mental model, and replaced it with things like double dispatch and code-data coupling. When I'm writing a piece of Java code and I want to express that there are 3 known states that the data can be in, I have no choice but to use an abstract State class, add dynamic dispatch and either tightly couple the state-handler code with the state definition, or bloat the code further with double dispatch. I literally cannot do anything else, unless I start writing completely non-idiomatic code. From a code organization point of view the issue is "open sums". Open sums(aka interface-like views on concrete implementations) do actually have their place, however OOP encourages their use way beyond what's reasonable. This results in code that's very difficult to read, it becomes time consuming to piece together what the hell a function is actually doing, because all you see are calls to interface functions. What you need to do as you read the code is essentially "close the sum" and substitute the various possible implementations into the control flow, which results in a conceptual blowup of the possible states of the program. That, or you just observe how the code is behaving at runtime. I'm not ashamed to admit that I've done the latter quite a few times with legacy codebases because the code itself was in a worse shape than the execution stack. From a debuggability point of view the issue is similar, it's an intractable CFG. During debugging you need to re-build a conceptual mental model of "runtime behaviour" where you need to find the conditionals that actually decide what concrete objects are being dispatched to under what circumstances. Anyone who has any experience debugging such pieces of code will know exactly what this means. Sidenote: The FP hype can also result in very similar CFG issues, but this time it's due to overuse of lambdas/closures. In terms of the damage.. well, it's the countless hours of writing, maintaining and debugging these codebases. It's the lost dev hours, the lack of progress, the "stalling" of codebases after becoming a giant mess. I'd wager it threw back software engineering as a discipline maybe 10 years and by extension humanity as well (I wanted to say more, but the natural sw company/startup birth-death cycle mitigated a lot of the legacy-buildup issues, at least from what I've seen in my career).