This is a typical conflict, and I think my main problem is that I spend too much time worrying about it. The important thing is that you make sure that they cannot become inconsistent (you can do this by always going through a function that ensures that when updating them). A thing I have done somewhat recently is:
where the value of the corresponding variable is derived (in just one place that is called when any input changes!) from many inputs, and it's the authoritative source of information. If you want to know whether the current state allows to proceed with login (which can be local if so configured or the connection definitely failed), call:
static bool connectionStateAllowsLogin(AuthConnectionState state)
{
return state == Disabled || state == Connected || state == TimedOut;
}
(Note for people who don't know C++: this is a file-static function, which is basically as private as it gets in C++, and it's also a pure function, not by any language feature though. It could access globals.)
It has a couple of sister functions like isWaitingForWhatever() or isLocalLogin().
The naive alternative is a very nasty and error-prone forest of booleans, each of which you must remember to update when something about the connection changes, and to make sure it's all consistent. It's almost impossible to get right without exhaustive testing.
Somehow I often end up with classes containing lists or hash tables containing structs, more often than other people apparently. A technique that is IMO underused is getting creative with the key in a hash table or an ordered map - it does not have to be a primitive type, and even an integer can be divided into ranges or an integer plus a few bit-flags.
I also like to use enums, but these are widely used anyway.
It's hard to say something general because the answer is "it depends".
- minimal (amount and lifetime)
- well conceptualized (~= easy to understand the organization)
- well named
- minimally exposed
- coherent by construction (make inconsistency impossible by design of the format or by offering updating functions that ensure the invariants)
OOP can actually help with some of these things! I develop mainly in C++, which doesn't encourage a purely OOP style like Java.