Hard coupling—putting the name of one class inside of another—is a problem for both design and testing. It makes adjusting the objects' boundaries harder because the static names must be changed and different dependencies can't be swapped in for those hard-coupled points. It makes testing harder because you can't test one object without it invoking the other, so focusing a test is difficult. Dependency injection can help with this, but it's really a special case of a more general principle: separating the arrangement of a program's pieces from the work that they actually do.
This screencast is an example of separating arrangement of work, but not by dependency injection. Instead, we separate the data flow between objects from the objects themselves, which eventually allows us to convert to a simple actor-based concurrency model in one smooth transition.
Execute Program
Looking for something more interactive? Try Execute Program, an interactive learning platform from Destroy All Software LLC! It has courses on TypeScript, SQL, regular expressions, JavaScript concurrency, and more. All Destroy All Software subscriptions include full access to Execute Program, or you can subscribe to Execute Program directly.