I fully agree with Konamiman's answer, but I'd like to add one thing:
There are cases where you really don't want that abstraction. And that's fine.
A simple example I like to use here is a class for a 3-dimensional float vector:
class Vector3f {
public:
float x;
float y;
float z;
};
Could you make those fields private and provide setters instead? Sure, you could. But here you might argue that the class is really just supposed to provide a tuple of floats and you don't want any additional functionality. Thus adding setters would only complicate the class and you'd rather leave the fields public.
Now, you can easily construct scenarios where that might bite you later on. For instance, you might one day get a requirement that Vector3f
s are not allowed to store NaN
s and should throw an exception if anyone tries to do so. But such a hypothetical future problem should not be enough to justify introducing additional abstractions.
It's your call as a programmer to decide which abstractions make sense for the problem at hand and which ones would only get in your way of getting the job done. Unnecessary abstractions are over-engineering and will hurt your productivity just as much as not abstracting enough.
Bottom line: Don't blindly use setters everywhere just because someone claimed that's good practice. Instead, think about the problem at hand and consider the tradeoffs.