Human Who Codes Newsletter - Working with Legacy Code


Working with Legacy Code

The term “legacy code” often strikes fear into the hearts of software engineers. While there’s no single definition, IBM describes it as “code that still serves its purpose but was developed using now outdated technologies.” Any successful tech company has some amount of legacy code because that code worked well enough to attract and keep customers. When something is working, especially if it’s difficult to change, the logical choice is often to let it keep running until it can’t anymore. And that’s where the real challenges begin.

The trouble with legacy code is that it’s rarely easy to replace. It often has a large footprint and would take significant time and effort to rewrite. Add to that the risks of a rewrite and the possibility that the original authors are long gone, and you’re facing a difficult situation. Losing that institutional knowledge makes any change riskier. Many companies get stuck here because they can’t afford to remove the legacy code, yet the product suffers because changes are too risky. Leadership ends up with a tough question: how to move forward.

So where do you start?

Imagine that everything makes sense. Think of working with legacy code like an archaeological dig. At first, you may feel lost, but if you let frustration take over, you’ll end up overwhelmed. The key is to trust that every line of code was written for a reason. If it doesn’t make sense, it’s probably because you lack context. Regardless of how you feel about previous engineers, no one sets out to write unnecessary code. Assume the code matters until you can prove otherwise. Instead of saying, “This doesn’t make sense!” try asking, “If this did make sense, what would the reason be?” That simple shift in mindset can help you uncover the logic behind what you’re seeing.

Carve out the smallest logical piece. Start by finding the smallest piece of code you can fully understand; the smaller, the better. For example, on a recent project converting Angular 1 code to React, I began with a small toggle button component. Once I understood how it worked, I converted it. Then I noticed other code handling date formatting and converted that too. Each success built momentum, and soon I was able to tackle larger sections as I replaced legacy components with new ones.

Write tests. Legacy code often lacks tests, which is a big reason we’re afraid to change it. Once you’ve identified a small piece you understand, write tests to confirm that understanding. As a rule, you shouldn’t replace legacy code without tests that validate its behavior. If tests don’t exist, that’s where your work should begin.

Document everything. Everything you learn in this “dig” needs to be captured somewhere—a README, a wiki, or any shared space. Don’t rely on memory. The knowledge of how legacy code works is too valuable to lose. For example, I once couldn’t find documentation on how to restart a dev server deployed in the cloud. After tracking down someone who knew, I added that information to the repository README. Small details like that can save future engineers hours of frustration.

Working with legacy code can feel daunting, but it’s also an opportunity to learn, document, and improve a system that’s stood the test of time. By approaching it with curiosity instead of frustration, breaking it down into manageable parts, writing tests, and documenting what you discover, you turn a challenge into progress. Legacy code isn’t just old code—it’s the foundation your product was built on. Treat it with respect, and it will guide you toward building something even better.

Key Takeaways

  • Legacy code exists in every successful product because it once worked well, but replacing it is risky and time-consuming.
  • The best way to work with legacy code is to approach it patiently—understand small parts, write tests, and document what you learn.
  • Treat legacy code as a valuable artifact, not a burden; with the right mindset, it can guide you toward safer, more maintainable improvements.

Understanding JavaScript Promises

My e-book, Understanding JavaScript Promises, now includes information about Promise.withResolvers() and a whole new chapter on using and creating abortable functions.


Stuff I've Enjoyed this Month

🎬 GPT-5: Five AI model improvements to address LLM weaknesses by IBM Technology
GPT-5 isn't just the next iteration of GPT, but rather an step forward with how models decide what to do with your input. This video explains how the routing algorithm improves user experience.

📝 Europe's cookie law messed up the internet. Brussels wants to fix it. by Ellen O'Regan
Who hates cookie banners? Answer: everyone. There's actually hope that this might change thanks to some proposals in the EU.

🎬 WebAssembly might actually save the web by Awesome
It's been a while since WebAssembly has been on my radar but the last changes make it an even better compile target for all kinds of languages.

📝 A beginner-friendly guide to view transitions in CSS by Yash Raj Bharti
View transitions are one of the coolest new features in browsers, allowing you to animate the viewport between different states both within a page and across pages. This gentle introduction explains the basics.

🎧 The Last Invention by Longview
AI is such a transformative technology that it may be the last invention humans ever make. This podcast explores the history, present, and possible future of AI.

📖 Ask by Jeff Wetzler and Amy Edmondson
There is only one proven way to know what's on someone's mind: ask! This book explores the power of staying curious both in your personal and professional life.

🎬 High school basketball team gives up title... by CBS Evening News
This one is for a dose of positivity: a high school basketball team that gives up their championship trophy when the coach reviews the game and discovers a scoring error meant the team didn't actually win.


What I'm Working On

🏠 Real Estate: It's been another quiet month aside from new property assessments coming in. It's always shocking to me when the local government decides a house that has had no major changes in the last year is suddenly worth 15% more. Follow my Instagram for real estate photos.

🍞 Bredbox: Bredbox has a bunch of new features, including collections and full-text search. I spent a lot of time working on the Pocket CSV import workflow after a user reported a large CSV file didn't import properly. It turns out Cloudflare's subrequest limits really make processing large files challenging, but I think I finally got it figured out. I also added the ability to clear all of your data and delete your account.

💻 Open Source: I released version 1.0.0 of Crosspost, my JavaScript library/CLI/MCP server that lets you post across multiple different social media (and other) platforms. New in this release was Nostr, a new open, decentralized protocol for sharing content.

💻 ESLint:

  • We officially announced the most significant changes coming in v10.0.0.
  • I spent a lot of time switching over ESLint packages to use npm trusted publishing.

Coaching for Tech Leads and Staff+ Engineers

If you're a tech lead or staff+ engineer, chances are your manager has no experience in your role. While they may be well-intentioned, they may not know how to help you grow in such a challenging position.

That's where working with me can help. As a former tech lead and principal engineer at multiple companies, I learned firsthand the ins and outs of these roles. I work with my clients one-on-one to develop their leadership, communication, organization, and problem-solving skills to succeed in the upper ranks of the individual contributor track.

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

npm Security For the past few weeks, an ongoing supply chain attack on npm packages has shaken the JavaScript community. It’s not that npm packages haven’t been compromised before, but this time, the targets were surprising. Attackers went after popular packages maintained by well-known authors, creating the potential for widespread damage. In late August, the popular monorepo tool Nx was compromised, leading to several malicious package versions. These included a postinstall script that...

Code portability If you’ve been following me recently, you’ve probably seen me mention Bredbox, my new application for saving bookmarks. This is the first time in years I’ve built a web application, so I put a lot of thought into the process. My philosophy is to leave as many options open as possible in case I need to change direction later. That’s why I recommend targeting Node.js for JavaScript applications, even if you plan to run them on Deno or Bun. Both Deno and Bun are largely...

The return of tech specs When I was studying computer science as an undergraduate from 1996 to 2000, I took a course called Software Engineering that focused on the formal process of developing software. We learned to write a functional requirements document describing what the application should do, followed by a technical specification outlining how the software would achieve that. Only after completing both documents, often a semester-long effort with multiple review cycles, were we...