How is it a good practice to version your helm charts for each deployment?
Approach you are describing - where app version is substituted at helm upgrade command - is pretty popular as well. Maybe it's not well documented - I'm not sure about that.

Yet another approach that people use is doing helm template which would compile everything (including variable resolution) into fixed k8s definitions and then doing GitOps on that.

There is no universally accepted approach here among those 3 (1st being updating helm chart itself with new versions every time). So you should decide what works better for your use case.

One thing that is worth mentioning is versioning issue (disclaimer: I'm solving it with Reliza Hub, which I develop). Basically, you need some system which would tell you what version tag of each microservice to actually use on different environments. That problem may become quite complex, especially if you have many microservices and many environments.