Human Who Codes Newsletter - Rates of Change


Thoughts on Rates of Change

One of the first things I realized about working in codebases is that different parts of the codebase change at different rates. There are some files that are touched very frequently while others can go months, or even years, without being touched. This fascinated me, partly because it reminded me of my closet (why do I even still have those jean shorts?), and partly because people seemed to put such little thought into optimizing their projects to reflect this reality.

The reason this matters is because every time you touch a piece of code, you have the opportunity to introduce a bug. It’s not like you’re intending to introduce a bug, but sometimes things happen when you’re working with code. Mistakes happen, but they can’t happen in that file if you don’t open the file. That’s why it’s important to separate out the parts of the code that will be touched frequently from the ones that won’t.

When I first wrote ESLint, I organized the repository in a way that separated the high-touch code from the low-touch code. I reasoned that the ESLint core, the parts that actually do the linting, would probably change infrequently. On the other hand, rules were likely to be added, fixed, and updated very frequently. So I separated the core from the rules, creating separate directories for each. I also designed the core so that rules were loaded dynamically through configuration, meaning the core didn’t need to be touched just because a new rule was added.

Here are some general guidelines for separating parts of your codebase based on the rates of change:

Use the single responsibility principle. Robert C. Martin coined the term “single responsibility principle” to describe assigning specific responsibilities to specific pieces of code. He says, “Gather together the things that change for the same reasons. Separate those things that change for different reasons.” Practically speaking, this often means creating single-purpose classes in such a way that they can be composed together to create an application but can still be changed without affecting other classes.

Keep code loosely coupled. Closely related to the single responsibility principle is the concept of loose coupling. Tight coupling means when class A changes that requires a change to class B. Unfortunately, tight coupling is difficult to identify in a code base and typically is found through the introduction of a bug where someone forgot to make the required change to another part of the code. Designing code in such a way that you don’t need to change anything other than the part you’re working on allows different code to change at different rates.

Keep configuration out of code. Any data that isn’t dynamic (calculated or otherwise requiring logic) should be kept out of your code and in configuration or data files. For instance, if there’s an API URL that your code needs to hit, that shouldn’t be in the code. It should be read from a configuration file. Why? Because the URL might change in the future, and editing a configuration file is less likely to introduce a bug than editing a JavaScript, Rust, Java, or Go fil

Keep unrelated code separate. As I described with ESLint, it’s important to keep code that changes at different rates separate from each other in your project. In its simplest form, this means creating separate directories for code that isn’t directly related. A more complicated form is to create separate packages for functionality that can be completely extracted and should be changed infrequently related to the application as a whole. Doing so reduces the attractiveness of making changes to code that shouldn’t be changed frequently.
You may be thinking, “well that’s great if you’re starting from scratch, but it’s too late now.” It’s never too late to start cleaning up the codebase. I recently went through this exercise in ESLint, separating out the parsing logic and processor logic into their own classes (after 11 years!). These two pieces of functionality haven’t changed significantly in a long time and moving them out into their own classes meant simplifying some of the most complicated logic in ESLint. While you may not get the opportunity to completely refactor an existing project, you can always take the opportunity to carve off a small piece here and there.

Key Takeaways

  • Separating out code, whether at the start or later on, is an important tactic for creating a manageable codebase in the long term.
  • The single responsibility principle states that code that changes together should be grouped together and kept away from code that doesn’t change with it.
  • Ideally, pieces of a codebase are loosely coupled, meaning that you can change one piece of code without needing to change unrelated pieces of code.

Understanding JavaScript Promises Print Book

My self-published e-book, Understanding JavaScript Promises, is now available as a printed book! Everything I know about promises is included in this book, including a whole new chapter on using and creating abortable functions.


Stuff I've Enjoyed this Month

🎬 How Canva saved millions in AWS S3 costs by KiKi's Bytes
AWS pricing model can get quite complicated, and expensive, when you're dealing with a lot of data. This video walks through how Canva optimized their use of S3 to reduce costs significantly by splitting up where different types of data are stored.

📝Garbage collection and closures by Jake Archibald
Jake uncovers an edge case in JavaScript where closures may prevent the JavaScript engine from garbage collecting variables.

🎬 Master VS Code's keyboard shortcuts in 13 minutes by Visual Studio Code
Periodically, I find myself reaching for my mouse while coding. That's when I look for video's like this one, that explain some useful keyboard shortcuts in Visual Studio Code.

📚 Outlive by Peter Attia, Bill Gifford
As someone who has been dealing with health challenges for decades, I'm always interested in latest research. This book focuses specifically on longevity, or rather, how to not die too soon from the most common deaths: heart attack/stroke, cancer, neurodegenerative disease (dementia, Alzheimer's), and metabolic disease (diabetes, fatty liver). The authors go through explicit detail of what research says and how we can improve our healthspan, not just our lifespan.

🎬 React vs HTMX: Why we chose HTMX? by Kodaps Academy
This is a nice walkthrough of the decision that one engineering team made to use HTMX instead of React. It walks through the decision points and rationalization, which is helpful for understanding if HTMX might also work in your situation.

📝Regexes Got Good: The History and Future of Regular Expressions in JavaScript by Steve Levithan
No one understands JavaScript regular expressions better than Steve (which is why I invited him to write a chapter on them in High Performance JavaScript). In this article, he goes through all of the recent additions to regular expressions in JavaScript and shows why they're helpful.


What I'm Working On

🏠 Real Estate: More bad news for my real estate investments this month. A couple years ago, I invested in several apartment building syndications. One of them was scheduled to refinance this year to return money to the investors, but that didn't happen. Interest rates are so high that refinancing would have led to bankruptcy. Instead, they sold a big part of the investment to a private equity group. While investors like me are technically still in the investment, the likelihood that I'll see any of my investment again is slim. I won't know for sure for another three years. It's a good reminder to diversify your investments. Follow my Instagram for real estate photos.

💻 ESLint: I created the official Markdown plugin to go along with the official JSON plugin. This is part of the language plugins work, allowing ESLint users to lint languages other than JavaScript...and there is more to come!

Human Who Codes Newsletter

A once-per-month newsletter discussing topics important to senior-level software engineers, with a particular focus on frontend technology and leadership.

Read more from Human Who Codes Newsletter

Thoughts on Node.js, Deno, and Bun If you started working in the tech industry after 2005, what’s going on now may seem like a shock. Large tech companies continue to lay people off despite record profits. Smaller tech companies are also laying people off, and in some cases, having “quiet layoffs,” where they find other ways to reduce headcount, including offering employees three months of salary to voluntarily leave the job. As a result, there are more software engineers looking for jobs in...

Thoughts on Node.js, Deno, and Bun For well over a decade, if you wanted to run JavaScript on the server, your only choice was Node.js. It has been battle-hardened by some of the most demanding companies in the world, many of whom paid employees to help maintain or contribute to the project. Then in 2018, Node.js creator Ryan Dahl announced Deno, a new server-side JavaScript runtime that was intended to fix a lot of the problems of Node.js. Fast forward to 2023, and Bun was released as...

Thoughts on Google In 2023, Google Search generated $175 billion in revenue. The next closest unit was Google Cloud with $33 billion (YouTube generated $31.5 billion, in case you were wondering). That’s a pretty big step down from your top money-maker to second place. And that’s why we’ve seen a big change in how Google is operating. For over two decades, we’ve been trained to think of search as the way to find important information. Need to know where the closest supermarket is? Google it....