Where you know code boundaries are an issue I've found functional designs tend to work a little better than OOP with regards to managing transactions but a lot of that could just be down to how my brain is wired (while I'm not a FP evangelist I do tend to favour breaking code down to stateless functions rather than stateful classes).
It's fair to say spaghetti code will be a problem on most reasonably mature code bases but there are approaches and frameworks that help somewhat with managing transactions across code boundaries -- just as there are tools that make working with transactions harder. But in my experience there are much harder problems to solve than working with transactions.
> but it's not like they are a zero-overhead feature.
Is there such thing as a zero overhead feature? (I say this semi-flippantly).
The only thing that should ever stop you from returning a resource is a malicious scheduler.
You might want to take a look at rust.
To span a transaction over two functions, it has to be assigned to some variable and the lifetime of this variable is tracked by the compiler.
Many languages have some sort of `finally` or `with` construct tailored for this use case.
Remember, we’re code writers, not arbitrary discriminators.
The question "prove this program reliably closes the transaction I started" starts to become equivalent to "prove this program halts"
Obviously they are useful tools and heavily used, but it's not like they are a zero-overhead feature.