Symptom

Modules reach into each other's internals to coordinate behavior, bypassing public interfaces.

Goal

Cooperation happens through narrow, explicit interfaces; secrets stay secret.

Smellier version

class A { _data; }
class B {
read(a) {
return a._data.value;
}
}

Fresher version

class A { value() { return this._data.value; } }
class B { read(a) { return a.value(); } }
Example source: Illustrative example written for this site, not a quotation from any source.
Pressure

Coupling at the implementation level — refactoring one breaks the other in non-obvious ways.

Tradeoff

Establishing a real public interface between modules forces both sides to commit to a contract; until the interface stabilizes, the boundary is more painful than the original direct access.

Relief

Module boundaries become real; tests exercise the public surface; refactoring is local.

Trap

Building elaborate public APIs between modules that genuinely belong together — the encapsulation overhead exceeds the coupling cost the boundary was meant to fix.