* Data storage: what does the schema look like? Even if it is not persisted to a relational DB, is it possible to draw out a schema of a data model and all the relationships ("JOINS")
* Add logging to code you are trying to debug but are hard to understand and repro bugs for in production. Once you have logs about the full state that reproduces the error, the issue will be easier to fix. Don't roll out a fix before fully understanding an issue. As a corollary to this: always add a task to remove this verbose logging you added once the bug is fixed!
This is a great idea and should absolutely be a standard. There's a whole logging level ("DEBUG") devoted to this that I think goes way underused.
Another, related idea is to use a debugger. Using PDB for Python codebases has sped me up A LOT.
The ability to switch to DEBUG level, get a wall of text from a problematic spot, and switch it back to WARN was very, very helpful for troubleshooting prod.
Reminds me of Fred Brooks' famous "Show me your flowcharts and conceal your tables, and I shall continue to be mystified. Show me your tables, and I won't usually need your flowcharts; they'll be obvious." quote
I've found that for most systems, there are three great ways to "figure it out".
* Start from input. (Browser, API, whatever starts a process.) Map from there.
* Start from data storage. (Database, flat files, whatever.) How does state get persisted?
* How does the system move into production? If you can make a small change (even adding an innocuous comment) and see it all the way from your machine to prod, you can iterate and start to map the system.