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.
Either that or they were aware of what they were doing and left the extreme irony of what they chose to repeat as a kind of Easter egg for anyone familiar with the source.
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.
> House construction is far, far more standardized and strict that programmers coding crap code. It's not a good analogy.
the way i took it was that in home construction what they describe is completely absurd and yet that is how most businesses do software, so the contrast there drove the point home (no pun intended)
"programmers coding crap code" vs. builder building crap houses. Both exists and both are very real.
In many ways the builders are even worse because they can usually hide the faults with caulk and paint if you want. Problem becomes evident when things start to leak or rot. That can be later but been causing damage in the meantime.
Here's an example of an arguably good builder who had one team install a in-wall tank toilet, then another team drills right through the tank causing a leak. The repair work essentially meant ripping out everything and doing it over, even though there should have been mitigations in place to prevent it and having the plans/documentation available to everyone.
While construction has more standardization, planning, and inspections, it still relies on implementation and is going to have failures.
No analogy is good when you dissect it to pieces. Being perfect encapsulations of reality is not the point of analogy, they are simply there to increase understanding.
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.
Depends on what I’m writing. For anything vanilla I use the chatgpt site Ui. For anything that maybe censored like smut I use prompt engineering and gpt 3.5 turbo via api to get past the censors, although they just announced this model is to be deprecated in January so I’m playing with local language models to some success. For now been using gpt4all and it’s surprisingly good, although slow on my hardware.
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.
Not just infra. It’s the tests, it’s the crud, its getting clients and config setup, it’s banal decisions around copying existing patterns or trying to refine them for next gen copy pasting.
It’s fun early in career, but gets boring fast IMO. These are good things to have junior and mid eng cut their teeth on.
The sweet spot is for someone with deep experience to lay down the skeletal structure of the tests, rpc, infra, lifecycle, etc… then hand it off to a broader team who could learn the intention behind the decisions.
> who could learn the intention behind the decisions
If people did learn those intentions we wouldn't have the problems we have.
I inherited a project like this once as the third generation to take it over. The (evidently, I never met them) well trained and experienced first developers laid down a foundation using a textbook OO style with a few little tricks needed to make that work in a language where OOP support was bolted on. The code was not perfect, but it was professional work and I would put it around the 80th percentile in terms of code quality.
These tricks caused the virtues of that foundation to be overlooked entirely, and so the project was essentially reimplemented in spaghetti style over time with various ad hoc stovepipes to pass data back and forth between the two sides when the original had functionality that wasn't understood well enough to be reimplemented.
The importance of training, communication, and retention can not be overstated.
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 would love to team up with someone like you. Having a person that can start a new code base and not be overwhelmed by the task is a godsend. I'm much more comfortable diving into an existing project and extending it or fixing bug than I am starting something new. Somehow it's just more natural for my brain.
My favorite musical partnerships have a balance of a starter and (me) a finisher. I really struggle with producing raw material, but am good at revising, reworking, and cutting out fluff and my best writing partners are great at spewing out ideas, most of which are cut. It together, we are able to make something we’re both excited about.
That's the dream! I think it won't work at most public companies unless you end up in a department with a dead-end product whose raison d'être is to keep one or two whale customers happy.
I have a friend who does migration tools that help businesses move their data from ancient versions of software that the big players don't support any more. It's a niche, but it's a niche that banking/insurance/etc customers are willing to pay for. I've applied for jobs like this and never even made it to the screening call. When I asked how she got the job, it was through a former colleague of hers. I actually interviewed with that colleague at a different company several years prior and I heard from her that his impression of me was that I would be bored in the role. So I think it's really important to emphasize to the hiring manager that it is exactly what you are looking for, especially if you have a background in more "hip" companies.
If the "boring" companies don't call you back, my recommendation would still be to look for B2B software, or an internal/tooling-focused team where your customers are your colleagues. It has to be on a product that is already profitable (or seen internally as valuable) so that you don't get pressured into adding new features or having the whole product killed from under you. Ideally a company that is not on the IPO track. There are some maintenance roles to be found in these "hip" companies, but they're rare, and I think you have to accept that you might only be able to fly under the radar for a year or two until an ambitious executive comes along who wants to reorg the department into a boondoggle production line.
My brother works for Birds Canada making 40k CAD a year. Got dropped into a 500-1M line Java codebase and asked to do site redesign and is now implementing SSO for them.
I recommended “Working With Legacy Code” and he read it.
His first job so great experience. I guess be underpaid is the answer.
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.
You're right, one needs to be able to take criticism, not about the code, but in everything, however being able to give criticism correctly is equally important.
This is not about style (kind or to the point, or in any style), but again about keeping in mind that you're talking with a human being.
You can say "This doesn't work (because of this), so do it this way", in thousand different intonations, and you can add the underlying message in anywhere on the spectrum of "this works better for our case" to "you're a triple distilled idiot".
This is not about being sensitive or having a skin, this is about mutual respect in a professional setting. When you do your to the point, brutal criticism, you cannot hurt the other party if you keep in mind that you are talking with a human being.
During my M.Sc. jury, one member called me a liar, and my professor had to intervene politely yet forcefully, and in my Ph.D. jury one member flat out insulted me, yet I defended myself politely yet forcefully.
They could have said the same thing, with the same words, in a much politer tone, but they preferred to attack me directly instead of attacking my work, so there's that.
I tend to give direct criticisms as well, yet I do my best to make sure that it's plain and simple I'm trying to guide and it's about the work, not about the person.
Because, I do not do anything to anyone which I don't want to experience myself.
Your handling of the PHD situation sounds perfect and it seems like we're in agreement.
I want to reiterate you will never be in a situation where everyone is respectful even if it's a professional setting. You also can't control what other people do so there's no point expecting people to give criticism respectfully or trying to teach people how to do so - you can't correct someone's behavior if they don't want to change it.
Every time I catch myself wanting to say "people should act like xyz" I stop myself and think "I will react a different way when someone acts like xyz" instead if I'm not happy with how the situation went. Especially if I've already expressed my feelings and someone has ignored them and still acts in a way I don't like.
I think I misrepresented myself. I don't expect anything from anyone, in any setting, or I don't intend to change anyone. Who am I to expect to change someone?
I just wanted to say that, I behave the way which I want to be treated. I ask myself, "what would I feel if that's done to me", and if I don't like the answer, I change myself, and try to better myself step by step.
Actually "The Four Agreements" by Don Miguel Ruiz sums up pretty well how I live this life. It's a surprisingly thin yet dense book. I recommend it wholeheartedly.
Looks like we try to do the same things with slightly different methodologies. My hat's off to you dear sage internet stranger.
I agree so strongly with this. It’s all about the code! You need a tough skin in this game, and the ability to seperate emotion from the end goal “good code!”.
I love the Eastern European approach; blunt and to the point. The French are also good for this. We anglos are so sensitive, and so afraid of offending, that you end up with a silly inefficient dance. “Have you considered? Perhaps if we tried this approach…”. No! Give me “this won’t work, do it this way” every time!
> 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.
Also important is Chesterton's fence and the history lesson when touring existing code. What were the business requirements the first time around that were thrown out the window for version two, but there was no time for refactoring so version three has this known wart that version four tried to refactor but that wasn't complete until version five which had this new feature that needs another refactor.
Too many developers remain hyper committed to shiny object syndrome, or wanting to relearn lessons of the past as if they are the first to ever lay eyes on it.
No code is perfect, and lots can be learned even from a well intentioned approach gone wrong.
It’s far easier learning from other folks and their rattlesnake bites instead of insisting of recollecting that baggage yourself, first.
Greenfield is still useful, but too often it has to do with preference and interpretation or a lack of willingness to do so.
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.
Most of my clients were from a local meetup where I eventually got to know most people quite well and they me. It was mostly word-of-mouth where people remembered "Oh! <other startup> had similar problems and WJW solved it for them".
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.
Sounds like SRE has afforded you a unique "who's writing what code small-org-wide"
semi-impartial perspective. Thanks for sharing!
I'm curious if the ~three devs that "wrote 80% of the codebase" mutually recognize one another? i.e. do you think they think of themselves as in a "writes a lot of code" category along with the other ~two devs? Do they think of themselves as "writes a lot of code"? Does management recognize this and/or plan around it?
I've sometimes been one of the "people writing a lot of code" in a small org. When I'm in that mode/context, I find myself daily appreciating the types of contributions made by the larger body of folks less deep in the woods. They do a different and complementary type of work, and I've found both types bring something valuable (and different) to the codebase.
When I was a developer I hated it. I was almost always the #1 in LOC, Jira Tickets, Scrum Points, you name it. I was naturally good at it, but the environment was always very competitive and the other top performers would brush it off as just me being lucky with "LOC Heavy" tasks. And it would piss me off that I would get paid the same as a guy who wrote 200 LOC a month and wasn't doing much more than those lines.
Being a manager/lead developer today, I enjoy the people doing small work. I just let them pick tasks as they wish, and it takes longer, but they eventually pull through.
The problem is just that they're a bit unpredictable, so if something has a tight deadline, we gotta assign to someone else.
As a developer I don't mind that other people don't do work. If they want to stagnate in their career that is their problem, but it certainly isn't a problem for me... until they make it my problem. This typically happens when entitlement sets in and the baseline lowers so dramatically that not doing work becomes a mandatory expectation only shattered by the crying when conveniences are peeled away.
Worse than that are the people who work their ass off, but just aren't good at it. I would rather work with people who prefer to not do work. The output is generally the same, but the people who work their asses off cannot see the difference and believe they somehow deserve more.
In my career the single biggest failure that I see repeated EVERYWHERE is confusion about what software really is. There is only one purpose to any of this: automation. In that mantra actually not doing work is supremely desirable so long as the output meets expectations.
I think the biggest risk with the people who work their asses off more than they should (doesn't matter if it's good or bad code) is that they end up with a non-sustainable output. Productivity is artificially high, and often achieved by overtime, working weekends, and overworking themselves. Eventually that leads to burnout, lower quality, and it becomes hard to replace. When it's people working too much and delivering bad code it's probably not as bad, though.
At my current company we have someone in this situation, with work affecting their day-to-day stress levels very much, to the point of damaging their personal relationships. Their manager is young and inexperienced, and doesn't see the issue, but he was flagged by HR and I hope something gets done.
This is why the tech interview is still an unsolved problem (for non-tech ppl).
How does a non-tech role sift through the 32 devs who did 10YOE flipping bools vs. the 3 that built the entire system? They'd look similar on paper and in superficial conversation.
This is the plague of hiring senior engineers, and one of the reasons we needed a new code test/challenge to get fewer bool flippers in our senior engineer hiring process. If you make them do something complicated/complex you get a lot more signal than if the test is bool flipping/a simple project from scratch
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.
And you enjoy and prefer this kind of work? OK! I guess occasionally I enjoy this kind of work too, when I'm in an environment with reasonable expectations of how challenging it will be/long it will take, when I have room for it.
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).
Fair question, I suppose I didn't express myself clearly.
Firstly, I'd like to abolish the idea that "greenfield" and existing are somehow opposites. Greenfield projects take on a bunch of existing abstractions and complexities from all the stuff they are built on. Instead, these two terms are actually very similar, "greenfield" projects just chose to throw out one more layer than using the existing system. My argument here is that the dichotomy here is false, and that the two terms are instead a classification of degrees to which you abandon existing abstractions.
As I said, I understand that this is what you mean when you say greenfield, I'm not asking you to use different words. I'm asking you to pay notice that this is what you are saying. That you are explicitly not in a "green field" with nothing around you. You've thrown all the furniture out, but the building is still there, the walls are still the same color, and the windows are still overlooking the same parking lot.
This makes no sense to me... Greenfield projects have problems that legacy projects don't (What language to use, what framework to use, where/how to deploy, etc.), and vice versa (How do I design my feature with the existing limitations of the system in mind, do I need to to redesign a part of the existing system to get it to work, etc.).
None of that has anything to do with "Time thinking about the problem", nor does either one imply that its questions are easier or harder to answer in all scenarios. They're just very different questions, but some devs prefer dealing with the issues a greenfield project presents.
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.
The main value a big bang rewrite has is that for six to eight months the dev team gets a break from being asked a lot of uncomfortable questions. By the time the questions get properly uncomfortable again, you’ve worked there long enough for it to be reasonable for you to leave.
Incremental improvements require more skill. The sorts of skills that make you a better developer. So even though it’s more difficult, it’s much more valuable to all parties for you to attempt it.
The only reason for a rewrite is when you have a language or framework that’s dead, and there are often other dynamics that put you in that spot in the first place.
There are a bunch of common mistakes people make with trees that take years off their life expectancy. The worst guarantee the tree will be dead in twenty years (and potentially dangerous before that). Software has similar phenomenon, on a much shorter time scale.
I am sure there are good reasons for it, the postgres proposal for switching concurrency models[1] comes to mind. I actually just posted this question to see what people come up with: https://news.ycombinator.com/item?id=36646299
My knee jerk reaction to rewrites is so negative I actually would like some counter evidence on when it worked out.
We're in the midst of a couple rewrites that are going/have gone well. Perl to golang and angular1 to react.
The common factor is doing it gradually, basically page by page. There is no big switchover, new code goes live as it is ready. We have some very competent people with long tenures which surely helps.
I'm not a usually a huge fan of buzzwords and I usually give trends time to pass before bothering with them but this is an advantage of micro services that I really like.
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.
It's also possible to incrementally change the architecture. It doesn't have to be a Big Bang.
Edit: refactoring is usually considered to be done on existing code base. I really mean thowing a whole component away and re-doing it from scratch. The components need to be small enough though, that you can deliver them to production within 2-5 months.
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.
You say that as if these events are unfortunate accidents instead of lack of technical leadership.
I’ve met quite a few “unlucky” people in my life and what nearly all of them had in common was the inability to connect their actions and inactions to consequences. They were blindsided by predictable outcomes over, and over, and over again. Eventually the people who could actually help you get tired of your drama and move on, and then you’re left in an echo chamber where your narrative makes sense.
I’ve spent a lot of time on this job thinking about the thoughts and plans of the people who have left. If our vertical were more compelling I believe we could make a better product with the people who have left than with the people who stayed. Even considering the lack of depth in domain knowledge. There’s a lot of things that don’t change because they were the right thing to do ten years ago. That’s an explanation for how we arrived here, not a reason to stay.
You say that as if these events are unfortunate accidents instead of lack of technical leadership.
Sometimes they are. I've seen several applications that were successful for many years but eventually had to be rewritten because some vital dependency was no longer viable.
In web development we had an early generation of web apps that used plugins like Flash or Java to do things. Fast forward five years and those plugins have been brutally killed off by the browser developers. However other web technologies have become viable alternatives for some of those things. That's a big rewrite.
Some programming languages have had big jumps that weren't entirely compatible. Python 2 to Python 3 is an obvious example that took years but eventually resulted in not only Python 2 no longer being supported but some libraries never being updated to support Python 3 and others being created to provide similar functionality. In this case many of the direct code changes could be automated but you can't automate swapping out each obsolete library for a replacement with a similar purpose but a different API. And maybe you wouldn't want to because in the 5 or 10 years since you built the last version new ideas have come along and you're better off adopting them instead since you have to make a big change anyway.
Browsers discontinuing Flash support is indeed a good reason for porting an app to a different platform.
But this is also a very different scenario than the grandparent example, where the cost of maintenance due to bad code quality is supposed to justify a ground-up rewrite. In the Flash example there is a clear business case for porting, even though it is understood the porting will expensive.
The fallacy is believing a ground-up rewrite will lead to more maintainable code. This is just developers deluding themselves. There is no reason to think a ground-up rewrite of existing working code will lead to better and more maintainable code.
There is no reason to think a ground-up rewrite of existing working code will lead to better and more maintainable code.
As with almost every argument in this area that depends very much on context.
A substantial rewrite might be an opportunity to use better tools and improved techniques that have been developed since the original was written. In some cases that could represent a huge improvement in things we actually care about like developer productivity and the quality and performance of the product. Importantly this doesn't imply anything was done wrong or any bad decisions were made by the developers of the original product or the people who have maintained it so far. It's just that we work in a fast-moving industry and sometimes even a few years can see some big improvements in what the available technologies can do.
A development team starting with a relatively clean slate can take into account all the knowledge and feedback received over the lifetime of the existing system. Maybe it was too expensive to make use of those insights while evolving the original system but a new version can take advantage of them. Again that can represent big gains in areas that we care about.
It's often observed that a big rewrite risks losing a lot of small improvements and fixes that have accumulated over the lifetime of the existing system and of course that's true. However it's also true that a big rewrite can avoid a lot of existing design problems or get rid of long-standing bugs that no-one was ever going to get around to fixing.
I've seen big rewrites that didn't end well. But I've also seen big rewrites that were done for sensible reasons and had very positive outcomes. And I've also seen things that should have been rewritten but weren't and instead became a drag on everything. There is no universal rule here.
A substantial rewrite is developers asking for a do-over, which is infantile behavior (or as GP more kindly put it, delusion).
This is a hill I will die upon: The people who don't deserve rewrites ask for them, early and often. The people who deserve a rewrite rarely mention them, and in fact they likely already have done it, bit by bit as a sibling comment mentioned by way of example. I will say that I've often surprised myself with features I never would have hoped for on the refactoring road. Things that would have been entire Epics become six weeks of work, sometimes less.
Refactoring is the Ship of Theseus scenario. You replace the ship bit by bit, until it's both a new ship and the same ship. Yes, it's a titanic pain in the ass, but it's also atonement for your past bad decisions. Which are heavily populated with cut corners you will be able to spot the next time.
All worthwhile learning is effortful, and greenfield is the lowest effort path to anything. You don't learn much from greenfield except why greenfield is not a panacea.
> A substantial rewrite is developers asking for a do-over, which is infantile behavior
That depends entirely on the reasons why they ask for a rewrite.
"I like this tech better", "I don't want to work with this tech", "This new tech is shinier": I agree with you, those are not solid engineering reasons.
"This doesn't interface well with the rest of the system because...", "This is going to cost us in the future because, ...", "This won't scale well because..."; I strongly disagree.
You may notice that the operative difference here is the term "because". If someone can give a quantifieable, technical, verifieable reason for a rebuild, then management should at least hear the guy out. They can still say no. But then the engineer did his job, and if the whole show goes haywire later because the 14 year old Java backend fails to scale up and the company loses money over that, nobody can say he didn't warn them.
You approach scalability problems by identifying bottlenecks through measurements, and then you redesign the problem areas to solve the problem. This might be changing an inefficient algorithm, add caching, partitioning a database or whatever the problem calls for. Most likely the majority of code will be unaffected by these changes.
If an engineer propose that the only way to solve scalability problems is to rewrite everything from the ground up, it just tell you they haven't been able to identify the root cause of the problem. The rewrite will probably end up having he same problem.
Unfortunately that argument is like saying you approach security by identifying vulnerabilities and patching them or you approach performance by profiling to find hot spots and optimising them. Of course those things are often true in specific instances and that's usually where you should start.
However all of these are systemic issues and once you've picked the low-hanging fruit you can still be left with systemic problems that are not concentrated in one place but spread throughout your code. Eventually your profiler curve is nearly flat but your JavaScript or Python code still isn't going as fast as C or Rust. Eventually you think you've patched all of your injection points but if you're using manual string concatenation to build your SQL queries you'll probably keep missing others. And eventually you run out of places to add caches and load balancers and it turns out that your existing data storage model is fundamentally limited and needs to be replaced.
In each of these cases you may end up needing to rewrite a whole section of your application or a whole service in your distributed system because you can no longer paper over the cracks. Fortunately it happens relatively rarely but it certainly does happen!
That is the calculus of a project that has been running for 1-2 years.
The calculus of a project that has been running for 10-20 years is often different.
I've explained why - and why in some cases the approach you advocate is literally impossible - in my other comments in this discussion, which I invite you to read if you haven't already.
> A substantial rewrite might be an opportunity to use better tools and improved techniques that have been developed since the original was written. In some cases that could represent a huge improvement in things we actually care about like developer productivity and the quality and performance of the product.
Can you give an example? I have a hard time imagining what kind of techniques cannot be applied to an existing code base with some adaption, but require the code to be written from scratch.
One example is adopting a safer or more productive programming language for a new version. The Rust ecosystem has now reached a point where it's a viable replacement for a lot of things we would almost certainly have used C++ for a decade ago with Rust offering significant safety and productivity benefits. Rust is also now being used to replace tools for web developers where the incumbents were written in JavaScript and in this case the advantage is order(s) of magnitude performance improvements.
Another is when your platform evolves and forces the issue like the web plugins being replaced by new web standards that we were talking about before. Here you might not need to rewrite your entire application but you probably are forced to rewrite the affected parts and possibly significantly change the software architecture around them. A related example is if you previously wrote your application targeting a specific environment and now want to support multiple environments but the operating systems or frameworks or other dependencies follow very different conventions that impose some constraints on your software design.
The key is identifying which parts of the code needs to be adapted or replaced and which do not. If the code is well designed with separation of concerns, replacing a framework or library or external dependency should not require all the code to be scrapped, just the layers directly interacting with replaced part.
Some trivial applications are basically just glue between frameworks, but most non-trivial application of value will have lots of code which is not tied to any particular framework, and often this is the most valuable part of the application.
Scalability is improved by identifying the bottlenecks and improve the design at those core points - not by rewriting everything from scratch.
I guess moving to a different programming language is a case where you literately have to touch all the code, but even then code can often be ported semi-mechanically instead of starting from scratch.
In my experience one of the main reasons for wanting to scrap code is not only that it has scaling/other tech issues, it also has very poor separation of concerns.
Granted, that concept can and should be introduced into old codebases. Last year my team successfully warded off the Sirens of Rewrite by just doing the hard work of extracting all of the dead framework calls and then NOT adding them back in drag-and-drop style, but properly exposing them through interfaces that don’t require everything to know everything about the particular replacement framework we used.
Sure, but my point is, if the code is not well designed, the result of a ground-up rewrite will not be well-design either, for the same reasons which caused the scrapped version to be badly designed.
It is even likely the new version will be worse, since it wont be developed incrementally, and that harsh deadlines will be imposed when the organization realize they can't evolve the product as long as the ground-up rewrite is underway.
> Sure, but my point is, if the code is not well designed, the result of a ground-up rewrite will not be well-design either,
That doesn't follow for me, sorry.
A rewrite, as I understand and use the term, doesn't mean transpiling what exist to, say another language or to another framework. The old version is essentially just a very detailed and testable list of functional requirements; everything the old thing can do (as long as that functionality is still actually useful), the new thing must be able to do as well.
How this functionality is implemented in the rewritten version, and how it's internals are designed, is entirely up to the rebuild. The way functionality is implemented in the predecessor does not necessarily determine how it is implemented in the new version.
If the rewrite is by the same organization, the same forces which caused the first version to be badly designed will cause the rewrite to be badly designed.
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.
> 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.
Why are the current developers not able to maintain code they didn't write themselves? Is it because the new developers are less experienced, or because the organization culture have encourage writing convoluted, idiosyncratic and badly documented code? Whatever the reason, the root problem is certainly not solved by rewriting the code base from scratch, since you will just have the same problem next time there have been a few replacements.
I don't think that follows at all. I've seen my share of development groups where someone had previously made a bad hire or brought in the wrong consultants and that had left them with a body of code that simply wasn't very good. That doesn't necessarily reflect the overall culture at the organisation and it doesn't say anything about whether the people currently available would make the same mistakes.
The assumption that a big rewrite would be too expensive and end up with the same problems is itself quite dangerous. Some of those groups I mentioned knew very well they had a pile of junk but management had apparently read the usual advocacy about how Big Rewrites Are Bad and stubbornly insisted on adapting the existing code instead of recognising that it should be written off. They spent far more time and money on the updates than it would have taken to do a clean rewrite. And then they got into this kind of sunk cost fallacy where because they'd spent months doing what should have been weeks of work once they then became even more attached to the flawed code and kept repeating the same mistake.
> They spent far more time and money on the updates than it would have taken to do a clean rewrite
Of course this claim assumes you can reliably estimate the time and cost of the rewrite and the claimed improved productivity after the rewrite.
It is still unclear to me what kind of improvements cannot be applied to an existing code base through refactoring and gradual improvements, but requires all the code to be written from scratch.
Of course this claim assumes you can reliably estimate the time and cost of the rewrite and the claimed improved productivity after the rewrite.
I almost preempted that counter-argument in my previous comment. :)
Some software development is 90% research and 10% development and it's true that you never really know how long it's going to take and how well it will work until it's almost done anyway. But the tar pits I'm talking about were not that kind of software development. Most of the cases I'm thinking of were the stereotype over-engineered "enterprise" code that had become bloated and excessively interconnected. Others were "clever" code where someone had tried some fancy design patterns or data structures or algorithms, typically with a severe YAGNI complex as well. Either way making simple changes required many times the effort it should. And yet a drop-in replacement for the whole system would have been a low risk project, with very predictable work required that could be done by any mid-senior developer on the relevant team, taking a fraction of the time.
> 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.
I find it to be more nuanced. Your code has to work correctly in a bunch of scenarios. Some are very simple to see, others are nuanced corner scenarios.
A good developer will write code that passes many of these scenarios, but even the best will miss some. And an inexperienced developer might write code which passes some basic scenarios.
So, “this code works” is really a range, not a binary condition.
My high school computer science teacher (almost 30 years ago that is) used to say: "A program that 'almost works' is like a plane that 'almost flies'".
Now I'm just trying to mentally picture what a mode of transportation that almost flies would work like via animal metaphors - would it almost fly like a chicken? or like a flying squirrel?
There are only a few experiences in life that give me a dopamine rush as intense as when I delete code. I used to think I was weird, but apparently I'm just a senior engineer.
To me, it isn't about the code itself, it's about communication, it's about a relationship with others through code, systems and architecture.
Using the relationship analogy, when you can hear something small from your partner and know what they are thinking, understand what they may do next it feels effortless.
When you look at some code, can you trust what the function name implies is done, without concern?
When something is complex in a relationship we pause to take time to communicate and come to a common understanding, we write notes to each other.
When we have something complex in code do we write down information to help the other engineers work through it?
In a lot of ways the way we relate to our peers through code is possibly a reflection of how we relate to others in life.
All code is not created equal. In a project there is normally some divide between shared code and service specific code. This divide can be as simple as a base class and its children or a library and the microservices that use it. I declare that shared code is sacred and should only be touched for a good reason. (Note: sacred does not imply good)
So when reviewing my carelevel is highly dependent on if shared code is touched. If the commit only contains changes in the leafs eg subclass / single microservice my gut instinct is to trust the code and go into LGTM mode (if it goes wrong it's at least localized). But if shared code is touched I don't trust it, I deep dive and complain about everything I can think of.
Only junior software engineers hate other peoples code. The progression of a skilled software engineer starts with writing code, then reading code, then writing code in the context of others code. The more you work the more crucial it is to be able to operate in a zone of non ownership in the code base, your value really unlocks when you can sniff code and improve it without rewriting it. At this stage 30y into my career I can step into a completely foreign code base and make material improvements quickly in situ, and sometimes have to do it several times a day. I don’t mind other peoples code - in fact I learn an awful lot of cool things spelunking!
I tend to avoid the “let’s rewrite it” engineers - they’re usually going that route due to lack of practice and skill in developing software. There are times for sure a rewrite is necessary, but IMO it’s sort of like blaming the compiler for build errors. Usually it’s not the compiler, it’s you. But rarely there’s a compiler bug and you’re justified in asserting it as such. Likewise, rarely does code need to be rewritten, you are just unskilled at code surgery - so practice. When you have practiced enough you’ll see that the initial revulsion you felt at their code was mostly your brain reacting to the unknown. The people who wrote that code are often as good or better than you, and understood the domain a lot better if you’re new to the code base. Show a bit of respect for those who came before and learn to learn.
Doesn't seem right to say that engineers hate code. IMO, in a sense, code is lossy; rarely does it document the full set of assumptions, intentions and context relevant at its inception or over its life. Possibly more appropriate to say that writing new code can sometimes avoid the lack of those things which make modifying code simpler. Do engineers hate being in a position where they have to rely only on intuition and inferences rather than hard evidence? Well, I do, at least. Do I hate code? Nope
That is non sense. Like any peace of art, code can be a delight to contemplate or an awful experiment that was done as is just because, see, it's possible.
Of course 99% of everything is crap, and no one like to ingest crap.
Add to that impossible deadlines and usual exponential accumulation of hot fixes to a point where a bright new product will be more effective than paying the technical debt. Crafting software is on far worse road than most form of art.
All that said, yes, there are great peaces of code that are a delight to contemplate.
sturgeon’s law applies. most of the time they are right to.
put another way, 90% of code is a liability, 10% of code is an asset.
i’m not sure any code ever moved from one group to the other, though good ideas may be stolen sans code.
greenfield is the only way to grow that 10%. it’s the reason startups exist.
it’s like all the failed rewrites. those engineers gained knowledge and fitness through that failure. if their current employer doesn’t retain them, that knowledge and fitness will pay dividends to the next one.
Rewrites are a phenomenal way to sprint through an incredible number of Chestersons fences. That is one way to find out why they are there though it’s just a bit more expensive
>Senior engineers hate extraneous code. They hate seeing time and effort invested in building yet another solution to an already-solved problem. [...]
>Don't write new code when you can use, improve or fix what already exists.
Caveat: Refusing to write new code often means pulling in and/or writing a whole bunch of extraneous code.
Senior engineers also hate dependency hell, having to patch other people's code because upstream hasn't fixed it yet, knowing that might break on the next update, yoinking in massive complex frameworks and libraries when you could've just used a few simple functions, and having lots of kludgy plumbing code to wire up all those third party dependencies and generic abstractions.
All those things that people do just because it's best practice not to "reinvent the wheel". All those things that require extra work, maintenance, and system resources, but aren't directly related to solving the business problems. All that time wasted not even working on the valuable domain logic.
And then when you do eventually get around to implementing or modifying a domain case, can you even find where the domain code is in all that mess of extraneous code?
Why is this much more true of programmers than writers[1]? To what extent is it true of "proper" engineering disciplines?
[1] A couple of people here doubt it being true. It is though, and I say that as someone who enjoys reading interesting code. A good case in point is this great, probing interview by Peter Seibel of Hal Abelson:
Abelson: Read a lot of good code. That’s the real issue—that people don’t read code.
[...]
Seibel: I want to dig a little deeper on this. You, like many other people, say programmers should read code. Yet when I ask what code have you read for fun or edification, you—also like many other people—answer that you read students’ code, which is your job, and review code at Google, which is also your job. But it doesn’t sound like you sit down of an evening with a nice printout and read it.
Abelson: Not for a long time.
I can't imagine a professional writer answering like this.
> we deprecate it as legacy and replace it with something new. Rolling green fields forever!
That's a good way to put it. The nuance is that, most of the time, "deprecated" means "not going anywhere anytime soon, so now we have 2+ subsystems for the same thing."
You really do need someone with a grand plan to keep this in check.
The people who truly hate code work in upper management. Coders are expensive, hard to hire, and tend to say no a lot.
You can make so much money selling hoax ”zero code” solutions, as management is very happy to drop money into projects that promise to replace coders with Magic Product(tm)
It’s because you can only understand why things are structured the way they are, if you go on the journey from scratch yourself.
It would probably be easier if there was a video or scrubber/slider to see how the code evolved.
So many times you look at something and go: why is this so complex. Could be simpler. And you miss an edge case that causes the need for the complexity/abstraction. There are times too though that after a refactor someone can’t see some redundancy or is hanging onto an abstraction that looks great but is unnecessary.
> The more code that gets written, the more things there are to break, and more of those precious hours will be taken up by maintenance
Can definitely relate - PRs with lots of new code immediately trigger alarm bells for me, and while reading through all that new code ain't necessarily fun, coming up with ways to reduce it is a worthwhile and rewarding challenge - unfortunately you're then stuck with the thankless task of convincing the author why they should throw away all their hard work.
Interesting. I'd say that's true for the majority of engineers yeah. For my own career I've been stuck on projects (with the exception of one last month) that was all over 3 years old and needed maintenance. Some projects were learning to read AS400 RPG code then converting that into java code. So I guess that is kinda greenfield? I don't know, I enjoy reading code and understanding what's happening But I absolutely get the distaste for it
It’s not 100% true. It depends on how well the code was written and documented. When we see patterns or complex code which are different from what we are used to, it takes some amount of effort to understand and to make changes.
code that is simple, documented and well written is best thing any developer can inherit.
I loved this article! In the end, it is exactly to the point: code adds and adds complexity; complexity we hate. At the same time, complexity comes from our flawed knowledge, and only true knowledge gained in battles shows us simple ways. Simple ways bring us joy.
I love code (similar to how an artist might love a type of paint brush), but what I don't love is code that's designed to impress or an attempt to show off hOw SmArT i Am. More often than not, that code isn't the most efficient or the cleanest, it's just a contraption that looks impressive to an untrained eye. That type of code is guaranteed to turn a code base into a mess—all for the sake of someone's ego.
My preferred heuristic is: "will I or any other developer be able to understand this—quickly—in six months (preferably without comments)?" If the answer is "no," refactor using a different approach.
There is only one more thing I am afraid of more than duplicate code.
Shared code that someone changes to make their code work better that breaks yours.
Literally my primary motivation to not be productive at work is people maxing the ratio of their code to my code. They do all the work and management is still fine with paying me more because of seniority. I think this is a fair trade as all freedom comes with responsibility -- I used to be the same way earlier in my career.
Better yet, engineers in general hates discipline. A lot argue it stifles innovation, makes them work slower, a bunch of red tape. While it’s true to a certain degree, you also can’t scale without discipline. If you can’t scale, it’s not engineering, it’s a science project. It is a balance, too much processes hinders execution, too little means everything will be a mess by the time you deliver.
I dont like this, but it's hard to find fault in it in the context of an aging (eg 50yrs+), large, corporation. There are always corner cases and workarounds that would require inverting the expected output of an 'if statement', requiring yet-another-one altogether.
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?!