002. 의존성 주입
"소소한 백엔드 개발 이야기 97" 이라는 주제로 잡다하고 가벼운 글을 작성해서 공유합니다. 매주 주말 1편씩 발행 목표로 시작하였지만, 생업으로 인해서 몇주 늦어질 수 있습니다. 시니어 개발자에게는 너무 쉬운 내용이며, 주니어 개발자에게 적합할 것입니다.
이번 주 주제는 의존성 주입 입니다. 일요일 오후에 가볍게 작성한 글이라서, 내용이 허접합니다. 가벼운 마음으로 편하게 읽어주시면 됩니다. 잘못된 내용은 댓글로 제보해주세요!!
001. Java equals(), hashCode()
003. 백엔드 vs 프론트엔드 vs 풀스택 개발자
004. 미정
...
100. 미정
소프트웨어에서 어떤 작업을 처리하기 위해서, 다른 객체가 필요한 경우가 있다. 이때 필요한 다른 객체가 바로 의존성이다.
아래와 같이 간단한 요구사항을 구현해보자.
- 사용자로부터 검색어를 입력받아서, 웹문서를 검색 결과를 응답한다.
- 네이버 오픈API 를 메타 데이터 조회 용도로 사용한다.
필요한 입력 값은 String 타입의 검색어 이다. 이때 우리는 네이버 오픈 API 를 사용해야하기 때문에, 검색 서비스 입장에서, 네이버 오픈 API 는 의존성이다.
네이버 오픈 API 사용을 위해서 NaverOpenAPIRepository 라는 객체를 생성해서 사용하였다.
하지만 위와 같은 방법은 필요한 의존성을 모든 메서드에서 생성해야 하는 상황이다. 그래서, 보통 의존성은 아래 코드와 같이 생성자에서 정의해서 사용하는 것이 좋다.
SearchService 클래스는 NaverOpenAPIRepository 에 매우 강하게 결합하고 있다. 만약, 네이버 오픈 API 를 카카오 오픈 API 로 변경해야 하는 상황이라면 어떻게 해야할까? 간단하다. 생성자에서 의존 객체를 변경해주면 된다.
하지만 위와 같은 방법은, 의존 객체에 너무 강하게 결합되어 있다.
NaverOpenAPIRepository 에서 KakaoOpenAPIRepository 로 변경하게 되면, SearchService 에서도 변경을 해야 하는 상황이다.
의존성 주입에 대한 설명은 위키백과 를 참고하였다.
소프트웨어 엔지니어링에서 의존성 주입(dependency injection)은 하나의 객체가 다른 객체의 의존성을 제공하는 테크닉이다. "의존성"은 예를 들어 서비스로 사용할 수 있는 객체이다. 클라이언트가 어떤 서비스를 사용할 것인지 지정하는 대신, 클라이언트에게 무슨 서비스를 사용할 것인지를 말해주는 것이다. "주입"은 의존성(서비스)을 사용하려는 객체(클라이언트)로 전달하는 것을 의미한다. 서비스는 클라이언트 상태의 일부이다. 클라이언트가 서비스를 구축하거나 찾는 것을 허용하는 대신 클라이언트에게 서비스를 전달하는 것이 패턴의 기본 요건이다. 의존성 주입의 의도는 객체의 생성과 사용의 관심을 분리하는 것이다. 이는 가독성과 코드 재사용을 높혀준다. 의존성 주입은 광범위한 역제어 테크닉의 한 형태이다. 어떤 서비스를 호출하려는 클라이언트는 그 서비스가 어떻게 구성되었는지 알지 못해야 한다. 클라이언트는 대신 서비스 제공에 대한 책임을 외부 코드(주입자)로 위임한다. 클라이언트는 주입자 코드를 호출할 수 없다. 그 다음, 주입자는 이미 존재하거나 주입자에 의해 구성되었을 서비스를 클라이언트로 주입(전달)한다. 그리고 나서 클라이언트는 서비스를 사용한다. 이는 클라이언트가 주입자와 서비스 구성 방식 또는 사용중인 실제 서비스에 대해 알 필요가 없음을 의미한다. 클라이언트는 서비스의 사용 방식을 정의하고 있는 서비스의 고유한 인터페이스에 대해서만 알면 된다. 이것은 "구성"의 책임으로부터 "사용"의 책임을 구분한다. [3]
코드가 추상화에 의존해야 한다고 명시하고 있다. 의존성 역전의 목표는 구상적인 것에 결합하기보다는 추상적인 것에 결합하는 것이다. [1]
- 의존성 역전 : 의존체들을 역전시키는 원칙
- 의존성 주입 : 의존체들을 역전시키는 행위
- 생성자 주입 : 의존성 주입의 방법 중, 생성자를 통해서 의존성을 주입하는 방법
의존성 주입을 사용하기 위해서 인터페이스를 정의한다.
인터페이스를 구현하는 KakaoOpenAPIRepository , NaverOpenAPIRepository 클래스를 정의한다.
SearchService 에서는 의존성 객체를 직접 생성하지 않는다. 인터페이스를 생성자에서 주입 받는다.
그림을 그려보면 아래와 같다.
SearchService 클래스는 OpenAPIRepository 인터페이스의 어떤 구현체가 주입이 되어도 영향을 받지 않는다. 대신, SearchService 를 사용하는 곳에서 구현체를 주입해줘야 한다.
필자의 글이 이해가 되지 않는다면, 직접 소스 코드를 작성해보길 바란다.
의존 객체 주입은 유연성과 테스트 용이성을 높여준다. [2]
간혹, 신입 개발자들과 대화해보면, DI 는 스프링의 개념으로 알고 있는 주니어가 꽤 많다. 의존성 주입과 프레임워크는 별개의 개념이다. 단지, 스프링 같은 의존성 프레임워크에서 의존성 주입을 핵심 기능으로 제공하기 때문에, 주니어 개발자들이 오해를 많이 하고 있다. 스프링 프레임워크가 없어도 의존성 주입을 사용할 수 있다. 위 작성한 코드는 순수 자바 코딩이다. 스프링과 전혀 관련이 없다.
스프링 프레임워크는 의존성 주입을 지원하는 경량 컨테이너 프레임워크이다. 위 코드에서는 SeachService 클래스에 Repository 구현체를 주입해주는 코드를 작성하였는데 개발자가 직접 의존성 주입을 작성하였다. 반면에 스프링 프레임워크는 의존성 주입을 대신 해준다. 단, 개발자는 어떻게 주입해야 한다고 명시를 해줘야 한다.
의존성 주입이 되는 객체는, 스프링 컨테이너에서 관리를 하는데.. 이런 객체들을 Bean(이하 빈) 이라고 부른다. 빈 객체들은 스프링 애플리케이션이 실행되는 시점에 스프링 IoC 컨테이너에 등록이 되며 관리 대상이 된다.
그리고 스프링 프레임워크는 이런 빈 객체를 의존성 주입을 대신 해준다.
.....
시간 관계상 자세한 내용은 생략하겠다. ㅠㅠ
심심한 개발자는, 아래 글을 참고하길 바란다.
https://brunch.co.kr/@springboot/532
이번 글에서는 의존성 주입에 대해서 설명하였다. 너무 허접하게 작성하였는데, 주니어 개발자는 반드시 의존성 주입에 대해서 따로 공부하길 바란다.
다음 글에서는 진로를 고민중인 취준생 대상으로, 백엔드 개발자 와 프론트엔드 개발자 커리어 차이에 대해서 설명하고, 각자 어떤 방향으로 진로를 정하는게 좋을지에 대해서 이야기를 나눠보겠다.
[1] 객체지향 사고 프로세스 [제이펍 출판사]
[2] 이펙티브 자바 [인사이트 출판사]
[3] 위키백과 : https://ko.wikipedia.org/wiki/의존성_주입