많은 프로젝트에서 싱글톤을 자주 쓰고 있다. 나 역시도 많이 써왔다.
그 이유는 간단하다. 쓰기가 매우 편하다.
언제 어디서든 쉽게 호출할 수 있고, 데이터 캐싱 역할까지 맡기면서 쓰기 좋다.
하지만 이렇게 편리하게 쓰면서도, 그 안에는 여러 가지 문제들이 숨어 있다.
오늘 포스팅에서는 이 문제를 구조적으로 어떻게 해결할 수 있는지, 간단한 로그인 샘플 프로젝트를 만들어서 풀어볼 생각이다.
로그인 프로젝트를 예제로 선택한 이유
회사에서 프로젝트를 진행할 때, 가장 초반에 마주하는 게 바로 로그인이다.
특히 빌드 환경(Dev, QA, Live)에 따라 실행 과정, 로그인 플로우, 접속 주소 등이 달라진다.
그만큼 분기 처리가 많아지고, 구조적으로 깔끔하게 정리하지 않으면 관리가 힘들어진다.
게임을 시작하는 첫 번째 관문이 로그인이라 생각했고, 그래서 이번 샘플도 로그인 프로젝트를 기반으로 진행해보기로 했다.
그래서 싱글톤에 문제가 뭔데?
아래는 싱글톤으로 로그인 서비스를 구현 내용이다.
// LoginPanel.cs
public class LoginPanel : MonoBehaviour
{
public void OnClickLogin()
{
AuthService.Instance.Login("testId", "1234");
}
}
// AuthService.cs
public class AuthService
{
private static AuthService _instance;
public static AuthService Instance => _instance ??= new AuthService();
public bool IsLoggedIn { get; private set; }
public void Login(string id, string pw)
{
// Dev, QA, Live 분기를 여기서 직접 처리
#if DEV
string url = "https://dev-login.server.com";
#elif QA
string url = "https://qa-login.server.com";
#else
string url = "https://live-login.server.com";
#endif
// 실제 로그인 로직 (간단화)
Debug.Log($"Login Request → {url} : {id}/{pw}");
IsLoggedIn = true;
}
}
문제점으로 크게 3가지다.
1. AuthService가 싱글톤인 만큼 어디서나 호출 할 수 있다. (뭐 예를 들어 LoginManager.cs이런 매니저류 클래스)
2. 환경 분기 지옥이다. (Dev, QA, Live)가 내부에 하드코딩 되어있다. (지금은 url만 있지만, 환경에 따라 QA는 자동로그인, DEV는 테스트 로그인만 가능, LIVE는 보안로직 강화 등 분기 지옥이 시작된다)
3. 테스트 환경 변경 어려움 (이건 앞으로 추가적인 예시로 설명 보강하겠다)
실무에서 느낀 문제
실제 회사 프로젝트에서 로그인 과정을 싱글톤으로 관리하다 보면, 환경에 따라 다른 주소/설정/로직을 처리하는 코드가 한 군데에 몰린다. 결과적으로:
- 조건문이 계속 늘어나고
- 유지보수가 점점 힘들어지며
- 테스트 환경에서 특정 동작만 분리하기도 어렵다
즉, 편하다고 쓰던 싱글톤이 장기적으로는 프로젝트 속도를 늦추는 원인이 될 수 있다.
그~래서 이부분을 해결 할 수 있는 방법이 DI(Dependency Injection)이다.
DI(Dependency Injection)란?
DI(의존성 주입)은 말 그대로 객체가 필요한 의존성을 직접 만들지 않고, 외부에서 넣어주는 방식
쉽게 말해서
- 싱글톤: “내가 필요하면 직접 가져다 쓴다.”
- DI: “필요한 건 외부에서 준비해주고, 나는 받기만 한다.”
왜 좋은가?
- 테스트성
- 명시적 의존성
- 확장성
DI(의존성 주입)로 해결할 수 있는 포인트
DI는 필요한 객체를 스스로 만들지 않고, 외부에서 주입받는 방식이다.
이를 통해 다음과 같은 개선이 가능하다:
- 테스트성: 실제 서비스 대신 Mock/Stub 객체를 주입해서 테스트 가능
- 명시적 의존성: 어떤 클래스가 무엇을 필요로 하는지 코드에 드러남
- 확장성: Dev, QA, Live 환경별로 다른 객체를 주입하면 깔끔하게 분리 가능
마무리 & 다음 편 예고
이번 글에서는:
- 싱글톤을 왜 많이 쓰는지
- 그로 인해 어떤 문제가 발생하는지
- 로그인 샘플 프로젝트를 예제로 선택한 이유
까지 다뤄보았다.
다음 글에서는 실제로 VContainer를 사용해 DI 환경을 구성하고,
간단한 로그인 플로우를 어떻게 개선할 수 있는지 코드와 함께 살펴볼 예정이다.
깃허브: