--- title: Avoid Service Locator Anti-Pattern impact: HIGH impactDescription: Hides dependencies and breaks testability tags: dependency-injection, anti-patterns, testing --- ## Avoid Service Locator Anti-Pattern Avoid using `ModuleRef.get()` or global containers to resolve dependencies at runtime. This hides dependencies, makes code harder to test, and breaks the benefits of dependency injection. Use constructor injection instead. **Incorrect (service locator anti-pattern):** ```typescript // Use ModuleRef to get dependencies dynamically @Injectable() export class OrdersService { constructor(private moduleRef: ModuleRef) {} async createOrder(dto: CreateOrderDto): Promise { // Dependencies are hidden - not visible in constructor const usersService = this.moduleRef.get(UsersService); const inventoryService = this.moduleRef.get(InventoryService); const paymentService = this.moduleRef.get(PaymentService); const user = await usersService.findOne(dto.userId); // ... rest of logic } } // Global singleton container class ServiceContainer { private static instance: ServiceContainer; private services = new Map(); static getInstance(): ServiceContainer { if (!this.instance) { this.instance = new ServiceContainer(); } return this.instance; } get(key: string): T { return this.services.get(key); } } ``` **Correct (constructor injection with explicit dependencies):** ```typescript // Use constructor injection - dependencies are explicit @Injectable() export class OrdersService { constructor( private usersService: UsersService, private inventoryService: InventoryService, private paymentService: PaymentService, ) {} async createOrder(dto: CreateOrderDto): Promise { const user = await this.usersService.findOne(dto.userId); const inventory = await this.inventoryService.check(dto.items); // Dependencies are clear and testable } } // Easy to test with mocks describe('OrdersService', () => { let service: OrdersService; beforeEach(async () => { const module = await Test.createTestingModule({ providers: [ OrdersService, { provide: UsersService, useValue: mockUsersService }, { provide: InventoryService, useValue: mockInventoryService }, { provide: PaymentService, useValue: mockPaymentService }, ], }).compile(); service = module.get(OrdersService); }); }); // VALID: Factory pattern for dynamic instantiation @Injectable() export class HandlerFactory { constructor(private moduleRef: ModuleRef) {} getHandler(type: string): Handler { switch (type) { case 'email': return this.moduleRef.get(EmailHandler); case 'sms': return this.moduleRef.get(SmsHandler); default: return this.moduleRef.get(DefaultHandler); } } } ``` Reference: [NestJS Module Reference](https://docs.nestjs.com/fundamentals/module-ref)