I would say a prerequisite for safe retirement is to have enough to buy a home outright in cash, otherwise mortgages will weigh you down like a stone:6% interest on a 1 million gbp loan in the UK is unpayable for majority of people even in London and yet you wont find anything worth buying there below that price.
Also we should stop saying a house has equity: it doesn't. You are a paying off a loan for a commodity. A house is like a car or groceries: necessary, yes, but not an investment, unless its luxury. This is how we exploded house prices.
> But perhaps we should not be surprised by the lack of interest in fraud exhibited by Twitter’s former management. The tech industry in general suffers from a cancerous disposition towards encouraging fake traffic, fake users, and fake online activity because it makes businesses appear to be more successful than they really are. Criminals are fed millions of dollars by executives who think that price is worth paying if it will mislead investors into believing inflated valuations. The presumption is that current losses are also worth sustaining because the business will turn today’s paper valuation into real value at some vaguely-defined point in the future.
That's it. If you can't figure someone's intentions, look at their actions, and infer the intentions.
At a previous job, we had a product that was attractive with criminals. We were seeing some elevated chargeback rates and refund rates, so I dug in and determined that at least 25% of our new account purchases were fraudulent (unreported stolen credit cards). I put in some rudimentary fraud analysis, and injected a hoop that suspected fraud users had to go through before their account would be billed, simply to prevent the credit card networks from blacklisting our merchant account. The fraud rates dropped considerably with a small false-positive rate, but the new-user metrics slowed with it.
A week after I left my role, the company disabled it. They were sure that the system was a significant cause of some major userbase declines. Within three months, one of their credit card processors threatened to lock them out for elevated fraud rates, and they spent the next six months getting it resolved. Growth never returned.
No one was trying to be dishonest, but no one wanted to look bad, either. The entirety of the metrics showed something was off, but the growth narrative was so important, it was easy to ignore the questionable parts.
This was not a VC-backed business, so the pressure to perform was entirely internal. Nothing was faked, but the success wasn't (entirely) real, either.
Still those bots probably helped make TikTok popular and probably helped boost stock prices, like we see with other social media platforms and even SuperStonk!
> The non-recursive approach would first refactor A into a new private method C that is clearly documented (often with a naming convention as well) to assume that it is called while under lock. Then both A and B call C while holding the lock.
I'm sorry but that's literally advocating for spaghetti code. If the author really wrote a lot of real world code, it doesn't look like it was clean or well structured.
The blog post explains why it's the opposite, not using recursive locks kills two birds with a stone because you know which invariants are enforced at locking boundaries. Therefore, functions that take the lock know exactly what invariants to expect, those that are called with the lock taken don't.
Yeah it seems pretty disappointing to be advocating for invariants protected only by thoughts and prayers (i.e. comments, naming convention) in a statically typed[1] language like C#.
This bit me in Rust when I was goofing off / exploring with one of the AOC'22 puzzles back in December. One of Rust's selling points is supposedly "fearless concurrency" but it turns out deadlocking is trivial to do: did you know a mutex is not re-entrant in rust? Just acquire the lock again in a nested function and blam, at runtime when you reach that codepath you'll learn you have a deadlock.
I'll probably never stop trying new approaches, I love exploring languages for how they can open your eyes but so far Clojure's approach to this problem - by that I mean immutable everything by default and then using atom's, I'm not talking about the richer STM stuff, I haven't played with that yet - is peak concurrency handling in the context of writing business applications.
[1] As I wrote this the 'dynamic' type jumped into my mind, would its presence mean its technically wrong to say c# is statically typed? It's not "only" statically typed I guess is what I'm uncomfortable with.
Indeed. I worked on a non-trivial project (~300kLOC C++) which was heavily multi-threaded and relied on recursive locks. It had lots of issues with not taking locks at the right time and so on.
I took some time to refactor it all to not use recursive locks, instead having a clean boundary between internal (non-locking) methods and external methods which did the locking and called the internal ones.
Not only did our locking issues go away immediately, it lead to a much simpler developer experience since there was never any question if this new function needed to lock or not etc.
I've not written that heavy multi-threaded code since, but my takeaway from the experience was that requiring recursive locks was a sign of poor design.
I forgot to mention performance increased a fair bit as well, since a lot less locking was done.
Instead of one "public" function call resulting in locking the same lock recursively 4-5 times as the "public" function called other functions and so on, a single locking operation was done at the boundary.