Dependency Injection(DI, 의존성 주입)
의존성이란?
public class Person {
private name;
public getFormatName() {
Format format = new Format();
}
}
- getFormatName() 메서드는 Format 에 의존성을 가진다.
= Person 클래스는 Format 클래스를 의존하고 있다. - 위와같은 경우는 A 가 B 에 의존하고 있다. (A 는 B 없이 작동 할 수 없음)
의존성이 발생하면 어떤 문제가 발생할까?
- 긴밀한 결합(tight coupling)이 생기므로, Format 클래스가 변경이 되면 Person 클래스도 변경이 된다.
왜? A 는 B 가 없으면 작동을 할 수 없다고 하였다. 그런데 B 가 변경이 일어나면 A 는 그전 처럼 정상 동작을 하는가? 결국에는 B 가 변경됨에 따라 A에도 영향을 준다.
개발을 진행하다 보면, 요구사항, 객체 또는 모듈간의 합성은 언제든지 변경 될 수 있다.
이 처럼 의존성이 높아질 경우, 아래와 같은 단점들이 발생한다.
- 코드 재사용성 감소
- 유지보수 비용 증가
- 테스트 코드 작성 어려움
Javascript 에서 DI ?
ES6 에서 ESM 이 추가가 되었다. (import, export)
Node.js 에서는 CommonJS 모듈을 제공한다.(require, module.exports)
위 내용들만 보면, 굳이 DI 가 필요없는거처럼 보인다. 나 또한 ESM 자체가 싱글턴(singleton)으로 생성해 주기 때문에 필요한 코드내에서 import 해서 사용하면 되지 않는가? 생각을 하였다.
틀린 생각은 아니지만, DI 를 적용하면 코드가 유연해지고 결합도를 낮춘 모듈 작성이 가능하다.
// userRepository.js
import axios from 'axios';
export default {
findUserList() {
return axios.get('/v1/users');
}
}
간단한 예제 코드를 작성하였다. 특별히 문제는 없어보인다.
- (상황1) 그런데 axios 에서 fetch 로 변경을 할 경우는?
- (상황2) 리파지토리를 테스트하기 위해서 무엇을 해야 하는가? 지금은 axios 1개의 의존성만 보이는데, logging 이라던가 이것저것 추가 시, mocking 이 쉬운가?
mock : 테스트를 위한 더미 객체(가짜 객체)
jest 를 활용하면 axios 도 mocking 이 가능
상황1을 해결하려면 어떻게 해야할까?
만약 저렇게 작성한 리파지토리들이 많다면 위의 코드를 싹 변경을 해줘야한다.
변경이 자주 일어난다는거는 확장성이 떨어지고 결합도가 높다는 의미다.
상황2 같은 경우는 userRepository 에 대한 더미 객체를 만들어야 하는데, 기왕이면 외부 라이브러리를 사용안하는게 훨씬 편한 테스트 방식일거다
// fetchUtils.js
export const api = {
vaildTargetUrl(targetUrl) {
return targetUrl === '';
},
get(targetUrl) {
if (!vaildTargetUrl(targetUrl)) return false
return fetch(targetUrl, { method: 'get' });
},
post(targetUrl) {
//...
},
put(targetUrl) {
//...
},
delete(targetUrl) {
//...
},
}
// repositoryIndex.js
import { api } from '../utils/fetchUtils';
import userRepository from './user/index';
export const repository = {
userRepository: userRepository(api),
};
// userRepository.js
export default (api) => ({
findUserList() {
return api.get('/v1/users');
}
})
// example (사용 예)
const getUserList = async () => {
const result = await repository.userRepository.findUserList();
};
의존성 주입을 써서 코드를 리팩토링 하였다.
이제 우리는 api
를 직접 인자로 넘겨주기만 하면 된다.(자바 또는 OOP 에서는 생성자 주입, setter 등에 방법으로 의존성을 주입해주기도 한다)
이제 userRepository 는 axios 와 직접 엮여있지 않은 상태다. 이를 통해서 외부 요소의 변경상항으로 부터 격리가 가능하며 테스트가 쉽고 간단해진다.
- 저렇다고 의존성이 없어진거는 아니다. 우리가 기억할점은 coupling(결합도) 이 낮아짐에 따라 얻는 이점들을 기억해야 한다.
마무리
- 의존성 주입은 유연성을 제공해준다.
- 의존성 주입은 다양한 언어에서 적용되고 사용되어지고 있다.
Inversify, TypeDI, Awilix
등 DI 컨테이너들이 존재한다.
참고
- https://dev.to/paularah/dependency-injection-in-javascript-1bfk
- https://tsh.io/blog/dependency-injection-in-node-js/
부족한 내용이나 잘못된 내용 피드백은 항상 감사합니다!🙂
Author And Source
이 문제에 관하여(Dependency Injection(DI, 의존성 주입)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@katanazero86/Dependency-InjectionDI-의존성-주입저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)