본문 바로가기

DesignPattern

[DesignPattern] 의존성 주입(Dependency Injection) 왜 필요한가

최근 프로젝트를 진행하면서 처음으로 hilt를 사용하여 의존성 주입을 사용하여 보았다. 의존성 주입의 필요성에 대해 자세히 알아보고자한다.

 

의존성 주입(Dependency Injection)이란

의존성 주입은 필요한 객체를 직접 생성하거나 찾지 않고 외부에서 넣어 주는 방식이다.

의존성 주입 그 자체는 클래스간 의존성을 외부에서 주입하는 것을 뜻하지만 일반적으로 우리가 사용하는 의존성 주입은

클래스에 대한 의존성의 인터페이스화를 통한 코드 유연성 증대 & 클래스의 인스턴스를 외부에서 생성하여 주입을 동시에 하는 방향으로 진행된다.

 

그렇다면 의존성이란 무엇일까?

 

의존성이란

객체 지향 프로그래밍에서 클래스간에 의존성이 있다는 것은 클래스간에 의존 관계가 있다는 것을 의미한다.

즉, 클래스 간에 의존 관계가 있다는 것은 한 클래스가 바뀔 떄 다른 클래스가 영향을 받는다는 것을 의미한다.

 

클래스간 의존관계에 있는 경우 코드를 변경한다면 해당 변경에 의존성을 갖는 코드를 하나라도 수정하지 않는 곳이 있다면 오류가 발생될 것이므로 코드의 품질은 물론 안정성이 떨어진다. 이러한 점을 방지하기 위해 우리는 의존성을 유연하게 만들어야한다.

 

그렇다면 어떻게 의존성을 유연하게 만들 수 있을까?

유연하게 만들기 위해서는 소스 코드 의존성이 추상에 의존하며 구체에는 의존하지 않도록 만들어야한다.

 

추상 인터페이스에 변경이 생기면 이를 구체화한 구현체들도 따라서 수정해야 한다.

반대로 구체적인 구현체에 변경이 생기더라도 그 구현체가 구현하는 인터페이스는 대다수의 경우 변경될 필요가 없다.

따라서 인터페이스는 구현체보다 변동성이 낮다.

즉 변동성이 큰 구현체에 의존하는 것을 지양하고 안정된 추상 인터페이스를 선호한다.

이렇게 의존 역전 원칙에 따라 인터페이스로 클래스로부터 의존성을 유연하게 만들 수 있다.

 

의존 역전 원칙 (DIP)

DIP 원칙이란 객체에서 어떤 Class를 참조해서 사용해야하는 상황이 생긴다면,
그 Class를 직접 참조하는 것이 아니라 그 대상의 상위 요소 (추상 클래스 or 인터페이스)로 참조하라는 원칙이다.
(변동성이 큰 구체 클래스를 참조하지 않고, 대신 추상 인터페이스를 참조)

 

의존성 주입의 필요성

의존성 주입(Dependency Injection)을 받으면 클래스 간의 결합도가 약해진다.

즉, 클래스간의 결합도가 약해진다는 것은 한 클래스가 변경될 경우 다른 클래스가 변경될 필요성이 적어진다.

 

- 클래스간의 결합도가 약해져 리팩토링이 용이해진다.

- 클래스간의 결합도가 약해져 특정 클래스를 테스트하기 편해진다.

- 인터페이스 기반 설계는 코드를 유연하게하고 확장을 쉽게 한다.

- UI가 있는 프로그램에서는 생명주기가 중요한데, 생명주기별로 Container를 관리할 수 있게 되면 리소스 낭비를 방지 할 수 있다.

 

안드로이드 앱에서 의존성 주입을 사용하면, 앱의 여러 컴포넌트(Activity, Fragment, Service, ViewModel 등)에서 공통적으로 사용되는 객체(예: 데이터베이스, 네트워크 등)를 한 곳에서 관리하고, 이를 각각의 컴포넌트에서 사용할 수 있다.

이를 통해 코드의 중복을 줄이고, 유지보수와 테스트 용이성을 증가시킬 수 있다.

 

 

의존성 주입 어떻게 ?

DI 자체의 구현은 매우 간단하다.

사용할 객체를 전달받을 수 있는 방법을 제공하면 DI를 적용하기 위한 모든 준비가 끝난다.

 

안드로이드에서는

의존성 주입을 하기위한 라이브러리로 Dagger Hilt 가 있다.

 

 

마치며 ...

DI에 대해 막연하게 코드 중복을 줄일 수 있다는 정도만 알고있었는데 왜 쓰면 좋은지에 대해 자세히 알아보니 더욱 중요성을 느끼게 되었다. 현재 진행중인 프로젝트에 hilt를 적용하며 리팩토링을 해봐야겠다.