별 볼일없는 학부생이, 동기들과 함께 공부하면서 느꼈던 것을 예쁘게 정리해서 써놓을 다름입니다.
모듈끼리 생긴 의존성은 추상적 의미의 고수준으로 변화되어야 한다.
통상 프로그램을 모듈로 나누어 설계할 때는, 같은 관심(사)을 가지는 코드 뭉치를 묶어 클래스로 이룬다. 워드 프로그램 코드에서는 파일 시스템에 저장하는 코드를 FileSaver로 묶을 것이다. 어쩌면 크롤링한 기사의 정보와 기타 기능 수행을 위해서 Article이라는 클래스로 묶어둘 수도 있다.
클래스가 제공하는 기능을 서비스라고 하자. 그 클래스 바깥에 서비스를 제공하면 그 클래스를 서비스 제공자 Service Provider 이라고 하고, 서비스를 사용하는 클래스를 서비스 사용자 Service Consumer 이라고 할 수 있다. 이 관계를, 서비스 사용자는 서비스 제공자에 의존한다고 표현한다. 단순하게 의존성, 의존관계가 형성되었다고 표현하기도 한다.
서비스 사용자가 서비스 제공자의 서비스를 사용하기 위해서는 서비스 사용자 클래스는 다음처럼 작성될 것이다.

서비스 사용자 ServiceUser
providerRefer을 멤버로 가진다. 이 코드는 내제된 문제가 있다.
1. 서비스 사용자가 무슨 (which) 서비스 제공자를 사용할지는 정적으로 결정된다. 서비스 제공자를 정적으로든 동적으로든 바꾸고 싶다면 프로그래머는 직접 코드를 수정해야 한다.
2. 서비스 사용자와 제공자간 규약이 묵시적이다. 규약이 지켜지지 않으면 프로그램은 실행될 수 없다. 서비스 제공자는 어떤 메서드를 제공하고, 서비스 사용자는 어떤 메서드를 사용할 수 있으며 어떻게 사용해야 하는가?
상기 첫 번째 문제는, 무슨 제공자에 대한 의존성인지가 사용자 클래스에 정적으로 각인되었기 때문이다. 이는 사용자 클래스 외부에서 서비스 사용자가 사용할 제공자를 직접 알려줌으로써 간접적으로 해결할 수 있다. 자신이 사용할 서비스 제공자를 선택할 권리를 외부에 이양하는 것이다. 이를 의존성 주입 Dependency Injection이라고 한다.

그렇다면 서비스 사용자 클래스는 다음과 같이 작성될 것이다.
이 구조는 추가적인 이점을 가지고 있다.
하지만 두 번째 문제를 해결하지 못했다. 코드가 작성되고 나서 시간이 흐르면 묵시적 약속이 잊혀지는 날이 온다. 상속 관계도 불문율을 완전히 지킬수는 없다.

이는 제공자와 사용자 끼리의 규약을 인터페이스로 명시적으로 정하여 해결할 수 있다. 서비스 제공자와 사용자 사이의 약속을 인터페이스로 정하고, 생성자(또는 레퍼런스 설정 메서드)는 그 인터페이스를 구현하는 클래스를 인자로 제공받는다.
서비스 사용자는 기존에 구현된 서비스 제공자라는 구상적인 객체에 의존하는 것에서 벗어나, 규약 인터페이스에 자신의 동작을 의탁한다. 서비스 제공자도 규약 인터페이스를 구현하는 것으로 추상적 객체에 자신을 의탁하게 된다.
일련의 과정을 통해 개선된 구조는 의존성 주입을 직접 코드로 구현한다. 이로써 서비스 제공자 결정 시점과 서비스 사용 시점을 분리하고 서비스 규약을 명시할 수 있다. 그러면 코드의 파편화, 무질서한 확장을 억제할 수 있다.
의존성 주입을 기반으로 하는 프레임워크는 로직을 구현하고, 모듈 끼리의 의존 관계를 설정하는 행위만 개발자에게 맡길 뿐, 무엇을 언제 실행하는지는 프레임워크가 전임한다. 이를 제어의 역전 IoC; Inversion of Control이라고 하며, 클래스 내부 상태를 예측하고 적절한 타이밍에 호출할 클래스를 결정하고 생성하는 일에서 개발자는 해방될 수 있어 의존성 주입은 대규모 개발에서 큰 이점을 가진다고 볼 수 있다.