Yes, many times it boils down to practice and (a lot of) discipline. But I think we also want quick ways of "ensuring" that some assumptions hold true, as it frees us from keeping a large amount of contextual information in our head while reasoning about some part of the code. Eg. to get back to the public/private member discussion, you don't have to remember if this member has been touched in some weird way because you know its private. The "no globals" rule of thumb is a rather extreme version of this : you don't have to remember how you manage global state because there's none (although it carries its own price). It's not necessarily the kind of assumption I need, but I understand that it might facilitate some people's thought process.
I personally lean to a C style approach and try to be disciplined, because I find that C++/OOP style puts safeguards where I don't really need them. But sometimes I get lazy or I just forget something, and I get hurt by bugs that would be easy to spot and fix if I had a better way to specify invariants.
For instance, with a state-related bug, if I specified that these functions A and B are purely functional, I don't have to spend time investigating them and can concentrate on this other function C, where I specified that only these variables will be touched, etc... (Also maybe it's just me having a hard time remembering a lot of context in a sufficiently large code base, and I just need practice.)
A lot of subtleties get lost communicating across a forum.
Yeah, and English is not my native language, which doesn't help. I most certainly lack some sense of nuance compared to a native speaker, so don't be offended !