It helps when you can use the type system to restrain what can touch what. I've been doing this in some of my high performance C, where some global mutable state is unavoidable - passing around empty structs to indicate context. It doesn't guarantee I don't violate my rules, but it more likely I notice when I do.
It's almost never as bad when you design it yourself. Then the logic and reasons are apparent. Coming into such a system from the outside can be tough though. An explanation of the rationale and pre and post conditions is very helpful, even if all it does is keep a future programmer from trying to circumvent the system and causing the problems it was implemented to avoid.