To do this, I used a number of generally proprietary tools, where part of the project was getting the company to them buy these tools and fix their practices so that perhaps they would avoid the problem in the future.
Anyway, my point is there are open source and proprietary tools out there in the world that will instrument an application and generally based on usage patterns will build out various visualization of the application. While these are often sold or marketed as tools for operational triage, I always argued that the best practice was for developers to use these tools in order to both understand the performance characteristics of their work as well as look for unexpected interactions.
These tools will generally build out a topology of how various components interact and will often do other type of visualizations that will show class and method level chain of invocation. The good ones show end to end across distributed systems every bit of code that gets called from the time a user attempts some kind of action.
The benefit of this approach over a UML diagram or something similar is that it shows how the system was actually built and is working, rather than what a developer intended to be built. The larger the system and the more years / developers involved, the greater the delta.