[TIL] Dependency Injection(DI) in JS

Soo·2023년 2월 22일
0

❓ DI이란

클래스간 의존성을 클래스 외부에서 주입하는 것

🟢 장점

  • 의존성 주입을 하지 않았을 때의 코드 [example]
//users-service.js
const User = require('./User');
const UsersRepository = require('./users-repository');

async function getUsers() {
  return UsersRepository.findAll();
}

async function addUser(userData) {
  const user = new User(userData);

  return UsersRepository.addUser(user);
}

module.exports = {
  getUsers,
  addUser
}

위의 코드를 보면, ./users-repository을 require했기 때문에 다른 곳에서 이들을 사용할 때 유동저으로 사용하지 못하고 결과 값이 정해지는 문제점을 볼 수 있다.

다른 곳에서 userRepository의 내용 말고 userDB에서 가져오고 싶어도 사용할 수 없다는 뜻이다.

🤔 How to resolve this

const User = require('./User');

function UsersService(usersRepository) { // check here
  async function getUsers() {
    return usersRepository.findAll();
  }

  async function addUser(userData) {
    const user = new User(userData);

    return usersRepository.addUser(user);
  }

  return {
    getUsers,
    addUser
  };
}

module.exports = UsersService

위의 코드로 고치면 다른 곳에서 UserService.getUsers(아무거나)를 통해 다양한 값을 주어
user.js, userRepository.js -> UserService(내부는 정해져 있음 무조건 userRepo)였던 부분을
user.js -> UserService(userDB)으로 바꿀 수 있다.
user.js -> UserService(userRepo)
user.js -> UserService(kakaoUserRepo)
user.js -> UserService(naverUserRepo)
user.js -> UserService(googleUserRepo)

의존성 주입의 장점은 테스트코드를 작성할 때 더 들어나게 된다.
위의 의존성 주입을 적용하지 않은 코드의 테스트 코드를 보면

const UsersRepository = require('./users-repository');
const UsersService = require('./users');
const sinon = require('sinon') ;
const assert = require('assert');

describe('Users service', () => {
  it('gets users', async () => {
    const users = [{
      id: 1,
      firstname: 'Joe',
      lastname: 'Doe'
    }];

    sinon.stub(UsersRepository, 'findAll', () => {
      return Promise.resolve(users)
    });

    assert.deepEqual(await UsersService.getUsers(), users);
  });
});

서버 호출은 비용이 높은 작업이다.
이를 테스트하기 위해 위의 코드는 userRepository를 모킹하여 완전한 usersService를 만들어야 한다.

🟢 의존성을 잘 주입한 코드는 usersRepository를 모킹 라이브러리 없이 모킹할 수 있다

const UsersService = require('./users');
const assert = require('assert');

describe('Users service', () => {
  it('gets users', async () => {
    const users = [{
      id: 1,
      firstname: 'Joe',
      lastname: 'Doe'
    }];

    const usersRepository = {
      findAll: async () => {
        return users
      }
    };

    const usersService = new UsersService(usersRepository);

    assert.deepEqual(await usersService.getUsers(), users);
  });
});

🟢 TypeScript로 더욱 편해지는 DI

profile
Soogineer's Devlog

0개의 댓글