I see humans do this all the time, especially abuse of exception handling, even among “Senior” developers. They don’t have a semantic understanding of what they are doing or why they are creating a race conditions or creating perverse control flow logic N layers down in the stack.
The fact that researchers get it wrong is, well, unsurprising. LLMs might actually be an improvement.
Well, there's no "correct" answer. Depending on the context, the "correct" thing might be 1) to log and swallow the exception and move on; 2) Let the exception percolate up to caller, who can handle and recover; 3) implement your own recovery and handling; 4) kill the process. To know which one to do, one needs to understand the context. Logging and swallowing is not the worst default, but it's also likely not the best.
But this is because almost everyone gets taught this badly. When you ask how to do exception handling best practices etc, even from teachers/college profs etc you get wildly different answers from every single one of them. So people either learn themselves or from colleagues or, most likely, not at all.
Now hopefully I won't get horribly dinged for mistakes and poor advice here. What I am trying to say is that I too read "even senior devs don't understand the race conditions they create downstream." And I thought - oh God, don't I.
But five minutes thought can help you walk through most issues. For most applications most of the time you can reason your way through without fear, and when you do encounter gnarly problems they often can go away by redesigning your application! Often the problems you encounter you caused. retrace your steps and find an easier path. Save the hard thinking for genuine problems / value creation.
So race conditions are simply when two processes / threads are likely to affect a single resource. In this case it's a file - and the problem is test if a file exists, then if it does not, create it and then write to it.
If two threads do this, say a log file, the first one creates the file and logs it's important stuff, the second then creates it again wiping out the first log data.
Solutions in this area include
- create as append file (the concept is basically deviates old because this is a decades old problem)
- avoid sharing resources. for logging log to per thread locations. Not always possible but you sure as hell can minimise this to one or two resources you must share.
- hand off creating files to a seperate part of the application. There is a balance between "scripting" and "application" and using small little library functions to do in one line indirectly something that also takes one line using the methods shown in the docs.
- handing off batons / mutexes etc etc. This gets wildly complex. Honestly given a world of async libraries, Erlang, and distributed computing, if you find yourself having to use multi-threading think very carefully if this is the right approach.
Yeah that's more or less "don't do simple one liners in your application code - write a simple library that does the simple thing, but wraps the simple thing in lots of checks"
There probably is a "design pattern" for that but darned if I can draw it in UML
The fact that researchers get it wrong is, well, unsurprising. LLMs might actually be an improvement.