본문 바로가기

Backend/Node.js

Service Locator (서비스 로케이터)

이번 포스팅에선 DI 와 비슷한 의도를 갖고 있는 다른 패턴인 Service Locator 에 대해 적어보고자 합니다.

 

Service Locator 는 중앙에서 컴퍼넌트를 관리하고 모듈이 필요한 종속성을 로드할 수 있도록 레지스트리 역할을 하는 것입니다.

Service Locator 에 종속성이 등록되어있고, 각 모듈에선 필요한 종속성을 Service Locator 에 요청하는 방식이라고 보시면 될 것 같습니다.

 

export class ServiceLocator {
  private dependencies: Map<string, any>;

  constructor() {
    this.dependencies = new Map();
  }

  public register<T>(name: string, instance: T) {
    this.dependencies.set(name, instance);
  }

  public get<T>(name: string): T {
    const dependency = this.dependencies.get(name);

    if (!dependency) {
      throw new Error('Cannot find dependencies');
    }

    return dependency;
  }
}

export const serviceLocator = new ServiceLocator();

 

아주 심플한 Service Locator 를 만드는 방법은 인스턴스(종속성)를 등록하는 register 와 해당 인스턴스를 요청할 수 있는 get 메서드로 구성하는 것입니다. 뭐 정해진건 없지만, 저는 싱글톤처럼 동작하도록 만들었습니다.

 

import { ServiceLocator } from './service_locator.ts';

class MemberService {
  private readonly serviceLocator: ServiceLocator;
  
  constructor(serviceLocator: ServiceLocator) {
    this.serviceLocator = serviceLocator;
  }
  
  public getMembers() {
    const config = this.serviceLocator.get('config');
    ...
  }
}

 

뭔가 예시를 만들다보니 Service Locator 객체 자체가 DI 형태로 들어가버렸는데.. 그냥 예시로 봐주시기 바랍니다.

Service Locator 패턴은 이제 어떠한 의존성이 필요한 서비스나 컨트롤러, 또는 함수등에서 Service Locator 를 통해

의존성을 불러와 사용하는 것입니다. 위에선 Service Locator 를 통해 등록되어있는 config 를 가져와 로직을 수행하고 있습니다.

 

그럼 저런식으로 사용할 수 있게 Service Locator 에 종속성을 등록하는 작업은 어디서 할까요? 그건 메인 영역에서 합니다.

 

import { serviceLocator } from './service_locator';
import { MemberService } from './service/member_service';

serviceLocator.register<any>('config', config);

const memberService = new MemberService(serviceLocator);

...

 

너무 허접한 예시입니다만.. 이러한 app.ts 와 같은 메인 영역에서 Service Locator 초기화 및 의존성 등록을 담당하게 됩니다.

만들고나니 DI 와 비슷한 것 같기도하고, 제가 예전 회사에서 프레임워크를 쓰지 않고 DI Container 라는걸 직접 구현했었는데 이제 와서 생각해보니 그건 DI Container 가 아니라 Service Locator 에 가까웠던 것 같기도 하네요.

 

DI 와 비교하면, Service Locator 는 단점이 많은 방법입니다.

공통점으로는 둘 다 의존성 처리 책임이 컴퍼넌트 외부로 빠져 있습니다. 또한 의존성이 런타임에 해결되기 때문에

역시나 컴퍼넌트 간의 관계를 식별하기엔 어렵습니다.

 

차이점은 DI 는 생성자 주입등을 통해 주입하는 객체가 명시적이기라도 하지만, Service Locator 는 그마저도 숨어 있으므로 파악하기 더

어려울 수 있습니다. 재사용성이나 테스트에도 단점이 있고, 구현을 보셔서 아시겠지만 하나의 키에 대해 객체는 하나만 등록되므로 만약 같은 타입의 객체를 등록하려면 메서드를 더 만들어야 하는 단점도 있습니다. register 와 같은 메서드와 그대로 노출되어있으니 등록되어
있는 의존성이 변경될 위험도 크구요.

 

이렇다보니 어딘가에선 안티 패턴이라고 말하기도하고, 제가 봐도 DI 를 사용할 수 있는 환경에선 굳이 사용할 필요는 없어 보입니다.

큰 장점이라고 하면 구현이 압도적으로 간단하기 때문에, 바로 위에 적은 것처럼 Service Locator 는 DI 를 사용할 수 없는 환경이거나

비교적 심플한 앱 또는 모듈의 경우엔 사용할 수 있을 것 같습니다.

 

'Backend > Node.js' 카테고리의 다른 글

peer-to-peer load balancing  (0) 2023.01.08
Node.JS 어플리케이션 확장  (0) 2023.01.01
의존성 주입  (0) 2022.12.10
Use Github private packages  (0) 2022.11.20
모듈과 의존성  (0) 2022.11.12