My personal copy-paste summary of a similar topic on HN some time ago (https://news.ycombinator.com/item?id=9784008):

# Getting familiar with a new codebase

### Use the right tools

- grep, ack, ag, global search (Visual Assist)

- doxygen, javadocs

- sourcegraph, pfff (facebook), open-grok, SourceInsight

- Proper IDE, REPL

- chronon (dvr for java)

- SWAG (Software Architecture Group)

- Static code analysis

### Use the repository

- Find most relevant (frequently, recently edited) files

- Find dependancy graphs

- Get basic information like which languages are used for what

- Use good source control so that you don't have to worry about breaking things

- Look at commits, in general or for specific issues

- Browse the directory structure, packages, modules, namespaces etc.

- Use "blame" to see when things changed

### Ask questions

- Talk to the customer, find out the purpose of the application

- Pair up with another developer who is more familiar with the code

### Read the documentation

- Look at use cases, diagrams describing architecture, call graphs, user docs

- Understand the problem domain

- Add more documentation as your knowledge grows

- Comments and docs might be wrong!

### Browse the code

- Skim around to get a general idea and a feeling for where things are

- Look at public interfaces, header files first

- Find out which libraries are used

- Take some important public API or function in the UI and follow the code from there. Find implementations of functions, dive into related functions and data structures until you understand how the it's done. Then work your way back out.

- Use tools to quickly find declarations, definitions, references and calls of variables/functions/etc., usage patterns

- Find the entry point of the program

- Figure out the state machine of the program

- Focus on your particular issue

- Use a large, vertical screen with small font size with a pane to show file/class structure

### Take notes

- Use pencil and paper to write down summaries, relationships between classes, record definitions, core functions and methods

- Write a glossary: Function names, Datatypes, prefixes, filenames

- Document everything you understand and don't understand

- Use drawings to create a mental model

### Look at the data

- Find out how the data is stored in the database

### Build the project

- First make sure you can build it and run it

### Use the debugger, profiler and logging

- Set breakpoints, poke around the code, change variables, inspect local variables, stack traces, ...

- Watch the initialization process

- Start from main() and see where it goes

- Find hotspots with the profiler

- Set logging level to max/add logging and use the output to go through the code

### Edit the code

- Adopt the existing coding style

- Try to recreate and fix small bugs, make sure you understand the implications of the fix to the rest of the program first

- Tidy up the code according to the common standard after talking with the team

- Make the code clearer (best with tests)

- Add TODO comments

- Add comments describing what you think the code does

- Hack some feature into the code, then try to not break other stuff, build up a mental model over time, re-write the feature properly

### Use Tests

- Run the tests, make sure they are all passing

- Create new tests

- Browse the tests as an examples reference