I start with a feature or use case, and start from the outside in to trace the codepath that the feature follows. During this process, I take notes about the files, lines, and functions I’m going through, but I do not yet attempt to understand how anything works. This is the “trace down” phase.
In my opinion this is what makes it easy to discover how programs written in Go, Rust and C work, while it typically is not easy to discover how programs written in Java or C# [1] work typically - abstracted wireup via IOC containers often makes it difficult to to determine which code is likely to run.
One thing you can do is go to the code you care about and modify it to dump a stack trace, so you can see how it ended up being wired up instead of how you might have assumed it would be.
Comments
Some excellent advice here about "tracing in":
In my opinion this is what makes it easy to discover how programs written in Go, Rust and C work, while it typically is not easy to discover how programs written in Java or C# [1] work typically - abstracted wireup via IOC containers often makes it difficult to to determine which code is likely to run.
[1]: Yes, yes, not all Java etc etc...
One thing you can do is go to the code you care about and modify it to dump a stack trace, so you can see how it ended up being wired up instead of how you might have assumed it would be.
Yes, that’s my usual method, though dtrace function boundary tracing makes this far easier.