There are scenarios where your app servers might be varied as well -- I've leveraged reverse proxies in front of a PHP application that had parts in .NET and parts in Go, for instance.
Technologies/competencies change as projects evolve, and being able to effortlessly reorganized and reroute is so profoundly powerful.
What about just exposing the multiple instances of app server, and have the frontend code select one for load balancing or failover purpouses? There could be a load balancing config read by the client, or you can have static rules in the frontend js, like choosing shard number based on a hash from the client ip address.
Round-robin DNS might also work or complement this.
So you're answer to not using a reverse proxy is to fake your own via client-side logic? It's far better to have a tested, reliable, dynamic, and scalable solution right next to the actual app servers instead.
Almost everything on the internet is behind layers of proxies, it's not a bad thing and isn't much cause for concern.
I think your viewpoint might be somewhat inflexible if routing logic in the client & server looks like "faking a reverse proxy" to you. That's where the rest of the logic is, after all, and when designing systems we generally prefer to have the logic in fewer places.
It's a proven design rule (the end-to-end principle) to prefer the smarts at the edges of your system, and the problems stemming from the reverse proxy described in the article, in my book, counts as further evidence for this idea.
Technologies/competencies change as projects evolve, and being able to effortlessly reorganized and reroute is so profoundly powerful.