싱글턴은 정적이지 않다

얼마전 페이스북에서 많은 프로그래머들이 당연시하게 기록자(logger)를 정적(static)으로 사용하는 것을 비판했는데, 비슷한 주장을 하는 다른 분의 글에서 기록자는 인스턴스 범위(scope)에 있지 않고 클래스 범위에 있다는 반론을 발견했다. 나는 반론 제기자에게 그것은 논점을 벗어나니 의존성 역전 원칙(dependency inversion principle)를 공부하라고 조언했다. 아쉽지만 반응에 의하면 아마 내 조언은 무시된 것 같았다.

응용프로그램 또는 프로세스와 생명주기를 함께하는 단일 서비스 인스턴스는 상태를 가지지 않거나 공유 가능한 비싼 자원을 관리하거나 하는 경우에 유용하다. 그런데 이 하나의 서비스 인스턴스는 반드시 정적 변수에 담겨야 하는 걸까? 아니다. 그렇게 하지 말라. 특히 IoC 컨테이너를 사용하고 있다면 그래야 할 이유도 없다. 정적 변수에 담긴 인스턴스는 명시적으로 공유되는 자원임을 의미한다. 이런 자원을 사용하는 클라이언트 코드는 사용하기 어렵고 재사용하기 어렵고 테스트하기 어렵다.

그렇다면 클라이언트 시스템은 싱글턴 서비스 인스턴스에 어떻게 접근해야 할까? 고민할 것 없다. 다른 서비스와 마찬가지로 생성자를 통해 주입하라. 다음 예제 코드를 살펴보자.

using System;

public class SingletonService
{
    public string GetMessage() => "Hello World";
}

public class ClientModule
{
    private readonly SingletonService _service;

    public ClientModule(SingletonService service)
    {
        _service = service ?? throw new ArgumentNullException(nameof(service));
    }

    public void PrintMessage() => Console.WriteLine(_service.GetMessage());
}

public class IocContainer
{
    private readonly Func<ClientModule> _factory;

    public IocContainer(Func<ClientModule> factory)
    {
        _factory = factory ?? throw new ArgumentNullException(nameof(factory));
    }

    public ClientModule GetModule() => _factory.Invoke();
}

public class Program
{
    public static void Main(string[] args)
    {
        var singleton = new SingletonService();
        var container = new IocContainer(() => new ClientModule(singleton));
        Run(container);
    }

    private static void Run(IocContainer container)
    {
        for (int i = 0; i < 5; i++)
        {
            ClientModule module = container.GetModule();
            Execute(module);
        }
    }

    private static void Execute(ClientModule module) => module.PrintMessage();
}

어떤가? 응용프로그램은 SingletonService 인스턴스를 단 하나만 가지지만 코드 어디에도 정적 필드는 존재하지 않는다. ClientModule은 API를 통해 SingletonService에의 의존성이 명시적으로 드러나고 이 의존성이 해결되지 않으면 개체를 생성할 수 없도록 엄격히 설계되었으며 테스트하기 쉽다.

항상 최고의 코드 품질을 유지하는 것은 다양한 이유로 비현실적이다. 정적 기록자 변수를 사용한 프로그래머가 처벌 대상은 아니다. 나름의 사정이 있었을 것이다. 하지만 바람직한 기술 조직은 더 나은 설계에 대해 지속적으로 고민하고 실천하려 노력한다.

싱글턴은 정적이지 않다”에 대한 1개의 생각

  1. jino

    잘 읽었습니다. 컨테이너가 수명관리를 하는 것에 대해서 이해가 어려웠는데 이 글 덕분에 감을 잡을 수 있게 된 것 같아요.

    응답

댓글 남기기