---
title: Your legacy software is a ticking bomb
teaser: Tick tock... Act now, or this mess might blow up in your face.
tags: technical debt,programming
author: Matheus Richard
published_on: 2025-12-29
---

You start a project with the latest tools. You're shipping features left and
right, tests are fast, CI is green, life is good. Everything is perfect!

Then one day, a new version of your favorite framework drops.

> "Huh, some cool features there. Anyway, back to work."

A few months later, a major release drops.

> "Oof, there are breaking changes. These early releases often have bugs. Let's
> wait until more people try it and it's stable."

Time passes. You try to update some other library. Requires _framework_ >= 3.2.

> "Our version isn't supported? Wait, it is deprecated already?! Fine, a monkey patch will do."

This cycle repeats: write a monkey patch here, a compatibility shim there. A
million lines of code and a few hacks later, that _slick, modern codebase_ has
decayed into abandonware, held together by bubblegum and shoelaces.

## Entropy swallows you

There is no hope in waiting. Even if you don't change, the _environment_ around
you sure will. Nature is relentless, and entropy always wins. Vendor
dependencies, lock versions, never update anything — [time will still erode your software] (https://thoughtbot.com/blog/what-happens-when-you-stop-maintaining-your-rails-application).

Package registries remove old builds, CI images disappear, hosting platforms
stop supporting your runtime. Keeping that alive with patches and workarounds
will be more and more work, until one day, it simply breaks. The world moved on,
and you're left behind.

<aside class="info">
  <p>
    GitHub <a href="https://www.youtube.com/watch?v=vIScxVu00bs">famously forked
    both Rails <em>and</em> Ruby</a> because they
    had so many monkey patches and customizations that upgrading seemed impossible.
    Do you have the resources to maintain that kind of codebase?
  </p>
</aside>

## Stay ahead of the clock

Treat it [like brushing your teeth, exercising, or doing house
chores][kitchen-sink]: routine, boring, and fundamental. The earlier you do
this, the cheaper and easier it will be.

If you wait too long, the app will become so painful to work with that none of
your devs will want to touch it, hiring will be a nightmare, security
vulnerabilities will pile up, upgrades will seem so hard that a rewrite in
microservices suddenly will look like a rational solution. And if you go that
route... well, you just got yourself [a whole new set of problems][microproblems].

Luckily, there are tools to help us stay ahead
in this game:

- [**Dependabot:**](https://github.com/dependabot) let it handle what it can.
  - Minor and patch updates are basically just a "Merge" button away now.
  - CVEs are automatically flagged and PRs created.
- **Audit your dependencies:** your package manager probably has a command for
  that (`npm audit`, `bundle audit`).
  - Integrate it into your CI pipeline to catch issues early.

You don't need to be on the bleeding edge (all the recent NPM attacks are a
testament to that), so [a cooldown is healthy][cooldown].

## End of life is here

That's why I built [End of Life], a command-line tool that scans your GitHub
repositories and flags any that depend on end-of-life software versions.

Here's how it looks in practice:

```sh
$ end_of_life scan ruby
[✔] Searching repositories that might use Ruby...
[✔] Scanning 27 repositories for EOL Ruby...

Found 2 repositories using EOL Ruby (<= 3.1.7):
┌───┬──────────────────────────────────────────────┬──────────────┐
│   │ Repository                                   │ Ruby version │
├───┼──────────────────────────────────────────────┼──────────────┤
│ 1 │ https://github.com/MatheusRich/my_rails_app  │ 2.5.8        │
│ 2 │ https://github.com/MatheusRich/some_repo     │ 2.5.0        │
└───┴──────────────────────────────────────────────┴──────────────┘
```

If you're clever, you can add it to your CI pipeline and fail the build when
using a version that will be deprecated in the near future, so you can plan
ahead.

```sh
# fail the build if using a version that will be EOL in the ~6 months
$ end_of_life check ruby@$(ruby -v | awk '{print $2}') --max-eol-days-away=180
┌─────────────────┬──────────┬──────────────────────────┐
│ Product Release │ Status   │ EOL Date                 │
├─────────────────┼──────────┼──────────────────────────┤
│ ruby@3.2.9      │ Near EOL │ 2026-03-31 (in 3 months) │
└─────────────────┴──────────┴──────────────────────────┘
```

## Back to the future

If you got yourself into an old version, there's still a way out. We need to
tourniquet that codebase before moving forward. Here are some strategies to help you:

- Use [Rails LTS][rails-lts] to get security patches for old Rails versions.
  This will *buy you some time* to plan your upgrade, but it's not a long-term
  solution for a living codebase.
- Use [Ruby Next][ruby-next] to backport modern Ruby features to older versions.
  This might be necessary to run newer dependencies.
- Use a [dual boot upgrade strategy][dual-boot] to gradually migrate your app to
  a newer version without a feature freeze, massive rewrite, or downtime.

[rails-lts]: https://railslts.com/en
[ruby-next]: https://github.com/ruby-next/ruby-next
[dual-boot]: https://medium.com/oreilly-engineering/upgrading-rails-apps-with-dual-boot-e5c271e68a6e

Learn from [the lessons of GitHub][github]. With time and effort, you too can be back on latest!

## Need a hand?

Feeling stuck with your legacy code? Can't make time for updates while juggling
new features? Afraid of touching anything because it might break everything?
We've seen it all and we're happy to help. [Reach out to us][reach] and let's
discuss how we can assist you in modernizing your software without the headache.

Prevention is better than cure. ⏱️ _Tick, tock..._

[kitchen-sink]: https://www.matheusrich.com/kitchen-sink/
[cooldown]: https://blog.yossarian.net/2025/11/21/We-should-all-be-using-dependency-cooldowns
[github]: https://www.youtube.com/watch?v=vIScxVu00bs
[microproblems]: https://thoughtbot.com/blog/making-the-case-for-monoliths-over-microservices
[reach]: https://thoughtbot.com/hire-us
[end of life]: https://github.com/MatheusRich/end_of_life/
