It does help by telling you what's wrong. But in a way, increased precision makes the problem worse.
Suppose you have have a language with two categories of functions, those that can fail (returning an error) and those that can't.
It's nice that within the "functions that can fail" category, you don't have to worry about what kind of error it might be. Error propagation can happen in a generic way. Adding a new kind of error doesn't change any API's.
If instead, you have different kinds of errors and declare them everywhere, you end up with a situation like Java's checked exceptions. The problem is being too precise, which doesn't leave room for changes later.
Similarly, we could be very generic about effects. Maybe we could just say "this function has effects" and treat them all the same? By not being precise about what the effects might be, we aren't promising too much, so we allow ourselves room for change.
The downside is that the caller has to assume any effect is possible. This is a fundamental tradeoff between caller and callee convenience. You need to be specific enough for the caller to be able to deal effectively with the effects you declare, but not too specific, or you're painting yourself in a corner.