싱글톤은 안티 패턴일까? #19
Replies: 1 comment
-
발제이펙티브 자바 스터디를 하며 싱글톤이 안티패턴이라는 이야기가 나왔다. 그렇다면 왜 스프링은 싱글톤을 사용하는 것일까? 두 가지 질문에 이야기해보자
0. 싱글톤 디자인 패턴이란?reference) [Singleton Method Design Pattern - GeeksforGeeks](https://www.geeksforgeeks.org/singleton-design-pattern/)
1. 싱글톤은 안티패턴인가?여는 발언리비 : 스프링 진영에서 싱글톤을 사용해서 빈 컨테이너를 구축하고 있기에 긍정적이다. 멀티 스레드 환경에서의 동시성 문제나 경합이 심해지면 문제가 될 수 있지만 stateless한 싱글톤은 괜찮다 에버 : 메모리를 절약할 수 있다. 상황에 맞게 싱글톤 도입은 적합하다 제리 : 싱글톤은 안티패턴이다. 안티패턴이라 함은 유지보수가 어렵거나 에러 발생시 디버깅이 어려운 패턴이라 생각하는데, 싱글톤 사용시 stateless하게 만들어야 하는 것처럼 주의사항이 많다. 이러한 주의사항의 존재만으로 안티패턴이라 불릴 수 있을 것 같다 콜리 : 싱글톤은 안티패턴이다.
1-1) 싱글톤은 SRP를 침해하는가?리비 : 싱글톤이 아닌 객체도 그 생명 주기를 caller 객체가 관리하게 된다. 그럼 생명 주기에 대한 책임은 상위 모듈이건, 하위 모듈이건 누군가가 가지게 된다. 따라서 생명주기 관리의 책임을 또하나의 책임으로 바라보는 건 어색하다. 예를 들어 엔진이란 클래스가 있을 때, 엔진이 스스로 생명주기를 관리하지 않더라도 자동차라는 클래스가 그 생명주기를 관리하게 된다. 그렇다면 자동차는 SRP를 침해한 것인가? 콜리 : 그 경우에는 상위 모듈이 하위 모듈의 생명주기를 컨트롤 하고 있는 구조이다. 그런데 반대로 싱글톤은 생명주기에 대한 책임이 저수준 모듈에 결합한다. 엔진의 역할을 하는 하나의 객체가 있다면 엔진은 엔진의 역할만 맡아야 하는데 지금은 생명주기에 대한 책임도 엔진 스스로에게 맡기고 있는 것 같다. 이야기한대로 생명주기 관리 책임은 누군가가 져야 한다. 그렇다면 그 책임이 이미 특정 메인 책임을 부여받은 객체여야 할 이유가 있는지 의문이 든다. 1-2) 싱글톤은 테스트를 어렵게 만드는가?에버 : 테스트에서 메인 책임과 생명주기 책임, 이 두 가지 책임을 분리할 필요성에 대해 의문이 든다. 싱글톤 패턴에 따라 생명주기를 보장받기 때문에 메인책임만 테스트하면 되는 것 아닌가? 리비 : 동의한다. 싱글톤은 set up cost를 절약시킨다. 인프라 비용을 절감하기 위해 도입한 패턴인데 메인 책임에 대한 테스트가 어려워진다는 의견은 동의하기 어렵다. 인프라 로직과 비즈니스 로직은 결합되어 있을 수밖에 없고 저것을 엄격하게 떼어내는 것이 더 어렵게 느껴진다 콜리 : 만약 메인 책임에서 state가 필요하면 어떻게 되는가? 그럼 우리가 멀티스레드 환경에서 검증해야 하는 책임은
두가지로 분화하게 된다. 또한 병렬 테스트 환경에서는 특히 동시성 컨트롤이 힘들 수 있다고 생각한다. 리비 : 그런데 테스트를 할 때 두가지 책임을 분리하여 테스트할 수 없지 않는가? 동시성 테스를 하고 싶으면 동시성 테스트를 짜면 되고 그렇지 않으면 비즈니스 로직 테스트를 짜면 되지 않는가? 콜리 : 상태가 있는 싱글톤에서 테스트를 직렬로 실행했을 때는 통과하는데 병렬로 실행하면 깨지는 경우는 쉽게 상상가능하다. 에버 : 스프링 빈의 경우 stateless rule이 있고, 싱글톤 패턴 도입의 전제는 stateful하지 않은 상태라 생각한다 리비 : 상태를 가지더라도 싱글톤이 적합할수도 있다. 경합이 두려운 것 같은데 동기화를 유지하는 여러 방법이 있기에 싱글톤을 적용하고도 사이드 이펙트를 줄일 수 있는 방안들은 존재한다 1-3) 싱글톤은 OCP를 침해한다리비 : 아래는 확장이 안되지만 위로는 확장 가능하다. 싱글톤을 감싸는 인터페이스를 만들면 다양성을 줄 수 있다 콜리 : 대부분 확장이 열려 있다는 것은 아래 방향으로의 확장 아닌가 리비 : SRP 측면에서도 아래 방향으로 확장해야할 만큼의 책임을 가지고 있다면 SRP를 위반하는 것이 아닌가. 굳이 아래방향으로 늘려야 되는가에 대한 생각도 든다. OCP 를 침해한다기보다 OCP의 방향을 제한한다는 의견에는 동의한다 콜리: 상속이 막힌다는 것은 확장의 여지가 막혔다고 해석가능하다. 방향을 제한한다는 것 자체가 OCP 침해라고 볼 수 있다 리비 : 만약 아래로 다양성이 적용되어야 하는 상황이라면 싱글톤 도입 자체를 고민해보아야 하지 않는가 2. 스프링 빈은 왜 싱글톤을 사용하나?발제 싱글톤 디자인 패턴과 싱글톤 컨테이너는 서로 다른 배경이다. 스프링 빈의 경우 싱글톤만으로 관리하지 않는다. Scope 설정에 따라 객체의 생명주기를 정할 수 있다 Spring Bean
무엇이 다른가?콜리 : 싱글톤 디자인 패턴은 생명주기 관리를 본인이 직접하지만 스프링의 경우 spring bean registry가 전담한다. 즉 SRP를 유지하며 생명주기 관리를 한다 우리가 싱글톤 디자인 패턴을 사용하면 싱글톤 디자인 패턴의 단점도 함께 상속한다. 스프링 빈은 이러한 싱글톤 디자인 패턴의 단점을 해결하면서도 컨텍스트 내의 객체의 생명주기를 싱글톤으로 보장한다. 그럼 왜 싱글톤인가?콜리 : 영한 님 강의의 내용을 인용하자면 스프링은 근본적으로 기업용 웹 어플리케이션을 위해 만들어진 프레임워크이기 때문에 멀티 스레드 환경을 유의하고 만들어졌다. 그에 따라 스레드별로 셋업 코스트를 피하기 위해 stateless한 싱글톤 rule을 통해 효율적인 요청 응답을 가능하게 만들었다. 최종 발언콜리 : 싱글톤 디자인 패턴과 싱글톤 빈에 대한 구분을 이번 토론을 계기로 명확히 구분하게 되었다. 내가 가진 오개념을 바로잡을 수 있어서 좋았다. 싱글톤 디자인 패턴은 OOP를 침해하기에 안티패턴이라 부를 수 있다. 그러나 셋업 코스트를 줄인다는 점에서 효용이 없는 것은 아니다. 그러나 구구가 남겨준 리뷰의 속뜻을 풀이하면 생명주기를 싱글톤으로 관리하기 위해 싱글톤 디자인 패턴을 도입하는 것은 잘못되었다는 뜻인 것 같다. 오히려 크리에이터 객체처럼 생명주기 전담 객체를 만드는 것이 좋지 않았을까 하는 아쉬움이 든다 에버 : 그럼에도 싱글톤을 도입해야 하는 상황이 생기면 도입할 것 같다. 안티패턴이라는 이유로 싱글톤 패턴이 아닌 다른 방법을 생각하지는 않을 것 같다 리비 : 싱글톤 디자인 패턴은 여전히 강력한 도구라 생각한다. 그러나 안티패턴이라는 것에는 70%까지는 동의한다. 그러나 분명 사용되는 맥락이 있고 단점을 넘어서는 장점이 존재하는 순간도 분명히 있다. 스프링 컨테이너의 전략이 싱글톤 디자인 패턴의 단점을 상쇄하기 위해 나왔다는 점을 알아가서 좋았다 제리 : 나는 싱글톤 디자인 패턴이 필요한 순간에 망설이지 않고 도입해왔다. 그러나, 인스턴스를 유일하게 관리하는 다른 방법이 있다면 다른 방법을 찾아보는 걸 우선순위로 두고 정말 확실할 때만 적용할 것 같다. 발제자 회고확실히 토론은 준비를 하고 들어가야하는 것 같다. 추상적으로만 다루어질 수 있는 주제에서 정확한 학습 포인트를 잡고 크루들과 공유한 시간이라 의미 깊었다. 싱글톤 디자인 패턴과 싱글톤 컨테이너의 차이를 추상적으로만 알고 있었는데 이제 누군가에게 설명할 수 있는 정도가 된 것 같다. 같은 맥락올 싱글톤 디자인 패턴이 왜 안좋은지 다른 누군가에게 설명할 수 있게 되어 기분 좋았다 |
Beta Was this translation helpful? Give feedback.
-
싱글톤 패턴은 놀랍게도 이펙티브 자바에서 특정 상황에 추천하는 패턴이다.
그러나, 싱글톤이 안티패턴이라는 자료는 어렵지 않게 찾아볼 수 있다.
우리가 문제라 일컫는 것은 정말 싱글톤 패턴을 부정할만큼의 문제라 할 수 있을까?
혹은 주의해야할 점일 뿐인걸까? 이야기나누어보자
Beta Was this translation helpful? Give feedback.
All reactions