Good design should be open for extension and closed for modification. You can extend the module instead of modifying some working code.
Abstraction is the Key: for example, a Client should use an Server object that implemented some interfaces instead of a concrete Server object.
Interface’s name should be named more closely associated to the dependent side instead of the implement side.
A function that is closed for modification: if we add some changes for this function, it must be modified for working right, it may unconform OCP. For example, a function that draw all shapes in a shape list, it should be draw shapes one by one, and don’t care this shape should draw in this way, another shape should draw in that way, etc.
No matter how “closed” a module is, there will always be some kind of change against which it is not closed.
Abstraction may gain “closed” software entity(func, module, class, etc), but it also need trade off.