Apply refactorings
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(); } }
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.