I like writing legible code for its own elegance and for my own sanity, but given that you found your way to be productive, I admire your radically honest (and accurate) understanding of what happens to received code no matter what!
In 23 years of software development I've picked up or handed over, both solely or as part of teams (mainly the latter), dozens of projects across seven companies. Some of these were projects bought as part of acquisitions.
In only three cases was a rewrite performed, and in only two of those cases was it justifiable (both of which involved creating a new version of the product with substantially better capabilities, and on a completely new technical foundation without which those capabilities couldn't have been enabled, nor the commercial value they unlocked).
None of the acquired projects were rewritten even though they'd mostly been built by single developers.
The idea that developers want to rebuild everything from scratch is a pretty tired cliche. Maybe it's true in some contexts but it's certainly far from a universal law.
Essentially most rewrites I am aware of were either of really small tools or when a project had been written in an esoteric programming language.
Ok, maybe unfair and it is based on some experience, but mine is that code sticks no matter how bad.
Most people and industry have grown up and fears a total rewrite unless it really really hurts, and this sometimes taken to absurd levels where every dev knows it should be done, but management is like: but it works, just add me that tiny (lol) feature.
On the other hand, single devs code is usually quite good, otherwise they wouldn't have gotten that far... and it usually also has some consistency in itself. I'd say 70% good, 10% too clever guy with code that noone understands but is amazing too look at, 10% too unexperienced student but still good enough too gradually improve on, and 10% bug ridden shit. Who cares about frameworks that much nowadays, except the to be feared teams described below (and unless you have to integrate and it is a conflict)?
But what has to be feared is the code base of a mediocre team with a lacking vision and a lacking lead, that's where the horrible code bases that need an immediate full rewrite for me always stemmed from (:
“Never gets finished” takes different forms. Two I’ve observed: Form (1): half the product gets rewritten in the new language/framework/stack, but the other half stays in the original - for whatever reason, rewriting the other half never happens. I once worked on a product where the UI was a mix of Java Swing, Struts, and Angular. The Angular UI opened the Struts screens in new browser windows. I wanted to switch to IFRAMEs to make it more seamless but never happened. For the Swing UI, you had to download and install it - I daydreamed about embedding it in the web UI using a JavaScript-based VNC client (e.g noVNC) but that never got beyond daydreaming. I suppose it would have made more sense to just rewrite Swing+Struts in Angular but nobody was volunteering for that painful grunt work.
Form (2): new customers go on the rewrite but existing ones stay on the original. Sometimes the easy customers get migrated (small scale implementations with few customisations), but the massive customers with heaps of customisations don’t. “If it ain’t broke don’t fix it”, and people are scared that the migration will go bad, the customer will get upset and you’ll lose them. Eventually they’ll churn, or embark on some radical change in direction that requires reimplementing it anyway, or maybe even M&A with another customer and want to merge their instances.
Sometimes this is called the “lava layer anti-pattern”
You could see the SQL Server 7 era database with tables names taken directly from AS/400 mainframe fixed field width text files. Then you could see the mid-to-late noughties era SQL Server 2005 tables, as part of the same actual database, with its more human readable table and column names, but it was effectively a copy of the old database. All the business logic was triggers and sprocs.
And then the latest iteration, which I was working on, had been broken into "micro"-services, with our service using a Couchbase cluster (which, by the way, was a bag of spanners, and which I will never use again if I can possibly help it) to store yet another partial copy of the same data, and then all the business logic at the "application layer" in the closest thing I've ever seen to an actual seven layer architecture. They were pretty keen on enforcing those layers so what you had was just a ton of boilerplate function calls. The cognitive load of understanding what was going on was completely unnecessary for a system that basically just stored names, email addresses, addresses and phone numbers. Actually it didn't store addresses: it stored references to addresses that were stored by a different micro-service. These kinds of decisions meant that most function calls that actually did anything were also RPCs. You can imagine how this all performed.
Latterly I discovered that the blasted AS/400 mainframe system also still existed when I had to work with some files it was spitting out, and had to write an EBCDIC to UTF-8 converter (not actually difficult at all) to do so with 100% reliability.
The main reason for all of this was dependencies: to retire any given iteration of the system you'd have to migrate all its dependencies (of which there were many) to use the new variant. This sometimes meant we still had to sometimes extend the capabilities of the old versions of the systems, even though almost nobody understood them. So yours truly ended up having to write a stored procedure that updated a bunch of both the SQL 2005 and SQL 7 era tables to get a particular business process to work, and this sproc was called by our new microservice.
Even with the number of people they had migrating dependencies was a huge undertaking that they were only just starting to look at when I decided to tap out. An interesting project and a valuable experience for someone, certainly, but something I realised I didn't have the patience or fortitude for. They weren't idiots though: they knew they had problems, and that they were being choked by complexity, but there's no easy route to getting out of that kind of situation.
> Now the fact that it's plain JavaScript and messy, console.logs all over the place, I would argue, actually helps that new team. Because it makes it easy for them to trash my code.
That being said, your code is going to be rewritten, but you are not making it easier. No one needs you to write crap to be able to trash your code and people do not need to trash your code to rewrite it.
But messy code is much harder to rewrite while clean one is much easier to rewrite. Especially if your goal is different technology, having original clean means that you spend a lot less time puzzling over what it done.
You're describing an interesting take, and it makes sense in theory.
Unfortunately I don't think it happens in practice.
I have inherited code written by teams and it was not good quality. I just rewrote each section when I needed to change something. This seems like a much better approach then trying to write maintainable code - write code that can be thrown out and rewritten.
100% of the time if it's feasible, the next version will be a rewrite of all or a significant portion. Especially for relatively small projects in terms of lines of code, which all of mine are.
Now the fact that it's plain JavaScript and messy, console.logs all over the place, I would argue, actually helps that new team. Because it makes it easy for them to trash my code. Which they definitely will want to do anyway. Why? Because they don't want a back end in JavaScript. Actually they didn't want it in TypeScript either. They wanted it in Python.
What if it was in Python? Well chances are they wanted it to use a different Python framework. Or actually Rust.
But what if the front end was very very well factored React. AND the front end team loves React. Well sorry but it uses React Hooks which they hate. And they really switched to Svelte months ago actually.
I would argue the part that matters the most is just not having a lot of code. Which you accomplish by not reinventing the wheel. Another big part is having relatively small functions and low cyclical complexity, and descriptive but not overly long names.
So in my mind although my code is a mess on the surface and easy to trash, and could be organized better, it will be easier than average to rewrite they way the want. And easy to trash means less likely to be stuck maintaining someone else's code for an extended period of time.
What I care about is getting a usable product out that has features that provide value before I run out of money. I could do half the features and MAYBE if I am lucky they won't trash my code.. but they will actually be worse off because then they will be stuck maintaining a code base that actually isn't using the frameworks they preferred anyway.