As a developer, joining a new project or company is often a daunting and scary task. You have to get aquatinted with not just a whole new team of people, but you also have to familiarize yourself with an entirely new codebase that might use new naming conventions, follows patterns that you’re not familiar with, or even uses tooling that you’ve never seen before.
There are plenty of reasons to be overwhelmed when you’re a new member of any engineering team, and there’s no reason to feel bad about that.
In the past two years, I’ve done a lot of contracting and consulting which means that I’ve had to explore and understand lots of codebases in short amounts of time. Sometimes even having to explore multiple codebases at once whenever I’d start to work for more than one client in a given week or two.
I guess it’s fair to say that I’ve had my fair share of confusion and feeling overwhelmed with new codebases.
In this post, I’d like to provide you with some tips and tricks that I use to get myself comfortable with codebases of any size in a reasonable amount of time.
Meet the team
While it might be tempting to get through your introductory calls as soon as possible so you can spend as much time as possible on navigating and exploring a new codebase, I highly recommend letting the code wait for a little while. Meet the team first.
Getting to know the people that wrote the code that you’re working with can truly help to build a better understanding of the codebase as a whole. Ask questions about team dynamics, and ongoing projects, who’s an expert on what? Building empathy around the code you’ll be working with is a very valuable tool.
Knowing which team members know most about specific features, parts of the codebase, tools that are used in a company, and so on also helps you figure out the right person to ask any questions you might have while you explore the codebase.
For example, when I joined Disney almost six years ago I wasn’t all that familiar with Swiftlint. I had heard about it but I had no idea what it did exactly. In the codebase, I saw some comments that looked as follows:
// swiftlint:disable:next cyclomatic_complexity
Of course, I could paste this comment into Google and go down a rabbit hole on what’s happening and I’d probably have learned a lot about Swiftlint but instead, I chose to figure out who knows most about Swiftlint within the team. Surely that person could help me learn a lot about what Swiftlint was used for and how it works.
I asked my team lead and luckily it was my team lead that actually knew lots and lots of things about Swiftlint, how it was set up, which linter rules we used, and so on.
We had a good chat and by the end of it, I knew exactly why we had Swiftlint at Disney Streaming, which rules we had disabled or enabled and why, and why it was okay to disable certain rules sometimes.
Google could have taught me that the comment you saw earlier disabled a specific linter rule to allow one exception to the rule.
My coworker taught me not just what that comment did but also why it did that. And why that was okay. And when I should or shouldn’t disable certain linter rules myself.
Another example is a more recent one.
One of my clients had a pretty large codebase that has had many people working on it over the years. There’s some Objective-C in there, lots of Swift, it has UIKit and SwiftUI, multiple architecture patterns, and much more. It’s a proper legacy codebase.
Instead of figuring everything out on my own, I had conversations with lots of team members. Sometimes they were one-on-one conversations but other times I met with two or three people at once.
Through these conversations, I learned about various architectural patterns that existed in the codebase. Which ones they considered to be good fits, and which ones they were looking to phase out. I learned why certain bits of code were still in Objective-C, and which parts of the Objective-C codebase should be refactored eventually.
I learned that certain team members had spent a lot of time working on specific features, patterns, and services within the app. They would tell me why certain decisions were made, and which choices they were and weren’t particularly happy with.
After meeting the team I knew so much more about the project, the codebase, the people working on the project, and how things move and evolve within the team. This was incredibly helpful information to have once I started to explore the codebase. Through knowing the team I knew so much more about the why of some bits of code. And I knew that some code wasn’t worth exploring too much because it would be gone soon.
On top of that, through knowing the team, I felt more empathic about bits of code that I didn’t like or didn’t understand. I know who was likely to have worked on that code. So instead of getting frustrated about that bit of code, I knew who I could ask to learn more about the confusing section of code.
In addition to meeting the team behind your new codebase, you’ll want to start exploring the codebase itself sooner rather than later. One of the key things to figure out is how the project is set up. Which code is responsible for what? How does one thing impact the other?
Hopefully, the codebase follows some well-established patterns that help you figure this out. Regardless, I find it useful to try and break things while I explore.
By introducing flaws in the business logic for an app on purpose, you can learn a lot about the codebase. Sometimes it helps you uncover certain “this should never happen” crashes where a team member used a force unwrap or wrote a
guard let with a
Other times things break in more subtle ways where the app doesn’t quite work but no errors are shown. Or maybe the app is very good about handling errors and it indicates that something went wrong / not as expected but the app informs you about this.
When you break the networking layer in your app, you might uncover some hints about how the app handles caching.
By making small changes that most likely break the app you can learn tons. It’s a technique I often use just to see if there are any threads I should start unraveling to learn more and more about the cool details of a codebase.
Of course, you don’t want to go around and start poking at random things. Usually, when I start exploring I’ll choose one or two features that I want to focus on. This is exactly the focus of my next tip.
Focus on a narrow scope
When you join a large enough codebase, the idea of having all of that code in your head at some point sounds impossible. And honestly, it probably is. There’s a good chance that most developers on the team for a large project will have one or two parts of the codebase internalized. They know everything about it. For everything else, they’ll roughly know which patterns the code should follow (because the whole team follows the same patterns) and they might have some sense of how that code interacts with other modules.
Overall though, it’s just not realistic for any team member to know all of the ins and outs of every module or feature in the codebase.
So why would you be attempting to explore the entire codebase all at once?
If you’re hired on a specific team, focus on the code that would be maintained by that team. Start exploring and understanding that code in as much detail as possible, have team members show you how the code works, and see if you can break some of the code.
Sometimes there will be bug tickets or features that you can start looking at to give you a good starting point to begin learning more about a codebase. If that’s the case, you can use your tickets to help you determine your scope. If you’re working on a bug, focus on understanding everything you can about the section of code that seems most likely to be the source of the bug.
And as always, you’ll want to be in touch with the team. Ask them if they can help you find something to focus on initially. When you have a bug ticket to work on, see if somebody on the team can help you kickstart your research; maybe they have some thoughts on where you can start looking first.
And in an ideal world, leverage pair programming to double the speed at which you learn.
Leverage pair programming
One tool that I usually find to be immensely underused is pair programming. In lots of places where I have worked, developers prefer to work alone. Headphones on, deep in the zone. Questions should be initiated on Slack so you’re disturbed as little as possible. Disable notifications if you have to.
There’s absolutely a time and place for deep focused work where you’re not to be disturbed.
However, there’s an enormous benefit in pairing up with a teammate to explore topics and work on features. Especially when you’ve just joined a team, it’s super important you have access to your team members to help you navigate the company, team, and codebase.
When you’re pairing with a teammate during your exploration phase, you can take the wheel. You can start exploring the codebase, asking questions about what you’re seeing as you go. Especially when you have something to work on, this can be extremely useful.
Any question or thought you might have can immediately be bounced off of your programming partner.
Even if you’re not the person taking the wheel, there’s lots of benefit in seeing somebody else navigate the code and project you’ll work on. Pay close attention to certain utilities or tools they use. If you see something you haven’t seen before, ask about it. Maybe those git commands your coworker uses are used by everybody on the team.
Especially when there’s debugging involved it pays dividends to ask for a pairing session. Seeing somebody that’s experienced with a codebase navigate and debug their code will teach you tons about relationships between certain objects for example.
Two people know more than one, and this is especially true while onboarding a new coworker. So next time a new person joins your team, offer them a couple of pair programming sessions. Or if you’re the new joiner see if there’s somebody interested in spending some time with you while working through some problems and exploring the codebase.
When I was working on this post I asked the community how they like to explore a codebase and a lot of people mentioned using a symbolic breakpoint on viewDidLoad or viewDidAppear which I found a pretty cool approach to learning more about the different views and view controllers that are used in a project.
A symbolic breakpoint allows you to pause the execution of your program when a certain method is called on code you might not own. For example, you can have a symbolic breakpoint on
UIViewController methods which allows you to see whenever a new subclass of
UIViewController is added to the navigation hierarchy.
Knowing this kind of stuff is super useful because you’ll be able to learn which view controller(s) belong to which screen quite quickly.
I haven’t used this one a lot myself but I found it an interesting idea so I wanted to include it in this list of tips.
When you join a new team, it’s tempting to keep your head down and study your new codebase. In your head, you might think that you’re expected to already know everything about the codebase even though you’re completely new to the project.
You might think that all patterns and practices in the project are industry standard and that you just haven’t worked in places as good as this one before.
All of these kinds of ideas exist in pretty much anybody’s head and they prevent you from properly learning and exploring a new codebase.
In this post, you have learned some tips about why human interaction is extremely important during your exploration phase. You also learned some useful tips for the more technical side of things to help you effectively tackle learning a new codebase.
Good luck on your next adventure into a new codebase!