I was recently asked to answer the somewhat vague question, “How do you interact with a large undocumented code base?”
One small step at a time.
A large code base can be overwhelming. Rather than trying to get to know the whole thing, I tend to focus on the problem at hand.
Say I have been asked to change the way the system calculates sales tax for items being purchased. I would find the place where the tax is actually calculated. If I am lucky, the names of the modules give me a clue. If not, I can perhaps start with the checkout flow and traverse the code until I find where the tax is calculated or at least applied.
Once I’ve located the area in question, I’ll spend time writing character tests around the behavior I can observe or infer from the code itself. This gives me a safety net. It does not guarantee that my changes are safe, but it helps a great deal.
Next, I’ll do a surgical strike. I’ll make an attempt to implement the change in the simplest way possible. I do this by writing a new failing test or changing one of my existing tests to articulate the new behavior, causing it to fail. I will then make the simplest change I can think of to implement the new behavior.
If that simple change causes something to break elsewhere in the code, I will note what broke, revert the change, and move to the area that was broken by my change to see if I can get tests around it and prepare it to readily accept my change. Take a look at Mikado Method for more on this approach to changes to large coupled systems.
Essentially - make the smallest change necessary and expand from there. Try to make every small step as safe as possible.