<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: technical-debt</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/technical-debt.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2026-03-06T21:58:33+00:00</updated><author><name>Simon Willison</name></author><entry><title>Quoting Ally Piechowski</title><link href="https://simonwillison.net/2026/Mar/6/ally-piechowski/#atom-tag" rel="alternate"/><published>2026-03-06T21:58:33+00:00</published><updated>2026-03-06T21:58:33+00:00</updated><id>https://simonwillison.net/2026/Mar/6/ally-piechowski/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://piechowski.io/post/how-i-audit-a-legacy-rails-codebase/"&gt;&lt;p&gt;&lt;strong&gt;Questions for developers:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“What’s the one area you’re afraid to touch?”&lt;/li&gt;
&lt;li&gt;“When’s the last time you deployed on a Friday?”&lt;/li&gt;
&lt;li&gt;“What broke in production in the last 90 days that wasn’t caught by tests?”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Questions for the CTO/EM:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“What feature has been blocked for over a year?”&lt;/li&gt;
&lt;li&gt;“Do you have real-time error visibility right now?”&lt;/li&gt;
&lt;li&gt;“What was the last feature that took significantly longer than estimated?”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Questions for business stakeholders:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Are there features that got quietly turned off and never came back?”&lt;/li&gt;
&lt;li&gt;“Are there things you’ve stopped promising customers?”&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://piechowski.io/post/how-i-audit-a-legacy-rails-codebase/"&gt;Ally Piechowski&lt;/a&gt;, How to Audit a Rails Codebase&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/rails"&gt;rails&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/software-engineering"&gt;software-engineering&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/technical-debt"&gt;technical-debt&lt;/a&gt;&lt;/p&gt;



</summary><category term="rails"/><category term="software-engineering"/><category term="technical-debt"/></entry><entry><title>Quoting Steve Francia</title><link href="https://simonwillison.net/2025/Nov/4/steve-francia/#atom-tag" rel="alternate"/><published>2025-11-04T02:54:07+00:00</published><updated>2025-11-04T02:54:07+00:00</updated><id>https://simonwillison.net/2025/Nov/4/steve-francia/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://spf13.com/p/the-hidden-conversation/"&gt;&lt;p&gt;Every time an engineer evaluates a language that isn’t “theirs,” their brain is literally working against them. They’re not just analyzing technical trade offs, they’re contemplating a version of themselves that doesn’t exist yet, that feels threatening to the version that does. The Python developer reads case studies about Go’s performance and their amygdala quietly marks each one as a threat to be neutralized. The Rust advocate looks at identical problems and their Default Mode Network constructs narratives about why “only” Rust can solve them.&lt;/p&gt;
&lt;p&gt;We’re not lying. We genuinely believe our reasoning is sound. That’s what makes identity based thinking so expensive, and so invisible.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://spf13.com/p/the-hidden-conversation/"&gt;Steve Francia&lt;/a&gt;, Why Engineers Can't Be Rational About Programming Languages&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/programming-languages"&gt;programming-languages&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/psychology"&gt;psychology&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/technical-debt"&gt;technical-debt&lt;/a&gt;&lt;/p&gt;



</summary><category term="programming-languages"/><category term="psychology"/><category term="technical-debt"/></entry><entry><title>Quoting Steve Krouse</title><link href="https://simonwillison.net/2025/Jul/30/steve-krouse/#atom-tag" rel="alternate"/><published>2025-07-30T21:21:16+00:00</published><updated>2025-07-30T21:21:16+00:00</updated><id>https://simonwillison.net/2025/Jul/30/steve-krouse/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://blog.val.town/vibe-code"&gt;&lt;p&gt;When you vibe code, you are incurring tech debt as fast as the LLM can spit it out. Which is why vibe coding is &lt;em&gt;perfect&lt;/em&gt; for prototypes and throwaway projects: It's only legacy code if you have to maintain it!&amp;nbsp;[...]&lt;/p&gt;
&lt;p&gt;The worst possible situation is to have a non-programmer vibe code a large project that they intend to maintain. This would be the equivalent of giving a credit card to a child without first explaining the concept of debt. [...]&lt;/p&gt;
&lt;p&gt;If you don't understand the code, your only recourse is to ask AI to fix it for you, which is like paying off credit card debt with another credit card.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://blog.val.town/vibe-code"&gt;Steve Krouse&lt;/a&gt;, Vibe code is legacy code&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-assisted-programming"&gt;ai-assisted-programming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/technical-debt"&gt;technical-debt&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/steve-krouse"&gt;steve-krouse&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/vibe-coding"&gt;vibe-coding&lt;/a&gt;&lt;/p&gt;



</summary><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="ai-assisted-programming"/><category term="technical-debt"/><category term="steve-krouse"/><category term="vibe-coding"/></entry><entry><title>Quoting Tom MacWright</title><link href="https://simonwillison.net/2024/Nov/3/tom-macwright/#atom-tag" rel="alternate"/><published>2024-11-03T16:36:13+00:00</published><updated>2024-11-03T16:36:13+00:00</updated><id>https://simonwillison.net/2024/Nov/3/tom-macwright/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://macwright.com/2024/10/25/good-software-knip"&gt;&lt;p&gt;Building technology in startups is all about having the &lt;em&gt;right level&lt;/em&gt; of tech debt. If you have none, you’re probably going too slow and not prioritizing product-market fit and the important business stuff. If you get too much, everything grinds to a halt. Plus, tech debt is a “know it when you see it” kind of thing, and I know that my definition of “a bunch of tech debt” is, to other people, “very little tech debt.”&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://macwright.com/2024/10/25/good-software-knip"&gt;Tom MacWright&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/tom-macwright"&gt;tom-macwright&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/technical-debt"&gt;technical-debt&lt;/a&gt;&lt;/p&gt;



</summary><category term="tom-macwright"/><category term="technical-debt"/></entry><entry><title>Tech debt metaphor maximalism</title><link href="https://simonwillison.net/2023/Jul/8/tech-debt-metaphor-maximalism/#atom-tag" rel="alternate"/><published>2023-07-08T05:11:24+00:00</published><updated>2023-07-08T05:11:24+00:00</updated><id>https://simonwillison.net/2023/Jul/8/tech-debt-metaphor-maximalism/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://apenwarr.ca/log/20230605"&gt;Tech debt metaphor maximalism&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I’ve long been a fan of the metaphor of technical debt, because it implies that taking on some debt is OK provided you’re strategic about how much you take on and how quickly you pay it off. Avery Pennarun provides the definitive guide to thinking about technical debt, including an extremely worthwhile explanation of how financial debt works as well.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=36635496"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/software-engineering"&gt;software-engineering&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/technical-debt"&gt;technical-debt&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/avery-pennarun"&gt;avery-pennarun&lt;/a&gt;&lt;/p&gt;



</summary><category term="software-engineering"/><category term="technical-debt"/><category term="avery-pennarun"/></entry><entry><title>Quoting Paul Kedrosky and Eric Norlin</title><link href="https://simonwillison.net/2023/Mar/27/paul-kedrosky-and-eric-norlin/#atom-tag" rel="alternate"/><published>2023-03-27T17:14:01+00:00</published><updated>2023-03-27T17:14:01+00:00</updated><id>https://simonwillison.net/2023/Mar/27/paul-kedrosky-and-eric-norlin/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://skventures.substack.com/p/societys-technical-debt-and-softwares"&gt;&lt;p&gt;Every wave of technological innovation has been unleashed by something costly becoming cheap enough to waste. Software production has been too complex and expensive for too long, which has caused us to underproduce software for decades, resulting in immense, society-wide technical debt. This technical debt is about to contract in a dramatic, economy-wide fashion as the cost and complexity of software production collapses, releasing a wave of innovation.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://skventures.substack.com/p/societys-technical-debt-and-softwares"&gt;Paul Kedrosky and Eric Norlin&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/economics"&gt;economics&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/software-development"&gt;software-development&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-assisted-programming"&gt;ai-assisted-programming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/technical-debt"&gt;technical-debt&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/paul-kedrosky"&gt;paul-kedrosky&lt;/a&gt;&lt;/p&gt;



</summary><category term="economics"/><category term="ai"/><category term="software-development"/><category term="generative-ai"/><category term="llms"/><category term="ai-assisted-programming"/><category term="technical-debt"/><category term="paul-kedrosky"/></entry><entry><title>Software engineering practices</title><link href="https://simonwillison.net/2022/Oct/1/software-engineering-practices/#atom-tag" rel="alternate"/><published>2022-10-01T15:56:02+00:00</published><updated>2022-10-01T15:56:02+00:00</updated><id>https://simonwillison.net/2022/Oct/1/software-engineering-practices/#atom-tag</id><summary type="html">
    &lt;p&gt;Gergely Orosz &lt;a href="https://twitter.com/GergelyOrosz/status/1576161504260657152"&gt;started a Twitter conversation&lt;/a&gt; asking about recommended "software engineering practices" for development teams.&lt;/p&gt;
&lt;p&gt;(I really like his rejection of the term "best practices" here: I always feel it's prescriptive and misguiding to announce something as "best".)&lt;/p&gt;
&lt;p&gt;I decided to flesh some of my replies out into a longer post.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://simonwillison.net/2022/Oct/1/software-engineering-practices/#docs-same-repo"&gt;Documentation in the same repo as the code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://simonwillison.net/2022/Oct/1/software-engineering-practices/#create-test-data"&gt;Mechanisms for creating test data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://simonwillison.net/2022/Oct/1/software-engineering-practices/#rock-solid-migrations"&gt;Rock solid database migrations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://simonwillison.net/2022/Oct/1/software-engineering-practices/#new-project-templates"&gt;Templates for new projects and components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://simonwillison.net/2022/Oct/1/software-engineering-practices/#auto-formatting"&gt;Automated code formatting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://simonwillison.net/2022/Oct/1/software-engineering-practices/#tested-dev-environments"&gt;Tested, automated process for new development environments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://simonwillison.net/2022/Oct/1/software-engineering-practices/#automated-previews"&gt;Automated preview environments&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="docs-same-repo"&gt;Documentation in the same repo as the code&lt;/h4&gt;
&lt;p&gt;The most important characteristic of internal documentation is trust: do people trust that documentation both exists and is up-to-date?&lt;/p&gt;
&lt;p&gt;If they don't, they won't read it or contribute to it.&lt;/p&gt;
&lt;p&gt;The best trick I know of for improving the trustworthiness of documentation is to put it in the same repository as the code it documents, for a few reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You can enforce documentation updates as part of your code review process. If a PR changes code in a way that requires documentation updates, the reviewer can ask for those updates to be included.&lt;/li&gt;
&lt;li&gt;You get versioned documentation. If you're using an older version of a library you can consult the documentation for that version. If you're using the current main branch you can see documentation for that, without confusion over what corresponds to the most recent "stable" release.&lt;/li&gt;
&lt;li&gt;You can integrate your documentation with your automated tests! I wrote about this in &lt;a href="https://simonwillison.net/2018/Jul/28/documentation-unit-tests/"&gt;Documentation unit tests&lt;/a&gt;, which describes a pattern for introspecting code and then ensuring that the documentation at least has a section header that matches specific concepts, such as plugin hooks or configuration options.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="create-test-data"&gt;Mechanisms for creating test data&lt;/h4&gt;
&lt;p&gt;When you work on large products, your customers will inevitably find surprising ways to stress or break your system. They might create an event with over a hundred different types of ticket for example, or an issue thread with a thousand comments.&lt;/p&gt;
&lt;p&gt;These can expose performance issues that don't affect the majority of your users, but can still lead to service outages or other problems.&lt;/p&gt;
&lt;p&gt;Your engineers need a way to replicate these situations in their own development environments.&lt;/p&gt;
&lt;p&gt;One way to handle this is to provide tooling to import production data into local environments. This has privacy and security implications - what if a developer laptop gets stolen that happens to have a copy of your largest customer's data?&lt;/p&gt;
&lt;p&gt;A better approach is to have a robust system in place for generating test data, that covers a variety of different scenarios.&lt;/p&gt;
&lt;p&gt;You might have a button somewhere that creates an issue thread with a thousand fake comments, with a note referencing the bug that this helps emulate.&lt;/p&gt;
&lt;p&gt;Any time a new edge case shows up, you can add a new recipe to that system. That way engineers can replicate problems locally without needing copies of production data.&lt;/p&gt;
&lt;h4 id="rock-solid-migrations"&gt;Rock solid database migrations&lt;/h4&gt;
&lt;p&gt;The hardest part of large-scale software maintenance is inevitably the bit where you need to change your database schema.&lt;/p&gt;
&lt;p&gt;(I'm confident that one of the biggest reasons NoSQL databases became popular over the last decade was the pain people had associated with relational databases due to schema changes. Of course, NoSQL database schema modifications are still necessary, and often they're even more painful!)&lt;/p&gt;
&lt;p&gt;So you need to invest in a really good, version-controlled mechanism for managing schema changes. And a way to run them in production without downtime.&lt;/p&gt;
&lt;p&gt;If you do not have this your engineers will respond by being fearful of schema changes. Which means they'll come up with increasingly complex hacks to avoid them, which piles on technical debt.&lt;/p&gt;
&lt;p&gt;This is a deep topic. I mostly use Django for large database-backed applications, and Django has the best &lt;a href="https://docs.djangoproject.com/en/4.1/topics/migrations/"&gt;migration system&lt;/a&gt; I've ever personally experienced. If I'm working without Django I try to replicate its approach as closely as possible:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The database knows which migrations have already been applied. This means when you run the "migrate" command it can run just the ones that are still needed - important for managing multiple databases, e.g. production, staging, test and development environments.&lt;/li&gt;
&lt;li&gt;A single command that applies pending migrations, and updates the database rows that record which migrations have been run.&lt;/li&gt;
&lt;li&gt;Optional: rollbacks. Django migrations can be rolled back, which is great for iterating in a development environment but using that in production is actually quite rare: I'll often ship a new migration that reverses the change instead rather than using a rollback, partly to keep the record of the mistake in version control.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even harder is the challenge of making schema changes without any downtime. I'm always interested in reading about new approaches for this - GitHub's &lt;a href="https://github.com/github/gh-ost"&gt;gh-ost&lt;/a&gt; is a neat solution for MySQL.&lt;/p&gt;
&lt;p&gt;An interesting consideration here is that it's rarely possible to have application code and database schema changes go out at the exact same instance in time. As a result, to avoid downtime you need to design every schema change with this in mind. The process needs to be:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Design a new schema change that can be applied without changing the application code that uses it.&lt;/li&gt;
&lt;li&gt;Ship that change to production, upgrading your database while keeping the old code working.&lt;/li&gt;
&lt;li&gt;Now ship new application code that uses the new schema.&lt;/li&gt;
&lt;li&gt;Ship a new schema change that cleans up any remaining work - dropping columns that are no longer used, for example.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This process is a pain. It's difficult to get right. The only way to get good at it is to practice it a lot over time.&lt;/p&gt;
&lt;p&gt;My rule is this: &lt;strong&gt;schema changes should be boring and common&lt;/strong&gt;, as opposed to being exciting and rare.&lt;/p&gt;
&lt;h4 id="new-project-templates"&gt;Templates for new projects and components&lt;/h4&gt;
&lt;p&gt;If you're working with microservices, your team will inevitably need to build new ones.&lt;/p&gt;
&lt;p&gt;If you're working in a monorepo, you'll still have elements of your codebase with similar structures - components and feature implementations of some sort.&lt;/p&gt;
&lt;p&gt;Be sure to have really good templates in place for creating these "the right way" - with the right directory structure, a README and a test suite with a single, dumb passing test.&lt;/p&gt;
&lt;p&gt;I like to use the Python &lt;a href="https://cookiecutter.readthedocs.io/"&gt;cookiecutter&lt;/a&gt; tool for this. I've also used GitHub template repositories, and I even have a neat trick for &lt;a href="https://simonwillison.net/2021/Aug/28/dynamic-github-repository-templates/"&gt;combining the two&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These templates need to be maintained and kept up-to-date. The best way to do that is to make sure they are being used - every time a new project is created is a chance to revise the template and make sure it still reflects the recommended way to do things.&lt;/p&gt;
&lt;h4 id="auto-formatting"&gt;Automated code formatting&lt;/h4&gt;
&lt;p&gt;This one's easy. Pick a code formatting tool for your language - like &lt;a href="https://github.com/psf/black"&gt;Black&lt;/a&gt; for Python or &lt;a href="https://prettier.io/"&gt;Prettier&lt;/a&gt; for JavaScript (I'm so jealous of how Go has &lt;a href="https://pkg.go.dev/cmd/gofmt"&gt;gofmt&lt;/a&gt; built in) - and run its "check" mode in your CI flow.&lt;/p&gt;
&lt;p&gt;Don't argue with its defaults, just commit to them.&lt;/p&gt;
&lt;p&gt;This saves an incredible amount of time in two places:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As an individual, you get back all of that mental energy you used to spend thinking about the best way to format your code and can spend it on something more interesting.&lt;/li&gt;
&lt;li&gt;As a team, your code reviews can entirely skip the pedantic arguments about code formatting. Huge productivity win!&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="tested-dev-environments"&gt;Tested, automated process for new development environments&lt;/h4&gt;
&lt;p&gt;The most painful part of any software project is inevitably setting up the initial development environment.&lt;/p&gt;
&lt;p&gt;The moment your team grows beyond a couple of people, you should invest in making this work better.&lt;/p&gt;
&lt;p&gt;At the very least, you need a documented process for creating a new environment - and it has to be known-to-work, so any time someone is onboarded using it they should be encouraged to fix any problems in the documentation or accompanying scripts as they encounter them.&lt;/p&gt;
&lt;p&gt;Much better is an automated process: a single script that gets everything up and running. Tools like Docker have made this a LOT easier over the past decade.&lt;/p&gt;
&lt;p&gt;I'm increasingly convinced that the best-in-class solution here is cloud-based development environments. The ability to click a button on a web page and have a fresh, working development environment running a few seconds later is a game-changer for large development teams.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.gitpod.io/"&gt;Gitpod&lt;/a&gt; and &lt;a href="https://github.com/features/codespaces"&gt;Codespaces&lt;/a&gt; are two of the most promising tools I've tried in this space.&lt;/p&gt;
&lt;p&gt;I've seen developers lose hours a week to issues with their development environment. Eliminating that across a large team is the equivalent of hiring several new full-time engineers!&lt;/p&gt;
&lt;h4 id="automated-previews"&gt;Automated preview environments&lt;/h4&gt;
&lt;p&gt;Reviewing a pull request is a lot easier if you can actually try out the changes.&lt;/p&gt;
&lt;p&gt;The best way to do this is with automated preview environments, directly linked to from the PR itself.&lt;/p&gt;
&lt;p&gt;These are getting increasingly easy to offer. &lt;a href="https://vercel.com/features/previews"&gt;Vercel&lt;/a&gt;, &lt;a href="https://www.netlify.com/products/deploy-previews/"&gt;Netlify&lt;/a&gt;, &lt;a href="https://render.com/docs/pull-request-previews"&gt;Render&lt;/a&gt; and &lt;a href="https://devcenter.heroku.com/articles/github-integration-review-apps"&gt;Heroku&lt;/a&gt; all have features that can do this. Building a custom system on top of something like &lt;a href="https://cloud.google.com/run"&gt;Google Cloud Run&lt;/a&gt; or &lt;a href="https://fly.io/blog/fly-machines/"&gt;Fly Machines&lt;/a&gt; is also possible with a bit of work.&lt;/p&gt;
&lt;p&gt;This is another one of those things which requires some up-front investment but will pay itself off many times over through increased productivity and quality of reviews.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/documentation"&gt;documentation&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/software-engineering"&gt;software-engineering&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/testing"&gt;testing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/version-control"&gt;version-control&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/zero-downtime"&gt;zero-downtime&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/github-actions"&gt;github-actions&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/technical-debt"&gt;technical-debt&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/gergely-orosz"&gt;gergely-orosz&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="documentation"/><category term="software-engineering"/><category term="testing"/><category term="version-control"/><category term="zero-downtime"/><category term="github-actions"/><category term="technical-debt"/><category term="gergely-orosz"/></entry><entry><title>Quoting Will Larson</title><link href="https://simonwillison.net/2018/Apr/23/will-larson/#atom-tag" rel="alternate"/><published>2018-04-23T15:03:37+00:00</published><updated>2018-04-23T15:03:37+00:00</updated><id>https://simonwillison.net/2018/Apr/23/will-larson/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://lethain.com/migrations/"&gt;&lt;p&gt;Migrations are both essential and frustratingly frequent as your codebase ages and your business grows: most tools and processes only support about one order of magnitude of growth before becoming ineffective, so rapid growth makes them a way of life. [...] As a result you switch tools a lot, and your ability to migrate to new software can easily become the defining constraint for your overall velocity. [...] Migrations matter because they are usually the only available avenue to make meaningful progress on technical debt.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://lethain.com/migrations/"&gt;Will Larson&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/migrations"&gt;migrations&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/software-engineering"&gt;software-engineering&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/will-larson"&gt;will-larson&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/technical-debt"&gt;technical-debt&lt;/a&gt;&lt;/p&gt;



</summary><category term="migrations"/><category term="software-engineering"/><category term="will-larson"/><category term="technical-debt"/></entry><entry><title>How can I convince my boss that I should dedicate time to clean an important part of our code base?</title><link href="https://simonwillison.net/2013/Nov/22/how-can-i-convince/#atom-tag" rel="alternate"/><published>2013-11-22T17:10:00+00:00</published><updated>2013-11-22T17:10:00+00:00</updated><id>https://simonwillison.net/2013/Nov/22/how-can-i-convince/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;em&gt;My answer to &lt;a href="https://www.quora.com/How-can-I-convince-my-boss-that-I-should-dedicate-time-to-clean-an-important-part-of-our-code-base/answer/Simon-Willison"&gt;How can I convince my boss that I should dedicate time to clean an important part of our code base?&lt;/a&gt; on Quora&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It sounds like your boss needs to learn about the concept of Technical Debt: &lt;span&gt;&lt;a href="http://www.codinghorror.com/blog/2009/02/paying-down-your-technical-debt.html"&gt;http://www.codinghorror.com/blog...&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/programming"&gt;programming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/software-engineering"&gt;software-engineering&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/quora"&gt;quora&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/technical-debt"&gt;technical-debt&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="programming"/><category term="software-engineering"/><category term="quora"/><category term="technical-debt"/></entry></feed>