Ask HN: Is average code getting worse?

68 points by Aeolun ↗ HN
Hi HN,

There used to be a time, in the dark dark ages of history, 10 years ago or so, when I would encounter issues during the course of my work, and I could fairly confidently assume I was doing something wrong, or I just hadn’t read the manual correctly.

Contrast that to now, when I regularly write code, or include a library to do a certain thing, and I find it just does not work. Following my historical logic, I spent a day trying to figure out what I did wrong, only to figure out that it was a bug, or edge case that someone just hadn’t covered (never mind that my life seems to consist of edge cases now) or the documentation is just plain out of date (or nonexistent).

Is this a trend? And does it have to do with the average code, or myself? Have you experienced something similar? It’s driving me nuts.

I want to rely on other code, but more and more I find that it’s safer to just assume it’ll be broken from the start.

85 comments

[ 2.8 ms ] story [ 170 ms ] thread
I find this varies by ecosystem. Certain ecosystems have incredibly high quality libraries on average. However ecosystems also vary in their breadth and quantity of available libraries also so that may play into it.

I find Rust and Perl to both have very high quality libraries available. JVM/Java ecosystem has a huge number of libraries and some extremely high quality ones but also a massive number of abandoned or low quality libraries left to decades past.

The ecosystems I find troublesome are JS, Python and to a much lesser degree Ruby. Huge numbers of low quality libraries and dependency hell.

The differences seem to stem from the culture of said ecosystems. Java code is often flexible to a fault, Rust code is strictly correct and fast but with less emphasis on flexibility/ease of use. JS/Python hail from the "get shit done" culture and as such there are many half-baked libraries.

These are just generalisations. Even the ecosystems I don't enjoy working with have some very high quality libraries of course. JS has React, Python has Tensorflow, Requests, etc.

If you want to be able to rely on library code though I would go for Java/C#/Rust maybe Go if it doesn't annoy you for other reasons.

Regardless of ecosystem, I think it's important to choose packages carefully. Python may have some trash libraries but there are also some very stable and trustworthy ones. I've used Python long enough that I have a selection of libraries I know and use. Javascript / NPM land has been a lot more difficult for me. I've been writing Go a lot lately and it's a breath of fresh air in that I rarely need packages outside of the standard library, which means I simply don't need to think about dependencies very often. That might change if the type of projects I'm working changes.
Have you vetted the vendors of the library? Is it something that a reputable company offers that you /payed/ for? Or is it some side-project of some rando?
These metrics don't matter. Almost every library you care to pull for a popular (read: widely used and written) language will be trash. Yes, even if you pay for it. Even if it was a "reputable" company making it.
Never thought about it in that way about majority of .NET libs, even those made by 3rd party and most popular ones
It does not seem to matter. Paid things, if anything, seem to be more likely to be trash than the free ones, but the free things are certainly not blameless.
Where are you getting these libraries compared to 10 years ago? What languages do you use?
I generally assume code is broken from the start now, but I don't think that this is because average code is getting worse. I think it's because there are more "solutions" to problems online (also, I'm more critical than I was a decade ago).

In the past, I had to write almost everything from scratch, and that meant I'd have worse code than what is open-sourced nowadays for the time period that I was implementing (and possibly longer if the problem is gnarly).

Nowadays, I can do a search on GitHub and find something that appears to solve my problem, but when I use it it'll turn out the author was solving a slightly different problem than mine and so his solution only partially solves my problem or doesn't handle certain edge-cases/bugs that will be a problem for me.

That doesn't mean that the code is worse. I am just using something that was created to solve another person's problem and expecting it to solve my own problems with no extra work.

Basically, you can still choose to implement everything from scratch if you want to. In these situations you should make sure to learn from the people that came before you, by reading other people's code first and spending time thinking about your design/implementation.

But if you want to use other people's code off-the-shelf to implement something faster, you can't just assume that because their solution solved their problem without running into edge-cases, that it'll do the same for yours. You have to be responsible for every line of code that you integrate with, and should assume that is not guaranteed to work for your problem/data.

---

What is an issue and wasn't before, are problems that occur due to a particular combination of packages and incompatabilities. These problems are difficult because they can require impossible levels of co-ordination to fix upstream. I think in many situations we should rewrite things to be more monolithic than they are.

> you can't just assume that because their solution solved their problem without running into edge-cases

I agree in general, but there’s a class of general problems with good solutions. Such libraries tend to just work. Like database engine, XML/JSON parser, multimedia codecs. If you pick the most popular and compatible one, like sqlight or libpng, you’re very likely get your problem solved without too many edge cases.

In my experience yes. Average code is much, much worse than it used to be. Regardless of the origin. Then again, there's also much more of it. It could be argued to be a mixed blessing.
This talk deals with the issue you are describing as well as the underlying reason for it: "Preventing the Collapse of Civilization" by Jonathan Blow https://youtu.be/pW-SOdj4Kkk

It's very informative and engaging. Highly recommended.

Preface: I've worked on code ranging between FORTRAN 77 to a rather nuts react, typescript, webpack,... combination.

From my experiences, what I have observered first and foremost is that the problems that software is solving are getting more complex as time progresses, causing software complexity. That is often proportional to the number of bugs.

Many popular FORTRAN packages out there solve a particular (or set of) well(ish)-documented mathematical or physical problems. Matrix manipulation, eigenvalues, weather simulation, etc. What i've observed is that these problems are, although sometimes complex, require minimal dependencies. The primary dependency is some journal paper somewhere, which you don't have to install as a software dependency!

Constrast that to a couple recent codebases i've worked on, easily >300MB of npm dependencies for a mix of react, typescript, webpack, sass (gyp!! >:(), jest, cypress, etc.

Having said all of that, for both of the above eras of software, i've encountered annoying bugs. It's just that nowadays i see most bugs are package compatibility issues (looking at you, steaming pile of webpack 5), whereas with FORTRAN it has instead been a mathematical error.

My point is that software is solving very complex problems right now. Back then, a web application was 3 types of files, because web applications were simpler. But now entire businesses use them, all their processes can rely on a single web app. Important processes sometimes with regulatory involvement. This necessitated typescript (scalable js), testing (jest and cypress), better performance (webpack), etc....

I see TypeScript more as a bandaid patch which solves small problems but causes bigger future problems than it solves. TypeScript and its many dependencies add to the kinds of compatibility problems you allude to.

I'm a strong believer that the language's type system doesn't matter that much. Statically typed or dynamically typed. It's possible to write equally good quality code in both paradigms. The key to good code is logical separation of concerns (high cohesion) and simple interfaces which have simple parameters and return values (loose coupling). Also, having well defined concurrent event loops is important if your system requires a lot of async logic.

The obsession with TypeScript now is mostly the result of the fact that people have a tendency to blame tools (dynamically typed languages in this case) for their own incompetence.

I feel very productive in statically typed languages like Rust and Swift but hard agree on Typescript and I’ve said it here before. It feels like the worst of both worlds, extra code and dependencies for limited type safety. The amount of times it causes some issues with compatibility or a library has missing or incorrect typings has left a bad taste in my mouth. Granted I always work on small teams or alone though.
I agree with the library compatibility issues for typescript, I've felt that pain before, but it is getting better by the day with more adoption.

I've always held the belief that the major flaw of Typescript was that it is preceded by Javascript. This caused fragmentation. If the web was Typescript first, I believe it would have been quite the "nirvana". But then again, Rome wasn't built in a day...

It is similar to "are teenagers worse than they used to be?".

But in all fairness - from my personal experience - the average code is getting better. It is mostly thanks to tooling: languages (write a readable code in PHP vs Python, or C vs Rust), version control (no need to keep tons of unused code that one does not want to throw away), linters getting more widespread, tests and CI becoming a standard.

I also find that this varies by the ecosystem.

In PHP I would not assume that an external dependency is without flaws. In fact, I'd assume that it's mostly buggy simply due to the lack of a type system, but fine if I navigate the happy path.

In Haskell I would assume that I'm using the library in a wrong way. In Haskell I also find that I can categorize libraries by quality and that, in the most cases, I'm not running into bugs, but rather lack of good examples or lack of pushing the dependency bounds to Stackage (the package distro on top of Hackage), either because the author doesn't use Stackage or because they've become too busy.

---

Comparing code 10 years ago and now:

I find that there are much more libraries in almost every ecosystem.

That means: More stale packages, more low-grade packages, more critical selection required, but also more opportunities! Hopefully you also experience that you can do a lot more with packages than you were able to 10 years ago.

This, in some ways, has shaped modern software development a lot.

In case OP or anyone else is interested: PHP lacks strict typing (by default). For older applications I agree with you, but in the last few versions it's been a lot better. Depending on your framework or tools, you can customise file templates and add strict typing to each file, i.e. Laravel's `php artisan make:xxx` can now always have declare(strict_types=1); . Of course you can't assume that for external packages, but it's highly recommended.
I don't think it's the code necessarily. It's the feature creep. It used to be that we just supported monitors - now it's touchscreens, tablets, watches, keyboards, mouse. It's LCD screens, plasma, TV, and so on.

I find that code become exponentially more costly the more features you add in, because of the number of architectural layers you have to add on. And if you haven't planned for that, well, now you have to deal with the pain of adding another architectural layer.

HN is likely in the sweet spot of good architecture, but it also means that it's not supporting things like infinite scrolling and reddit-like awards.

Interesting that you should mention device support as a cause of more complex code, as the best way to support the devices you list is generally to use LESS code.

Bare HTML is supported by pretty much everything...

But for some reason it's not cool to use HTML. We throw on megabytes of code just to bypass the page reload so that we can better control the user experience. This is why we end up with complex and bloated libraries like React and end up with a frontend and backend state that have to be kept in sync.

I wish we went back plain HTML, especially for sites that don't need to be dynamic.

Browsers shouldn’t let you bypass reloads outside of the window unload event, and that is standardized and doesn’t leave much room to mess with. Can you elaborate if that was a real thing you are referring to?
I assume the parent is referring to the rise in popularity of single-page applications.
I believe it's due how huge the demand has become. Entry into software engineering has become really easy. Thus, people without proper are contributing to projects and the result is a mess.
Yes, but this is always the case when more people are doing something. The less gated something is, the worse the quality will, in general, get. When writing was the privilege of the few, written words carefully curated and edited and survive for ages. When everybody could write, there was a lot of trash, along with a lot of great stuff. The average will usually decline in such cases, because most people will not have the drive and resources to become excellent at it.

In the same way, when we are pushing coding at kids barely above kindergarten, there is going to be lots of crap code, but also much more excellent code, in general though, the amount of crap will overwhelm the amount of excellence so average will trend down. If you applied some kind of cutoff at the base, removing the absolute worst, the average might trend up. This is the case with anything that gets more democratized.

Extended pool of engineers, as the field has grown, has diluted the quality of software.

Post "Social Network" (the movie), and the economic downturn of 2008-2012 there is a new generation of engineers that started programming/entered the field because that's where the money is....

There is also proliferation of the code-academies, who often encourage trainees to create a 'github portfolio', often with low quality libraries.

2001 tech bust acted like a great filter. During the 2001-2012, a lot of people that remained in the field were there because general passion towards it, and had the skills to be employed after the bust.

People that couldn't cut it, did leave the field. Hence, the software was often more of a work of passion, or craft. A lot of the open source libraries that we use today, were created during this times (and the 90s, for the databases, and Linux), also a lot of the culture of startups (good and bad), was cemented during this time.

I think the field massively expanded after 2012, and people started doing engineering because that's where the money was/became trendy. Hence you will naturally have a dilution of overall quality.

Also all the bad pre-2001 programmers have come back and instantly jumped into tech lead and CTO positions.
If you suspect that greater expectations for easy money and prestige in the industry have lead to lower quality code, what else might fall from that?

Would you also expect pockets of the industry where money and prestige were hard to come by (such as video games or experimental open source operating systems) to have better code on average?

Well certainly video games are much harder than what most software engineers are doing. And game developers have a strong incentive to carw about performance and efficiency and really push the machine to its limits.

I am currently working at a FAANG company and doing game programming on the side. The problems I am facing at my day job are mostly trivial compared to the game and graphics programming I am doing on nights and weekends.

Maybe you're just getting better at coding so you make less mistakes so the mistakes you find are more often somebody else's? Kind of a regression to mean.
It's a mix.

I think that average or high quality code has increased in quality over time, because CI/CD is a lot more widespread. Increased computing power has improved tools such as IDEs, compilers, linters, testing tools, etc. So the ceiling is generally higher, I'd say.

However there are a ton more newbies in the field, because there's a need for more people, so there is also a lot more garbage and that garbage is even worse.

Plus, there are a ton of programming-adjacent folks which can now publish their stuff. Since their focus and background are not related to programming, their libraries and apps are generally of lower quality.

TL;DR: There is more of everything, and since 80% of everything is crap, there is more crap. It's also harder to find the gems, since we have to wade through crap. But good stuff is still out there.

Maybe the quality is still the same, and your skills improved? Sounds like 10 years ago you blamed yourself when something went wrong, and now you can see when it's the library that's broken. 10 years ago you may have not been able to spot defects, but now you can.
Maybe you've become a better coder and now the "average code" has dropped in your estimation. There are a multitude of potential explanations, and anecdotes from people will not reveal the answer to your question.

My small amount of experience has shown that people are astoundingly bad at intuiting generational change in crime, capability, and morality.

Here are some quotes of people complaining about "youngsters these days".

1. The world is passing through troublous times. The young people of today think of nothing but themselves. They have no reverence for parents or old age. They are impatient of all restraint. They talk as if they knew everything, and what passes for wisdom with us is foolishness with them. As for the girls, they are forward, immodest and unladylike in speech, behavior and dress.

2. The children now love luxury; they show disrespect for elders and love chatter in place of exercise. Children are tyrants, not servants of the households. They no longer rise when their elders enter the room. They contradict their parents, chatter before company, gobble up dainties at the table, cross their legs, and tyrannize over their teachers

3. I see no hope for the future of our people if they are dependent on frivolous youth of today, for certainly all youth are reckless beyond words... When I was young, we were taught to be discreet and respectful of elders, but the present youth are exceedingly wise [disrespectful] and impatient of restraint

#1 was written in the 13th century, #2 in the 5th century BC and #3 in the 8th century BC. Old people always think young people are worse than ever.

I say this not to invalidate your feelings of frustration with how people are coding these days compared to the good old days. But ask yourself if your skills haven't improved in that time. Bugs that you would miss 10 years ago are now obvious to you. Also, there's just a lot more code out there than there used to be, judging by number of repos. The friction to put something into a public repository is lower than ever. That gets us some gems that might not have existed otherwise, but also some turds.

Rest assured that 10 years from now, devs will be talking about the good old days of today and how much better it was compared to 2030.

This is a very generic ramble to (potentially) derail the thread with. I'm more interested in people's answers to the actual question the OP asked.
OP's comment has nothing to do with "youngsters these days" but with how code is nowadays vs at the past. Unlike humans, there are changes in how code is produced, what it targets, where it runs, the motivations behind writing it, etc.

E.g. to expand on what others have mentioned, having to target Windows on a desktop PC with regular monitor at around 800x600 or at most 1024x768 resolution and a mouse for English is a bit different than having to target any desktop OS, any tablet OS, any mobile OS, perhaps also provide a web-based version, with a UI that works under resolutions ranging from ~1366x768 up to ~5120x2880 on monitor sizes ranging from 5" to 55" (or above) and inputs handling that includes keyboard, mouse, touchscreens, TV remotes, etc while having support for unicode, multiple languages, emojis, etc.

Even with the exact same people (which certainly isn't the case) writing the code, the latter is going to have much higher likelihood for bugs and other issues to crop up.

This misses the mark, for reasons I can't see why. Maybe let's compare code 8 years ago to 4 years ago to today.

I did Android dev. 8 years ago it was a nightmare. To download an image, you had to build your own async thread, transfer the bits, resize the image, and then make sure there aren't any memory leaks and keep it small enough that it doesn't suck up all the RAM and crash the device.

4 years ago, it was easy. Just plug in the URL, and where you want it to go and it'll handle all the above + caching.

Today we have Android Jetpack. Now MVVM architecture is the default. Everything is cleanly handled - we make sure that there's no memory leak when someone makes a call within the half second it takes to download the image.

But for some reason, code is more tiresome to write. A single page used to be 2-3 files, now it's easily 12 files. Trying to debug a problem means sifting through those parts. The fact that we can code a full feature in 5 min means that very little thought is going into whether this feature is necessary, has side effects, or the responsibilities of the different parts. Budgets have gone up too, and now you can expect to deal with a freelancer from Qatar or Ukraine or whatever who builds a piece just fine, but nobody remembers how it works or whether this part was built correctly.

I'd say that the individual parts work fine but as a whole, they go together poorly.

> #1 was written in the 13th century, #2 in the 5th century BC and #3 in the 8th century BC.

Not true. These all appear to be fake quotes. Apparently #1 are not words of Peter the Hermit, #2 not words of Socrates/Plato, #3 not found in Hesiod.

#2 seems to be from 1907.[0] There are claims on the web it's a paraphrase of a speech of Justice in Aristophanes' comedy The Clouds[1], but I don't see much resemblance.

This[2] page contains all 3 quotes, #2 prefaced by "You may have seen this quote, often (apparently inaccurately) attributed to Socrates", then claims the other two quotes are real. But he links to a 2004 discussion page[3], which under quote #1 says "It should be noted that the attribution of this quote to Peter the Hermit is as shaky as the attribution of the other quote to Socrates."

[0] https://quoteinvestigator.com/2010/05/01/misbehave/

[1] http://www.perseus.tufts.edu/hopper/text?doc=Perseus:text:19...

[2] https://nickfalkner.com/2013/04/21/the-kids-are-alright-with...

[3] http://answers.google.com/answers/threadview?id=398104

https://en.wikiquote.org/wiki/Socrates#Misattributed

My experience is similar. I seem to stumble upon two different types of libraries:

- One that is so specifically designed to fix the authors' original problem. It is implemented in such a way that it doesn't cover a lot of use cases.

- One that is actually designed to be a general purpose library and to be used everywhere; but because of this there is a lot of feature creep and very complicated interfaces.

Yes. Average code quality is objectively worse than it used to be, and there is an objective reason why.

The barrier to entry is much lower.

In 1995, getting a C++ program compiled, tested, shrink wrapped and shipped (in waterfall fashion) required a lot more work. The "survivor" software you bought on your floppy disk or CD-ROM at the store meant it was high enough quality to jump through all those hoops. Some of those hoops were the software developers needed to know more about computers. Some were that you couldn't fix an issue after it was shipped in the wild pre-internet. Some of it was that a lot of those people had an intrinsic passion for the craft in which they weren't paid as well. They also did the work even though they were considered geeks, unlike now where a lot of "engineers" are indistinguishable from marketers and considered popular.

I think a lot of it has to do with higher education as well. Most courses focus solely on theory rather than teaching the best industry paradigms for writing clean code.
>The barrier to entry is much lower

Very true and i blame it entirely on the rise of "Web Programming". When it started off with HTML/CSS, a whole lot of non-programmers jumped into the industry and thus a lot of frameworks/libraries added layers of abstractions to cater to them to make it "as simple as possible" to write a "Web App". But then things only got more complex with the need to recreate desktop app experience within a browser and the explosion of mobile devices. The non-programmers were now out of their depth but since the software market had expanded exponentially they "upgraded" their skills and continued churning out "code" with predictable results.

It is more than likely your perception has changed with 10 more years of experience.
Not sure what you are doing but i don't think things got worse. They just changed.

Compare the situation on the web.

The days of Ie 6, polyfills and all that garbage are mostly gone. Browsers are an order of magnitude better than ever.

On the other hand you got the frontend js situation which is broken beyond belief. I dare you to pick any js framework and try to update it a version...

If you skip that and use the old and tested stuff, things are just way better than 10 years ago. Just compare Rails or Django to Jsp...

The god awful PHP std lib is still the same, but they clobbered some sort of object orientation and static typing onto PHP. So its as bad as ever and the libraries reflect that.

But in general whole library situation improved massively. Nowadays i can file a bug report on Github, or just fork it, get it fixed and make a merge request.

Back in the day you had to join someones IRC, talk to someone else who had the stuff on its cvs or whatever (hopefully) and then you wasted your day just fiddling around waiting for some random person to build a binary with some obscure version of a c compiler.

So there is more crap but the good old stuff matured and got way better.

There are better ways to discover problems for example it became quite the norm to use version control, a CI and automated tests..

It seems like you're comparing the current situation to more like ~20 years ago than ~10 years ago.

In 2011, both Rails and Django were well established and used heavily.

And in 2011, not too many people cared about IE6 either (some did, but even the big sites didn't support it anymore).

Even GitHub was used quite a lot in 2011, and was well known.

Still, I think you're right, it's just a different time scope...

Talking about averages is really tricky when the total amount of code/libraries is growing rapidly. In general though I think all of the following are true:

1. The number of high-quality libraries available has increased substantially. 2. The variance has also increased substantially. 3. The AVERAGE quality of polished libraries has gone down.

Basically, the number of open source libraries has exploded over the past decade or so but the majority of new libraries are of low quality because they are slapped together or only half-baked and then abandoned. But it is easier than ever to find high-quality open source libraries for any use case you can think of. In other words, things have never been better but you cannot assume that a library is of a reasonable quality just because it is published as an open source library.

Hum... Probably 10 years ago you were using a highly curated and very small set of dependencies, written by some of the top experts on your ecosystem, while nowadays you are using that same set plus a huge amount of code you download at random from the internet.

The many different communities of programmers made that transition at different times, but very few dependencies was basically the only model available at the 80's, while the tons of dependencies is the model basically everybody uses nowadays (the amount of stuff embedded software imports nowadays would surprise a desktop GUI developer at the 90's).

Maybe it's not the quality of code that has slipped but the quality of the sources you're relying on?

I tend to rely as much as possible on the standard library of the languages I'm using (especially for Python and C++, which ships with a pretty good set of libraries already), and when I have to go beyond that, I try to vet libraries as carefully as possible.

If a library deals with problems I know are going to be tricky, I try to take a peek beforehand at how it approaches dealing with those problems. If the approaches look obviously simplicistic/broken, I can save myself some time.

But when I want to deal with truly hellish code problems, I let my 8-year-old sweet-talk me into installing just one more mod into his Minecraft installation...