1. The popular "Find Usages" which varies widely in accuracy and reliability by language, IDE, and codebase meta-quirks.
2. Tools that show Callee/Caller trees, and sometimes possible data-flows between variables.
3. DSLs to search hierarchies, like how XPath lets you find XML elements based on nesting, rather than relying on a distinctly greppable single tag-name for the leaf you're interested in. (e.g. `<Product><Name>` vs `<ProductName>`)
When things go well, the actual variable name no longer needs to restate certain aspects and relationships that can instead be found through metadata.
For example, `GiftCard.purchaser_customer_uuid` is nicely greppable, but you could relax that to `GiftCard.purchaser` if it had a static type of `UUID<Customer>`. Or perhaps you could go to the `Customer.uuid` definition and say "Show me all variables that can populate or be-populated-by this one, up to X steps out, and excluding ones that are function scoped."
That said, I do advocate for "greppability" as a general practice, since I seldom trust that languages, tools, or institutions will come together in a way that makes it unnecessary.