Hacker News new | ask | show | jobs
Write shitty code (cyclic.sh)
154 points by seekayel 1616 days ago
58 comments

I have some shitty code that runs an important part of one of my SaaS businesses. I'd love to refactor it. I'd love to swap out the HTTP library that it uses with the better one that the rest of the project uses. I'd love to remove all the nesting and complexity. I'd love to make it not an eyesore.

But here's the problem:

- In the past five years, it has never failed.

- In the past five years, it has not needed to adapt.

- If I change it successfully, it will make exactly zero difference to my paying customers.

- If I change it unsuccessfully, it will break a core part of the system that people are paying for.

If I were to refactor it at this point, it's really only to pander to my own ego, which probably isn't a sensible business goal.

We have very different definitions of shitty code. The shitty code I have dealt with in the past is unreliable, slow, hard to fix, and when someone does try to fix it, it doesn't stay fixed.

The code you are talking about here sounds very low drama, which is code that I love.

Maybe we should distinguish between "pretty" code and "shitty" code?

"Low drama code" is now officially the term I'm gonna use for reliable code.
This would be the crux of my disagreement with the phrasing of the article, even though I agree with many of the details, in specific contexts.

For me, shitty code implies poorly-named variables, confusing logic, brittle tests that couple tightly to the implementation and resist refactoring the code under test, etc. Shitty code makes it harder to understand what is going on, and makes it harder to adapt to new requirements.

At the other end of the spectrum is what I call "gold-plated" code. This is over-engineered, or just overly aesthetically pleasing for a practical and utilitarian tool that will eventually be replaced. It's code that was written to satisfy the perfectionist impulses of the author (we all have these), rather than to add business value.

In the middle is pragmatic, utilitarian code. The level of quality required to be in the sweet spot of course depends on the audience and longevity of the code in question. A language stdlib should be much higher quality in many dimensions than a startup's prototype. So shitty library code might look nicer than gold-plated startup code. It's all relative to your use-case.

In other words, as with about 50% of such thought-pieces that get posted here, I can summarize my objection as "don't give unidirectional advice when you're optimizing a U-shaped error function". You can err by making your code too polished and not polished enough. For a given startup, it might be that the most common error is to gold-plate, and so the advice "make it shittier" is right most of the time. But you're missing the underlying principle if you think that's the right advice all the time.

> "don't give unidirectional advice when you're optimizing a U-shaped error function"

I like it. Seems broadly applicable to any kind of advice-giving.

I think here it's more about the split between hypothetical and practical shittiness. In most business cases, code needs to change frequently and so writing code in a way that supports that is important. In GP's case, the code hasn't needed to change and so the fact it's overly complex (and presumably hard to change) doesn't actually matter in any practical sense.
> In most business cases, code needs to change frequently

That has not been my experience in several industries. Sure, there is always something that is being changed, but once the project matures the changes tend to be at the boundaries or around new features that were recently introduced. A relatively small % of the code is changed each year.

I think I took an online course on the applications of hypothetical and practical shittiness. That was presented out of the MIT online school, right?

Though, jokes aside, other than refactoring for efficiency, I think you're right. The term "shitty code" generally applies to the readability and not really the efficacy of code. We can usually go back and make it "prettier" with no real practical effect except to make ourselves look better during code review =/

I'm not sure you do. Code that runs fine for years but breaks if you change something is still shitty, albeit not necessarily shitty along the axis you currently care about.

One of the arts of software development is deciding when it is worthwhile to optimize along some quality axis and how much to invest.

That is, knowing when to churn the code out fast, knowing when to optimize and for and what and when to leave it alone are all much more subtle trade offs than they appear on the face of it.

I've been in the OP's situation before and the shitty code lasted until it's natural end of life successfully.

I've also been in the situation where everything was fine for years and then sudden new business priority changes dictated a slew of simple feature requests we couldnt handle.

Yeah, if someone's avoidance of what they consider shitty code leads them down the path of dancing with future hypotheticals it's a problem that needs to be fixed. Not by embracing shitty code, but by fixing their criteria for shittyness. Non-shitty can be full of elaborate dance moves with those hypotheticals, but most likely it's not. Non-shitty always stays clear of bug magnets though, and badly performed dance moves clearly are bug magnets.

As are "it works, so it must be good enough, right?" implementations, when it only works for circumstantial reasons. Code that would fail on encountering single-digit hours is still shitty code even when it works in 0-23 instead of am/pm and happens to never run before noon.

this is the crux of the matter - relative definition of “shitty.”

i’ve been told i wrote shitty code because i didn’t use abstract types or generics or i wrote overloaded methods that repeated themselves. but i knew the domain and i knew the task and my code fit within the domain and accomplished the task.

i’ve also supported code that was beautiful, idiomatic, flexible, and downright professional-looking, but it tried to do too much or it had severe antipatterns (especially in data access layer) and was a nightmare to troubleshoot. also, the lead developers on these projects seemed to be far less open to feedback than the people whom i’ve supported who wrote code like i did

Agree, "Shitty" is a very broad and relative term.
I'd take 'shitty code' than runs flawlessly for years on end, over non-shitty code that doesn't.

I've worked with too many 'architecture astronauts' over the years who over-design everything based on the latest-and-greatest thing they just read online someplace, and make it so complex no one understands how it works, or how to maintain it, and often doesn't do what it was intended.

I worked with both, 'architecture astronauts' (lol!) and shit-coders. I'd prefer there to be a balance. Code has quality can be measured in more than just one dimension. It's fine if code works, but it's even better if you know how. (No obvious errors vs. obviously no errors)
Reliable but bad old code becomes the piece labeled "do not touch" and can spawn bad code around it. By itself it never gets worse but it might be like the broken window theory of a code base.
In case you haven't heard of it before, that term comes from this blog post, quite a good read!

https://www.joelonsoftware.com/2001/04/21/dont-let-architect...

> Code has quality can be measured in more than just one dimension.

Well, if you don't need to change it (like the GP), most dimensions are moot. We used to call that "maturity", but the entire concept is out of fashion nowadays.

What leads to a correct architecture being probably the most relevant one by a long shot. Because a good architecture is a hard requirement for parts of your code to stop changing (the other being requirements maturity, that is not a dimension of code quality).

But yes, before reaching maturity, there are many dimensions of quality you may want to optimize for, and they conflict between themselves. Also, architecture astronauts get this name because they don't create good architectures, so you don't want them designing it anyway.

> Well, if you don't need to change it (like the GP), most dimensions are moot. We used to call that "maturity", but the entire concept is out of fashion nowadays.

Isn't that how you get ancient COBOL monoliths running on mainframes which everyone is afraid to touch?

Do you not need to touch it or are you afraid to touch it? Those things are different.
I agree but I'd go a step further and say that good design simply doesn't mean over using abstraction. It's really easy to fall into the trap of thinking "if I just pulled out this abstraction this would be so much cleaner!". This leads to the architecture astronaut situation you described.

In my humble opinion, what makes code non-shitty is that it is clear (well named variables, state manipulation is very explicit), well documented, as concise as reasonable, and handles the full range of inputs/outputs properly either by restricting the input/output space via types or assertions.

I think the problem is extensibility. Architecture astronauts tend to create abstractions, which are useful for eventual extensions to to the original design. Shitty code is hard to change, but astronautic code is difficult to understand and, more critically, often is planned for hypothethetical developments that not necessarily match with future needs.
It’s funny how the term “refactor” has evolved to include “rewrite/rearchitect.”

As originally championed and coined by Ralph Johnson and his protégés at UIUC, it was strictly a (semi provable) safe transformation to the code structure/syntax (usually motivated by trying to make the code easier to understand and/or maintain). Since it was a new word in those days, we still used the terms rewrite and rearchitect as the primary lexicon of “change the code” and “refactor” stated to its niche.

Of course pure refactorings sometimes aren’t as pure as we hope. And they’re often coincident with rewrites and rearchitectures, because we often transform the code first to make a change in behavior easier to implement.

I’m not complaining about the use here. A drop in replacement of an http library would indeed be a true refactoring if indeed none of the externally viewed behavior changed, but as the OP has undoubtedly learned through their own experience, most refactorings end up being something like refarcotring++.

I’m mostly just marveling how in 30 short years, I got to witness the transformation of this term in coumputing lingo.

You're still maintaining it. In the sense that _if_ it fails in the future (which is admittedly unlikely, given that it hasn't done so in the past 5 years. But as stock investment services say: Past results are no guarantee for the future!) - you must fix it, and fairly quickly. So you need to maintain the toolchain and be at least sufficiently familiar with it that you or somebody in the team can hop in and fix things if needed.

That, on its own, is a cost, and that cost can warrant a refactor. To go for an extreme:

It's written in COBOL, it is the last cobol code in your entire code base, and the only engineer with any experience in cobol is about to retire.

If that happens, I'd refactor it. If you don't, and 2 years hence the customer calls in a panic that the product they are still paying for isn't working, you're really screwed. I doubt the customer is willing to wait for you to __learn COBOL first__.

But, merely 'the code is not at all written with modern practices and our current team's preferred style and such in mind; it wouldn't pass code review right now?' - yeah, don't refactor that, absolutely.

> If I change it unsuccessfully, it will break a core part of the system that people are paying for.

This is such an underutilized heuristic. I find phrasing the question as “Should we risk having a detrimental impact on customers for an aesthetic desire?” helps me to either get my head straight or to realize that the refactor has genuine value beyond aesthetics.

Well, that's humblebragging for ya^^ - your code isn't shitty, au contraire mon ami, if it ain't broke don't fix it.
Complexity is a function of how hard something is to understand multiplied by how often it needs to be understood (and modified).

If it is impossible to understand, but never needs to be understood, it has no cost... Until you or someone else needs to understand it, that is :)

> If it is impossible to understand, but never needs to be understood, it has no cost

You've just argued that difficulty of understanding times need to understand is cost, not complexity. It doesn't make sense to claim that complexity becomes simplicity if you no longer need to understand it.

> Complexity is a function of how hard something is to understand multiplied by how often it needs to be understood (and modified).

I like this. Sums it up pretty nicely.

This is not a shitty code. It does the job. It is shitty when it becomes the source of issues.

What you are describing is a perfect code, made for the sake of perfectness.

I have one single-file single-function spaghetti monstrosity running one non-critical service since 2009. I've contemplated rewriting it, but... it still works. As long as the db is there and the file itself is there, it'll keep going. And there are users using it. It's become my favorite wart. It will die with the server it's on.
I feel you. Some people are saying that, if it works, it's not shitty code, but it's not the truth.

I made a service that was reliable, but only because there are a lot of ifs inside the code that fixed bugs. It was really shitty code that somehow worked reliably.

The service was replaced because someone else rewrote the whole thing in another language.

> If I were to refactor it at this point, it's really only to pander to my own ego, which probably isn't a sensible business goal.

But it could be fun! You are aware of the risks, so if you'd really love to do it, knock yourself out! :D

Another perspective: It has occupied your mind for such a long time, why not get rid of it?

To paraphrase John Ousterhout: If a system has a few parts that are very shitty, but those parts almost never need to be touched, then they don't have much impact on the overall shittiness of the system.
> - If I change it unsuccessfully, it will break a core part of the system that people are paying for.

Every refactoring comes at risk of breaking something. So if you refactor this code often, you are risking an outage--the very thing you are trying to prevent!

As others have said, if it ain't broke, don't fix it.

It sounds to me like said shitty code got lucky in the tech debt casino. But great! Look at it, so you know how it works, but don't mess with it.

> Every refactoring comes at risk of breaking something.

Refactoring is code transformations that don't affect functionality. If something broke, that's a failed refactoring.

Which you discover after deployment...same deal
Manual refactoring is certainly risky. So it should be set about with automated tests, specifically to protect the refactored functionality.

But I think any legitimate refacvtoring can be carried out by automatic tools, with guarantees of unchanged functionality/semantics.

The number of refactorings possible for any piece of code is almost infinite; you can't just let some tool loose on your code to perform all possible refactorings. That's madness. You need a human to judge which refactorings are beneficial. But the actual transformation should be performed by a tool that knows the language, and can guarantee semantic equivalence.

And you still need tests. You can scrap them once the refactoring has been shown to have not changed the functionality.

The problem is that you cannot evolve that part of the code.

All is fine as long as you don't need to.

When somebody change that library without approval, it will be a pandora box.

So it's a ticking time bomb.

From the OP:

> - In the past five years, it has never failed.

> - In the past five years, it has not needed to adapt.

It's not a ticking bomb. The longer this runs, the less likely it will be a ticking bomb. Nobody is trying to adapt the code. Nobody is changing a library.

Haha, I've worked at places like this where the whole business depends on a system that nobody touches and integration tests are put around it and the business never makes any progress and all ideas are stalled around "sorry Bob's old code prevents this from being possible".

The fact that in some instances this works is not a cogent argument for writing shitty code... there are some places where it is an absolute f-ing disaster!

This also has a tendency to create ever-building organizational pressure for the Big Rewrite. And when the pressure overcomes the resistance, the dam bursts and all the debris turns into a never-finished ball of mud because there are so many business hopes and dreams pinned on the new system. Identifying release valves along the way can prevent that quagmire.
Story time!

At my previous place they had an ancient java application that powered their entire business. It had some reasonable parts, but some of it was a total mess from top to bottom. Leaky abstractions, multiple layers of incomprehensible inheritance, helper classes everywhere etc etc, the usual things you expect from a decade old java application.

A fair chunk of the code quite literally hadn't changed for a decade. There were classes written by the first few employees at the company and hadn't changed since that time. Indeed, no time was invested in fixing it because of the 'if it ain't broke, don't fix it' paradigm, which was correct for the first 10 years or so.

One day, there was a huge shift in the direction of the company. They wanted their java application to become multi-tenanted SaaS platform instead of single-tenanted system. I was put to work on the task, and found we had to touch virtually every part of the tech stack. It was an utter nightmare, and frankly we still had to cut corners because it would have taken another 10 years to do it properly.

My point is anyway assumptions are just that, assumptions. Assuming code is never going to change is as dangerous as assuming how could might change and planning for a thousand possibilities. In the case of my previous company, assuming multi-tenancy would be coming along would probably slowed them down significantly and was well beyond the scope of the company at the time. However, if they had spent a bit of time polishing the turds, and putting in place proper testing, it would have made life a hell of a lot easier when strange requests come along.

What assumptions does it make? What if one of those assumptions fails? For example, what if it's never called with a certain combination of parameters because nothing generated them until a new process was added somewhere else and that combination of parameters now cause it to fail? What if the format of a parameter changes slightly and it fails on that?

We have code like this where I work and cases where a change to something has caused that one rock solid process written by an intern in 1998 that few people even remember exists to suddenly start to fail. I would call it a ticking time bomb, and if it's one that will explode in a big way, it might be worth analyzing it to see how it will react to non-obvious parameters or environments.

What happens when a vulnerability is discovered? What happens when the library's dependencies gets deprecated?

I mostly agree with you, but 5 years is not very long time either.

> What happens when a vulnerability is discovered? What happens when the library's dependencies gets deprecated?

The same as what happens with non-shitty code, you fix it.

Is it to pander to your ego, or is it to make it easier for a new joiner to onboard successfully into the tech part of the business?
It's a solo project, so definitely the former.

As with anything in engineering, the answer is always "it depends". I think programmers too often take for granted this idea that all code must adhere to some strict "clean code" rules, or follow some kind of laws or naming conventions or whatever.

"if it does not break, don't fix it. If you fix it it breaks, you must hold both ends"
Undefeated for 5 years.

That sounds like amazing code, shitty code breaks prod.

> - In the past five years, it has never failed.

Five years! Reminds me of the first five years of the Challenger's operation, in which it never failed!

poor analogy - physical things wear out over time, running code doesn't suffer from fatigue.
Code does suffer from a kind of fatigue over time, but related to the environment around it changing, called "bit rot". If you're able to control the environment (and you can replace the hardware components which will eventually fail), then sure, the software doesn't really age. However, if your operating system, compiler, standard library, host hardware, network layer, or other things change, then the software will "fatigue" and eventually fail.

This can be mitigated, look at languages which compile to byte code and are executed with a virtual machine. If it's sufficiently well-defined and stable, then the software can, more reliably, survive underlying hardware changes. Changes to network protocols are often out of our hands, though. Consider the push for HTTPS as well as updates to the HTTP spec itself. A web app from 2003 may or may not function, as written, today. Or it may "function" but users will see random failures (the browser insists on ignoring those HTTP requests for images hosted on another domain, for instance). And even if all the connectivity parts work, you rely on the client to still be able to render things correctly, good luck with your circa 1998 ISP hosted homepage's <blink> tags showing up correctly these days (which is probably a good thing, though).

The more control you have over the system, the less likely your software will be struck by "fatigue". The embedded systems I helped maintain that were written in the 70s and 80s and still running on the same hardware, no bit rot to speak of. Desktop application written in 1995 using Visual Fortran, massive bit rot.

Poor understanding of the facts! LOL

It didn't wear out over time. The design of the seal was bad from the beginning.

If you don't count security issues.
It's people who read it that do
> I know how to write good code.

> Usually it means spending more time now to make the code better for some future state of the world.

No. That is called premature optimization/abstraction/development and should be avoided. Shitty code is shitty today. Poorly chosen names, copy-pasted pieces, implementation doesn't reveal intent, mismatch in code and comments, etc. Doing these right should be habitual and shouldn't be a function of cycle time. Otherwise, they tend to creep easily.

> Shitty code is shitty today.

This is really helpful.

I think I write reasonably good code. When people who are junior to me ask me, how to differentiate between premature abstraction and writing good code, I don't generally have an answer. This comment made me realise what I actually think while writing code.

Naming things is hard, copy-pasting is fast compared to extracting shared logic if you need small changes. Implementation will not reveal your intent, if you are not sure what you intend to do.

I'm working in ML research so I kind of write shitty code for a living. All these problems are small things, that are okay if you just try something new. If it sticks, you'll build on your previous code so the junk just piles up. The challenge is spotting the time when the shit just starts o bog you down.

I guess it will bog you down from the minute you (or someone else) has to go back to a piece of sh... er, code you wrote a few months ago in order to implement a new feature or fix a bug. So I'd say following some minimal standards of non-shittiness would be real nice: names don't have to be perfect, but e.g. shouldn't be completely misleading or contain typos (ok, pet peeve of mine), you shouldn't use strings where a boolean is obviously better (like in the screenshot above the article) etc. etc. So, not stuff that will require hours of thinking and planning, but stuff that should be second nature to any programmer worth their salt. Of course, if you're a beginner or someone dabbling with a new programming language, by all means, go ahead and write all the shitty code you want, until you get better at it...
If you can't come up with a good name for a function or variable, you will find it difficult to make progress because you do not have a high-level understanding of what you are trying to accomplish. Laboring on without achieving that may be possible but it will never be as efficient as building up a good mental model of the problem space before spewing more lines of code.
If one makes it a habit to think about how to name things, it will become easier. Copy-pasting is not fast if you factor in the time spent on problems because of it, even in the same coding session. One may not be sure of their intent, but they should have some intent. So at least reflect that one in the code.

I don't mean to be perfectionistic. There are certainly cases where “good programming habits” could be compromised. But people tend to excuse bad habits quite easily, without thinking of better ways.

That is all fine if you're the only one that needs to understand that code. Otherwise you're wasting other people's time and sanity. Unless, of course, it all works for everyone, in which case carry on. At least until a new-enough team member arrives and starts pulling their hair out :)
Data Science is all about writing shitty code. Most of the time you're just digging for data in a notebook, and then you can write things out proper once you've got something that could work.
I guess we can distinguish between programming and prototyping. Prototyping is more forgiving because it has narrower scope and spans shorter time. Even then, bad habits tend to carry on to the programming part. So better be deliberate about it.
Nope.

The startup I work at has been compartmentalizing and chipping away at our shitty code for the past eighteen months. We're not doing this because it offends our aesthetic sensibilities. The shitty part of our codebase is truly shitty. It fails to do its job regularly, causing significant toil in various parts of the business. Junior engineers can't make simple changes to it without causing serious regressions in seemingly unrelated parts of the system. It's slow as fuck. New engineers have to spend weeks reading the codebase if they hope to understand it, and some just give up. There's a big, measurable, drop in velocity whenever we have to work with the shitty codebase. So now we're effectively forced to do an incremental rewrite in order to build new features, which is terrible because rewrites suck and bring their own drop in velocity with them.

In practice, writing shitty code is not all that much faster than writing good code if you know how to write good code quickly - but I guess some people don't bother to learn.

I read somewhere once that at a growing company the next person who works on the code you wrote is highly likely to be new to the company and have less industry experience than you. When you write code, you should write so that that person can work on it productively.

I believe you, but would the startup even exist if they had spent 2 or 3 times as long developing the MVP?

The reality is that good engineering has higher upfront costs than quick-and-dirty. Sure, it's usually cheaper in the long run, but initially it either takes longer to plan or it takes more expensive engineers to execute. And for a lot of startups, getting that cheap MVP out the door is the only path to additional investment.

I'm all in favor of quality engineering, but I'm also pragmatic enough to realize that sometimes you have to sling a little shit in order to gain the luxury of doing it the right way.

This is the standard rebuttal, but I don't buy it.

> would the startup even exist if they had spent 2 or 3 times as long developing the MVP?

It does not take 2-3 times longer to write good software. Arguably a non-shitty version of our MVP would've actually been faster to develop, because we have a custom web framework, ORM, and build tool when we could've used mature open-source projects in their place.

> it takes more expensive engineers to execute

This is probably true, or perhaps "more carefully selected" (which just means a more expensive recruitment process).

Agreed. Once you have experience, writing good code takes less time than writing shitty code, even in the short term. Good code is easier to test, easier to reason about and it's easier to work on it as a team.

Shitty code is impossible to work on as a team. Only for solo developers. I think shitty code can be fine for bells-and-whistles kind of logic but the foundation has to be carefully thought out. Good code is code which anticipates requirement changes. I disagree with the author of the article that it's not possible to predict the future. You only need to have a very vague idea about different future possibilities in order to be able to design a very good architecture.

Compare the shitty code approach to the good code approach when building a very simple front end application:

---

Shitty code approach:

You happen to know Swift so you just start coding the thing natively in Swift for iOS... Then after 6 months you did a lot of work and you start getting a few users then you figure out that a lot of people are complaining that you don't support Android, so then you start to build the same app again for Android using Android Studio... After 6 months, you roll it out. Then after 1 month users are complaining that the mobile app is unwieldy and they're asking for a web version... You are shocked. You did not see this coming. So then you spend another 6 months building another version of the app with React. Users start complaining that the UI in the web version of the application doesn't match the mobile version... Also, now some users demand a new feature... Now you have to implement it and test 3 times (once for each device), you are wasting huge amounts of resources, your team hates you. You're moving too slow. Your investors decide to cut your funding. Your career is over.

Good code approach:

After carefully looking through the requirements, you figure out that users will probably want to run the app on desktop, web, Android and iOS... So you look at what frameworks support all these platforms... You decide on VueJS with Electron because it's lightweight, has few dependencies and can run on all platforms including mobile. You decide to use CSS media queries for responsive design because it provides a relatively consistent UX/UI accross different devices. You spend 6 month building the app, you ship. Users start using your product, telling their friends about it (who are using different devices)... Some users point out that a feature is missing... No problem, you develop it once, test it once and ship it to all devices at once. Your users love it. Your employees are happy, your investors are pleased, they invest more. Your career is looking promising.

I feel like the author is really saying "don't over-engineer". At no point does he say create code that does not work. The closest he says is that ALL systems will fail and that he'd rather fail with throw away code than some overly abstracted, lovingly hand crafted pile of code.

The point the author is trying to make is that trying to build a perfectly designed cathedral of code can often be counter productive.

ah, so shitty code got your startup to a point where multiple engineers and new hires can complain about it for 18 months? score one for OP
That's one perspective.

Another is that we're in a highly competitive industry. Our shitty code is severely hindering our ability to move fast and respond to competitive pressure. Had we paid more attention to quality while building earlier versions of our software we would be building an insurmountable competitive advantage right now.

NB: there are non-shitty parts of our codebase which have been able to evolve effectively as the company has grown. So I have definitive proof it's possible to produce good code at the MVP stage.

Better: Learn to write non-over-engineered code that is obviously written by a professional without thinking.

Even better: Learn to write boring code, fast.

There will be exceptions, but those are rare and better resist the urge for abstraction until the very last moment!

Two quotes from my favorite go (board game) player that seem appropriate:

For writing without thinking:

> You have to soak up the fundamentals as you practice on your own, studying them until they become a part of your very being. If the fundamentals do not operate subconciously when you sit down to play, you have not mastered them yet.

For fast boring code:

> Go is the kind of game in which you are an expert if you can just keep on making ordinary moves. You need not play any especially brilliant moves at all. Amateurs' moves, however, are frequently far from ordinary; in fact, I see them making the most nonsensical moves imaginable[.]

More here: https://arunkprasad.com/log/kageyama-7-dan-on-amateurs-and-p...

>>Even better: Learn to write boring code, fast.

Under-rated comment of the day.

That's not "shitty code", just "simple code". Also regarding the last paragraph, IME the more senior you get the more you realize that writing code for hypothetical future requirements doesn't make much sense. I've seen this sort of enthusiastic overengineering much more often with junior peeps fresh out of university (including my younger self).

PS: It also seems the author is still early in the learning process, my advice: what you describe are all good programming practices, they're not just useful for the "learning phase", keep them!

This present a false dichotomy of extremes: shitty code and hopelessly overly complicated intended to address all manner of eventualities that never materialize.

Both extremes are awful choices IMO. If the code you are writing is truly unlikely to be extended and adapted then it may be fair to relax your requirements for code quality. As for most things I'd say that applying some discretion to your actual context is more valuable than blanket approaches of embracing bad code.

Code can be good without taking forever and without being over-designed. On the other hand the accumulated effects of shitty code upon more shitty code is unlikely to be a net positive.

Well-designed code can be simple.

There is a huge difference between planning for the future (which you should not do, agreed, unless that future is < 3-4 tasks time, say) and writing shitty code. I class shitty code as not what he's said but things like works by accident, no tests, naming is misleading, 3000 line files, spaghetti code etc. etc. Doing these things does not make you faster or produce more software.

My opinion is "do the thing that another developer can understand quickly" is the minimum requirement. Even if the code doesn't work (or has a bug!) at least it has some chance that it can be fixed.

I think the author is conflating two issues, 1) planning for the unknown is impossible and time consuming (true!) and 2) all software engineering practices also make coding slow (false!).

So instead of prototype often, go production early and iterate frequently is now spelled: Write shitty code?

Oh boy...

If masters and geniuses of the past would read the "common-sensical" advice we hear today and how it is being expressed, they would not be surprised by the general shitty state of the world (all civilisations around the world) but to find it plain miraculous that we're still in a semi-funcional way or alive at all.

If you know how to write good code, write good code for the state of the world right now then. Care about the future in the future. Kent Beck taught us this already in a very detailed way two decades ago. Invented Unit Tests in Smalltalk to have fast feedback on regressions frequently and granularly. All languages have that today. Then why in the world do, instead, these software engineer self-serving rationalizations that will accumulate tech debt you're carefully not talking about?

How in the world an unexperienced developer would receive this advice as a propaganda in any way other than a push of self-indulgence for incompetence? How this advice makes you an A player?

I was thinking the exact same thing but I've read so many of these utter nonsense articles recently that I rarely even bother to comment on them anymore. Who knows. Maybe they're written by a bot with a job-creation agenda. It's just cringe.

I think your intuition is right, the world economy seems to have been hollowed out. Look at medicine, the media, big tech... They all suck. It seems as though they've been promoting idiots intentionally and now idiots are calling the shots.

Coding is an important skill to develop. But I'd rather develop my ability to NOT write code.

To choose libraries I won't have to mess with. To DRY up the architecture so I'm not implementing the same thing 5 times in a higher layer that would be trivial in the lower layer.

To not encourage sprawling piles of code by making sure there's one obvious way to to the things that need doing.

Shitty code will just teach me to code. But I already know how to code. I've been coding for a while now.

I don't need to be any better at writing average crappy code. I need to be better at writing bulletproof code that is as close to bug free as it can get, and architecting to prevent the need for shitty code.

Should musicians be lazy in their practice? Everyone outside of tech says you will play how you practice.

So if they encourage shitty code... you wonder if they really are all that committed to making bug free apps, or if they are dragging the old WorseIsBetter anchor.

Great code takes a while. I've learned to take this approach:

Works -> Like -> Love

First I write code that works, pretty much by whatever means I can. Sometimes it's great, but most often, shitty is the right word for it. But it works (sometimes, well, sometimes... um...). Then I try to refactor to something that is likable. It's often not perfect at this point because maybe it's not as performant, there are side effects or the api isn't as well designed as it should be. The final step is to really go for something that is lovable, which usually means will not have to be re-written for a while, and often becomes quite re-usable. The nice thing about this approach is that I'm able to get things working quickly (and make customers happy) and it differs optimization until enough is actually understood to optimize.

I've always thought of it as a kind of image rendering!

First pass gets me something that works, then every subsequent pass makes it a little better, like, outlines first, then some colours, then some shading, then some fine details etc

Not convinced. Unmaintainable code is the big problem. He is right that the future is unforseeable. That's why code needs to he maintained. A weird non-local bug is detected. The developer who wrote it found greener meadows. Sales has sold a feature we don't have yet. We notice that we do business with some different functionality that we originally envisioned. There will always be reasons why code needs to be maintained, whether it has worked for 3 days or 3 years.

Now if the code is unmaintainable and every change takes 5 times as long as soon it should and introduces 3 new bugs we are in trouble.

Shitty code is almost always unmaintainable. (Unless the shittyness is local inside small functions, but I doubt that's acommon case.) Of course over-engineering and needless optimizations also lead to unmaintainable code.

If the company policy were "Write shitty code" I would run away. I am sure it would lead to absolutely horrible results. At my work we stress the value of good code. Still we end up with shitty code regularly. We just didn't know better when we did it. And we do not rewrite everything once we believe to know better. It's hard enough to struggle with that level of shittyness, I don't want to have it increased fully intentionally. I do that for scripts I will never use again, but not for anything I merge to the code base.

> Shitty code is almost always unmaintainable. (Unless the shittyness is local inside small functions, but I doubt that's acommon case.) Of course over-engineering and needless optimizations also lead to unmaintainable code.

I was going to write something similar, so piggybacking. The shittiest code I've seen has always suffered from this.

Sometimes it was shitty (in this sense) because of an assumption that it was "throwaway" code, but it was never thrown away. Gross copy/paste throughout, highly redundant code (same variable, or variable with the same intent, created in many local blocks), mostly existing in mega functions (thousands of lines long) with complex conditional logic to navigate to specific desired sections from the entry point at the top. If it was really throwaway code, then this can be tolerated. But it doesn't require much thinking into the future to replace a 10-line block that's repeated 50 times with one change at each location into a single function. If, in the future, some of those 50 uses of the function need a different function, change it then. Better that than having to keep 50 locations in sync with each other because "making a function now is premature optimization" or "YAGNI!!!". Well, programmer time and delivering quickly has value too. When what would have been a 5-minute task (read function, change function, rebuild, rerun) becomes a 5-hour, 5-day, or 5-week task then everyone is losing out because of the shittyness that was trivially observable and correctable early on.

The other big example of shitty code that is unmaintainable (or becomes unmaintainable) is tight integration between IO and business logic. Without a clean separation, you typically end up with similar repetition to what I described above, or something where a "small" change ends up having massive knock-on effects. This brings maintenance to a crawl as you have to tease out the consequences of that small change, which is non-trivial. That's what makes the code shitty. Corrections and clean separation are often forestalled for the same reason that the previous example often ends up with a mega function instead of a nice, often small, set of utility functions: YAGNI. If your project is going to last more than a few months and has even a modest level of complexity, you will need that clean separation. Otherwise, you end up with increasingly complex (but unnecessarily) code that works around the initial self-inflected hamstringing, or you waste weeks or months cleaning it up and delivering nothing to customers, who become impatient so the cleanup gets cut short and you now have a hybrid mess: half-good code (that will decay rapidly) and half-shitty code (that still can't be maintained).

I recently made a similar observation: Write shitty!

Background: I am writing a novel. In the beginning I sat down and obsessed with every little detail, spending multiple days figuring out the perfect formulation and text flow. And then I would maybe change a little thing in the story-line and have to start over again. This really sucked the whole fun out of the writing process.

Then I changed my approach: I just write whatever comes to my mind, independent of whatever I just wrote before. Doesn't matter if the previous scene had character A as sidekick, if I like character B more, then I simply switch them. Some scene is way over the top and doesn't make sense? Doesn't matter, I write it. Writing is fun again. I sit down, get into deep-work-mode and just write. No constraints, no thinking.

Granted, this is only draft #0 and I will probably have a rude awakening when I have to merge all my writings for the next iteration of drafs drafts, but so far I am rolling!

This is expressing something I've been trying to express for _years_. I've come to call it "throw away code" instead of "shitty code" because of what's happening in the comments: people always came back to me and said "Shitty code doesn't work!" and we get into an argument about what I mean by shitty code.

I find that throw-away code gets my point across much more cleanly without people's objections being raised immediately. Most engineers understand that when I say "throw-away code" it doesn't mean the code doesn't work. It just means that I can _throw it away_ when I need to later. It is "shitty code" because it's _supposed_ to be replaced.

I believe it was Casey Muratori said "first: write the stupidest thing that will work". Meaning, it's code that is obvious and simple and does what you think you want to do. It doesn't have to be efficient, or flexible, it just has to do the job. Later you can change and/or improve it if need be.
> It doesn't have to be efficient, or flexible, it just has to do the job. Later you can change and/or improve it if need be.

I think the reality, though, is that that day never comes. Usually if something works, it will never be replaced. So the real trick is writing something that finds a perfect balance between "just works" and "elegant/aesthetic/maintainable/readable".

I do this too — and feel like “throw-away code” is a great moniker for it!
There’s a time and space for shitty code. Something you write once, as quickly as possible and throw away.

Anything else, that ships to any kind of production environment, needs to be reliable and maintainable.

Shitty code is a false economy. Time savings often fail to materialize if not out right end up costing more in maintenance.

Good code is not something extravagant nor expensive. It’s something simple that just works and looks obvious to anyone who looks at it.

Good code is not over designed code.

The difference between shitty code and good code is often the difference between a prototype and something production ready.

Take the prototype code you wrote, careful think of all the edge cases, maybe test them, rename anything confusing, comment non obvious things if any, and refactor, throw away as much as you can until every line matters.

Good code does not trouble your sleep because you know you did everything you could to ensure it is reliable and even if there is a bug, there’ll be enough info logged and the code is so clear, that fixing the issue will be obvious.

If you’re in the habit of writing good code, you will become better at it with practice and be extremely efficient. If you’re in the habit of writing shitty code, you’ll have to write more shitty code to work around shitty bugs and spend endless time chasing mysterious problems in production.

I think intentionally writing shitty code is not a good advice, but it does help with taking us out of the rut of perfectionism and over-engineering stuff!

For me I try to follow two principles:

First, write boring code, and I mean boring, long variable names, no syntax sugar, no clever combination of boolean chains... code that I would use to teach a beginner in the language (or more aptly, future me) how to start coding!

The second is plan to write things twice. This one is a double-edged sword inasmuch as it can help to further clarify or make even more boring the code, or be the place to start adding "optimization" and "cleverness" in the code... I try to stick to the former.

Some of the most valuable code I've written I would call either "hacks" or "scripts", not code, but nonetheless, it solved a real problem instead of being beautiful/elegant or whatever

My impression is a lot of the best practices spread today are suited best for FAANGs or at least high tier SaaS businesses (which often contribute to the frameworks used).

One thing I hear repeated over and over is: Code is going to change frequently. Well that's not universally true. I don't even think that's true for the vast majority of code in production globally.

If you build an app with one specific, well-defined purpose that iself is not going to change a lot (eq. supporting the workflow of a specific business, managing inventory, etc.) that might easily run for a decade with <10% LOCs ever being touched. I've build dozens of those in my career and I'm certain I'm not the only one.

If you're on the quest for the most beautiful code in this scenario you're wasting your client's time and money for your own vanity.

I agree with the author. Learning to write good code, and well designed systems, requires writing lots of code. The best way to do that is just pump it out. It’s harder to write a lot of code if you try to make it perfect and cover a lot of future scenarios.

The more code you write, the more you start to see larger patterns that hinder or improve your system design. You don’t see those things as easily if you are writing bits and pieces slowly. As an aside, writing code in a professional setting can be limiting as well since you may not be able to write code quickly (or shitty) enough to get to a place where you see the effects of your decisions. You’ll write less code and end up focusing on making safe decisions, which means less experimentation in techniques.

If you work on your own, that's probably not a disaster to write shitty code. BUt in a team it's a big no for me. And it's not really about the future extension of code, although modular approach generally helps here too. The biggest benefit of non-shitty code is that others can get through it quicker. In 99% of cases code is written to be read by others in the first place (including yourself after some time), then goes the bug-less priority and then anything else. 1% is where you really need something to be performant - the ease of reading is then not important at all as such code has to be messy.
Meh, not convinced. Sure you can craft a shitty built bike with cheap parts so to learn more quickly about how the bike fails, and sure you can probably make some money selling these shitty bikes.

But I’m in it for the craft. I want to build and sell super high quality bicycles that ride and look beautiful and will ride for a lifetime.

And for that, every little detail of the bike has to be crafted in a high quality manner.

In your analogy, what about the parts of the work that aren't building the bike, like the printer you use for shipping labels.

Sure you could buy a $1500 xerox, but you could also buy a $99 laserjet. Across the N items you buy, a handful will fail or need replacement. they're the things you buy quality versions of.

I've learned to embrace the jank. Architecture matters, but implementation rarely does. You can sit around all day dreaming up a perfect parsing library with full test coverage and a pure functional API to do some string manipulation, or you can smash out a 20 line function that works for your case and move on with your life to things that matter.
The problem is, future programmers only get to look at the artifact--your shitty code--rather than all the learnings you got, since I bet you never wrote it down.

Oh right, I'd have to ask you about it. And chances are, you're not even working here anymore. https://news.ycombinator.com/item?id=29919428

That said, there are definitely people that swing too far the other way. Some people create abstractions where there doesn't need to be. And they're usually not well thought out ones either.

I wish there was a way for code work like pen/pencil and paper, where if you're doing exploratory work, you can sketch. And it'll look like a sketch for other people reading your code, however that can be indicated. But once you learned enough of the domain, you can firm things up, like you do with a pen to add safety and other constraints.

Most of the previous comments seem to be firmly in the 'nope' camp when it comes to code quality. What most of the appear to be missing though is that they're looking at their production codebases, and in that instance, I would wholeheartedly agree - Production code (or code destined for Production) should be of high quality, developed to standards and over-engineered where applicable.

Where I think the OP is referring to writing shitty code is when coding either purely for the fun of it ... to learn a new technique, or a new language for instance, or when prototyping something - sending out the feelers to see if something you can hack together in a short space of time could be developed into a viable solution (at which point, you'd then start to either refactor it into decent, production ready code, or toss it aside and begin again).

Shitty code definitely does have its place, but anywhere near a production codebase isn't it.

I think this is OK in some situations and not OK in others.

To me it is a lot like writing in a human language. When I am texting someone I am close with there is no reason to avoid slang or to use the best grammar and punctuation. When I am writing my CV it would be advisable to be more formal.

The author of a dime-store novel will write at a different standard than the Encyclopedia Britannica.

My point is that you should write the code that is necessary for the situation and if you are part of an engineering organization the leadership or team as a whole should decide when to use what level of quality and should understand what the trade offs are. There are legit business reasons to write throwaway code when time is of the essence and there are times when you need to take the time to risk over-engineering/over-building something just to be as certain as possible that it won't fail.

My usual approach is a bit like how I wrote essays on loose-leaf paper back in school: Start with a rough draft, and then once all your edits are done, produce a "clean" copy.

I think a lot of code that is described as shitty comes from doing the first step, but due to time constraints the second step is skipped.

This is one of those posts that exclusively caters for reassuring the audience regardless of whether they are doing right or not just to make them feel better.

Refactoring is part of a cycle and you do it before you publish your code to others. If you don't clean it up, you are wasting someone's time.

I think there's a balance to be had. I used to write shitty(er) code, and often when I have to revisit it to mod for a slightly different purposes my thought is something like "that lazy ass, I'm going to have to nearly start from scratch to make it work for what I need now"

So now, unless time crunch is so bad I have no option (and even then I push back against it to try & get more time to do it right) those are the time I'll cut corners on robustness, readability, etc. I also put a comment in at the top with a deep apology to the angry version of my future self with a reminder if the circumstances at the time. It helps me not pound the keyboard so much in frustration.

Perhaps I don't subscribe writing "shitty code" on purpose, but there is something to be said about having a code playground where you can explore ideas, API and languages with little care about practices, design or having concrete goals.
I believe most shitty code is not a result of unfamiliar tech stack, tools or environment but not enough time spent on thinking about the problem at hand and how the solution can be open to modification. In that vein, the author encourages shitty code.
Ironically, for an article titled "Write Shitty Code", the entire article is blank for me because they wrote shitty CSS.

https://imgur.com/a/41eXasz

Anyone that did not write shitty code didn't do a lot of programming. The author picked a great example here.

You should feel good when you know what mistakes you did because that means you know better now. This process should be iterated a few times.

This is a false dichotomy that I see in a lot of developers(including myself a while ago): fast+ugly vs slow+futureproof.

In a big codebase futureproof is more important, but let's put that aside and talk about quick and dirty standalone programs. Even when talking about the needs of now, ugly code can slow you down significantly. Ugly code takes you longer to debug, longer to see errors, longer to modify, longer to built upon even in the next hour.

So for me it's a matter of writing code that is at least good enough for me NOW, and then I start thinking about futureproof and other maintainers as I get closer to a commit and during pull requests.

Slightly tangent but one thing that these code practices articles often miss is using the language to its fullest. Most beginner developers who are not very used to the language reinvent the wheel for a lot of in-built functions. For example, I've seen stuff like:

` const arr = []; for (let i = 0; i < anotherArray.length; i++){ arr.push(someOperationOnEachElement(anotherArray[i])) } `

instead of

` const arr = anotherArray.map(someOperationOnEachElement) `

Not knowing what your tool/language can lead to hard-to-maintain code. One should always try to leverage the expressiveness and syntactic sugar wherever relevant.

Slightly tangent but one thing that these code practices languages often miss is using the language to its fullest. Most beginner developers who are not very used to the language reinvent the wheel for a lot of in-built functions. For example, I've seen stuff like:

` const arr = []; for (let i = 0; i < anotherArray.length; i++){ arr.push(someOperationOnEachElement(anotherArray[i])) } `

instead of

`const arr = anotherArray.map(someOperationOnEachElement)`

Not knowing what your tool/PL can do can lead to hard-to-maintain code. One should really leverage the expressiveness and syntactic sugar wherever relevant.

EDIT:

code practices languages -> clean code practices articles* can do can lead -> can lead

(There's no edit option for me, so replying:)

I think developers, especially those with, say, under 15 years of experience, place far too much emphasis on code. No doubt, very shitty code can have a big adverse effect on long-term maintainability, but correctness is much more influenced by algorithm design, which is often better and more quickly explored in something like TLA+ or Alloy than in code. A bad algorithm design costs much more than ugly code. Focusing on code aesthetics also takes time away from other, more important, activities, such as profiling.
The shitty code/do it supposedly once is quite widespread in academia, and from what I have heard also in at least some biotech companies.

The problem: irreproducible results.

Once you chain dozens of command lines, unversioned shitty scripts, no md5 checksum-ed inputs/intermediate results etc. you are in a smelly swamp full of monsters. Even you one week later will not be able to do it again.

Markdown docs/jupyter notebooks are minimum even if one does quick and dirty proof of concept thingy IMHO.

> A lot of senior experienced people will talk about all the “shoulds” your code should be like. They are usually describing some far distance promised land that they have never visited either.

Oh how I can relate do this. I've seen so much guilt and inaction from developers who are paralyzed by "should". They so badly don't want to be a "bad engineer" that they'll over-engineer just about everything and end up causing a lot of problems.

Valid arguments but this is a terrible advice.

Good or bad code is a learned ascept of an engineer, or experience rather. If you care enough then eventually you will write great code unconsciously with high velocity. Someone's shitty code might be fucking beautiful if they practiced for many years.

My advice is, work in a place with good code review, code quality culture because it really does make the difference. We're unconsciously shaped by our peers.

I get it, but as a senior member of the team you have to be careful. Yes it is fun to get shit done really fast, yes it creates short term value but you have to be aware of the downstream effects. When you build new stuff, set patterns, create infra, you are setting the example that junior members will learn from at best, and copy/paste at worst. Do you want a ball of mud because its all too easy to get one
I think what you're talking about is not only shitty code but also poor design which is far more dangerous. Writing shitty code behind good design is a different story, and to my understanding, this is what the author describes.
Ok. there's shitty, and there's _shitty_.

I hope that screenshot is a joke, cause holy crap! That doesn't look good.

I seriously wish the author is not defending that kind of shittiness.

I am all good with the if(process.env.env !== 'notProd') part, but indentation, come on?

I think this can't be a real piece of code anyways, cause the author would have done console.log('here1'), console.log('here2'), and console.log('here3').

The valid point is: "Reconnect with the joy of creation"

Attempts to do everything absolutely correct are not productive on early stages.

So it's OK to write dirty during search for solution. Anyway it's my personal code on this stage.

But then comes time to publish code. I respect my colleagues, I can't make them read dirty code.

> shitty code

Still, I have never understood why anyone would want to write

  if (success == true)
instead of

  if (success)
Maybe both of those examples aren't great? Maybe you want something like this?

  case result of
    Error e -> -- some error handling code
    Ok a    -> -- the happy path
This article makes some very good points, all of which are ultimately false.

To make a medical analogy, I don't know that I would trust a surgeon with a billion operations record and a 50% complication rate more than one with a 1000 operation record and 1% complication rate.

And I certainly would hate to be the colleague inheriting their patient.

Totally agree with everything in the article. Unclear how this is different from prototyping code before you start on the industrial-strength version. https://en.wikipedia.org/wiki/Software_prototyping
I love when a project transitions from clean to shitty code (which eventually happens as quick fixes and shortcuts pile up). At that point I can start iterating much faster since I no longer care about making everything as clean and smart as possible. The battle is already lost so I can just embrace it.
Shitty code writers typically justify that it's some(thing/body) else that doesn't allow them to write OK code. They trade the imaginary speed gains (my estimate it's 10-20% of effort difference between shitty and OK work) for problems that start manifesting immediately or are ticking bug/maintenance bombs.

The problem is that a lot of engineers try to go the shortest way possible, instead of investing extra effort to think little about the future. They see it either black or white, either shitty or perfect - there is no middle ground. I just noticed that every type of copy/pasting is now ok if your application is using "microservices" architecture. Nobody knows why "microservices" were chosen (as there is no demand for it, nor the implementation of that "architecture" allows them to easily scale), but hell, now we don't need to isolate the common stuff into a single place. And then, when they see some crap, then they keep adding more crap for a sake of consistency.

For me some top qualities of good code is - Readable Maintainable Fault tolerant

If it works, there are no plans to extend it and there is no one to read it - then it doesn't matter what it is. I know its good code without having to look

Shitty code such as a website that shows 0 text with third party js being disabled?
“If a thing is worth doing, it's worth doing badly.” G. K. Chesterton
> A lot of senior experienced people will talk about all the “shoulds” your code should be like.

And the article itself is another "should".

That code snippet is like one of those Lovecraftian paintings where it looks normal, but the more you look at it, the more weird and horrifying it gets.

Bravo.

the best way to write code is: write code that you can delete without any effects on the rest of the program. and keep all related code as close as possible together in the source code. Also keep mutations as far up the call stack as possible. use pure functions whereever possible.
My interpretation of the actual post is less, write “bad” code, but more don’t let code quality prevent you from trying something. The former presentation of it though I can’t agree with while the latter I do.

I feel code quality is important, not because of future state and optimization but a strong architecture will facilitate other engineers learning, which is critical. For example, not all engineers have learned design patterns like the strategy design pattern or observer, etc (see https://refactoring.guru/design-patterns/catalog for great examples) where a little guidance can save them a lot of pain.

With that said, I understand we all bring different skills to the table. Some people love making every linter pass while others could care less and some actively hate it. This is fine, we just need to respect each other enough to try to build on each other’s strengths and support each other where we’re weaker.

TLDR: Rather than saying it’s fine to write “bad” code, say don’t let code quality intimidate you, and be willing to try. You can always refactor later and you’ll learn as you go.

If in 2022 you still don't know about design patterns (not using them, just knowing about them) I feel sorry for you.
Are people still talking about design patterns in 2022? When I learned to code 'properly' 20ish years ago design patterns where all the rage and we studied them at university and dozens of books where published on the topic. Now I don't think I've heard anybody even use the phrase "design pattern" in connection to programming for several years.
But is that because everybody knows them well enough to just be inherent in the way that they break problems down and build systems to solve them or because they've actually been abandoned as a concept?

I.e. we don't need to talk about it because we all just do it vs not talking about it and not doing it.

I don’t disagree, but I encounter a fair number of individuals, especially self-taught developers, without exposure to them.

While it’s fine to feel sorry that they weren’t exposed to it, I wouldn’t personally say I feel sorry as I find it hinders people’s willingness to ask for help. Invite questions don’t make people feel bad for not knowing something you or I may think is obvious. We all were beginners at some point.

The software priests who taught the MSCS courses I took did not teach these insights. No harm comes from studying the beautiful code of the ancients. But, indeed, less work gets done when you complicate your task with goals of beauty and future-proofing.
Why not just post an article on how to generate flame bait?
I love the code in the screenshot on top of the article.
Well that's one way to get me not to use your SaaS
DRY, KISS, YAGNI
Can do!