|
|
|
|
|
by geokon
17 days ago
|
|
You can use regular functions, but there are several things you lose: - intermediate keys are not recalculated if they're used across different resolvers. This means you basically never need to manage caches of precomputed results. So if you're calling `my-func` on `input-a` everywhere, you don't need to do all the ceremony of computing it once, storing it somewhere, and then passing it around to everyone that needs it. It's all just handled automatically. Code simplifies greatly - It's much easier to "inject" lower-level steps b/c resolvers are essentially declaring an interface. If you suddenly don't like your interface and want a new interface, then you make a new interface and a bridging resolver. Refactoring is much easier. If you want to introduce an entirely new input format that usually just involves adding a single new resolver that outputs the inputs to your system (at whatever part of the pipeline you want). While with a pipeline of function calls it's generally more messy. It hard to make a generalization here b/c it depends on how your functions are organized. - With the async engine you can automatically resolve branches concurrently without having to manage or think about it. You get a lot less stalls in the code. I haven't really hit an "exploding their fetches" scenario personally. Things like optional inputs and resolvers that rely on precedence rules are generally a bit of a code smell and are usually points where I start to think about how to reorganize my code |
|
I think what I'm suggesting is, if you can, avoiding intermediate keys at all can be helpful for performance, and graph querying encourages people to break their queries into small, atomic units that can fire in any order. Which is good for composability, but you don't want to run multiple queries if you don't have to. Using functions encourages writing what happens explicitly.
I'm coming at that not as someone who uses graph querying a lot, but someone who has worked on code bases where a single api call was dozens of DB calls. If people do that with regular function convenience, I imagine it happens even more often with libraries like Pathom, but that is speculation.
> It's much easier to "inject" lower-level steps b/c resolvers are essentially declaring an interface. If you suddenly don't like your interface and want a new interface, then you make a new interface and a bridging resolver
Is that exceptionally harder to do with regular functions though? I feel the same way about this as I do above. It sounds like this is only useful when your data topology is unknown and you can't be sure of the access pattern to begin with. I'm used to codebases where access patterns need to be documented and flexibility is not a huge concern. We just have repository interfaces, and we substitute the ones that we need.