Using a house analogy, I don't hate other people's houses. I hate it when other people blow a hole in the side of my house to put in a new window.
They blasted a hole through two walls because it was the quickest way. Then just taped some plastic over the second hole. The project manager said it's still summer and we don't really need that wall at the moment.
I know who will have to fix the wall when the winter comes and I'm not looking forward to it. There's nothing in it for me and I'll get asked why my wall wasn't OK in the first place?!
A follow up analogy is more typical in my experience. The foreman says that we should reinforce the walls. The PMP certified 6 sigma ninja Project Manager insists that the reinforced walls aren't necessary because no one is going to put anything on the wall. We will revisit the wall later when we the city tells us to enforce new wall codes.
No more than 6 months later a contractor tried to add a shelf to the unenforced wall. The contractor was never aware of what was in the wall and assumed he could find a stud. What he thought was a stud was actually the stud finder pinging on a water pipe. The construction workers didn't have time to run any tests with stud finders so they just wired everything up at the behest of management and hit the wall a few times with a rubber mallet to see if it held up. The project was behind by a week already due to the plans getting to the job site late.
He pounds in the nails, hits the water pipe, collapses the wall and floods the house. The on staff construction crew lose their jobs, the VP gets a promotion for showing they did something about this egregious error, and they are replaced with contractors.
this is also not a good analogy because building codes will often just require 20" O.C or 16" O.C studs and those are in the plans- drafted by a person that designed the home (self, architect, drafter). Reinforcements for shelves or cabinets are also part of the code for kitchen walls. Those are not to be expected in every location in the house.
The framers are locked into the house plans as far as stud distances and special framing members that are specified. County inspections will make sure that's all there.
House construction is far, far more standardized and strict that programmers coding crap code. It's not a good analogy.
Someone put fake shutters on the sides of the windows - the wrong size at that. This was accepted as a good solution because no one tried to close them. Would be impossible anyway, because there are no hinges.
That's an organizational issue. Code that does such things would not pass review unless it were specifically a requirement (or if your team is disogranized).
Once you're a senior dev, you start to look at the project holistically, adding your input to the design in order to ensure that the project serves its objectives. The code is still important, sure, but the success of the project is more important (and that can sometimes involve some short-term ugly changes).
If there's a business need for a hole in the side of the house covered with plastic that will probably be there for the next year, it's expected that you've all had many meetings discussing this modification and its necessity. By the time the code changes come, you've either long agreed with the reasoning, or have agreed to hold your tongue, or have started shopping out your resume.
Regardless, by the point this code is written, you'll already be expecting it and won't be blaming the dev who wrote it.
It's a good analogy if the reader understands it, and it is accurate.
Both are true here. People don't get away with quite that level of nonsense with buildings because even laypeople can see all the essentials, why it would be bad, who to blame if it did happen, etc. So it never happens and doesn't need any kind of illustraing analogy to explain it to anyone.
That DOES happen all the time in software and it's invisible to almost everyone including your own bosses, and does need some kind of analogy to illustrate what's wrong about it, and how wrong, and the nature of the wrongness.
Any other example that actually ever happens, would just be some other equally opaque phenomenon from some other esoteric field, and would by definition be useless as an analogy.
The whole point is so that anyone can see it and conclude "that would be crazy, outrageous, intolerable". Of course it never actually happens.
My house has a hole where a cable tv contractor inserted a coax line that they ran all the way around the house, from the service drop to right outside the living room. This despite the house being wired with coax internally, including between these two points. There was a disconnect where someone had replaced a tee with a coupler some years ago, but this was easy for me to find and fix.
Years later I spoke with an ISP about an install and they proposed exactly the same thing. I think people do this a lot.
I get the point but I do agree that it might not be a good analogy since when building structures people might disagree on where they should go but not on what a wall and a door are. In software your caretfully crafted "house" can just be a convoluted way to get from a to b to someone else.
To me writing a story comes closer to what writing software is. I can't just get an overview of their plans and know right away where I should be connecting the new "room" I want to build. Instead I need to understand what story the author was trying to get across and make my insertion in a way that makes sense with what was there before.
> This is the best-kept secret of the software engineering profession: engineers hate code. Especially code written by other people. It's why they love working on greenfield projects so much. No code, no maintenance, no headaches!
Except that I've met lots of engineers who were the opposite. They hate greenfield projects and prefer maintaining existing code. I noticed this broad division of personality early in my career. And it's a great thing -- both sorts of engineers are critical to a successful project.
I am one of those who prefer working on existing code. I like making things better, understanding how a code works is thrill, adding new features on existing premises.
I am also an amateur fiction writer, and I notice the same thing in it. I like planning, but the first draft writing is a chore to me. An effort to vomit all my ideas as words. Then, I love rewriting. Revisiting what I wrote and improving it, fixing it, perfecting it.
> I am one of those who prefer working on existing code.
Me too, mostly because I hate starting a project form scratch, it's something I'm not particularly good at. Like you, I love rewriting, I love improving things, making them better, faster, or easier to understand.
The notion that software engineers hate code is wrong, depending on who you consider a software engineer. SREs, systems administrators, operations people, they hate software with a passion. Developer (who in my mind are software engineers) freaking love code and will write more code to cover up problems which should have been address by revisiting designs and earlier assumption. I've meet with developers who's understanding of IT outside the realm of development have been so extremely poor that they frequently reinvent basic webserver or database feature, but badly.
Currently I'm working on a Django project, in the back of my mind I always have a notion that if something requires more than 20 - 30 lines of code, then it's either already a feature of the framework, or I'm doing something terribly wrong. That rules has yet to fail me.
I'm similar, and I've found AI to help with this. I'm able to guide the AI to write the first draft, then I go in and rewrite it. It's helped remove that frustration at the first draft.
I think the reason to like working on existing code is that infra is usually very complex nowdays, and for greenfield project you need to do lots of boring tasks to bootstrap it, and for existing code it is already bootstrapped by someone.
hah humans are interesting! I'm the opposite. I love starting a codebase, I also make music and it's way easier for me to make 100 cool unique sketches live and improvised but not finish anything. it really takes all kinds
I think it's a spectrum. For example I like writing new code and designing new things, but I don't hate or dislike my or other people's old code.
That code also has been written by a human, and it's disrespectful to approach somebody else's work with this prejudice.
It might not be good code, by our standards, but who knows how it was written. Was the author under stress, under time obligations, or happy, or something else?
Also, being able to approach somebody else's code and work with it is humbling and deeply educative for me. You get a (free) passage to a wisdom of a person or a group. That's priceless.
> That code also has been written by a human, and it's disrespectful to approach somebody else's work with this prejudice.
Small piece of advice: it is much better to learn how to take criticism of your code as exactly that - it's criticism of your code. People will always be unkind when reviewing code. Even if it's the best code ever written someone will have a different opinion and express it in a seemingly unkind way. It's easy to be unkind in code reviews because it's _code_ being reviewed and NOT a person with feelings.
Like you said, a different human (the more junior version of you) wrote that code, not you. It's not a criticism of you no matter how much your brain tries to tell you it is. People will never stop saying "who the fuck wrote this shit!?" and you will hear that phrase until the end of time. It's still not personal when people yell that in frustration.
For example, I have learned that Eastern Europeans tend to be absolutely brutal in code reviews. Everything will be nitpicked and the most benign design decisions you've made will be questioned. They make you feel stupid and inadequate but that's your own feelings. It's more likely you're dealing with a direct and to-the-point perfectionist who can see the code beyond your PR and how your code fits in with the rest of the application. They're not the greatest at communicating this context and their comments seem like personal attacks without that context.
> That code also has been written by a human, and it's disrespectful to approach somebody else's work with this prejudice.
Not only has it been written by a human, but one should also remember that they're missing the context in which the code was written. Was the author stressed about their latest children being born? Fearful of possible layoffs? Under time pressure? Tired?
I've definitely written code myself that came to bite me later, and I marveled at how badly written that was.
We're all human, which, among others, means that we're all inconsistent to a large degree.
I’m pretty good at writing code but I consider one of my “superpowers” to be that I also love to read code. I cannot even begin to estimate how this has affected my career and abilities. It’s a task that most seem to dread, but is something that I do for fun.
Indeed! This phenomenon has been a great source of freelancing customers for me.
Startups naturally thrive on an early team that loves building new things, but the flip side is that they rarely seem to go back to fix existing stuff. That leaves a gap for people like me, who prefer to take something that works poorly and make it bulletproof. For some reason this quite often seems to involve db access patterns but there's a fair bit of algorithms work too. Usually the "building new things" engineers are quite happy to let me take over the investigation into why the 150 line SQL query is slow, so it's a win-win.
Startup teams also aren’t great as they should be at being even slightly kind and thoughtful to their future selves.
Understanding greenfield usually means iteration, a small amount of conceptual architecture and organization before dialing into the matrix to go full Neo can go a long, long way.
Specifically, it’s easier for startups to create productive new beginners in their codebases.
Sure. Of course there are actually software developers out there in the world that read and write code. After all, that's where all this software in the world actually comes from.
But for the other 85+% of people in the profession its basically a game of AdLibs. Fill in the blank. That's why there is such heavy reliance on things like frameworks, dependencies, and Invented Here Syndrome (people who don't trust their own or teammates code). That's why you have expert beginners, because you can get really masterful at coloring with crayons.
Try to take any of this color by numbers nonsense away and see immediate full on emotional apocalypse. It's not a choice. The number one priority is to retain employment, and if your employer has failed to provide you the preparation or environment necessary to perform with confidence this is what you get.
> But for the other 85+% of people in the profession its basically a game of AdLibs
This is so true. I work at a fairly small organization (~35 devs). Large enough to see roles form but small enough that I can tangibly see everyone's contributions. I work SRE, so I see lots of code from all the teams and ultimately talk to almost all the devs.
In our impressive enterprise-level codebase (our SaaS product has average annual subscriptions in the range of $1.5M per customer), there are probably 3 developers that wrote 80% of the codebase. I can name them all and call them up. But I said we have 35 devs in the organization. So what do they do? Mostly little things. Flipping a conditional or making a slightly more explicit test case to fix an unexpected edge case we experienced.
Most of these 32 other engineers are solving simple problems, basic refactoring, and so forth. Not too different from the adlib, fill-in-the-blank analogy you provide.
Also, to be clear, it isn't like we hired 3 seniors and expect them to write all the code. These are just groups people fall into naturally.
The reality is most software engineers have only ever done the adlib style work and have built an entire career around never solving any real problems. They know just enough syntax in a language to solve the little problems and with software, there is a near infinite supply of these little problems.
I think this is an orthogonal point. Certainly there are lots of bad developers in the industry whose code appears to only work by accident. But there are just as many of them doing greenfield projects as maintenance tasks. In fact, I would guess that in growth-oriented companies there are far more of these bad developers doing greenfield projects.
The issue is that in many companies there is constant pressure from management to "innovate" by building new features or new products, even if they are of no particular utility. New stuff will bring new customers (or new subscriptions from old customers) and that will either make you personally rich, or at least look good on your CV so you can leverage the experience into the next job where you can get rich. And if the project fails, it still leaves you looking more valuable to the top brass than the people who quietly kept the systems running, because you took risks and had big ideas and showed a growth mindset.
I didn't really notice this at the start of my career, but once you see the pattern it makes so many jobs incredibly depressing. People just keep building more and more crap to advance their careers and enrich the shareholders, even when very little of it is actually useful. It's even more depressing in B2C where it becomes apparent that a large part of the money comes from exploiting individuals who simply get a buzz from buying new stuff, no matter what that stuff does or how good it is.
Personally, I am much more happy to work on an established system that already has real customers that value what it does. The phase of throwing huge amounts of crap at the wall to see what sticks is over, so what remains is an actually-useful piece of software that's full of bugs and superfluous functionality that the "innovators" (comprised of both good and bad developers) left behind. I think it's worth it to have good engineers dedicated to this role of taking the mess and refining it into the best version of the thing that customers actually want. Leaving that task to the bad developers will just result in the system eventually collapsing, which might not matter to the entrepreneurial types who only care about growth, but it does matter to the customers who were getting value from it.
The way that masked language models are trained is nothing more than madlibs. This is how I've always explained it to normies and they get it quite well.
Most of my early career was "greenfield". I really loved doing that. Sometimes that meant me doing everything. Guess where the buck stops? There's no way to disconnect the final result from the work. Keep in mind though that green field pretty quickly turns into maintenance. You ship something, guess what, there's bugs to fix. You want to add a feature, you have an existing code base. The nice thing is that there's no one else to blame. Is it really hard to add a feature? You (or your team) messed up. Does the quality suck? You (or your team) messed up.
Even in well established code bases there can always be "green" new pieces. These are choices to make: should we refactor the code, should we fix the old code, should we rewrite pieces of it. There is no one answer that always works. The problem is when you look at something and your answer is always a rewrite just because you didn't write the original code. I've seen people/team rewrite perfectly good code for no business reason, just because they want to.
In terms of code written by others, sometimes that's a thing of beauty, a piece of art. Sometimes it's just garbage. I'm sure we've all seen some code where we go wow, this is incredible. And then we've all seen code where we go wtf. I don't really see the need to dig too deep there, what's great is great and what's garbage is garbage and then a lot is somewhere in the middle. I sometimes look at code I've written in the past and I think it's really great; and sometimes I go wtf. Usually the latter is where I was not familiar enough with the problem space or the code base I was working in. Questions to ask are: does it work? what's the cost of maintenance? Ugly code that works well, doesn't need to be touched, can be fine.
1. Only working on greenfield means you don't want to learn from others or have difficulty doing it. Lots of knowledge is expressed in the code you refuse to read and you need humility and patience with your own ignorance.
2. Only reading code is insufficient as you are not only a scholar of the code base, but a maintainer and developer who must extend and adapt it.
Working with a code base is more like a conversation. There's a back and forth, though not symmetrical. (1) is someone who monologues. (2) is an audience member only.
Earlier in my career, I was stereotyped as a "maintainer", but now I've been a self-employed indie developer for years, so all of the code is mine.
Once your own code gets to be 5 years old or so, it's almost like maintaining someone else's code. It's like, why in the world did I write that before??
I guess my focus has always been on the product and the user experience, so I don't make the code itself central to my work and my identity. The code is not the product.
I think it's a culture thing in SV/VC//startup world and I think that group is very public, outspoken and sure that they speak for everyone.
Most if us aren't that but we just continue about our business developing new features and squashing bugs. I like greenfield projects but the choices and freedom they present come with a lot of non-coding and missing infrastructure.
A nice brownfield project lets me check in code, see it auto built into the dev environment and have QA feedback the next day.
I mean, there are badly designed brownfield projects with tight coupling, bad documentation, and, where you have to spend half an hour to figure out why a simple change broke everything.
Funnily enough, personally, I can handle badly designed projects as long as I was part of the team designing it. At least then I understand it enough that changing things isn't too much of a pain, and I can pretend my refactors will eventually make the codebase look good (or if that fails, I can write enough documentation to at least mitigate the problem). It's a pain in the ass for new maintainers though.
But goddamn, working in a good established project where other people have done the hard work of figuring out non-coding project management stuff is a fricken breeze. No arguments there.
My experience is that people who love writing new projects are probably not well suited for it. It means they aren't stressing over the ambiguities and long-term consequences of every single architectural decision, and thus are more likely to produce a project that immediately suffers from many technical issues, such as scaling, performance, ease of monitoring/debugging, ease of extension, ease of onboarding new maintainers, etc.
Start your project on the right foot by finding that disgruntled senior engineer and giving them ample time for design and research.
I like both. Greenfield projects can be pretty boring when there isn't something special about the functionality or a new architecture to try out, but it feels good to spurt out stable features when you know what you are doing.
Repairing / fixing / retrofitting an old code base always has it's wonders. I've seen much code in my life that was in a bad shape and my approach for fixing was seldomly the same, it was always tailored to the team and situation.
To rephrase from Tolstoy: "Good code bases are all alike, every bad code base is bad in it's own way."
I like greenfield projects but I also have the problem where a blank page gives me writer's block. Sometimes "like" doesn't go far enough.
It seems like this is a good opportunity for LLMs…
A related problem is that "maintenance" is conflated with editing code, but IME some languages especially """bug free""" would prefer you rewrite every time you make a change rather than edit things, because the code becomes impossible to understand after it has more than one author.
I didn’t realize how unique my circumstances were until I started reading r/experiencedevs.
I’ve had 8 jobs over 25 years and over that time, I’ve mostly done green field work, including at my first job out of college.
I’m not even sure I have the skillset to modify a huge existing code base.
Even at one job where there was a large codebase that I was “modifying”, it was mostly to add new CRUD features to an API or website and I did my own vertical “slice” that didn’t involve modifying existing code.
Because a greenfield project would require to do something that software engineer abhors more than writing code: giving time estimates in an "agile" environment.
I'm one of the persons who loves refactoring existing code. It's much easier to get started than writing something from scratch. I change a few bits, then I get more ideas on how the code can be further improved. I always try to consider the business value - is the a maintainability problem? Does the code need upgrades to reduce tech debt? Etc. Hard to sell this sort of work to PMs who just keep pushing for new features.
Depends on the project and the person I guess. The trust of your manager is tremendously important. N=1 here, but at my current client it took me several hours of staring at a huge SQL query before I understood why it wasn't fast but the client was trusting enough that it was time well spent. I've also has PMs who could barely understand the concept of refactoring at all.
I always apply Chesterton's fence when working on existing systems. You don't get to add, remove, or change things before you understand what exists. That discovery is inherently exciting to me.
Well, I'm currently trying to reverse engineer something done by an open source SaaS offering, to patch a tool written by another person which works with that part I'm trying to reverse.
I just wanted to use the tool without any effort, but I have to understand the interface and patch the tool to make it work again. I'm not complaining.
Just wanted to add a data point for the former part of your comment.
I like both types of work. It’s fun to do greenfield projects because of less maintenance and the ability to do it the way you want. But it’s also fun to take something years old that’s barely working and try to gradually improve it while minimizing down time.
Yep I have a hard time with a blank page and love the flywheel of incrementally iterating on a working baseline. I didn't realize this until very recently; I think I had internalized "well everyone loves greenfield projects, so I must too".
This is a really great point, and it’s awesome when a team strikes the right balance. In my experience these engineers tend to be rarer than the group I talk about in this post, but when you find them they’re worth their weight in gold!
They prefer maintaining existing code until they get a project that's full of legacy stuff and nobody wants to replace it, because it works (most of the time at least).
I'm not so sure about software engineers. We often value working solutions even if the code base is not perfect. I certainly do and I very much agree with Joel Spolsky in his classic:
"Things You Should Never Do, Part I
"They did it by making the single worst strategic mistake that any software company can make:
They decided to rewrite the code from scratch."
[1] (Emphasis his.)
Where I'm 100% sure is that consultants hate code. I've never ever seen one recommending the reuse of existing code - not once.
And it's understandable: They have nothing to gain from recommending reuse of existing code.
In the best case the code is good and everything else goes well and the client saves some money. If the consultant can not pull this of repeatedly their benefit will still be limited. The praise will be with the programers.
On the other hand, if the old code is bad or anything else goes wrong everyone will blame the consultant for the recommendation.
For the consultant it's a risk-return tradeoff that just always favors a rewrite from scratch.
Im a big advocate of rewriting code from scratch. Because on a rewrite you have a much better starting point. You have a (mostly) working solution, you understand the problem much better than on the first attempt, you have some tests and some data. Most of the time you don't rewrite it 100% from scratch, often you can copy a lot of code from the old solution.
To utilize all those benefits you can't rewrite everything at once from scratch. You need to do it incrementally.
The incrementally part is extremely important and often overlooked. I have seen project after project attempt some major big bang rewrite that always takes way longer than expected, delivers less value than promised, and causes problems in areas that used to work fine. We often understand some big picture things better as time goes on but there's a thousand small decisions baked into the existing code that are very easy to overlook
On incremental improvements you should be able to stop what you are doing within a week or two and be ok with leaving the code like that for a long time.
What you are describing is called "refactor" not "rewrite". Incremental changes that use existing code don't allow for great changes in the architecture.
I'm not against rewrites, sometimes the company grew so much that you need to start from scratch and rethink given your current knowledge. Or you started with a low fidelity prototype and you rewrite to create a production ready feature, without the crufts in the design you had when you started.
Of course Joel was wildly hyperbolizing, to the point of absurdity.
Code gets re-written from scratch all the time, for perfectly legitimate reasons. As even Joel Spolsky knows. He just meant that you should be aware of the trade-off, and that most of the time, you probably don't want to re-write from scratch.
But "Never do X" sounds much catchier. And succeeded in getting the article shared and quoted infinitely and endlessly, to this very day.
Even though everyone knows it isn't, you know, actually literally true. Even Joel.
Yea, mechanics love to complain about metric and imperial sizes and when they don’t thread in correctly, but at the end of the day a good mechanic loves seeing a smooth running car.
Similarly, a good software engineer loves it when they have a smooth running service. Updates work without hiccup and the system can be inspected to see how things are running. Having clean and maintainable code is directly proportional to the ease and pleasure of work on this service.
I believe in quality over quantity and I also believe that beautiful code exists. My hatred of code comes from lazy or rushed implementations, which can and should be improved over time.
LGTM culture is a product of bad management and should not be used as an excuse to ship lazy code or code written by people who hate what they do.
A good engineer should take pride in their work, even on the bad days. And even when the product itself isn’t what they would personally want.
What percentage of code you have worked with in your career is that beautiful code that you love to work with?
To make it more fair, code you wrote yourself doesn't count, because you aren't an objective observer -- and more importantly, have a different relationship to it making it easier to work with since you wrote it, and often to your own preferences.
I think I agree with you, it's just that... the actual way software is written doesn't seem to allow for much clean and maintainable and easily extensible code to be written, so I'm not sure how much it matters practically.
A healthy percentage of the open source projects companies I’ve worked for have used and opened PRs against I would call pretty good looking. Ruby on Rails was always nice to read through and well documented. I also find a lot of datasheets and RFCs to be highly elegant and beautiful, if not a bit dense and verbose. It just depends sometimes, what makes something like art beautiful.
I disagree strongly that “the actual way software is written …”, though it does feel like trying to write clean code is an uphill battle sometimes.
Back to the shop analogy. Cleaning up oil spots and maintaining well polished tools requires time and care.
> Don't write new code when you can use, improve or fix what already exists. If you must write new code, write only what you need to get the job done.
While the article resonates with me alot, I would like to, in the best spirit of the article, propose an addendum to that line:
When modifying existing code, do a very careful cost-benefit analysis; On the one side is the cost of a rebuild. On the other side is the projected cost of keeping this thing and maintaining it, not just for this change, but for changes in the forseeable future.
I realise that this is essentially an impossible requirement. We cannot forsee the future. But: We can make predictions. And when the predictions say, that, forseeably, the company will lose money down the line because we waited to long for a rebuild, it may be time to pitch that to whoever allocates resources.
Because, dragging a legacy-system along incurs it's own set of costs. This is especially true when it's not just maintained, but modified and extended. And many of those costs have a nasty tendency to remain hidden until they suddenly don't, and at that point, people often already expended inordinate amounts of resources on them.
So yeah, the first instinct should be: Use what already exists. But check the costs of doing so. Premature rebuilds are a waste of resources. And so is holding on to legacy systems past their expiration date.
I notice that on your “one side”, you have the cost of the rebuild — but not the “projected cost of keeping this thing and maintaining it”.
That’s a common fallacy of programming: the existing code is convoluted and hard ti maintain, but the new code I would replace it with will be much better and much cheaper to maintain.
That's a very good point you make there, and I should have mentioned that in my post.
Yes, the cost of the rebuild itself, PLUS it's own maintenance, fit with the rest of the codebase, extensibility and so on, must be considered in that equation.
I glanced over that, because usually the rationale for a good rebuild is an improvement regarding exactly these metrics.
In addition to projected cost to maintain, there is also the potential ill will you are continuing to generate with your customers if the existing buggy/legacy system affects them. Your reputation with your customers matters. This is one of the biggest factors I see companies ignore all the time.
Conversely...in a lot of cases you can reasonably project it's likely you won't be maintaining it. So what you're really projecting is how much trouble you expect to save yourself for your forseeable remaining time at the company.
> when the predictions say, that, forseeably, the company will lose money down the line because we waited to long for a rebuild, it may be time to pitch that to whoever allocates resources.
Only developers who love greenfield or need a new framework on the CV would suggest a company could lose money by not rebuilding.
If the developers are not competent enough to write maintainable code or maintain existing code, then you will have exactly the same difficulties after the rebuild.
If they are competent enough to write maintainable code and maintain existing code, then you have no need for a rebuild. Just adapt and extend the existing code to meet the new requirements.
> If the developers are not competent enough to write maintainable code or maintain existing code
Or if the old system simply doesn't work with modern environments.
Or if it depends on long abandoned frameworks.
Or if the business grows but the old implementation scales badly or not at all.
Or if it depends on components that incur licensing fees that become prohibitively expensive when it's scaled up.
Or if there are other legacy systems on different technical baselines that it could work with better after being rebuilt on the same base.
Or if its tech simply requires more maintenance than an alternative, thus binding dev resources the company could otherwise use more productively.
There are alot of reasons why maintaining an old system may be an undesireable move in the long run, that have exactly zero to do with the competence of the developers involved.
If the developers are not competent enough to write maintainable code or maintain existing code, then you will have exactly the same difficulties after the rebuild.
Why assume the same developers would be doing the rewrite as the original? Maybe the reason for the rewrite is because the original is hopeless and most of the people who worked on it are no longer around.
Also everything usrbinbash said in a sibling comment - but if something like a changing environment forces a big rewrite of an otherwise successful code base then having the original developers still around can dramatically increase the chances of success IME.
> And many of those costs have a nasty tendency to remain hidden until they suddenly don't, and at that point, people often already expended inordinate amounts of resources on them.
Any business that employs software developers knows exactly how much it costs to employ them. If that math doesn’t work then the software developers loose their jobs. This basically establishes a baseline for “value” that must be delivered, at minimum.
Above the baseline, software devs are left to their own devices: There will be no hard accounting of weather development effort is “worth it”, rather it’ll mostly be about whether people feel like it was. (This is sort of the origin of “too much money spoils things”.) As long as the effort doesn’t destroy everything, it can be argued that it was a success!
So, the “hidden” costs are actually “bearable costs” because the business is just fine. The costs are “revealed” only when they’re no longer bearable. Ironically, well designed software “hides” the costs much longer than poorly designed, so what is missing is that we don’t have a great way of assigning value to in-house developed software that “just works”. Developers don’t even really think about it much because they get paid for writing code.
I think that’s why the advice…
> Use what already exists
… becomes very hard, in practice, for devs to follow, even though it’s excellent advice. It’s a problem for management to solve.
By the estimates of another team, it will take 2-3 months to build a wrapper around their codebase (it is that entangled) and throw that in EC2. The whole project will become infested with that codebase and those issues because as we all know, a “temporary fix” is never temporary. The codebase doesn’t cover anywhere near what we have in mind for features and extensibility is … yeah.
>On the other side is the projected cost of keeping this thing and maintaining it, not just for this change, but for changes in the forseeable future.
That's going to be very difficult, especially when you then also have to consider that the changes you could do could REDUCE the cost of maintaining it. If you're only ever appending code, then the cost to maintain can quickly skyrocket. If you're also diligent about removing the features that you don't need, there should be no significant difference at the limit.
Basically, assuming you are properly maintaining the existing system, you should be continually refactoring it to be what you would build if you started from scratch. In that view, the cost of maintaining it will be identical, and the only cost that matters is the cost of bringing the existing system into alignment with what you would build now.
This is a really good addition, and something I wish I’d thought to cover. I’ve added a link back to this HN thread to the post so that people who find it from other sources can benefit from your perspective!
Reusing code cause issues if you are not very careful because if not checked people often keep adding to it or someone modified it for their use case and breaks others. Many times is just better not to reuse
Reading this article I realize how different I am from, I guess, some of my peers. I do like working on new things, but methodically shaping old software, bringing it up to date, and all the tactical thinking you need to employ to do so is very fun. Microservices are okay, and I use them mainly when I have a particular part of a codebase that's best suited to scale on its own. Outside of that, I'm a big fan of starting with monoliths that are written so they can be decomposed at a later date. There's something really nice about a well put together codebase.
Stack overflow is probably another place I differ from other engineers. I'll use it to discover patterns I'm not aware of, but I'm much more inclined to actually Ctrl+click and look at how a thing is implemented and it's sibling methods. Of course, you need well put together local configuration to do all that. I'm always looking for ways to keep my debugger in-tact, even when dealing with things like secret storage on a zero trust network. I use flags a lot for this that let me use mock-local responses.
Then again, I work on infrastructure stuff. The kind of applications I work on have to exist for a long time because of internal contracts and dependencies. Maybe this piece is more aimed at product SWEs.
I hit a turning point at some point where I stopped being afraid to read library code and ctrl click through things. Not sure when exactly it happened but I think it was related to some imposter syndrome and holding the library code as “holy”.
Looking through library code instead googling can be incredibly productive and polishes your code reading skills which are very important.
Reading and untangling code is the best part of coding in my opinion. It’s like solving a fun puzzle and trying to incrementally evolve a system.
What I hate is inconsistency. Inconsistency is what makes code intolerable to work with, because changing it becomes so much harder.
Consistency, in the way I mean it, does not mean DRY or over-abstraction. What I mean is, pick a mindset or design philosophy and stick to it. Don’t randomly switch between exceptions and returning errors. Don’t over-abstract some areas early on and then spaghetti code other areas. Have some consistency in how you do this.
For example, have a rough standard for when something is X or Y. Either accept spaghetti code for areas and keep things uncoupled as much as possible (my preferred), or have some concept of abstraction you apply to new layers. Just rough examples.
If it turns out you did it wrong, which is likely, then it is relatively easy to reason about a change. But as soon as you lose the consistency then it becomes a nightmare. Don’t have special snowflakes in your code.
The last thing I’ll write is.. sometimes the over-generalization this article makes is used as a weapon to justify sunk cost fallacy. Sometimes throwing away a part of your codebase and starting from scratch is the best thing to do. But you should work with it for a bit to understand the code before doing so.
They blasted a hole through two walls because it was the quickest way. Then just taped some plastic over the second hole. The project manager said it's still summer and we don't really need that wall at the moment.
I know who will have to fix the wall when the winter comes and I'm not looking forward to it. There's nothing in it for me and I'll get asked why my wall wasn't OK in the first place?!
No more than 6 months later a contractor tried to add a shelf to the unenforced wall. The contractor was never aware of what was in the wall and assumed he could find a stud. What he thought was a stud was actually the stud finder pinging on a water pipe. The construction workers didn't have time to run any tests with stud finders so they just wired everything up at the behest of management and hit the wall a few times with a rubber mallet to see if it held up. The project was behind by a week already due to the plans getting to the job site late.
He pounds in the nails, hits the water pipe, collapses the wall and floods the house. The on staff construction crew lose their jobs, the VP gets a promotion for showing they did something about this egregious error, and they are replaced with contractors.
The framers are locked into the house plans as far as stud distances and special framing members that are specified. County inspections will make sure that's all there.
House construction is far, far more standardized and strict that programmers coding crap code. It's not a good analogy.
Someone put fake shutters on the sides of the windows - the wrong size at that. This was accepted as a good solution because no one tried to close them. Would be impossible anyway, because there are no hinges.
This happens more often than it might seem.
Then, I agree on the point of someone else blasting a hole in your house.
Once you're a senior dev, you start to look at the project holistically, adding your input to the design in order to ensure that the project serves its objectives. The code is still important, sure, but the success of the project is more important (and that can sometimes involve some short-term ugly changes).
If there's a business need for a hole in the side of the house covered with plastic that will probably be there for the next year, it's expected that you've all had many meetings discussing this modification and its necessity. By the time the code changes come, you've either long agreed with the reasoning, or have agreed to hold your tongue, or have started shopping out your resume.
Regardless, by the point this code is written, you'll already be expecting it and won't be blaming the dev who wrote it.
What you are describing happens in an ideal world of software development. It exists but it's rare.
Both are true here. People don't get away with quite that level of nonsense with buildings because even laypeople can see all the essentials, why it would be bad, who to blame if it did happen, etc. So it never happens and doesn't need any kind of illustraing analogy to explain it to anyone.
That DOES happen all the time in software and it's invisible to almost everyone including your own bosses, and does need some kind of analogy to illustrate what's wrong about it, and how wrong, and the nature of the wrongness.
Any other example that actually ever happens, would just be some other equally opaque phenomenon from some other esoteric field, and would by definition be useless as an analogy.
The whole point is so that anyone can see it and conclude "that would be crazy, outrageous, intolerable". Of course it never actually happens.
Years later I spoke with an ISP about an install and they proposed exactly the same thing. I think people do this a lot.
To me writing a story comes closer to what writing software is. I can't just get an overview of their plans and know right away where I should be connecting the new "room" I want to build. Instead I need to understand what story the author was trying to get across and make my insertion in a way that makes sense with what was there before.
Except that I've met lots of engineers who were the opposite. They hate greenfield projects and prefer maintaining existing code. I noticed this broad division of personality early in my career. And it's a great thing -- both sorts of engineers are critical to a successful project.
I am also an amateur fiction writer, and I notice the same thing in it. I like planning, but the first draft writing is a chore to me. An effort to vomit all my ideas as words. Then, I love rewriting. Revisiting what I wrote and improving it, fixing it, perfecting it.
Me too, mostly because I hate starting a project form scratch, it's something I'm not particularly good at. Like you, I love rewriting, I love improving things, making them better, faster, or easier to understand.
The notion that software engineers hate code is wrong, depending on who you consider a software engineer. SREs, systems administrators, operations people, they hate software with a passion. Developer (who in my mind are software engineers) freaking love code and will write more code to cover up problems which should have been address by revisiting designs and earlier assumption. I've meet with developers who's understanding of IT outside the realm of development have been so extremely poor that they frequently reinvent basic webserver or database feature, but badly.
Currently I'm working on a Django project, in the back of my mind I always have a notion that if something requires more than 20 - 30 lines of code, then it's either already a feature of the framework, or I'm doing something terribly wrong. That rules has yet to fail me.
Some authors really need an editor.
I don't want level 3 support or on-call rotation, just established software that needs diagnostics, bug fixes and upgrades.
I guess you just have to apply and ask in the interview.
That code also has been written by a human, and it's disrespectful to approach somebody else's work with this prejudice.
It might not be good code, by our standards, but who knows how it was written. Was the author under stress, under time obligations, or happy, or something else?
Also, being able to approach somebody else's code and work with it is humbling and deeply educative for me. You get a (free) passage to a wisdom of a person or a group. That's priceless.
Small piece of advice: it is much better to learn how to take criticism of your code as exactly that - it's criticism of your code. People will always be unkind when reviewing code. Even if it's the best code ever written someone will have a different opinion and express it in a seemingly unkind way. It's easy to be unkind in code reviews because it's _code_ being reviewed and NOT a person with feelings.
Like you said, a different human (the more junior version of you) wrote that code, not you. It's not a criticism of you no matter how much your brain tries to tell you it is. People will never stop saying "who the fuck wrote this shit!?" and you will hear that phrase until the end of time. It's still not personal when people yell that in frustration.
For example, I have learned that Eastern Europeans tend to be absolutely brutal in code reviews. Everything will be nitpicked and the most benign design decisions you've made will be questioned. They make you feel stupid and inadequate but that's your own feelings. It's more likely you're dealing with a direct and to-the-point perfectionist who can see the code beyond your PR and how your code fits in with the rest of the application. They're not the greatest at communicating this context and their comments seem like personal attacks without that context.
Not only has it been written by a human, but one should also remember that they're missing the context in which the code was written. Was the author stressed about their latest children being born? Fearful of possible layoffs? Under time pressure? Tired?
I've definitely written code myself that came to bite me later, and I marveled at how badly written that was.
We're all human, which, among others, means that we're all inconsistent to a large degree.
Startups naturally thrive on an early team that loves building new things, but the flip side is that they rarely seem to go back to fix existing stuff. That leaves a gap for people like me, who prefer to take something that works poorly and make it bulletproof. For some reason this quite often seems to involve db access patterns but there's a fair bit of algorithms work too. Usually the "building new things" engineers are quite happy to let me take over the investigation into why the 150 line SQL query is slow, so it's a win-win.
Understanding greenfield usually means iteration, a small amount of conceptual architecture and organization before dialing into the matrix to go full Neo can go a long, long way.
Specifically, it’s easier for startups to create productive new beginners in their codebases.
But for the other 85+% of people in the profession its basically a game of AdLibs. Fill in the blank. That's why there is such heavy reliance on things like frameworks, dependencies, and Invented Here Syndrome (people who don't trust their own or teammates code). That's why you have expert beginners, because you can get really masterful at coloring with crayons.
Try to take any of this color by numbers nonsense away and see immediate full on emotional apocalypse. It's not a choice. The number one priority is to retain employment, and if your employer has failed to provide you the preparation or environment necessary to perform with confidence this is what you get.
This is so true. I work at a fairly small organization (~35 devs). Large enough to see roles form but small enough that I can tangibly see everyone's contributions. I work SRE, so I see lots of code from all the teams and ultimately talk to almost all the devs.
In our impressive enterprise-level codebase (our SaaS product has average annual subscriptions in the range of $1.5M per customer), there are probably 3 developers that wrote 80% of the codebase. I can name them all and call them up. But I said we have 35 devs in the organization. So what do they do? Mostly little things. Flipping a conditional or making a slightly more explicit test case to fix an unexpected edge case we experienced.
Most of these 32 other engineers are solving simple problems, basic refactoring, and so forth. Not too different from the adlib, fill-in-the-blank analogy you provide.
Also, to be clear, it isn't like we hired 3 seniors and expect them to write all the code. These are just groups people fall into naturally.
The reality is most software engineers have only ever done the adlib style work and have built an entire career around never solving any real problems. They know just enough syntax in a language to solve the little problems and with software, there is a near infinite supply of these little problems.
The issue is that in many companies there is constant pressure from management to "innovate" by building new features or new products, even if they are of no particular utility. New stuff will bring new customers (or new subscriptions from old customers) and that will either make you personally rich, or at least look good on your CV so you can leverage the experience into the next job where you can get rich. And if the project fails, it still leaves you looking more valuable to the top brass than the people who quietly kept the systems running, because you took risks and had big ideas and showed a growth mindset.
I didn't really notice this at the start of my career, but once you see the pattern it makes so many jobs incredibly depressing. People just keep building more and more crap to advance their careers and enrich the shareholders, even when very little of it is actually useful. It's even more depressing in B2C where it becomes apparent that a large part of the money comes from exploiting individuals who simply get a buzz from buying new stuff, no matter what that stuff does or how good it is.
Personally, I am much more happy to work on an established system that already has real customers that value what it does. The phase of throwing huge amounts of crap at the wall to see what sticks is over, so what remains is an actually-useful piece of software that's full of bugs and superfluous functionality that the "innovators" (comprised of both good and bad developers) left behind. I think it's worth it to have good engineers dedicated to this role of taking the mess and refining it into the best version of the thing that customers actually want. Leaving that task to the bad developers will just result in the system eventually collapsing, which might not matter to the entrepreneurial types who only care about growth, but it does matter to the customers who were getting value from it.
Even in well established code bases there can always be "green" new pieces. These are choices to make: should we refactor the code, should we fix the old code, should we rewrite pieces of it. There is no one answer that always works. The problem is when you look at something and your answer is always a rewrite just because you didn't write the original code. I've seen people/team rewrite perfectly good code for no business reason, just because they want to.
In terms of code written by others, sometimes that's a thing of beauty, a piece of art. Sometimes it's just garbage. I'm sure we've all seen some code where we go wow, this is incredible. And then we've all seen code where we go wtf. I don't really see the need to dig too deep there, what's great is great and what's garbage is garbage and then a lot is somewhere in the middle. I sometimes look at code I've written in the past and I think it's really great; and sometimes I go wtf. Usually the latter is where I was not familiar enough with the problem space or the code base I was working in. Questions to ask are: does it work? what's the cost of maintenance? Ugly code that works well, doesn't need to be touched, can be fine.
1. Only working on greenfield means you don't want to learn from others or have difficulty doing it. Lots of knowledge is expressed in the code you refuse to read and you need humility and patience with your own ignorance.
2. Only reading code is insufficient as you are not only a scholar of the code base, but a maintainer and developer who must extend and adapt it.
Working with a code base is more like a conversation. There's a back and forth, though not symmetrical. (1) is someone who monologues. (2) is an audience member only.
Earlier in my career, I was stereotyped as a "maintainer", but now I've been a self-employed indie developer for years, so all of the code is mine.
Once your own code gets to be 5 years old or so, it's almost like maintaining someone else's code. It's like, why in the world did I write that before??
I guess my focus has always been on the product and the user experience, so I don't make the code itself central to my work and my identity. The code is not the product.
Most if us aren't that but we just continue about our business developing new features and squashing bugs. I like greenfield projects but the choices and freedom they present come with a lot of non-coding and missing infrastructure.
A nice brownfield project lets me check in code, see it auto built into the dev environment and have QA feedback the next day.
Funnily enough, personally, I can handle badly designed projects as long as I was part of the team designing it. At least then I understand it enough that changing things isn't too much of a pain, and I can pretend my refactors will eventually make the codebase look good (or if that fails, I can write enough documentation to at least mitigate the problem). It's a pain in the ass for new maintainers though.
But goddamn, working in a good established project where other people have done the hard work of figuring out non-coding project management stuff is a fricken breeze. No arguments there.
Start your project on the right foot by finding that disgruntled senior engineer and giving them ample time for design and research.
Repairing / fixing / retrofitting an old code base always has it's wonders. I've seen much code in my life that was in a bad shape and my approach for fixing was seldomly the same, it was always tailored to the team and situation.
To rephrase from Tolstoy: "Good code bases are all alike, every bad code base is bad in it's own way."
It seems like this is a good opportunity for LLMs…
A related problem is that "maintenance" is conflated with editing code, but IME some languages especially """bug free""" would prefer you rewrite every time you make a change rather than edit things, because the code becomes impossible to understand after it has more than one author.
I’ve had 8 jobs over 25 years and over that time, I’ve mostly done green field work, including at my first job out of college.
I’m not even sure I have the skillset to modify a huge existing code base.
Even at one job where there was a large codebase that I was “modifying”, it was mostly to add new CRUD features to an API or website and I did my own vertical “slice” that didn’t involve modifying existing code.
Nothing is universal, but I think often the latter.
I just wanted to use the tool without any effort, but I have to understand the interface and patch the tool to make it work again. I'm not complaining.
Just wanted to add a data point for the former part of your comment.
I also spend a lot of time repairing and maintaining old cars, houses and fixing up stuff to be better and stronger than it was when I found it.
It’s very difficult for me to leave well enough alone. If it ain’t broke, it could certainly be better!
Dead Comment
"Things You Should Never Do, Part I
"They did it by making the single worst strategic mistake that any software company can make:
They decided to rewrite the code from scratch."
[1] (Emphasis his.)
Where I'm 100% sure is that consultants hate code. I've never ever seen one recommending the reuse of existing code - not once.
And it's understandable: They have nothing to gain from recommending reuse of existing code.
In the best case the code is good and everything else goes well and the client saves some money. If the consultant can not pull this of repeatedly their benefit will still be limited. The praise will be with the programers.
On the other hand, if the old code is bad or anything else goes wrong everyone will blame the consultant for the recommendation.
For the consultant it's a risk-return tradeoff that just always favors a rewrite from scratch.
[1] https://www.joelonsoftware.com/2000/04/06/things-you-should-...
To utilize all those benefits you can't rewrite everything at once from scratch. You need to do it incrementally.
On incremental improvements you should be able to stop what you are doing within a week or two and be ok with leaving the code like that for a long time.
I'm not against rewrites, sometimes the company grew so much that you need to start from scratch and rethink given your current knowledge. Or you started with a low fidelity prototype and you rewrite to create a production ready feature, without the crufts in the design you had when you started.
Deleted Comment
Code gets re-written from scratch all the time, for perfectly legitimate reasons. As even Joel Spolsky knows. He just meant that you should be aware of the trade-off, and that most of the time, you probably don't want to re-write from scratch.
But "Never do X" sounds much catchier. And succeeded in getting the article shared and quoted infinitely and endlessly, to this very day.
Even though everyone knows it isn't, you know, actually literally true. Even Joel.
Yea, mechanics love to complain about metric and imperial sizes and when they don’t thread in correctly, but at the end of the day a good mechanic loves seeing a smooth running car.
Similarly, a good software engineer loves it when they have a smooth running service. Updates work without hiccup and the system can be inspected to see how things are running. Having clean and maintainable code is directly proportional to the ease and pleasure of work on this service.
I believe in quality over quantity and I also believe that beautiful code exists. My hatred of code comes from lazy or rushed implementations, which can and should be improved over time.
LGTM culture is a product of bad management and should not be used as an excuse to ship lazy code or code written by people who hate what they do.
A good engineer should take pride in their work, even on the bad days. And even when the product itself isn’t what they would personally want.
To make it more fair, code you wrote yourself doesn't count, because you aren't an objective observer -- and more importantly, have a different relationship to it making it easier to work with since you wrote it, and often to your own preferences.
I think I agree with you, it's just that... the actual way software is written doesn't seem to allow for much clean and maintainable and easily extensible code to be written, so I'm not sure how much it matters practically.
I disagree strongly that “the actual way software is written …”, though it does feel like trying to write clean code is an uphill battle sometimes.
Back to the shop analogy. Cleaning up oil spots and maintaining well polished tools requires time and care.
https://www.goodreads.com/quotes/57688-i-hate-writing-i-love...
What are you referring to specifically here? A culture where nobody is actually doing reviews and just LGTMing everything?
While the article resonates with me alot, I would like to, in the best spirit of the article, propose an addendum to that line:
When modifying existing code, do a very careful cost-benefit analysis; On the one side is the cost of a rebuild. On the other side is the projected cost of keeping this thing and maintaining it, not just for this change, but for changes in the forseeable future.
I realise that this is essentially an impossible requirement. We cannot forsee the future. But: We can make predictions. And when the predictions say, that, forseeably, the company will lose money down the line because we waited to long for a rebuild, it may be time to pitch that to whoever allocates resources.
Because, dragging a legacy-system along incurs it's own set of costs. This is especially true when it's not just maintained, but modified and extended. And many of those costs have a nasty tendency to remain hidden until they suddenly don't, and at that point, people often already expended inordinate amounts of resources on them.
So yeah, the first instinct should be: Use what already exists. But check the costs of doing so. Premature rebuilds are a waste of resources. And so is holding on to legacy systems past their expiration date.
That’s a common fallacy of programming: the existing code is convoluted and hard ti maintain, but the new code I would replace it with will be much better and much cheaper to maintain.
Assumptions and Environment change. New becomes old. And old has maintenance cost.
Yes, the cost of the rebuild itself, PLUS it's own maintenance, fit with the rest of the codebase, extensibility and so on, must be considered in that equation.
I glanced over that, because usually the rationale for a good rebuild is an improvement regarding exactly these metrics.
Only developers who love greenfield or need a new framework on the CV would suggest a company could lose money by not rebuilding.
If the developers are not competent enough to write maintainable code or maintain existing code, then you will have exactly the same difficulties after the rebuild.
If they are competent enough to write maintainable code and maintain existing code, then you have no need for a rebuild. Just adapt and extend the existing code to meet the new requirements.
Or if the old system simply doesn't work with modern environments.
Or if it depends on long abandoned frameworks.
Or if the business grows but the old implementation scales badly or not at all.
Or if it depends on components that incur licensing fees that become prohibitively expensive when it's scaled up.
Or if there are other legacy systems on different technical baselines that it could work with better after being rebuilt on the same base.
Or if its tech simply requires more maintenance than an alternative, thus binding dev resources the company could otherwise use more productively.
There are alot of reasons why maintaining an old system may be an undesireable move in the long run, that have exactly zero to do with the competence of the developers involved.
Why assume the same developers would be doing the rewrite as the original? Maybe the reason for the rewrite is because the original is hopeless and most of the people who worked on it are no longer around.
Also everything usrbinbash said in a sibling comment - but if something like a changing environment forces a big rewrite of an otherwise successful code base then having the original developers still around can dramatically increase the chances of success IME.
Any business that employs software developers knows exactly how much it costs to employ them. If that math doesn’t work then the software developers loose their jobs. This basically establishes a baseline for “value” that must be delivered, at minimum.
Above the baseline, software devs are left to their own devices: There will be no hard accounting of weather development effort is “worth it”, rather it’ll mostly be about whether people feel like it was. (This is sort of the origin of “too much money spoils things”.) As long as the effort doesn’t destroy everything, it can be argued that it was a success!
So, the “hidden” costs are actually “bearable costs” because the business is just fine. The costs are “revealed” only when they’re no longer bearable. Ironically, well designed software “hides” the costs much longer than poorly designed, so what is missing is that we don’t have a great way of assigning value to in-house developed software that “just works”. Developers don’t even really think about it much because they get paid for writing code.
I think that’s why the advice…
> Use what already exists
… becomes very hard, in practice, for devs to follow, even though it’s excellent advice. It’s a problem for management to solve.
By the estimates of another team, it will take 2-3 months to build a wrapper around their codebase (it is that entangled) and throw that in EC2. The whole project will become infested with that codebase and those issues because as we all know, a “temporary fix” is never temporary. The codebase doesn’t cover anywhere near what we have in mind for features and extensibility is … yeah.
That's going to be very difficult, especially when you then also have to consider that the changes you could do could REDUCE the cost of maintaining it. If you're only ever appending code, then the cost to maintain can quickly skyrocket. If you're also diligent about removing the features that you don't need, there should be no significant difference at the limit.
Basically, assuming you are properly maintaining the existing system, you should be continually refactoring it to be what you would build if you started from scratch. In that view, the cost of maintaining it will be identical, and the only cost that matters is the cost of bringing the existing system into alignment with what you would build now.
Stack overflow is probably another place I differ from other engineers. I'll use it to discover patterns I'm not aware of, but I'm much more inclined to actually Ctrl+click and look at how a thing is implemented and it's sibling methods. Of course, you need well put together local configuration to do all that. I'm always looking for ways to keep my debugger in-tact, even when dealing with things like secret storage on a zero trust network. I use flags a lot for this that let me use mock-local responses.
Then again, I work on infrastructure stuff. The kind of applications I work on have to exist for a long time because of internal contracts and dependencies. Maybe this piece is more aimed at product SWEs.
Looking through library code instead googling can be incredibly productive and polishes your code reading skills which are very important.
What I hate is inconsistency. Inconsistency is what makes code intolerable to work with, because changing it becomes so much harder.
Consistency, in the way I mean it, does not mean DRY or over-abstraction. What I mean is, pick a mindset or design philosophy and stick to it. Don’t randomly switch between exceptions and returning errors. Don’t over-abstract some areas early on and then spaghetti code other areas. Have some consistency in how you do this.
For example, have a rough standard for when something is X or Y. Either accept spaghetti code for areas and keep things uncoupled as much as possible (my preferred), or have some concept of abstraction you apply to new layers. Just rough examples.
If it turns out you did it wrong, which is likely, then it is relatively easy to reason about a change. But as soon as you lose the consistency then it becomes a nightmare. Don’t have special snowflakes in your code.
The last thing I’ll write is.. sometimes the over-generalization this article makes is used as a weapon to justify sunk cost fallacy. Sometimes throwing away a part of your codebase and starting from scratch is the best thing to do. But you should work with it for a bit to understand the code before doing so.
Sometimes, they even are able to create codes that match such abstractions.
Sometimes, those abstractions are now flawed.
Sometimes, those abstractions are properly tooled.
Sometimes, the rest of the team also understands those abstractions.
The conjonction of all these rarely happen.