이번 포스팅에선 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 |