How to Simplify your Codebase

This ad is not shown to multipass and full ticket holders
React Summit
React Summit 2025
June 13 - 17, 2025
Amsterdam & Online
The biggest React conference worldwide
Learn More
In partnership with Focus Reactive
Upcoming event
React Summit 2025
React Summit 2025
June 13 - 17, 2025. Amsterdam & Online
Learn more
Bookmark
Rate this content

Large, legacy codebases often suffer from tangled dependencies, lack of modular boundaries, and monolithic "barrel" files that bundle together many modules. This makes the codebase difficult to understand, modify, and scale. In this talk, we'll explore strategies for "untangling the barrel" and simplifying a complex codebase to prepare it for migration to a monorepo architecture.

We'll cover techniques for:

- Analyzing your code for cyclic dependencies

- Tools to help refactoring the code

- Establishing coding guidelines and automation to control codebase complexity going forward

This talk has been presented at Node Congress 2025, check out the latest edition of this JavaScript Conference.

FAQ

'Crappy texture' refers to a problematic software architecture where there are no clear module boundaries, leading to code repetition, cluttered flows, and difficulties in making changes and refactoring.

Common signs include unclear module boundaries, code repetition, cluttered flows, slow developer velocity, difficulty in refactoring, and unexpected bugs.

Reasons include time pressure, changing requirements, incomplete understanding, technological changes, and human factors where developers lack perfect knowledge.

Dead code increases cognitive load, creates confusion, adds maintenance burden, and can negatively impact performance and application size.

A barrel file is an index file from which multiple functions are exported, simplifying imports but potentially increasing import surface and cyclic dependencies.

Tools like linters can help identify unused code, but for exported functions, programmatic approaches using tools like TypeScript's AST and TSmorf can be more effective.

MADGE is a tool that can find circular dependencies in a codebase and generate call graphs to help visualize dependencies.

A good layered architecture ensures modularity, clarity, faster development, easier maintenance, and scalability.

Improving architecture can involve eliminating dead code, breaking cyclic dependencies, and reducing reliance on barrel files for clarity and efficiency.

Cyclic dependencies cause tightly coupled code, increase complexity, make refactoring difficult, and can lead to runtime errors.

Tally Barak
Tally Barak
35 min
17 Apr, 2025

Comments

Sign in or register to post your comment.
Video Summary and Transcription
This talk focuses on the challenges of working with large codebases, such as unclear module boundaries, code repetition, and cluttered flows. Dead code is identified as a major problem that adds clutter and cognitive load to developers. The abstract syntax tree (AST) is introduced as a tool for systematically accessing code. TSmorf is recommended for finding and removing dead code by traversing and manipulating the AST. Cyclic dependencies are discussed as another issue, and MADGE is suggested as a tool for identifying and resolving circular references. Barrel files are presented as a method for organizing code and resolving cyclic references. The process of replacing imports and removing empty calls is explained. The key takeaways include the importance of a good layered architecture, eliminating dead code, breaking cyclic dependencies, and reducing barrel files.
Available in Español: Cómo Simplificar tu Codebase

1. Understanding the Problem with Large Codebases

Short description:

This talk is aimed for people working on large codebases. The signs of bad architecture include unclear module boundaries, code repetition, and cluttered flows. These issues make it difficult to make changes, slow down developer velocity, and lead to unknown bugs.

So this talk, guys, is aimed for people that are working on large codebases. And large codebases that have been around for a few years and probably worked by multiple developers might look something like what might remind you of something that looks like here. And then you go to your large codebase and you go and you make a minor change that hopefully shouldn't do anything. But this is what's happening. Everything crashes. Your CI is red, your tests are failing, maybe the app doesn't build and so on.

And the technical term that is describing this situation is called crappy texture. And this is a sign that there's a problem with the architecture of your application. What are the signs that we see for bad architecture? The first one and I think the more critical one is that there are no clear module boundaries. We are not sure what module is doing, what it is responsible for, and so on. There are a lot of code repetition. Just because it's not clear what is doing what, you might find yourself writing the same code in different places. Hopefully, it works the same, but more likely it is doing different things. Cluttered flows.

If you're trying to understand a flow in the system, you might find yourself browsing through tens of files and trying to understand what is calling what, how does it go, where are the ifs and so on. And that makes it very hard to make changes. It slows down the developer velocity. It is hard to refactor. If you want to make change, even to try and improve something because you're trying to make it slightly better, you find yourself yak shaving and you can't really make the change. And eventually, you get a disease that we all suffer from, bugs that you have no idea where they came from.

2. Addressing the Problem of Dead Code

Short description:

Time pressure, changing requirements, incomplete understanding, technology maturity, and human factors contribute to the problem of large codebases. Instead of ripping everything off and starting from scratch, I suggest addressing specific issues. In this talk, I will focus on the problem of dead code, which adds clutter and cognitive load to developers.

Why is this happening? What are the reasons? The first one, and I think the most one that is common is time pressure. You know the term of let's make it quick and dirty. I can tell you that from a lot of years of experience of software. It is never quick and always dirty, and it's usually bringing a tech that takes a long time to fix. Requirements change. This is normal. This is part of the regular flow of software development, that you get a new requirement and then it changes. No longer we need the previous one, but maybe we don't have time to come and rethink about the whole way that we implement it. So we are just patching the software with different things that in different places saying, okay, this is what we are going to do. Incomplete understanding.

This is also happening. When you start, there's a new feature. Maybe you are still a relatively young company. You don't fully understand what is the feature going to be and what are the obstructions that we are going to, that we need in order to make it clear. Technology matures. You have seen that. You are working on, you start with a certain version of let's say Node and then it grows and all of a sudden you have ESM and you have async await and that sort of thing, but obviously you don't have the time to go back and refactor the whole codebase. And the last thing is, let's call it the human factors. Also developers are probably not born with all the knowledge to do the things the correct way, to write the code perfectly, and over time we mature and we see more and more things that we know how to improve.

Okay, so yeah, we have a problematic codebase, Tali. What do you suggest to do? Should we just come and rip everything off and rewrite from scratch? Well, that could be nice, but it's very likely that you're not able to do that. So instead, let me suggest something else. My name is Tali Barak. I'm a software architect at Ubiquit and this talk is called Log Stock and Barrel. The name will reveal itself later on and it is talking about restructuring large codebases. The first problem, I'm going to tackle three problems that can help you with creating a better architecture for your application and the first one is going to be about dead code. Dead code is code that is never executed. It exists in the system because someone put it there five years ago or so and no one have noticed that it is no longer being used. Why is that a problem? Because again, this is clutter. It creates a cognitive load on the developers.