Project Falcon
Don't call us, we'll call you
A dependency is anything your code knows about. That could be another class, method, or interface. It could also be knowledge of how an object does something. We say that code with a lot of dependencies is tightly coupled, while code with minimal dependencies is loosely coupled.
Code that is polymorphic and exhibits good encapsulation (clean code) is loosely coupled.
Consider the method below from BankingApp. What are its dependencies?
printAccountBalances(out) { const accounts = new Set(); accounts.add(new CheckingAccount()); accounts.add(new SavingsAccount()); accounts.add(new CreditAccount()); for(let a of accounts) { out.log(`Balance is ${a.balance()}`); } }
Let's take them in order.
Our method is dependent on console (or some other output method).
It is also dependent on its log(String) method:
printAccountBalances(out) { out.log(`Balance is ${a.balance()}`); }
Our method is dependent on Set (and its no-arg constructor):
const accounts = new Set();
Our method depends on the existence of an Account type:
const accounts = new Set();
Also, that it has a balance method that returns a value whose toString() method returns a String appropriate for display purposes:
out.log(`Balance is ${a.balance()}`);
Our method depends on their being three types of accounts, each of which isA Account: CheckingAccount, SavingsAccount, and CreditAccount. Also, that each has a default (no-argument) constructor:
const accounts = new Set(); accounts.add(new CheckingAccount()); accounts.add(new SavingsAccount()); accounts.add(new CreditAccount());
To sum up, it is dependent on the following:
Account and its balance() methodCheckingAccount and its default (no-argument) constructorSavingsAccount and its default (no-argument) constructorCreditAccount and its default (no-argument) constructorSetconsole and its log(String) methodDependencies are things that could change and break our code. Tightly coupled code (a lot of dependencies) is fragile.
The collections classes and console are unlikely to change, so we're a bit less worried about those dependencies
A family of techniques used to implement Inversion of Control. The simplest of these are constructor injection and direct instance variable injection (aka field injection). Setter injection is also oft-used, but usually a code smell.
Let's return to BankingApp. It has a lot of dependencies. We could use constructor injection to pass control of Account creation outside of our app. If we were using a framework (like Spring), we would allow the framework to inject our dependencies.
First, we would give our app a constructor that accepts Accounts and an instance variable to store them:
constructor(accounts) { this.accounts = accounts; }
Note that we have already eliminated the dependency on Set! We only know that we're dealing with a Collection.
printAccountBalances(out) { for (let a of accounts) { out.log(`Balance is ${a.balance()}`); } }
Now we have eliminated the dependency on specific Account types as well as how they are constructed. Our method no longer controls how accounts are created or which accounts are created.
We still have several of our stable dependencies on core Java classes. Our acceptance of dependencies should vary inversely with how likely they are to change:
console and its log(String) methodBut our dependencies on application-specific classes have now been reduced to Account and its balance() method.
In our simple example, we still rely on balance() returning something with a toString() method that renders a suitable String for display. In the real world, we would create another class responsible for converting balance to a String, so we would eliminate this dependency as well.
Often expressed as the Hollywood Principle: "Don't call us, we'll call you." (That links to Ward Cunningham's WikiWikiWeb. Not only is it the first wiki on the web, but he invented wikis!)
See Martin Fowler's Inversion of Control Containers and the Dependency Injection pattern.
The dependency inversion principle is the culmination of these tools and techniques. From the lips of our beloved Uncle Bob:
A. High level modules should not depend upon low level modules. Both should depend upon abstractions.
B. Abstractions should not depend upon details. Details should depend upon abstractions.
Easier to say than do, to be sure!

SOLID is an acronym introduced by Michael Feathers and promoted by Uncle Bob.
Dependency inversion is the D in SOLID.
SOLID is a mnemonic for a set of principles that represent an agile, clean object oriented development philosophy:
Remember, be agile or be fragile.