I liked using singletons back in the day, but now I simply make a struct with static members which serves the same purpose with less verbose code. Initialization order doesn't matter if you add one explicit (and also static) init function, or a lazy initialization check.
> A bit like how java people insisted on making naive getFoo() and setFoo() to pretend that was different from making foo public
But it's absolutely different and sometimes it really matters.
I primarily work with C# which has the "property" member type which is essentially a first-class language feature for having a get and set method for a field on a type. What's nice about C# properties is that you don't have to manually create the backing field and implement the logic to get/set it, but you still have the option to do it at a later time if you want.
When you compile C# code (I expect Java is the essentially same) which accesses the member of another class, the generated IL/Bytecode is different depending on whether you're accessing a field, property or method.
This means that if you later find it would be useful to intercept gets or updates to a field and add some additional logic for some reason (e.g. you want to now do lazy initialization), if you naively change the field to a method/property (even with the same name), existing code compiled against your original class will now fail at runtime with something like a "member not found" exception. Consumers of your library will be forced to recompile their code against your latest version for things to work again.
By having getters and setters, you have the option of changing things without breaking existing consumers of your code. For certain libraries or platforms, this is the practical difference between being stuck with certain (now undesirable) behaviour forever or trivially being able to change it.
Adding lots of code for the common case to support consumers of the code not recompiling for some uncommon potential future corner-cases seems like a bad deal.
In a product world where customers are building on your platform, requiring that they schedule time with their own developers to recompile everything in order to move to the latest version of your product is an opportunity to lose one or more of those paying customers.
These customers would also be quite rightfully annoyed when their devs report back to them that the extra work could have been entirely avoided if your own devs had done the industry norm of using setters/getters.
Maybe you're not a product but there are various other teams at your organization which use your library, now in order to go live you need to coordinate with various different teams that they also update their code so that things don't break. These teams will report to their PMs how this could have all been avoided if only you had used getters and setters, like the entire industry recommends.
Unless you're in a company with a single development team building a small system whose code would never be touched by anyone else, it's a good idea to do the setters/getters. And even then, what's true today might not be true years from now.