if code is hyper specific
it isnt.
!nostupidquestions is a community dedicated to being helpful and answering each others' questions on various topics.
The rules for posting and commenting, besides the rules defined here for lemmy.world, are as follows:
Rule 1- All posts must be legitimate questions. All post titles must include a question.
All posts must be legitimate questions, and all post titles must include a question. Questions that are joke or trolling questions, memes, song lyrics as title, etc. are not allowed here. See Rule 6 for all exceptions.
Rule 2- Your question subject cannot be illegal or NSFW material.
Your question subject cannot be illegal or NSFW material. You will be warned first, banned second.
Rule 3- Do not seek mental, medical and professional help here.
Do not seek mental, medical and professional help here. Breaking this rule will not get you or your post removed, but it will put you at risk, and possibly in danger.
Rule 4- No self promotion or upvote-farming of any kind.
That's it.
Rule 5- No baiting or sealioning or promoting an agenda.
Questions which, instead of being of an innocuous nature, are specifically intended (based on reports and in the opinion of our crack moderation team) to bait users into ideological wars on charged political topics will be removed and the authors warned - or banned - depending on severity.
Rule 6- Regarding META posts and joke questions.
Provided it is about the community itself, you may post non-question posts using the [META] tag on your post title.
On fridays, you are allowed to post meme and troll questions, on the condition that it's in text format only, and conforms with our other rules. These posts MUST include the [NSQ Friday] tag in their title.
If you post a serious question on friday and are looking only for legitimate answers, then please include the [Serious] tag on your post. Irrelevant replies will then be removed by moderators.
Rule 7- You can't intentionally annoy, mock, or harass other members.
If you intentionally annoy, mock, harass, or discriminate against any individual member, you will be removed.
Likewise, if you are a member, sympathiser or a resemblant of a movement that is known to largely hate, mock, discriminate against, and/or want to take lives of a group of people, and you were provably vocal about your hate, then you will be banned on sight.
Rule 8- All comments should try to stay relevant to their parent content.
Rule 9- Reposts from other platforms are not allowed.
Let everyone have their own content.
Rule 10- Majority of bots aren't allowed to participate here. This includes using AI responses and summaries.
Our breathtaking icon was bestowed upon us by @Cevilia!
The greatest banner of all time: by @TheOneWithTheHair!
if code is hyper specific
it isnt.
This.
As much as you try to keep various modules in your program functioning as independently from one another as possible so that you can unit test the shit out of them, the whole system is far more complex and interdependent in the end.
And that's just within your own code. Bring in external libraries, drivers, etc. and it's easy enough for fixes downstream to affect what happens further up.
One thing I find interesting is there seem to be cultural differences between platforms. In Windows, for example, it's super common to see multiple versions of the same library installed, and apps dependent on a specific version, even if it's rather ancient. Linux/Mac tends to frown on this? There may a stable version and development version, but that's about it. So the onus is more on the app developers to make sure their code works with the latest library.
It's also important to note that it's not always an unanticipated effect. There may be some need to change a library to no longer support a certain usage. In that case, the old usage is marked "deprecated" and anyone using the library is given a window of time to make adjustments to the new interface, but if they don't get there on time, the patch breaks their program. And in some cases, the adjustments can be major, requiring what amounts to a total rewrite.
Nothing exists in a vacuum.
There is a break in a sewer line in town, so a crew goes out to fix it.
The crew's only purpose is to fix sewer lines, but somehow, you're still late for work.
Imagine you're writing a book. In this book you need to be perfectly consistent and coherent because the people reading it are so incredibly literal that if there's ambiguity or inconsistency they will run into your home and defecate on your carpet.
Short stories are easy enough. There's only a character or two and you can generally remember what they're wearing and what they said, but as the stores get longer you start to work yourself into corners and lose track of what you said in the previous chapters.
Let's say you reach a scene where the main character needs to hop on a train. You write a scene where they purchase a ticket. But wait, a few chapters ago you said they got mugged! So you decide to cut that scene. Now they can pay for a ticket, but the scene where they said they got mugged is wrong and the scene where they said they can't pay their bill doesn't work!
Computers read instructions and interpret them. They follow orders. Programming raw hardware is tricky, so we add abstractions to make it easier. Collectively we agree, "we'll put a return pointer here, then push these instructions here and set the program counter here" as the way we call subroutines or send data or something else. If there's ambiguity in the specification then two people might build two different programs which they both expect to work. One of them will fail. If there are ten people implementing things with an API, perhaps all ten will fail.
Hyrem's Law says any observable behavior will eventually become part of a workflow.
Imagine you’re building a house, and you notice that a wall is not quite in the right spot, so you need to move it over a few inches. Sounds like a small change (just a few inches), but it’s easy to imagine that the construction might affect other parts of the house, or that you might see issues later because of the wall being moved over.
Not a perfect analogy, but a software change can sometimes seem small (just a few inches), but actually require a lot of complication
Software is generally built up in layers from reusable pieces. If there’s an assumption or a change in a lower layer or in one of those reusable pieces, things that might seem unrelated can break if they share one of those pieces
Your example is for graphics drivers, which are unbelievably complex, not to mention have to be designed to:
A) work in tandem with a crazy amount of different architectures, kernels, hardware setups and dependencies.
B) must reliably manage the demands of millions of complex calculations, monitor throughput and heat dissipation, handle complex and varying game configurations and technologies, all while simultaneously working as seamlessly as possible for us users.
The breaking could be from any one of the above systems and more having any number is issues or changes.
Simplified example: Function #185 requires specific feedback from system hardware output #768, but that output was updated by the another development team for another system driver to give the word “true” or “false” instead of a number indicating the same. Now, if that function is not designed to handle the change gracefully beforehand, then there is a problem. Hour severe the problem is depends on what subsystem of the driver software is affected.
Monitoring system? Maybe not a biggie, the graphing app gets killed or freezes. The actual driver gets the issue? Could be catastrophic failure, where the system freezes or restarts, or corrupts the driver install itself and you need to reinstall previous version. Worse case scenario, it really fails and fries hardware, but that’s rare. Failsafes usually kick in on the hardware side to mitigate that kind of damage.
Now times this by a probable factor of thousands of functions and hundreds of dependencies and you get the idea.
I’m not great at explaining things sometimes, so forgive me if the above doesn’t answer your question.
The different parts of software are (maybe) meant to be independent, encapsulated from each other, but in practice it's hard to actually do that. So if you change the behavior of one part, the other parts that depend on it directly or indirectly often need to be changed as well, and certain types of issues are easy to miss, especially when you aren't targeting a homogenous hardware platform like a game console.
If it was always happening the same way every time it wouldn't happen...
I'm system design there's almost always a tension between efficiency and adaptability / robustness.
You can write software where code is very isolated and not shared and it makes it really easy to update it quickly and ship it and know that it will run properly, but the cost is usually that there's more boundaries in the software that create little slowdowns and cause things to have to repeat and it adds up to a slower or more bloated program.
You also have instances where you write your software and it has a bug, and you later go to fix that bug, and you don't realize that a whole bunch of other software relied on that bug being there.
For instance the Node.js team recently released a security patch that caused them to emit a proper .closing event. Unfortunately an old version of a very popular fetching library breaks when it receives that .closing event because is thought it was supposed to close. It's fixable but it would be very hard for the node team to know that they would break another piece of software that was listening to undocumented events.
Good programmers try to follow the DRY principle: Don't Repeat Yourself. A lot of times you need to do the same actions over and over in different parts of a program, so you write a function to do that, then just repeatedly call the function. If you have to modify a function to fix a bug in one place it might change the input/output somewhere else unexpected.
I'll give you a real world analogy. Have you ever tried to balance rocks? You can get two or three rocks balanced but that could put one of the lower balance points out of balance. It's like that. That is the assumption that code has a singular dependence and it's all linear is incorrect in most circumstances. Code often has many dependencies and many other parts depending on it.
It's the tablecloth effect:
You sit at a beautiful and elegant table, with plates and glasses and food and all. You pull at the tablecloth on your side so maybe the glasses on your side fall over. But maybe also the glasses on the other side fall over.
They were connected somehow. Maybe you knew the connection, maybe not.
You want some examples?
Example 1:
lets say you have a variable named x
x is used in a lot of functions and classes, it's a very important integer.
A function requires x to be a floating point number, though. Instead of creating a new variable, the developer makes x equal a float, which breaks all the functions expecting an int.
Example 2:
Developer uses a library A to build his own library B which in turn is relied upon by others. When Dev has to change this library A to a new library C due to deprecation or security vulnerability, they might not even notice any problems until later when it turns out the people using his library were already using a different library with the same name as library C, causing an industry standard software to fail to build for several days and millions of dollars lost.
Example 3:
Your code actually had all the bugs the entire time but it broke before it could even reach them, so you only saw one error until you fixed it.
Exactly. Designs are tangled, causing unexpected explosions in the next building. And when I invite programmers to create less-tangled designs, they scoff and call it "overengineering".
And then another explosion in the next building.
🤷
(This isn't the only cause/effect path leading to unexpected defects, but it's a very common one.)
There are many routes, but in your example, for instance, Microsoft updates don't just have 1 fix for 1 issue but multiple fixes and new features, ideally Microsoft would have tests that cover all usages that they run before deployment, but they don't (it's a lot of code) but also it has to run on any combination of systems.
Then you throw vibe coding into the mix..
Another thing is if you had 2 similarly named variables and use the wrong one it might work one way but not another, someone is tasked to fix it and they see it using the wrong variable and correct it.. great, but maybe other stuff was made since that now breaks because that variable is correct now.
And any issue relating to timing issues can just appear and disappear based on environmental conditions, a true nightmare to resolve well.