103 comments

[ 2.6 ms ] story [ 167 ms ] thread
My guess at the problem: we all feel a sense of relief when the codebase gets smaller, but making an existing, working codebase smaller is really, really hard work. Deleting it and starting over front loads all the reward
"Deleting it and starting over front loads all the reward"

Except that you then have nothing that actually runs. So yes, no more bad code, no mess. But also no good code, except the theoretical possibility for shiny new good code.

Refactoring is usually the way to go. Can be painful as well, when you are in the middle of it and not sure if it works out (I am in the middle of it, while also switching to a different graphic engine, but I finally see the light) - but mostly you still have something that actually works. And then you can incrementially improve on it. Seperate things that should be seperated - remove things nobody uses anymore (tricky and hard to be sure). And rewrite parts, that need a clean rewrite.

With my limited energy now (or my more realistic conception of my limited energy) - that process is way more rewarding for me, than giving in to the illusion that if I just could do it from scratch, it will be all beautiful.

Related:

Things You Should Never Do, Part I - https://news.ycombinator.com/item?id=31122975 - April 2022 (7 comments)

It’s harder to read code than to write it - https://news.ycombinator.com/item?id=31117277 - April 2022 (2 comments)

Things You Should Never Do (2000) - https://news.ycombinator.com/item?id=23725867 - July 2020 (83 comments)

Things You Should Never Do, Part I (2000) - https://news.ycombinator.com/item?id=6327021 - Sept 2013 (154 comments)

Things You Should Never Do, Part I - https://news.ycombinator.com/item?id=3624830 - Feb 2012 (40 comments)

Things You Should Never Do [2000] - https://news.ycombinator.com/item?id=3449953 - Jan 2012 (2 comments)

Things You Should Never Do, Part I - https://news.ycombinator.com/item?id=608431 - May 2009 (40 comments)

I always thought it was easier to read code than to write it.
Other way around in my estimation.
I've read every line of a 300,000 line web application in less than a year working at a company. I doubt I could write that many lines of code in that amount of time.
What language do you use? In UI you can reach that 300k loc quite quickly.
PHP, so some of it was JS and some HTML
300,000 lines of code doesn't seem unattainable for a single developer in a year. If I'm in the zone, I can easily bang out 5-10k lines of code over a weekend if I know what I want to write.

But that's the thing: a lot of development involves not writing any code, as you re-think your abstractions, plan the architecture of the next bits you'll write, debug what you've written, etc.

So I don't think we're necessarily talking about speed when we say that it's harder to read code than to write it. I think reading -- and truly understanding -- code (especially when it's someone else's, or even yours, that you haven't seen in a long time) can require quite a bit more mental effort than writing code.

Surely you jest, nobody writes a full shopping platform by themselves in a year, yet I read it and deleted all the old code that we didn't need.
Interesting. I usually think about it at a different scale; its much easier to write something small and clever than it is to read and understand it later.
Meh. I rewrilote our backend in about 3 month, and in the end of rewriting another service. All good so far!

Sometimes stuff is broken so badly you better start over

Sure do that for a few lines or even tens of thousands of lines. Don't do that for millions of lines without real serious consideration, and I'd add, a good reading of Joel's post.
Well, millions of lines, you should just create a new company.
I think people tend to want to rewrite software for the psychological break from the old, bad and ugly thing they don't want to have anything to do with anymore.

It is so easy to think "If only I could start everything from scratch, life will be so beautiful and I will be so successful and everybody will be happy. I will fix all the problems of the current codebase and people will forever sing songs about how amazingly I turned everything around."

What more frequnetly (much more frequnetly) happens is usually some mix of:

* developers not really understanding why exactly the previous version failed,

* developers not really understanding what actually worked well in the previous version,

* developers completely underestimating actual amount of accumulated knowledge in the old system that they now have to replicate. Obviously, they only discover it along the way when it is suddenly too late to fix the design to take all of that stuff into account.

* developers not appreciating the fact they are in a much very different (worse) situation than original creators of the previous version. The creators of the previous version had time to build the system and then slowly evolve it. But the current team has typically a short time horizon to replicate ALL of it.

* as the resources are shifted from the maintenance of the old system to the development of the new, suddenly the clock starts ticking and the stakeholders are impatient to see the result. The pressure grows quickly and with it comes inevitable compromises and technical debt.

* at some point development team is told they have to start maintaining the old app. The resources devoted to the rewrite shrink, the work grinds to a halt. I have seen many more systems that have been in a state of perpetual migration than I have seen ones that have been successfully completed rewrite.

> * developers not appreciating the fact they are in a much very different (worse) situation than original creators of the previous version. The creators of the previous version had time to build the system and then slowly evolve it. But the current team has typically a short time horizon to replicate ALL of it.

On the other hand, developers writing the new system have the major benefit that the requirements are known. Second system effect is real, but if you can avoid it, and focus on addressing the real requirements (as determined by the lived experience of the first system), you can get something good. Sometimes, something really good, if the old system was built on the wrong abstractions, and the new system has better fitting abstractions.

Of course, if you don't actually know what the current system is doing, you're not really in a better place to design the second system.

that only really works for static or mostly stable requirements. not so great for something like the fast evolving web platform of the late 90s when we re-wrote the Netscape/Mozilla rendering engine.
I don't think real requirements are known and understood in general.

For example, consider a team that has been maintaining the system for a long time. Most or all of the people that has initially created the system have moved on to other positions or companies. Many of the people who stuck with the team did so for reasons of being experts but are also unable or unwilling to communicate well (for example, because they see the value in preserving their position of being one of the few people with expertise).

In a team like that, they might have good memory of things they have worked on recently, but not necessarily things that are working and the users take for granted. Users do not typically spend much time reaffirming the features that are working well.

One of the challenges of working with stakeholders is that close to 100% of the communication tends to be on things that are not working or are missing or they want to get done. As a developer or manager of the team, you need to find some way of answering the question "am I doing well?". Because users are of course unhappy with how the application works, but to understand levels of unhappiness you need to find some other reference (working for some other projects).

I was yesterday in a meeting with developers where they complained about how manual our deployment system is.

Our deployment system requires them to press a button to deploy a version of the application to the environment. Yes, log in and press a button.

I explained, that I worked in the past for teams that had hundred page manuals on how to compile and deploy the software and that manual would be compiled again and again for each release and the process would take from couple of days to a whole quarter.

So you need to have some perspective to be able to judge that kind of feedback.

In my experience, the biggest factors are:

* Many developers prefer working on greenfield code rather than adding to an old codebase

* Working on a rewrite buys you some time in limbo where you can write code while being free from the burdens of production operations. This period is shorter than people dream, but it's often long enough for developers to pitch a rewrite for 6 months, code for 12 months and then skip to the next job with "Spearheaded rewrite of critical infrastructure" on their resume. Time it right and you can get out of there before you have to support the code you wrote.

Oh, then from the ops perspective, the programmers who pretend that the production environment doesn't exist, are the worst nightmare.
It is similar with databases. Developers like to pretend that ten years worth of data doesn't exist or is of no consequence. They would like to pretend everything can be re-deployed from github. They fail to realize the database includes data from version .1 while the application version is now 4.7 with completely new business rules and application logic.
> developers not really understanding

Rewriting software is an excellent way to gain such understanding. I only understood what GNU autoconf was doing when I was in the middle of rewriting its core functionality in pure GNU make.

And who knows? You might actually make a better wheel against all odds.

Or make one you don't understand the purpose of, rewriting GNU Autoconf in GNU make would serve no purpose since what Autoconf does has nothing to do with building, but rather finding out details about the running system.

Maybe you were thinking of GNU Automake ...

Autotools in general, I guess. Detecting OS and features, conditionally including sources in the build, abstracting compiler flags. The most important feature though was automatically figuring out the list of source files in an arbitrary file system tree structure and then mapping them to the build tree as object and dependency files. I somehow conjured up a recursive wildcard function that implements a simple find command in pure GNU make. It's kind of horrifying now that I think about it.

I suppose I was rewriting automake too: I started metaprogramming GNU make by evaluating templates. It's a surprisingly lisplike turing tarpit.

I keep hearing this nonsense over and over. I've led two full and very successful software 50-100K LOC rewrites, both with the team and stakeholders who had a lot of experience in the problem space. We replaced unmaintainable systems by a much fresher, MUCH faster codebase. They used largely boring and reliable technology. Rewriting 1%, 10% or even 50% would make no sense and essentially get us little or nothing.

Yes, you need to know what you're doing if you plan to rewrite anything, and make sure that the people who know the little legacy details of your system are around, but it's absolutely the right thing to do in many situations.

50-100K LOC are less than the amount of code for the build system in a couple of projects I worked on.
Then you've got bigger problems
It turns out a lot of people have a lot of problems bigger than yours.
You would think that it would have been standardised by 2024, but building stuff is still a surprisingly hard problem.
Oh, for sure. Giant C++ projects have lots and lots of issues.

Yet, they do useful work and just abandoning them in-place and rewriting them from scratch is rarely a good solution for these problems.

that's a tiny project. call back when you've got millions of lines
The thing is, there are a lot of small systems maintained by a lot of small teams. Unfortunately, when Joel wrote

“They did it by making the single worst strategic mistake that any software company can make: They decided to rewrite the code from scratch.”

some people took the “any software company” to heart and now apply the same principle even in those smaller contexts when sometimes the code really is that bad and rewriting the whole thing really is by far the best plan. I’ve seen very senior people citing the Netscape case study to support a no-rewrite position while discussing a 10kLOC system that could be rewritten from scratch in a couple of weeks by a single developer.

The HN story immediately above this one is "A Social History of Jell-O Salad".

A perfect pairing.

(comment deleted)
I first read this as a 22-year-old software engineer. Re-reading it as a 46-year-old CTO, it still tracks and still is truer than not. Most re-writes happen because the engineers want to, not because they really need to.
Not only that, it’s often an unconscious way for engineers to regain a sense of self-direction and autonomy. As folks have difficulty actually articulating that need as such, it can often be accomplished in much more productive ways that are not harmful to firms.
Do you have any examples of more productive alternatives?
Not really. You have to begin by being able to be honest about the experience with yourself and decide what you want to do about it and if anything can be done.
Code may not rust, but it may be broken out of the gate. Joel and others may not have seen really bad code, but it exists. All of us have written code in our careers that we're not proud of. And there's code written by people who are proud of everything they've written or code written by people who just don't care. These two are usually good candidates for rewrites.
You are right. But IMO you're still missing his main point. His thesis is in that case, to rewrite ONLY THE REALLY BAD CODE.

There is not team that is 100% bad so you don't need a full rewrite of 100% of the code base.

That's exactly it - really bad code can be refactored piece by piece.

What people rewrite is not really bad code, it's just middling annoying muck code.

Weird to suggest that a veteran of the industry might not have seen "really bad code". I cannot imagine that's true.
I think there's two kinds of bad software

The first kind was written by people who know about software, has some attempt at following some conventions, variable names, etc. etc. It's not "clean and shiny", but you can see someone tried. Like if a bunch of first year apprentices built a house. They tried their best, and often did a half reasonable job - at least for a first timer. Plenty of companies are using this kind of software to make many of millions of dollars. I would say this is extremely common in the real world.

And then there's codebases that consist of a single source file that has hundreds of thousands of LOC and that file is called indexNEW.php, indexNEWNEW.php index2022-1.php (and so on). Nobody who works on it has ever studied any kind of software course at any kind of school, and literally nobody has any real understanding of what/why/how, because it gets passed along like a hot potato everytime someone quits due to the insanity. Nobody who works on it even knows what source control is, has no idea why you shouldn't copy and paste code, and has never heard of TDD or automated testing or bullding or literally any software discipline. This isn't like first year apprentices building a house, this is like Homer building the Canyonero - an utter disgrace that just barely functions at all. [1]

I wouldn't be surprized if Joel is talking about type one, and doesn't even really consider type two to be "software" or "a system". It's just a stinking pile of garbage.

(I worked at a very large Telco. The vast majority of code plugging the systems together was type two - it was a nightmare of spaghetti so bad that when a power outage and failed backup generator took down everything (including 911), it took more than two weeks just figure out how to start everything back up again.)

[1] https://www.youtube.com/watch?v=PI_Jl5WFQkA

Do you have any examples of type two code you could link to? I want to see how bad it can get!
I mean, it's not like it's in github or anything like that - again, the people that write it don't even know what version control is.

Imagine a file with 100,000 LOC, some commented out, copies of functions like "addCustomer()" and then "addCustomerNEW()" and then NEWAddCustomer() and then "makeCustomerDanGNewest()" and so on and so forth. Absolute gong show.

I often share this article to new team members as a part of the onboarding journey.
Something I've found useful for avoiding the ever-present urge to rewrite things: build software with comprehensive documentation and automated tests.

In my experience, the main reason a rewrite feels like a good idea is that the existing software has grown into what feels like an unmaintainable mess: changing the software in any way at all is so painful that it feels like you'd be better off starting from scratch.

Done right, automated tests dramatically reduce the cost of changing software. You can make a change and feel confident that you've not broken anything outside of the area that you're working on because the (mostly integration) test suite continues to pass.

Likewise, documentation. Without good, comprehensive documentation you quickly find that there are all sorts of areas of the project that you don't understand - which can also make a rewrite feel like it could be justified.

The catch there is that you have to _trust_ your documentation. If you (or your team) know it to be out-of-date you'll lose trust in it - so you have to get to a point where the documentation is thorough and any mistakes in it are treated as high priority bugs to be fixed.

But... if you can get both of these things in order - your automated testing strategy and your documentation process - my hunch is that rewrites will be FAR less tempting.

Yes and no, sometimes you have to shed weight and kill some older use cases to start going back fast again. But yes, maybe for smaller projects.
The main reason why developers do rewrites is because it is easier to read your own code than it is to read somebody else's code. Doing a rewrite means you only have to work with code that was written by your current coworkers or by yourself.

This is also the core motivation behind all of the schemes to force a single coding style on all developers at the cost of performance and usually with an extremely complicated design for seemingly no reason. Usually, these turn out to be unreadable messes as well a generation later once everybody has moved onto the latest and "greatest" coding style trend.

Instead of doing rewrites, you can just refactor code. That means, among other things, deleting obsolete code for platforms you no longer support and, in the case of C/C++, converting macros to functions. You can also document the codebase (with comments not commit messages) so that developers understand what the code does and why it is there. But a full rewrite is usually a bad idea that will just introduce new bugs and remove existing functionality.

Refactor vs rewrite is basically the software development equivalent of reform vs revolution in political science and everybody with even a minimal knowledge of history knows that revolutions usually end badly with an even worse regime taking power. Likewise, the failure to accept the need for reform (i.e. refusing to allow refactoring) inevitably leads to revolution.

In 2000, refactoring was not really a thing as few projects had many automated unit tests and any change to the code had to be tested manually.
This is why I recommend using a framework in commercial projects, and following it's idioms as closely as makes sense for your project.

It means there is a shared idiomatic approach across your team and all the documentation for it is just the framework documentation. It is also easier to hire devs, if you can vet their ability to write idiomatic code in a specific framework then you can better assume they will mesh well with yor codebase.

It is a communication and empathy problem at its heart. You are being empathetic to future devs and future you by acknowledging the knowledge they would need to work on your code. Then the communication of your idioms is baked into the framework ecosystem and docs.

Using a framework doesn't help at all because a framework is still somebody else's code. There is nothing special about somebody else's framework that makes it any easier to deal with that somebody else's non-framework.
The idea is that frameworks are generally designed to be used by other people, leading to greater focus on documentation, developer ergonomics, community support and generally more versatile code (scales with number of contributers/users; many will report obscure bugs and edge cases you may never consider testing but would impact your end users). Another huge benefit is you don't have to rewrite an entire system from scratch, saving time and mental load.

I'd say there's quite a bit "special" about all of these attributes, at least enough to warrant careful consideration.

Just because something is designed to be used by other people doesn't mean it's good. There are lots of things designed to be used by other people, leading to all of the features you list: documentation, community, other people finding bugs, yada yada yada... languages, operating systems, libraries... and many of those things still suck. There is nothing inherent about being designed for use by other people that makes things suck less, and there is nothing magical about "frameworks" that makes them suck less than all the other stuff designed to be used by other people but still sucks.

If you qualify this advice to the point where it actually becomes useful it turns into, "Use code written by other people that doesn't suck." And that, of course, is indeed a good idea, but it's a lot easier said than done.

Absolutely; most frameworks will not fulfill their design goal. Most ambitious open source programming efforts tend to wither away due to loss of interest, a failure to gain contributors, lack of experience, lack of time or energy and many other factors.

But despite that caveat, there do exist frameworks out there today that speed up development for some developers. Whether one has the time or energy or will to audit them to find one that works best for them (or learn that none of them do) is up to the individual.

I bring this up because many of us on this website are at times infected by NIH syndrome and think we can do better than a dedicated team of experienced front-end developers. And it's likely true for many frameworks, but not all. Additionally, we may want to extend that attitude to our workplace where our peers and bosses likely value development speed and cross-project consistency over code performance.

I used to eschew any and all frameworks, but now I realize that my values have changed. Projects like Svelte give me hope for a better future for front-end development.

> But despite that caveat, there do exist frameworks out there today that speed up development for some developers.

Of course. But there also exist frameworks that will slow development down. For any X in {frameworks, languages, operating systems, libraries} there exist X's that will be helpful and X's that will not, and so "use an X" by itself is not helpful advice for any X. You have to use a good X, but that isn't helpful either because it just begs the question.

Absolutely true.

I just intended to push back against the notion that frameworks should not be considered.

Until $framework decides to rewrite everything too, and now you're stuck on an old unmaintained version or waste time migrating to the new version.
I'll address both your comments here if that's alright,

It's not about code quality at all, it actually doesn't matter that much if the framework is excellent or just okay to reap the main benefit, which is knowledge diffusion through the team and having a set of agreed upon idioms that there's no need to bike shed over. Not every team has a software architect skillset so it's a bit of a risk hedge as well.

There's no need to argue over implementation details, you waste less time onboarding new staff and you have that rich ecosystem of docs and community of solved problems.

That's all. There are great reasons to build your own software but if you're working in a team I feel it's an easier experience to use a known framework. Also a bit more responsible from a business risk management perspective, since you don't have as big of a "bus problem". Only your business logic is trapped inside your org.

That's a sound argument under certain circumstances. If you're building a standard product using relatively unskilled labor then yes, using a framework -- any framework -- can be helpful. But if you're doing something where rewriting an existing code base is even an option you would consider then you almost certainly are not operating under those circumstances. For starters, you probably have people on your team who are plausibly capable of rewriting the existing code, and under those circumstances, hemming those people in with a bad framework can do a lot more harm than good. So I stand by my original statement: "Use a framework" is not good advice in general. It can be the right thing under certain circumstances, but the art is in recognizing those circumstances, not in the use of a framework. Blindly following "use a framework" with no further qualification is a PHB move.
>The main reason why developers do rewrites is because it is easier to read your own code than it is to read somebody else's code.

LOL: so did you read TFA, or just come up with this yourself?

[flagged]
I only have surface-level knowledge of any of these things, but I don't think most people would consider a defeated slave rebellion or a war of independence as "revolutions"

As for the other two ... maybe the people of those countries would have endured less suffering afterwards if they had reformed rather than revolted?

>war of independence as "revolutions"

The war of independence the 13 American colonies waged against Britain is generally called "The American Revolution", but yes, for some reason most other wars of independence aren't called revolutions -- for instance while there was a Mexican revolution in the early 20th century, the earlier war of independence against Spain is just called the "Mexican war of independence" (Guerra de Independencia de México)

> Should the French have tried reforming the feudal society?

Well, the English AFAIK have done exactly that, haven't they?

> The main reason why developers do rewrites is because it is easier to read your own code than it is to read somebody else's code.

Did you read the article? He says what you wrote explicitly, in fact there is an entire section on it.

(comment deleted)
Whenever I come across these Nevers and Always, I look for the exceptions.

I mostly agree with the sentiment. Slow, incremental changes, whether to code or even a website's style. Mostly. But sometimes you run across code so malign, so neglected, so undocumented, uncommented, twitchy, troublesome, inexplicable, that the risks of the Second System Effect are worth it.

Really, I think the crucial point comes when your system is a kind of obelisk. You tiptoe around it, make offerings, but you don't know how to appease its wrath. It's like the weather.

Then it is time.

That obelisk (we call it the monolith) effect is what led to the approval in my org to take a small team and start work on replacing our nearly 25 year old pile of enterprise Java with a new codebase. I agonized over doing this, tried to fix and refactor and guide effort to just having better code, but in the end the code base has become an inscrutable, angry monolith and it's impossible to know what code improvement appeases it or triggers a series of critical production bugs.

Joel Spolsky is a smarter man than I, but his examples here are table stakes stuff compared to two decades of poorly implemented Java enterprise MVC patterns. And we don't sell software, we sell a service, and that service will continue even if our rewrite team never delivers, so the rewrite can't be more than just an expensive financial boondoggle if I'm wrong.

> they think the old code is a mess. . . . they are probably wrong. The reason that they think the old code is a mess is ... It’s harder to read code than to write it.

I suppose I think the reason people think code is a mess is because it _is_ a mess. Just yesterday I saw a team decide to override $PATH in 50 separate files because they didn't understand how to package a python library. (I'm not innocent in crazy stuff either, we're all human).

My experience is that rewrites happen when a team doesn't have anything clear to do instead, so it's more like "teams/businesses with no clear objectives" struggle rather than inherently rewrites.

There's mess and there's "override $PATH in 50 files" mess. "The old code is a mess" is a really easy conclusion to come to when trying to grok a complicated codebase, and it's not always correct.
Genuine question, is your experience that it is often more your lack of understanding than the code actually being a mess? I ask because while I've been guilty of judging too soon myself, it's much more common the code is just bad, written by someone who's already left. (I work in healthcare and startups though, so different industries are probably different. Also, I've probably been the person who wrote that bad code too!)
It's usually a little of both. Sometimes it's a little messy but before you get full understanding, it appears a lot messier. But having the experience of coming across code that I think sucks until I fully understand it and recognize it as something I wrote two years ago (but maybe someone moved to a new location, so I didn't remember it) makes me a little more humble when it comes to judging code.
Am I wrong in understanding that this rewrite is what produced Gecko, which is still one of the top browser engines a quarter of a century later? I really think Joel called this one wrong.
He makes an exception for open source projects. But a from scratch rewrite is one factor that killed Netscape. Wonder how many thousands of hours were burned on xul at a critical moment.
He's giving business advice, and it's hard to argue a success from that perspective.
Netscape could have been as big as Google. Instead, Microsoft ate their lunch. Now, even Firefox too has become niche.

Off-topic: anyone else remember the Mozilla browser before Firefox? Remember XUL? That was with KDE and Gnome 1.x, when the Linux desktop was just round the corner. Who needs Word when you could use StarOffice....

Netscape Navigator used to be a commercial product that people paid for. Firefox is now free and is used by so few people (me included) that a growing number of sites see no economic value in supporting it.

I think Joel's advice is holding up pretty well.

One greenfield/rewrite project I saw had a large team, which previously was maintaining and evolving a legacy system that the new system was to replace. (I wasn't from that team, so more on the sidelines.)

The new system was to support new requirements, have fewer legacy constraints, and benefit from using more off-the-shelf libraries and frameworks. It was more complex than it was bulky (i.e., cross-domain designs to nail, not tons of rote coding to churn). They had an aggressive timeline.

One risk you might imagine is Second System Syndrome. And there was some of that, more with everyone wanting to jam in every feature, and maybe also Analysis Paralysis on some parts the architecture.

But the biggest problem was that, collectively, that particular team just couldn't build a new system that would come together in a sufficiently timely fashion.

At least part of the problem was that management definitely dropped some balls they couldn't afford to. Had the engineers been organized better, and used more appropriate process, I don't know whether they could've risen to the challenge.

I try to avoid rewriting code (especially if it was originally written by others), and when I do it, I try to do it selectively, and for quality reasons.

For example, one place I worked as a C and C++ programmer, they hired lots of recent grads from a top CS program. Unfortunately, production-grade C code is much harder than most people think it is. The bug reports in core code used throughout the system often to lead to functions that weren't even on the right track for the quality level of C that we needed. So I started killin' code that needed killin'. Management seemed to approve of those decisions, and I don't think I stepped on any toes. (I suspect that the recent grads who'd written code like homework assignments didn't care if anyone rewrote it, so long as it was done quietly.)

Another time, there was a single Web service endpoint that pretty much had to work correctly, if the company was going to stay in business. So I rewrote it much more methodically and resilient than Web backend code typically gets written.

There was another time I simply walked away from a new consulting project, once I saw the code and realized that it was unsalvageable, and that the client wouldn't understand rewriting. (Imagine an undergrad who enthusiastically kludged together something demo-grade from numerous off-the-shelf components, and now the client "just needs someone to polish it up and extend it".) The functionality could've been recreated rapidly, and rock-solid, in a fraction of the time it would take to start to improve this code. The barrier was political, and since it was a new client, and looking like it would be a bad client, not worth the ulcers to salvage.

Generalizations are generally wrong, and I'm always right. I prefer to assess objectively whether to rewrite or refactor on a case by case basis.
I’ve heard from a couple people that Stripe is in limbo because they started a rewrite of their monolithic ruby app, but it stalled when the champion of the rewrite left. So now they are supporting both the new app and the legacy app in prod. Sounds miserable.
So, ah, Square (aka Block, Inc.) are currently doing precisely the same thing...
The real question is whether you’re allowed to start a rewrite of gen 2 before gen 1 is completely decommissioned.
I hear Joel on this, I really do, but can one imagine using any code from Netscape Communicator 4 in whatever Firefox I'm typing this on?

Perhaps it's rose tinted glasses, but I distinctly remember that Netscape 4 had to repaint the screen on window resize. Like the code was that bad. The product was rushed to market and features were bolted on because there was a browser race/war where quality suffered greatly.

This POV would have been impossible to see if you use Netscape 6 because it was so unusable no one used Netscape 6 except for nerd points and to try out "does my browser support this CSS" tests.