[CS] 의존성에 대하여

Logun·2023년 9월 13일
0

CS

목록 보기
11/17
post-thumbnail

✅ 의존성 역전 원칙(DIP)


✨ 먼저 알아야 할 내용

  • 의존성 역전 원칙
    유연성이 극대화된 시스템
    추상에 의존하며 구체에는 의존하지 않는 것을 의미한다.

  • 추상 (interface)
    구체적인 구현 방법이 포함되어 있지 않은 형태를 의미한다.

  • 구체
    구체적인 일련의 동작과 흐름을 의미한다. 이런 구체적인 동작들은 굉장히 빈번하게 변경 될 여지가 많다.

  • 결과
    외부요소에 직접적으로 의존하는 코드를 최소화하고, 전체적인 제어권을 우리의 애플리케이션 안으로 가져 올 순 있다.

🎈 적용

구체가 아닌 추상에 대한 의존성을 중간에 추가하게 되면 특정 시점에서 코드의 실행 흐름(제어 흐름)과 의존성이 방향이 반대로 뒤집히기에 이를 “의존성 역전 원칙(DIP)”이라고 부르며 IoC(Inversion of Control)이라고도 표현한다.

class LocalTokenRepository {
  #TOKEN_KEY = "ACCESS_TOKEN";

  save(token) {
    localStorage.setItem(this.#TOKEN_KEY, token);
  }

  get() {
    return localStorage.takeItem(this.#TOKEN_KEY);
  }

  remove() {
    localStorage.removeItem(this.#TOKEN_KEY);
  }
}

const tokenRepository = new LocalTokenRepository();


fetch("todos", {
	headers:{
		Authorization:tokenRepository.get();
	}
}

fetch("todos", {
	headers:{
		Authorization:tokenRepository.get();
	}
}

fetch("todos", {
	headers:{
		Authorization:tokenRepository.get();
	}
}
  • 호출흐름: fetch → tokenRepository Interface(추상) tokenRepositry Class(구체) → localStorage

  • 의존성방향: fetch → tokenRepository Interface(추상) tokenRepositry Class(구체) → localStorage

✅ 의존성 주입


🎉 내용

의존성 주입이란 특정한 모듈에 필요한 의존성을 내부에서 가지고 있는 것이 아니라 해당 모듈을 사용하는 입장에서 주입해주는 형태로 설계하는 것을 의미한다.

  • 잘못된 의존성 주입
class LocalTokenRepository {
  #TOKEN_KEY = "ACCESS_TOKEN";

  save(token) {
    localStorage.setItem(this.#TOKEN_KEY, token);
  }

  get() {
    return localStorage.getItem(this.#TOKEN_KEY);
  }

  remove() {
    localStorage.removeItem(this.#TOKEN_KEY);
  }
}

class HttpClient {
  constructor(baseURL) {
    this.baseURL = baseURL;
    this.tokenRepository = new LocalTokenRepository();
  }

  fetch(url, options = {}) {
    return window.fetch(`${this.baseURL}${url}`, {
      ...options,
      headers: {
        Authorization: this.tokenRepository.get(),
        ...options.headers,
      },
    });
  }
}

const httpClient = new HttpClient(process.env.BASE_URL)
  • 성공한 의존성 주입
class LocalTokenRepository {
  #TOKEN_KEY = "ACCESS_TOKEN";

  save(token) {
    localStorage.setItem(this.#TOKEN_KEY, token);
  }

  get() {
    return localStorage.getItem(this.#TOKEN_KEY);
  }

  remove() {
    localStorage.removeItem(this.#TOKEN_KEY);
  }
}

class SessionTokenRepository {
  #TOKEN_KEY = "ACCESS_TOKEN";

  save(token) {
    sessionStorage.setItem(this.#TOKEN_KEY, token);
  }

  get() {
    return sessionStorage.getItem(this.#TOKEN_KEY);
  }

  remove() {
    sessionStorage.removeItem(this.#TOKEN_KEY);
  }
}

class TestTokenRepository {
  constructor() {
    this.#token = null;
  }

  save(token) {
    this.#token = token;
  }

  get() {
    return this.#token;
  }

  remove() {
    this.#token = null;
  }
}

class HttpClient {
  constructor(baseURL, tokenRepository) {
    this.baseURL = baseURL;
    this.tokenRepository = tokenRepository;
  };

  fetch(url, options = {}) {
    return window.fetch(`${this.baseURL}${url}`, {
      ...options,
      headers: {
        Authorization: this.tokenRepository.get(),
        ...options.headers,
      },
    });
  }
}

// ver1
const localTokenRepository = new LocalTokenRepository();
const httpClient = new HttpClient(process.env.BASE_URL, localTokenRepository);

// ver2
const sessionTokenRepository = new SessionTokenRepository()
const httpClient = new HttpClient(process.env.BASE_URL, sessionTokenRepository);

// ver3
const testTokenRepository = new TestTokenRepository()
const httpClient = new HttpClient(process.env.BASE_URL, testTokenRepository);
  • 의존성 주입을 적용하면 좋은 점은 해당 모듈에서 직접적으로 의존성을 가지고 있지 않기 때문에 모듈 내부의 코드는 전혀 건드리지 않고 모듈 외부의 일부 코드만 수정함으로서 동작을 변경할 수 있게 된다는 점이다.

  • 의존성 주입을 이용해서 필요한 모듈을 클래스 내부에서 가지고 있는 것이 아니라, 클래스를 생성할 때 외부에서 주입하는 식으로 변경하게 되면 추후에 HttpClient의 코드 수정 없이 HttpClient에서 사용하는 tokenRepository와 연관된 동작을 쉽게 변경해서 다양하게 사용할 수 있게 된다. (OCP: Open-Closed Principle)

  • 이는 곧 프로그램의 유연성, 테스트의 용이성, mocking등을 쉽게 활용할 수 있게 된다는 의미입니다.

  • 함수의 경우에는 인자를 통해서 내부에서 사용할 요소를 전달받을 수 있는데, 동작을 내부에서 전체 다 가지고 있는 것이 아니라, 외부에서 받을 수 있게 설정하면 훨씬 더 유용하게 사용할 수 있게 되는 것을 생각해보면 된다.


참고자료

  • 원티드 프리온보딩
profile
로건의 개발이야기

0개의 댓글