Edit: This is an article published in the context of my upcoming YouTube series on understanding unfamiliar code, and contains by personal recommendatins for approaching an unfamiliar codebase. You can watch out for the course on my channel.
As developers, we spend the majority of our time reading and trying to understand someone else's code. Specially in the consultant industry, you're introduced to several enterprise solutions with a large existing code-base, where you're now the maintainer, expected to provide deliverables on a timeline of code you didn't write. This can be challenging for even the most experienced developers, and you will need good code-browsing skills to make sense of the code.
By utilizing a few popular code-browsing techniques I'll explain throughout this article, you'll soon know everything you need to approach a large existing code-base.
In ideal world, all code would be well written, documented, structured and comprehensibly tested, both with automatic tools such as unit tests and end-to-end tests.
However, we don't live in an ideal world. We live in the real world, where code never dies and programmers come and go, which leads to people spending an enourmous amount of time reading code. This makes understanding unfamiliar code all the more important. Probably more important than writing code. Unfortunately, this skill is widely undertaught in school and not that well-recognized in the industry, which leads to people reading programs like they were books, trying to connect every piece of the puzzle. This is not the right frame of mind. You don't want to think of the scope to which you don't understand something, but instead, gradually start connecting the pieces until they fit.
So, what are you going to do when you're faced with a brand new codebase? Requirement gathering is usually the first stage in any big project, and talking with the prospective users of the system is always an important part of that. In order to fix the program, you first need to understand the problems it's trying to solve. There's usually a reason for why things are done a certain way. Remember. Dealing with other people's code is the norm, not the exception, and becoming adept and figuring out how the other programmers worked are an important part of that. By adopting their style when continuing their work, you'll also make it easier for the next developer to follow.
When we now something about the purpose and style the application is developed in, it's time to start breaking things down. We need to narrow things down to something we can actually process. By understanding the various components in the software, and how they relate to each other, you'll start figuring out how different parts are connected and start developing an understanding of the codebase as a whole.
So, how do we start breaking things down? One method the community strongly suggests is to set out breakpoint on methods that triggers behaviours that concerns you. If changing a line of code causes unexpected changes on other places, put a breakpoint on that line, and see what happens. You have a lot of information on the runtime state once the breakpoint hits. Breakpoints stops the execution of the code on a certain line, and from there, you can see from the stacktrace how the code got there. Use the step into and step out functions to see what the different methods does and how events are propogated in the application. This will teach you something about the structure of the codebase.
One other thing I also need to mention is the importance of testing. Cause although they are rare, they're a great resource for learning what a certain unit of code is meant to do. By reading and writing tests, you'll start understanding the expected behavior of the program, and can then compare that with the actual result. The more of those you build, the more confidence you'll have that your added code won't break something else.
Start by gathering information about which problems the program should solve and which code style to adapt.
Don't spend all your time figuring out how everything works at the beginning. Narrow things down to something you can actually process.
Step through behavior that concerns you with a debugger. The stack trace have a lot of information about how events are propogated in the application.
Although testing is rare, it acts as a wonderful documentation tool, and is a good introduction to a new codebase.
On a final note, I really would like you to share you're best methods for approaching unfamiliar code. This is a widely discussed topic, and there is no blueprint here.
Just don't spend all your time explaining your problems to a rubber duck. People will think you're insane 😉