I found this to be my favourite workflow for managing workspace variables in a way that was also flexible to being run outside of TFC/TFE for when that makes sense.
It sounds like a lot, but it ends up being fewer files to manage and edit and your workflow can be captured in github/terraform rather than in some arbitrary file structure. It also helps prevent mistakes like updating dev and having prod rerun by accident which I've seen happen.
https://github.com/ribbybibby/terraform-provider-hiera https://github.com/lyraproj/hiera_terraform
On the terraform registry here: https://registry.terraform.io/providers/chriskuchin/hiera5
Going DRY is a decision you pay for in complexity, it's the typical programming problem of genericity. Sometimes it absolutely makes sense and you're a mad man if you skip it, but in isolated cases making things DRY just for the sake of it is just as nuts as not doing it when required.
It's a fine line to walk and it requires hands-on experience to know when to employ DRY and when to repeat yourself.
If I change the common code, do I want all users of it to realize those changes implicitly?
Terraform provides good enough tools to allow for deviations (even significant ones) between dev, staging, and prod.
IMO one of the most valuable things Terraform can do for you is stand up _the exact same stuff_ in multiple environments. If you're applying different code, your confidence in that shrinks significantly.