DIP

movie·2022년 3월 13일
4

의존성 역전 원칙 (Dependency Inversion Principle, DIP)


리뷰어님의 피드백 🍔

로또 미션 2단계 PR에서

Lotto라는 도메인에 한정된 프로젝트다보니 
이번 프로젝트에서 생각해볼만한 부분은 아니지만 
OOP에 관심이 있으시다면 
DIP(의존성 역전 원칙)에 대해 알아보시는 것도 좋을 것 같아요

만약 로또만 있는게 아니라 다트게임이 추가될 수 있다고 생각해봤을 때 
Dart에 관한 Prize, Bundle(다트를 여러번 던진다의 개념의 Bundle)을 
새로 만들지 않고 생성자로 model과 처리할 방법에 대한 클래스를 인자로 받아 처리할 수 있는데요.

그렇게되면 Prize나 Bundle은 어떻게 동작하는지에 대한 추상화 메서드만 구현해두고 
인자로 받은 모델과 처리방법에 대한 클래스만으로 변경없이 가져갈 수 있어요.

하위 모듈을 새로 만들어서 쉽게 교체하는데 의미가 있다고 생각하는데 
관심이 있으시다면 위처럼 모듈을 변경해서 교체할 수 있는 패턴인 
전략패턴에 대해 공부해보시면 좋을거에요! 🥕

확장성 있는 설계나 추상화에 대해 한번 더 고민해볼 공부가 될 것 같아
추천드려요!

위와 같은 피드백을 받았다.

  1. 리뷰어님께서 OOP를 꺼내신 이유는 내가 class를 사용해 객체를 생성하고 private method를 작성했기 때문인 것 같다.
  2. DIP를 언급하신 이유는 여러 개의 도메인이 프로젝트의 존재한다면?라는 의문에서 언급하신 것 같다. - 확장성 있는 설계를 위해

나는 DIP를 들어는 봤지만, 전혀 사용해보지 않았기 때문에 리뷰어님이 주신 링크를 참고하여 공부를 진행했다.



의존성 주입 (Dependency Injection, DI)?

  • 하나의 패턴
  • 모듈 간의 의존성을 줄인다.
  • 의존성을 인자로 전달
  • 의존성을 외부로 주입해주므로써 모듈을 쉽게 갈아끼울 수 있다.
  • 모듈을 독립적으로 만드므로 유연성을 높인다.


내 코드가 확장되지 않는 이유

리뷰어님의 말씀대로 도메인에 로또와 다트가 존재한다고 생각해보자.
로또와 같이 다트도 dartBundle을 필요로 한다.

// src/js/model/LottoBundle.js
export default class LottoBundle {
  #lottos = [];

  get lottos() {
    return this.#lottos;
  }

  ...

  #pushLottoToBundle() {
    const lotto = new Lotto(); // 로또 모델

    lotto.generateLottoNumbers();
    this.#lottos.push(lotto);
  }

  ...
}

다트에 대한 Bundle을 추가해야할 떄 문제가 발생한다.

  • LottoBundle이 로또에만 귀속되어 있기때문에 로또 이외의 Bundle을 만들려면 새로 짜야한다.
  • LottoBundle만을 위한 테스트가 어렵다. Lotto모델도 코드에 포함되어 있기 때문이다.

즉, 현재 코드는 확장성이 떨어진다.



추상화를 통해 확장성 있는 설계를 해보자.

// 상위 모듈
class Bundle {
  constructor(items, manager) {
    this.items = items;
    this.manager = manager;
  }

  doSomething() {
    this.manager.printWho();
  }
}

// 주입되는 하위 모듈들

class LottoModel {
  #numbers;

  constructor(numbers) {
    this.#numbers = numbers;
  }
}

class DartModel {
  #score;

  constructor(score) {
    this.#score = score;
  }
}

class LottoManager {
  #item = 'Lotto';

  printWho() {
    console.log(this.#item);
  }
}

class DartManager {
  #item = 'Dart';

  printWho() {
    console.log(this.#item);
  }
}

// 의존성 주입
const lottoBundle = new Bundle(
  new LottoModel([1, 2, 3, 4]),
  new LottoManager()
);
const dartBundle = new Bundle(new DartModel(10), new DartManager());

lottoBundle.doSomething(); // Lotto
dartBundle.doSomething(); // Dart

이게 맞는지는 잘 모르겠지만.. 의존성을 주입해주므로써 Bundle이라는 클래스로 lottoBundledartBundle를 모두 만들 수 있다.



DIP

이 원칙은 두가지 중요한 요소를 가지고 있습니다.

  1. 상위 모듈은 하위 모듈에 종속되어서는 안됩니다. 둘 다 추상화에 의존해야 합니다.
  2. 추상화는 세부사항에 의존하지 않습니다. 세부사항은 추상화에 의해 달라져야 합니다.

즉, 세부사항은 상위 모듈이 아닌 주입되는 하위 모듈에 의해 정해져야 한다.



분명 읽을 때는 이해가 됐는데, 직접 코드를 짜보려고 하니깐 너무 어려웠다. 그래서 실제 코드를 리팩토링해보는 것이 아니라 공부 용도의 코드를 작성해본 것 같다. 아직까지의 미션에서는 도메인이 대부분 하나였기 때문에 써보지 못했지만, 다음 미션에서는 써볼 수 있을 것 같다.




참고

profile
영화보관소는 영화관 😎

0개의 댓글