home / skills / willsigmon / sigstack / dependency-injection-setup

dependency-injection-setup skill

/plugins/app-dev/skills/dependency-injection-setup

This skill helps you set up dependency injection in a TypeScript project by creating protocols, implementations, and DI container registrations.

npx playbooks add skill willsigmon/sigstack --skill dependency-injection-setup

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
1.3 KB
---
name: Dependency Injection Setup
description: Add new services to DIContainer, create protocol-based implementations, set up singletons or factories for Leavn app dependency injection
allowed-tools: Read, Edit, Grep
---

# Dependency Injection Setup

## Instructions

Add new services to Leavn's DIContainer:

1. **Create service protocol**:
   ```swift
   // Services/MyDomain/MyServiceProtocol.swift
   public protocol MyServiceProtocol {
       func doSomething() async throws -> Result
   }
   ```

2. **Create implementation**:
   ```swift
   // Services/MyDomain/MyServiceLive.swift
   public final class MyServiceLive: MyServiceProtocol {
       public init() { }

       public func doSomething() async throws -> Result {
           // Implementation
       }
   }
   ```

3. **Register in DIContainer**:
   ```swift
   // For singletons (stateful services):
   private lazy var _myService = MyServiceLive()
   var myService: MyServiceProtocol {
       _myService
   }

   // For factories (stateless services):
   var myService: MyServiceProtocol {
       MyServiceLive()
   }
   ```

4. **Use in ViewModels**:
   ```swift
   let service = DIContainer.shared.myService
   ```

Use this skill when: Creating new service, adding dependency, setting up DI, refactoring to protocol-oriented design

Overview

This skill describes how to add new services to the Leavn DIContainer using protocol-based design and register either singletons or factory instances. It shows how to create a service protocol, implement a concrete class, register it with the container, and consume it from view models. The goal is predictable, testable dependency wiring for the app.

How this skill works

Define a service protocol that exposes the API your feature needs. Provide one or more concrete implementations (live, mock, or test doubles). Register the implementation in the DIContainer either as a singleton for stateful services or as a factory for stateless services. Consume the registered service via DIContainer.shared from view models or other consumers.

When to use it

  • Adding a new domain service to the app
  • Refactoring code to protocol-oriented design for testability
  • Injecting stateful services that must be shared across the app
  • Providing lightweight, stateless helpers per use (factories)
  • Swapping implementations for testing or platform variants

Best practices

  • Always design a small, focused protocol that exposes only required behaviors
  • Use singletons in DIContainer for services that hold shared state or manage resources
  • Use factories when instances are lightweight and should not share state
  • Provide a test/mock implementation that conforms to the same protocol for unit tests
  • Keep registration code minimal and colocated in DIContainer to simplify discovery

Example use cases

  • Create an AuthenticationServiceProtocol, implement AuthServiceLive, register as singleton to share user session
  • Add AnalyticsServiceProtocol and register a factory to create short-lived tracker instances
  • Introduce a RemoteConfigProtocol and register a live implementation plus a mock for tests
  • Refactor networking helpers behind a NetworkClientProtocol to make view models easier to unit test

FAQ

When should I prefer singleton over factory?

Choose singleton for services that represent shared application state or manage shared resources. Use factory for inexpensive, stateless objects that should be independent per consumer.

How do I swap implementations in tests?

Implement a mock/stub that conforms to the protocol and register it in the DIContainer for test runs, or provide a test-only DIContainer instance configured with test doubles.