"없다" 시리즈 두 번째

스프링 빈의 lifecycle을 구분하는 스코프는 세 가지이다. 싱글톤, 프로토타입, 그리고 기타 스코프. 기타 스코프는 서블릿 컨텍스트(application), Request, Session 등등으로 다시 구분할 수 있다.

엄밀히 말해서 DI에는 스코프라는 것이 있을 수 없다. DI의 기본 전제는 모든 빈이 싱글톤이라는 것이다. 왜 그럴까? DI는 하나의 빈이 생성되면 필요한 collaborator들을 즉시 주입해주어야 한다. 그렇게 한번 DI되서 초기화된 빈은 다시 다른 빈이 DI되지 않는다. DI는 일생동안 한번 뿐이다. 이는 절대 바뀔 수 없는 원칙이다. 빈이 사용되기 시작한 후에 컨테이너가 임의로 빈에 다시 DI를 해버린다는 것은 말이 되지 않는다.

DI의 원칙이 하나의 빈 오브젝트가 생성되면 동시에 의존관계 빈을 DI해버린다는 것이라고 보면 DI되는 빈의 lifecycle은 DI당하는 빈과 같을 수 밖에 없다는 것을 알 수 있다. 즉, 싱글톤 빈에 DI되는 빈은 싱글톤이라는 얘기다. 싱글톤 스코프는 엄밀히 말해서 스코프가 관리되어지는 것이 아니다. 그냥 컨텍스트와 그 일생을 같이 하는 일체나 마찬가지이다. 컨텍스트가 만들어질 때 만들어지고 종료될 때 함께 제거된다. 따라서 별도의 스코프를 가지지 않는 것과 마찬가지다. 그래서 싱글톤은 상태를 가지지 않는 것이 원칙이며 한번 DI이면 끝이다.

문제는 lifecycle이 싱글톤 보다 작은 빈이 필요한 경우가 있다는 것이다. 단지 임시로 만들어 쓸 것이면 로컬 변수로 선언하고 오브젝트를 만들서 사용하면 된다. 메소드가 종료되면 깔끔히 그 오브젝트의 수명도 다할 것이다. 그런데 이렇게 필요할 때 만들어 쓰고 버릴 오브젝트가 컨테이너의 다른 빈을 DI해서 사용해야 하는 경우가 문제이다. 자신은 필요할 때마다 독립적으로 만들어져야 하지만 자신이 필요로 하는 다른 싱글톤 오브젝트는 컨테이서에서 DI로 받고 싶은 것이다.  DI 되거나 받으려면 자신도 컨테이너가 관리하는 빈이 되어야 하는 것이 원칙이다.

그래서 이렇게 필요할 때마다 여러 번 오브젝트가 생성되지만 그 오브젝트가 필요로 하는 또 다른 빈은 DI받고 싶은 경우 이 오브젝트를 스프링의 빈으로 등록하고 scope를 prototype으로 선언한다.

문제는 앞에서 얘기한 DI의 스코프 적용 원칙이다. 주입되는 빈의 스코프는 주입당하는 빈의 스코프와 동일하다는 것 말이다. A->B 의존관계로 B가 A에 주입된다면 DI의 동작원리에 따라 B의 스코프는 A와 동일할 수 밖에 없다.

그렇다면 singleton스코프를 가지는 빈이 prototype 타입 스코프를 가지는 빈을 DI 받는 다면 과연 그 각각의 스코프가 성립이 될까? singleton->prototype 관계의 DI는 DI의 스코프 원칙에 따라 singleton->singleton이 되버린다. A가 싱글톤으로 만들어지는 딱 한번만 B를 만들어 주입 받기 때문이다. 그 뒤로는 컨테이너가 절대로 B의 새로운 인스턴스를 만들어 넣어주는 일이 없다. 따라서 prototype으로 선언해봤자 DI에서는 무용지물이다.

따라서 DI에서는 prototype scope라는 것은 아예 의미가 없다고 봐야 한다.

Prototype scope를 그 의미대로 필요한 시점에서 매번 새로운 인스턴스를 만들어야 한다면 그때는 DI가 아니라 DL을 써야 한다. 명시적으로 컨테이너에게 해당 빈에게 새로운 인스턴스를 달라고 요청해야만 한다. 그래서 ApplicationContextAware를 써서 getBean을 하든, lookup method injection을 하든, 팩토리 빈을 끼든, ObjectFactory를 사용하는 등의 DL 방식을 사용할 수 밖에 없다.

 

이런 DI원칙은 prototype 스코프 외에도 동일하게 적용된다. Request, Session, ServletContext 스코프 따위는 아무리 만들어봤자 싱글톤에서 DI하면 단 한번만 생성하고 끝이다. 역시 제대로 쓰려면 DL이 필요하다. 물론 이런 진정한 의미의 스코프를 가지는 빈들은 매번 getBean한다고 새로운 인스턴스가 돌아오지 않는다. 각 스코프가 가지는 컨텍스트 내에서는 동일한 오브젝트를, 그 밖으로 나가면 다른 인스턴스를 받을 수 있다. 의미있는 레벨의 컨텍스트를 가지기 때문에 그 안에서 공유가능한 상태 정보를 넣어 사용해도 된다. 로그인 정보를 담고 있는 Session 스코프 같은 것이 그런 용도 이다.

DI원칙을 여기에 적용해보자. 만약 Session스코프를 가진 빈이 Prototype스코프를 가진 빈을 DI한다고 해보자. 그러면 Session스코프의 범위가 더 넓으므로 Prototype빈의 스코프는 Session스코프로 확장된다. 즉 Session scope->Prototype scope는 Session->Session이나 마찬가지라는 얘기다. 이건 DI 얘기임을 혼동하면 안된다. DL방식을 이용하면 Session->Prototype도 가능하다.

 

사실 이런 DI에서의 Prototype 스코프의 특징은 최신 자바표준인 CDI(일명 WebBeans)의 pseudo-context의 대표적인 케이스인 dependent pseudo-scope와 거의 동일하다. dependent pseudo-scopee는 다른 일반적인 normal scope와 다른 방식으로 만들어지고 동작한다. 그 특징을 잘 살펴보면 스프링의 prototype빈이 DI에서 사용되는 것과 거의 비슷하다. 다음은 CDI스펙에 나오는 Dependent psuedo-scope에 대한 설명의 일부이다.

- 다른 오브젝트에 DI된 dependent 오브젝트는 여러 오브젝트가 공유 할 수 없다

- 다른 오브젝트에 DI된 dependent 오브젝트는 주입된 오브젝트의 lifecycle에 바인딩 된다.

- Depedent psuedo-scope를 가지는 Context에 get()을 요청하면 매번 새로운 인스턴스를 돌려준다.

 

Singleton 빈이 주인 스프링에서는 원칙적으로 싱글톤 보다 작은 lifecycle을 가지는 빈을 DI하는 것이 의미가 없고 DL을 사용해야 한다는 것이 DI의 원칙이자 자바언어의 기본 sematics이다.

 

그런데 싱글톤 외의 다양한 스코프를 중시하는 CDI는 물론이고, DL의 사용방법을 귀찮게 생각하는 사람들의 불만이 많은 스프링에서도 DI의 기본 원칙을 무시하는 특별한 기법을 이용하기 시작했다.

CDI용어로 하지만 client proxy invocation이고 스프링 용어로 하자면 scoped proxy이다. 두가지다 비슷한 개념이다. 기본적인 아이디어는 lookup method injection과 비슷하다. lookup(DL) 코드를 다이나믹하게 주입하는 것이다. method injection이 미리 만들어진 abstract method를 확장 구현하는 방법을 이용한다면 client proxy invocation이나 scoped proxy는 DI 구조를 그대로 유지하면서 해당 scope의 context(또는 scope object)에서 DL하는 코드를 가진 실제 DI될 오브젝트의 프록시를 주입해주는 것이다. 그래서 겉으로 보기에는 완벽한 DI코드로 보이지만 사실은 DL이 일어나서 실제 의존한 인스턴스를 스코프에 따라 만들고 proxy를 통해서 그 오브젝트에 대한 요청을 bypass해주는 것이다. 일종의 routing proxy빈이라고 봐도 좋다.

아무튼 이런 스코프 DL을 지원하는 프록시를 DI방식으로 사용할 수 있는 것은 현재 컨텍스트에 따라서 적절한 scope를 결정할 수 있는 방법이 있기 때문이다. 같은 방법을 사용한다고 해도 prototype 스코프는 적용할 수가 없다. prototype 방식의 오브젝트의 스코프는 코드가 결정할 수 있지, 컨텍스트니 스코프 따위가 결정할 수 있는 것이 아니기 때문이다.

결국 싱글톤도 그렇고, 프로토타입도 이런 관점에서는 의미있는 스코프를 가진다고 볼 수 없다. 그래서 스프링에는 싱글톤, 프로토타입, (기타)스코프 의 세가지 빈이 존재한다고 말할 수 있는 것이다.

 

문제는 이런 scoped proxy 방식은 코드만 봐서는 평범한 DI코드와 동일하게 보인다는 점이다. scoped proxy는 주어진 스코프 안에서 상태 값을 변경할 수 있다. 그래서 그냥 보기엔 싱글톤 오브젝트의 인스턴스 변수를 마구 바꾸는 끔찍한 짓을 하는 듯이 보인다. 자바코드 semantics에서는 이상한 코드가 되어버린다는 말이다. 물론 proxy들이 알아서 관련 스코프의 독립적인 인스턴스만을 구분해서 조작해주기 때문에 걱정은 없지만 말이다.

이창신 님이 올려주신 CDI에 관한 예제를 살펴보자. 이 예제는 Glassfish예제인 것으로 아는데, 코드를 보니 CDI스펙에 나오는 것과 비슷하다. request스코프를 가지는 JSF빈 대신 Servlet이 이용하는 request스코프를 가진 Credential로 바뀌었을 뿐이다. 원래 서블릿은 잘 알려진 대로 기본적인 멀티쓰레드 모드라면 싱글톤으로 만들어진다. 그래서 절대로 서블릿에 인스턴스 변수를 두고 이를 고치는 짓은 하면 안된다는 것은 자바 쌩초보자 딱지만 뗏다면 누구나다 잘 아는 기초 중의 기초이다. 그런데 이 예제에서 LoginServlet은 인스턴스 변수인 Credential의 값을 마구 바꾸는 짓을 한다. 자바코드로 보기에는 미친 짓이다. 그러나 CDI에서는 기술적으로는 아무 문제가 없다. @Inject된 Credential은 Request스코프를 가지는 client proxy이기 때문에 매 request마다 다른 인스턴스를 호출하도록 보장해주기 때문이다. 문제는 Servlet코드에서는 그런 스코프가 보이지 않는 다는 점이다. 그저 같은 서블릿 인스턴스를 멀티쓰레드 환경에서 쓰면 문제가 될만한 짓을 하는 코드로 밖에 보이지 않는다. 환경을 떠나서는 자바언의 sematics가 달라지는 대표적인 경우이다.

이런 비슷한 것을 얼마전 @Configuration의 @Bean이 붙은 메소드가 동작하는 방식에서도 본적이 있다. 분명 새로운 인스턴스를 생성하는 메소드인데, 어떤 경우는 반복 호출을 해도 매번 동일한 오브젝트가 돌아온다. 역시 proxy로 확장되는 클래스이기 때문에 표준 자바 sematics와는 다르게 동작한다. 스프링에서 빈으로 만들어져서 사용되지 않는다면 일반 자바코드로 테스트 등에서 쓰면 원래 의도한 대로 동작하지 않는 문제를 만나게 된다.

scoped proxy를 쓰는 DI는 스코프가 서로 다른 빈들을 간단히 DI해주는 것만으로도 자신의 스코프를 지키며 동작하게 할 수 있다. 물론 여기에도 심각한 문제가 있긴 하다. 스코프가 넓어지는 참조는 보통 문제가 없지만 작아지는 참조는 매우 이상한 코드를 만들어 낼 수 있다. 이 것이 요즘 내가 가장 고민하는 주제인데.. 이 내용은 좀 더 정리하고 다시 적어봐야겠다.

 

DI가 가지는 의존관계와 스코프의 한계 때문에 DL을 써야 하는 불편함을 scoped proxy니 client scope invocation이니 하는 방법으로 깔끔하게 해결하고 DI 구조를 그대로 유지하게 만든 것은 분명히 장점이 있다. 제대로 이해하기는 힘들지만 기계적으로 사용하면 복잡한 스코프를 가지는 코드를 훨씬 쉽게 만들 수 있다.  하지만 애노테이션 다 떼고, 플랫폼 환경을 제거하고 순수한 자바 코드로 보자면 분명 왜곡된 코드이다. @NormalScope에 속한 다양한 @RequestScope같은 애노테이션(CDI) 또는 설정파일의 프록시를 위한 AOP선언(스프링)과 같은 것을 사용하지 않으면 원하는 대로 동작하지 않는다. 그리고 특정 플랫폼-컨테이너에서 동작시켜야만 한다. 그 밖에서는 다르게 동작한다. 이렇게 환경에 종속성이 매우 강한 코드임에도 단지 특정 클래스를 상속을 하지 않았다고 POJO라고 부를 수 있을지.. 나는 의문이다. Proxy Oriented Java Object의 약자라면 모를까.

물론 현실적으로 이런 접근을 받아들이지 못할 이유는 없다. 자바언어의 순수성을 고집하자면 이미 Java5를 거부했어야 한다. 지금까지 등장한 자바언어의 확장기능 중에서 애노테이션만큼 자바 언어의 개발방식을 송두리채 바꿔놓은 것은 없다고 생각한다. OO적인 특징도 그 때문에 많이 바뀌었다. 애노테이션을 마구 활용하는 개발방법에서 기본 타입체계에 기대는 OO적인 개발의 특징은 많이 제거될 수 밖에 없었다. 메타프로그래밍은 확산되었고 리플렉션과 바이트코드 조작, 위빙의 천국으로 만들어버렸다. 그 충격 조차 아직 다 받아들이지 못한 지금 프록시를 이용해서 변수를 참조하는 방식으로 코드의 동작방식 마저 바꾸는 이런 변화는 사실 굉장한 패러다임의 전환을 각오하지 않고는 제대로 받아들이기 쉽지 않을지 모르겠다.

 

자바언어는 진화하고 DI도 진화한다. 나는 IoC의 방법을 기존 DL/DI 두가지에서 DL/normal DI/proxy DI 세가지로 새롭게 구분해야 한다고 생각한다.

 

참, prototype 스코프란 DI(proxy방식이든 아니든)에서는 존재하지 않는다는 것을 얘기할려고 한 것인데 이런 저런 관련된 생각을 늘어놓다보니 또 얘기가 길어졌다.

Related posts:

  1. Prototype 빈을 위한 DL 전략
  2. Dependency Injection의 Dependency란 무엇인가?
  3. DI의 본질 – 다이나믹 (타입) 언어는 Dependency Injection이 필요없는가?
  4. Spring 3.0 (41) @Deprecated SpringMVC

Facebook comments:

to “Dependecy Injection에는 Prototype Scope가 없다”

  1. Servlet 3.0 에서 @Inject 된 인스턴스 맴버 변수를 맘대로 사용하는게 자바코드로 봤을 때 어색하다고 하셨는데요. … 왜 어색하죠?
    @Inject 된 것이 스태틱 맴버라면 인스턴스 메소드에서 스태틱 맴버를 사용하는게 OOP 적으로 어색해 보일 수가 있겠죠. 그런데 인스턴스 변수를 인스턴스 메소드가 접근하는 것은 매우 자연스러운 것 아닌가요?

    Servlet 이 싱글톤이라는 건 자바 언어 스펙에 있는 것이 아니라 Servlet 스펙에 있는 것이고, @RequestSoped 역시 같은 Servlet 스펙에 있는 것입니다. 서블릿이 싱글톤이라는 것을 알면 당연히 @Inject되는 것이 이상한 스코프를 가질 수 있다는 것도 알아야 맞는 것이겠죠.

    물론 Servlet 2.X 하고 Servet 3.0 하고의 일관성은 완전 망가졌다고 볼 수 있지만, 적어도 Servlet 3.0이 자바의 sementic을 왜곡하는 것으로는 해석되지 않는군요.

    자주 들리며 많은 도움을 얻고 있습니다만 이번 글에서는 오해의 소지가 있는 부분이 있는 것 같아 답글 남깁니다. 좋은 하루 되세요~!

  2. viz/ 날카로운 지적 고맙습니다.

    하지만 제가 볼 때는 CDI 예제 코드는는 어색합니다.
    제 생각은 이렇습니다.

    - 1. 말씀하신대로 저 클래스가 싱글톤으로 사용되어야 한다는 의무는 없습니다. (그건 서블릿 스펙일 뿐이죠)
    - 2. 동시에 저 클래스는 (싱글톤이든 뭐든) 멀티쓰레드 환경에서 안전하지 않다는 것도 알 수 있습니다. (이건 서블릿과 무관한 자바언어적인 클래스에 대한 이해입니다)
    - 3. 그럼에도 서블릿 3.0에서는 이 클래스를 싱글톤으로 사용해도 아무런 문제가 없습니다. 게다가 같은 서블릿 오브젝트의 인스턴스 변수를 다른 쓰레드가 접근할 경우 다른 내용이 나옵니다.

    그래서 저는 2번과 3번이 충돌하는 것으로 느껴지기 때문에 자바코드를 이해하는 방식에선 위화감이 느껴집니다. “인스턴스 변수를 조작하는 메소드를 가진 오브젝트는 멀티 쓰레드에서 공유해서 사용하면 그 인스턴스 변수를 공유한다”라는 자바의 semantics가 깨지는 것처럼 보이기 때문입니다.

    물론 클래스만 덜렁 놓고 보자면 문법적으로는 아무 문제가 없지만요. 그런 식이라면 예를 드신 “인스턴스 메소드에서 스태틱 멤버를 사용하는 것”도 언어스펙으로는 아무런 문제가 없지요. 그건 왜 OO적으로 어색하게 느끼셨죠? 여러 인스턴스가 공유하는 스태틱 정보를 일개 인스턴스에서 일방적으로 수정하는 것은 자연스럽지 않기 때문 아닌가요? 그뿐 아니라 스태틱 멤버를 각 인스턴스가 바꿔도 각각 독립적으로 저장되고 조회 된다라고 하면 이상하다고 느껴지지 않을까요?

    물론 스펙도 알고 왜 그런지 이해는 되죠. 하지만 어색합니다. 저만 그런건가요?

  3. 제 덧글에 대한 답글을 물음으로 끝내셔서 왠지 저도 다시 글을 써야 할 듯 해서 또 답글을 달아야 될 듯 하네요. ^^

    제가 말씀드리고 싶었던 것은 어차피 요즘 JAVA EE 기술은 모두 ‘마법’에 기반을 두고 있다는 겁니다. 스프링의 DI만 하더라도 요즘에는 다들 @Resource를 사용하는데 이것도 이런 ‘마법’ 중이 하나 입니다.

    초기화도 안되고 @Resource만 달랑 달려있는 필드 멤버를 인스턴스 메소드 안에서 null check도 하지 않고 접근하는 것. Spring이나 JAVA EE 경험이 있는 사람들에게는 전혀 어색하지 않겠지만 JAVA SE 만 경험해 본 사람들이 보기에는 정말 말도 안되는 코드 아닐까요?

    JAVA EE를 하는 입장에서 이런 ‘마법’은 그냥 받아들여야 하는 것이죠. DD지옥, boilerplate code 지옥에서 벋어나는 댓가로 지불해야 하는 비용이라고 할 수 있을 듯 하네요. ^^

    뭐 결론은 @Component & @Resource 조합이나 @RequestScoped & @Inject 조합이나 똑같은 ‘마법’일 뿐인데 왜 후자만 어색하다고 하시면 불공평하다는 겁니다. ^^

  4. viz/ 저는 후자만 어색하다고 한 적은 없습니다. :)

    제 글을 끝까지 읽어보시면 저는 “애노테이션”에 대해서 더 감정이 많다는 것을 아실 수 있으실텐데요. 스프링이 만든 것은 아니고 표준 애노테이션을 차용한 것이긴 하지만 아무튼 @Resource가 private 필드에 접근하는 DI방식은 이미 애노테이션이 등장하면서 부여되는 대상으로 필드가 포함된 시점에서 이미 예고된 것이나 마찬가지니까요.

    하지만 “이런 기술의 변화에 대해 자바의 언어적인 순수성을 고집하지 말고 받아들이는 것이 현실적이다”라고 제 글의 결론 부분에서 이야기 했습니다. 그게 이런 마법을 접하는 제 기본 입장이고, 그런 점에서 viz님과 근본적으로 생각이 다르지 않습니다.

    하필 @Resource를 비교 대상으로 드셨는지는 모르겠지만 저는 자바 semantics가 위배되는 것으로 JavaEE CDI 한가지와 스프링 scoped proxy, @Configuration/@Bean 두가지를 얘기했으니 불공평하다고 말씀하시려면 “왜 스프링을 주로 까느냐” 라고 하셨어야 하지 않을까요?

    그런 기술과 마법이 현실적으로 존재하고 사용해야 할 것이라는 점에서는 분명 동의하지만 불편함은 여전히 남습니다. 과연 댓가로 지불할 만큼의 비용이라고 할 수 있을지에 대해서는 계속 고민중입니다.

    컨테이너 밖에서는 제대로 동작하지 않는 코드와 아예 다르게 동작하는 코드에는 차이가 있다고 생각합니다. 저는 후자가 더 치명적이라고 봅니다. 그게 CDI와 스프링의 Scoped Proxy를 보면서 느끼는 불편합니다. “말도 안되는 코드”면 차라리 좋겠는데, 말이 되는 코드이면서 상식과 다르게 돌아가는 것이 더 문제가 있다고 생각합니다.

    스프링의 @Resource가 그걸 강제한 적은 한번도 없지만 아무튼 가능성을 열어줬다는 면에서 비난 받을 수 있는 “setter가 없는 필드 인젝션 방식”의 코드는 리플렉션을 이용한 메타 프로그래밍이 아니고는 컨테이너 밖에서 제대로 사용할 수 없습니다. 컨테이너 밖에서 쓸 수 없다면 가장 치명적인 것은 단위 테스트 작성이 어렵다는 것이고 그런면에서 로드 존슨이 @Resource니 @Autowired를 쓰더라도 setter 사용을 적극 권장한 것입니다.
    코드 이해면에서 보자면 동작할 플랫폼을 잘 모르는 자바개발자 입장에서는 필드 인젝션은 아예 정상적으로 동작할 가능성이 없는 이상한 코드입니다. 노련한 SE개발자라면 이미 JDK1.2부터 지원하기 시작한 리플섹션을 통한 private필드의 접근방법을 사용하면 되겠다 생각하겠지만요.
    차라리 불가능해보이는 코드가 낫습니다. “setter 추가”와 같은 대안을 찾던가 아니면 기술의 동작방식에 대한 깊은 이해로 이끌어주기 때문이죠. 또 환경에 따라 코드의 semantics가 달라지지 않습니다. 클래스 내에서 여전히 private 필드는 private 필드처럼 동작합니다.

    반면에 CDI의 client scope invocation은 훨씬 치명적입니다. 처음 viz님이 다신 답변이 그 증거입니다.

    처음 주장하신 것처럼 LoadServlet의 코드는 평범한 자바클래스로 보면 아무런 문제가 없습니다. 인스턴스 변수를 정의하고 그것을 사용하는 합법적이고 OO적인 코드입니다. 이를 JavaEE 밖에서 사용해도 됩니다. 정상적인 코드로 보이기 때문에 멀티 쓰레드 환경에서는 사용하지 않을 것이고, 사용한다면 어떻게 동작할지 뻔히 짐작할 수 있을 것입니다.
    하지만 CDI 환경에서는 당연히 생각했던 것과 다르게 동작합니다. 자연스럽게 이해하자면 Credentials는 모든 쓰레드가 공유하는 동일한 오브젝트로 생각하기 쉽습니다. 따라서 컨텍스트에 따라서 같은 변수를 썼지만 다른 인스턴스가 사용되는 것은 일반적인 자바 상식으로는 오해하고 잘못 접근하기 딱 좋은 코드라는 것입니다.

    그 자체로 너무 정상적으로 보이는 코드이기 때문에 오히려 잘못 이해하고 사용할 위험성이 큽니다. 같은 인스턴스 변수인데 스코프가 제각각이고 컨텍스트에 따라서 다른 오브젝트를 사용한다는 발상은 “마법”치도고 꽤 멀리 나간 것으로 보이는게 제 느낌입니다. @Inject를 붙인 쪽에서는 도무지 스코프가 보이지 않는 것도 불만입니다.

    그렇다고 CDI를 거부하느냐? 저는 사실 scoped proxy나 CDI의 팬입니다. proxy를 이용한 DI로 거추장스런 DL을 대신하게 했다는 점에서 처음 보고는 매우 감탄했습니다. 앞으로 열심히 쓸 생각입니다. 이건 아직 구상 단계지만 CDI의 오픈소스 구현 프로젝트도 준비하고 있습니다.

    그럼에도 이런 변화들이 썸뜩하게 느껴집니다. 애노테이션으로 치장한 언어자체의 확장처럼 느껴지고, 대다수의 개발자들에게는 매우 위험하겠구나라는 긴장감이 듭니다.

  5. 대다수의 개발자에게 매우 위험한게 아니라 오히려 안전하게 만드는걸로 보이는군요.
    대다수의 개발자는 멀티스레딩코드를 제대로 만들지 못하는 비즈니스 어플리케이션 개발자들이고, EJB가 이런 개발자들로부터 스레딩 이슈를 생각하지 않고 코딩하게 해주듯이, 서블릿 인스턴스 변수에 inject된 @RequestScoped 인스턴스 변수가 스레딩 이슈로부터 해방시켜주는걸로 봐주면 됩니다.

    그리고 인스턴스 메소드가 스태틱 변수를 건드리는것도 전혀 이상할 이유없고, 필요할때가 꽤 자주 있죠.

    사실 서버 프로그래밍의 이슈는 concurrency, transaction, caching, coherence, scalability, load balancing이지 dependency injection따위가 아닌데, 시스템 프로그래머들이 이런거 많이 가려주고, request, session, thread safety같은것들 가려주는 annotation들을 제공해주니까 비즈니스 어플리케이션 개발자들은 그냥 외워서 쓰면 되는겁니다.

  6. 근래 자바 Spec에 대해 무지해서 구경만 했는데 Viz님 덕에 본문에 버금가는 댓글이 이어지는군요. 한동안 Configuration 정보가 주로 XML 위주로 분리해서 존재했는데, 최근에는 다시 코드 옆으로 위치를 이동하는 듯 보입니다. 과거엔 Xdoclet 같은 녀석은 도우미 정도였는데, 애노테이션 등장으로 자바 언어에 Configuration 정보가 섞여 Java와 Java 같은 녀석(이반 자바와 다른 Semantics를 내포한 녀석… http://toby.epril.com/?p=939 에서 굵은 글씨 참조)이 공존하죠. 사실 저는 편의성 탓에 애노테이션을 팬입니다. 하지만, 아직 어떻게 사용해야 옳은지는 모릅니다.

    이런 글을 읽으면서, 비단 이 글뿐 아니라 최근 도래하는 다른 기술에 대한 인상도 한 몫하여 애노테이션에 특정 의미체계를 부여하여 자바 언어를 확장해가는 현상이 알수록 놀랍기는 하네요. 단순히 Configuration 정보라고 뭉뚱그리기엔 특정한 의미 체계를 부여하는 internal DSL 냄새가 나는 녀석들도 심심치 않게 보이고, 또 Spec으로 표준화해서 영역을 넓히는 녀석도 보이고…

    논쟁에 불을 당길만한 재능이 없어 아쉬운데… 지나가다 재밌어서.. :)

  7. franklyspeaking/ 저 같은 “멀티스레딩코드를 제대로 만들지 못하는 대다수 비즈니스 어플리케이션 개발자”들은 그냥 외워서 쓰면 되는거군요?

    그런데, 그게 “상태없는 빈으로 만들어서 인스턴스 변수 조작을 아예 안하는 것”이라고 외우는 것이 “@Inject가 붙었을 경우는 그 scope를 확인해서 그 종류에 따라 같은 컨텍스트 안에서는 맘 것 쓰고, 벗어났으면 조심하고, 같은 인스턴스 변수지만 @Inject가 안붙은 것은 멀티쓰레드를 고려해서 주의해서 쓰거나 아예 쓰지 말아야 한다”라고 외우는 것보다 편할 것 같은데요?

    정말 client proxy가 평범한 애플리케이션 개발자들의 실수를 잘 커버해줄 수 있는지는 여전히 의문입니다. 스펙도 정확히 알고 그 장점을 잘 살려서 쓸 수 있는 개발자라면 훨씬 편한 것은 사실이겠지만요.

  8. franklyspeaking/
    “사실 서버 프로그래밍의 이슈는 concurrency, transaction, caching, coherence, scalability, load balancing이지 dependency injection따위가 아닌데”
    ‘따위’라는 표현이 조금 걸려서 제 생각을 남겨 봅니다.

    정확히 하자면 DI는 수단에 불과하고, DI가 풀려고 하는 과제는 객체의 Lifecycle & Collaboration 관리라고 생각합니다. 객체의 L&C는 정적인 구조와 동적 구조에 동시에 영향을 미칩니다. 더욱이 concurrency와 밀접한 관계가 있으므로 매우 중요한 설계주제, 즉 concurrency… 등과 같은 레벨이라고 생각합니다.

    나머지 생각은 충분히 공감하는데,
    ‘위험’에 대한 표현은 toby님과는 다른 영역에서의 ‘위험’을 의미하시는 것 같습니다.

  9. 그래서 어떤 회사는 single thread model pooled servlet만 쓰게하기도 합니다.
    비즈니스 어플리케이션 개발자들이 마음대로 서블렛을 못만들게 관리합니다.

    스프링은 이름을 정말 못짓는다는 생각이 듭니다. 이름을 못 지으니 의미가 분명하지 않고 비즈니스 어플리케이션 개발자들을 헷갈리게 만드는 프레임워크라고 보입니다. 예를 들면, prototype scope나 client proxy라는 이름 자체가 그것의 실제로 의미하는바를 전혀 클리어하게 나타내지 못하고 있습니다. 그런 클리어하지 못한 이름들이 의미하는 바를 외우고 쓰게하는 보다는, 웹 서버 프로그램은 request, session을 다루고 request scope는 보통 thread-safe하다고 외워서 쓰게 만드는게 훨씬 직관적이고 기억하기 쉽죠.

  10. entworks/ DI가 있던 없던, 정적 구조와 동적 구조에 대한 설계를 해야하고, 할 수 있습니다.
    예를 들어, 서버 시스템 소프트웨어들은 보통 비즈니스 어플리케이션들보다 훨씬 Object Oriented 설계를 잘하는 엔지니어들이 설계 구현하는데, DI써서 만든거 한번도 못봤습니다.
    DI는 코드에 로직만 남겨두고 dependent component에 대한 생성과 연결 코드를 제거해서, 로직을 좀 더 쉽게 이해해주게 만드는 정도입니다.
    Guice같은 경우는 만든 동기를 유닛 테스팅시 모든 컴포넌트를 다 연결시키지 않고, Mock 컴포넌트를 테스팅 코드에서 쉽게 inject하는거였다고 밝히고 있구요.

    DI자체가 concurrency만큼 중요한게 아니라, DI를 써서 여러개의 스레드에서 동시에 사용할 수 있는 오브젝트를 inject하는 경우에는, 갑자기 concurrency 이슈와 엮여버리게 되니까, 그걸 이해해야 되게 되버리는겁니다.
    DI를 써서 thread-safe한 component만 inject하도록 설계하면, DI자체는 concurrency와 아무 관련이 없어져버리죠.

    원래 서버 프로그래밍에서 나타나는 이슈를 이해못하는 프로그래머에게 서버 프로그래밍을 맡기면 위험해지는겁니다. 그런 프로그래머들에게는 그 이슈들을 최대한 단순하게 만들어 가려주고, 그 쪽 부분에 손을 못대게 하는게 현실적으로 최선이 아닌가 생각되는군요.
    @Transactional이나 @RequestScoped나 제가 볼 때는 그게 그거 같은데, 솔직히 이 포스트는 뭘 걱정하는건지 모르겠습니다.

  11. “이렇게 환경에 종속성이 매우 강한 코드임에도 단지 특정 클래스를 상속을 하지 않았다고 POJO라고 부를 수 있을지.. 나는 의문이다.”

    저도 이부분에 동의합니다. 글을 읽어 내려가다가.. ‘이렇게 되면 이거.. POJO라고 하기도 힘들겠는데;’ 싶었는데 그렇게 생각하자마자 바로 이런 글이 적혀있어서 깜짝 놀랬네요.

    하지만 반면에, 그렇게 환경 종속적인 코드들을 해당 환경이 아닌 곳에서 사용하는 경우가 얼마나 될지.. 거의 없지 않을까 하는 생각이 들었습니다. 그래서 POJO가 아니라 특정 환경에 종속적인 코드여도 머… 어때.. 이런 생각이;;

    일부 댓글은 toby님에 대한 선입견이 영향을 미친것 같습니다. toby님이 스프링 짱이긴 하지만 그렇다고 해서 저처럼 일방적인 스프링 골수팬(제가 아는게 그것 밖에 없어서;;)은 아닙니다. KSUG(Korea Spring User Group)에서 탈퇴 하신것 만 봐도 알 수 있죠. 캬캬캬.

    저는 개인적으로 이 글을 통해서 스프링에서 벗어나 JSF와 CDI, Seam 등을 살펴보고 싶어졌습니다. 스프링의 주옥 같은 코드는 옆에 끼워놓고 (바람피는 기분으로) 새로운 기술들을 만나봐야겠어요.

  12. 썬/ 이런 천기누설을!

  13. 최근 올라온 글 중에서 가장 감동적인 글이었어.
    일하면서 시분할 리딩으로 읽었더니 상당히 오래 읽었고 힘들었는데 다 읽었다 싶은 순간… 이… 뭐.. 댓글 길이가…;;;
    개인적으로 마법을 별로 좋아하지 않고 개발자 바보로 만드는 기술은 더욱 싫어하지만 현실적으로 함량 미달의 단순 조립공 수준의 코더들을 데리고 일을 해야하는 사람들 생각하면 뭐라 할 수도 없네…
    이렇게 마법을 부려 당장 효과를 볼 수도 있겠지만 장기적으로 개발이 중세 시대처럼 각종 마술과 신비가 난무하는 상황이 되는 건 아닐지 걱정되는군. 디버깅 하려면 무당 부르는 건가? (TA 몸 값은 좀 오르겠다.)
    커뮤니케이션을 중시하는 코드는 안드로메다로…

    P.S. google groups에 관리자가 임의로 회원 가입 시키는 기능도 있더라고…. 뭐… 그렇다는 거지…

  14. 박성철/ 최신 기술들이 과연 “함량 미달의 단순 조립공 수준의 코더”에게 유용한 마법인지는 더 고민해봐야 할 것 같습니다.

  15. franklyspeaking/ prototype이라는 이름은 저도 별로 맘에 안듭니다만, client proxy (invocation)은 스프링 용어가 아니고 CDI용어거든요? “스프링과 JavaEE(CDI)는 둘 다 정말 이름을 못짔는다”로 정정하셔야 겠군요.

    저는 request scope가 뭐하러 필요한지도 잘 모르겠습니다. 같은 request/쓰레드에서 처리할 정보라면 그냥 파라미터로 넘기면 되죠. 사실 CDI가(사실은 그 원조인 Seam이) request scope를 들고 나온 건 JSF의 request scope form-backing bean을 바로 비즈니스 오브젝트에 주입하기 위해서 입니다. 폼 빈이 존재하는 JSF를 사용할 바 아니라면, 서블릿에서 자신이 직접 호출하는 오브젝트에게 전달할 정보를 마치 ThreadLocal 사용하듯이 thread-bound object holder에게 넣어두었다가 다시 전달 받는 건 무슨 희한한 짓인지 모르겠습니다.

    CDI에는 request/session 말고도 정의하기 나름인 임의의 conversation scope도 있죠. 이런 것들은 thread-safe 하다는 거 하나만 달랑 기억하고 제대로 쓸 수 있는 게 아닙니다. 제대로 알고 쓰려면 stateless 단독 방식보다 몇 배는 더 공부하고, 한참 더 헤맬 각오를 하고 써야 하는 것으로 보이는데요.

    주로 싱글톤인 서블릿에서 가장 단순한 request scope 하나만 가지고 생각하시면 별거 아닐지 모르겠지만 다양한 scope들이 서로 상호 참조하고 있는 상황에서도 과연 servlet을 stateless하게 개발하는 것도 힘겨워 한다는 평범한 개발자들에게 과연 쉬운 것이라고 말할 수 있다고 생각하나요? CDI나 JavaEE의 최신 기술들을 참 만만하게 보시는군요.

    그나저나 franklyspeaking님이 쓰신 글은 무조건 스팸목록으로 가는 군요. 금칙어도 없는 것 같은 데 희한하군요. Akismet 필터한테 찍히서 블랙리스트에 올라가 계신가봅니다. 매번 spam 확인해서 빼내는 것도 참 버겹군요.

  16. parameter로 넘기지 않는 이유는 많은 method들이 그 parameter를 그저 통과시키기 위해서 method signature가 지저분하게 되는것을 피하기 위해서 입니다. 이걸 피부로 느껴보지 못해서 희안한짓처럼 보이는 사람은 그동안 매우 간단한 작은 소프트웨어만 만들어봤다는걸로 해석하면 됩니다.

    request scope에 들어가는 대표적인 component로 transaction context를 들 수 있습니다.
    보통 한 request는 한 thread에서 해결되기때문에 thread local에 넣을수도 있는데, 한 request를 처리하는 과정에 중간에 thread pool을 거치는 경우, 반드시 그렇지 않을수도 있기 때문에, request scope context에 transaction context를 넣기도 합니다.

    JSF form bean이나 conversation은 웹 서버 어플리케이션 구현에 많이 나타나는 requirements를 구현한 하나의 example일 뿐이고, 그건 JSF나 Seam이 나오기 이전부터 풀어야 될 문제였고, 많은 proprietary web framework들이 유사한 방식으로 해결하고 있던것들입니다.

    JSF를 사용하지 않는 경우에는, 왜 그런식으로 하는지 모르겠다는 말은, 님이 이전에 그런 문제를 만나서 해결해야되는 일을 해본적이 없다는 걸 의미하는것 뿐입니다.

    request나, session이나 conversation이나 라이프사이클만 다르지 그 scoped context에 object를 넣고 빼고 사용하는건 같은 컨셉트인데, 몇 배 더 공부하고, 무슨 해멜각오를 하고 써야된다는건지는 잘 모르겠습니다.
    conversation state transition을 xml로 만들어 놓는 경우가 많기 때문에 그 data structure에 익숙해지기 전까지 디버깅할때 고생하는 경우는 있는데, 이게 conversation scoped object를 적절히 사용하는거하고는 별개의 문제입니다.

    JavaEE는 서버사이드 소프트웨어에서 풀어야될 문제들을 대부분 해결해놓은건데 제가 우습게 볼 이유가 없습니다. 스프링은 어떻게 보면 좀 우습게 보입니다.

  17. franklyspeaking/

    >> DI를 써서 thread-safe한 component만 inject하도록 설계하면, DI자체는 concurrency와 아무 관련이 없어져버리죠.

    하하하.. 정말 단순명료하고 속편하신 분이시군요. 그러니 제 고민이 이해가 안되겠죠. 그냥 멍청한 개발자가 신기술을 이해못해서 쓸데없는 고민이나 하나보다라고 생각하시고 내버려두세요. 아니면 블로그에 쓰셨듯이 신도들이랑 잡담이나 나누는가보다 하시던지요. 정신건강에 안좋다고 말씀드렸자나요.

  18. > 최신 기술들이 과연 “함량 미달의 단순 조립공 수준의 코더”에게 유용한 마법인지는 더 고민해봐야 할 것 같습니다.

    난 그렇게 생각 안하고 또 이런 해법을 좋아하지도 않지만 그렇게 주장하는 사람들이 이런 해법을 찾는 걸 뭐라고 할 생각은 없는 거지… 사실 그런 환경은 신경쓰고 싶지도 않은…

  19. franklyspeaking/ 제 글을 읽어보고 답글을 쓰신 것인지 궁금하군요.

    저는 “서블릿에서 자신이 직접 호출하는 오브젝트에게 전달할 정보를 RequestScope에 저장해서 넘기는 것”은 희한한 짓이라고 했을 뿐입니다. LoginServlet이 Login의 login()을 부르면서 파라미터 두 개를 Credentials에 저장했다가 다시 거기서 꺼내오는 게 안 이상합니까? 그걸 login메소드의 파라미터 두 개로 추가하든지, 아니면 Crendentials 오브젝트에 담아서 파라미터로 전달하는게 당연한거 아닌가요?
    설령 파라미터 갯수가 많더라도 그것은 도메인 오브젝트 등에 담아서 한 방에 전달하면 충분합니다. “그저 파라미터를 통과시키는 메소드가 많다”는 것은 작은 소프트웨어가 아니라서가 아니라 설계가 엉터리기 때문입니다.

    여기서 transaction context는 왜 튀어나오는지 모르겠군요. 그런걸 애플리케이션 개발자가 request scope에 넣어두고 사용하자는 것인가요? 그리고 RequestScope용 Context 구현은 역시 ThreadLocal을 쓴다는 것은 모르시나보죠? CDI의 RI인 Weld를 보시면 RequestContext의 빈은 ThreadLocal이 저장소로 쓰입니다. 그 외에 무슨 방법이 있는지 모르겠군요. Thread-pool을 거치는 경우도 있기 때문에 ThreadLocal 대신 RequestScope(역시 ThreadLocal인)를 쓴다는 것이 무슨 얘긴지.

    RequestScoped JSF 빈을 사용하는 경우에도 왜 직접 인스턴스 변수에 DI하는지는 모르겠습니다. 차라리 DIJ(JSR-330)의 Provider를 주입받아서 필요한 스코프 안에서 사용하든지 메소드의 파라미터로 주입 받으면 모를까요.

    request/session/conversation이 context에 오브젝트를 넣고 빼는 게 전부가 아니죠. 그 넣고 빼는 걸 감추고 마치 동일한 인스턴스 처럼 접근하게 하는 것이 핵심이죠. 똑같은 인스턴스 변수면서 다 제 각각 라이프사이클을 가지고 내용이 바뀌는게 개발자들에게 그렇게 간단해 보일까요? 간단해 보이면 그게 더 문제죠. SessionScoped인 Login에서 RequestScoped인 Credentials를 인스턴스 변수로 가지고 있으면, 그게 언제 의미있는 오브젝트가 될지 아닐지를 일일히 구분해서 각 메소드에서 사용해야 하는데 과연 쉬울까요.

    왠만하면 블로그에 직접 댓글 다신 건 성의있게 대답하고 싶지만, 말끝마다 “너는 경험이 없으니 모르는 거다”라는 식의 비아냥을 곁들이시니 앞으로는 별로 상대하고 싶지 않군요. 제가 무슨 JavaEE6를 까고 스프링이 낫다고 주장하려는 것도 아니고, 틈틈이 EE6의 기술과 프로그래밍 모델을 진지하게 공부하면서 드는 생각을 적어나가는 것 뿐이데.. 이거 영양가는 별로 없고 참 피곤하군요.

  20. 재밌는 토론 잘 보고 갑니다.

  21. RequestScoped와 Inject를 어떻게 사용할 수 있는지 보여주는 샘플에서 설계찾는건 웃기는 일이죠. 그럼 샘플 프로그램에서 call stack에서 수십 스텝지나서 저장된 데이타를 사용하는 샘플을 만들어 보여주겠습니까?

    transaction context를 어플리케이션 개발자보고 request context에 저장하란 얘기가 아니고, transaction context가 request context에 저장해두고 두고두고 꺼내서 쓸 수 있는 좋은 사례란 얘기입니다.

    Request context로 ThreadLocal을 사용할수도 있고 안 할수도 있습니다. thread local에 넣을수도 있다고 이미 언급했죠. 님이 ThreadLocal을 쓰는 코드만 본 것 뿐이고, 그렇게 하면 문제가 생기는 경우를 당해보지도 않았고, 그런 코드를 본 일도 없을 뿐입니다.

    DI를 쓰던 쓰지않던 request/session/conversation context에 오브젝트를 넣고 빼는 일은 필요합니다. DI framework를 전혀 쓰지 않는 시스템도 request/session/conversation 처리는 다 해왔습니다. request/session/conversation context에 넣고 빼는 자체가, 그 이전에 그 오브젝트들의 라이프사이클을 정확히 이해하고 사용하도록 설계되었다는걸 암묵적으로 의미하는거구요.
    님은 그거 두개를 섞으니까 복잡하고 헷갈려보이는거고, 분리해서 따지면 복잡할 이유도 없습니다.

    위에서 한번 말했지만, 님이 credential login sample가지고 거기서는 그렇게 설계할필요를 없고 파라미터로 그냥 넘기게 설계를 했어야 됐다고 따지는건 웃기는 일이라고 봅니다. 왜냐 하면, 그 샘플의 목적은 그 annotation들을 어떻게 사용하고, 어떤 의미가 있는걸 보여주는데 있을뿐이기 때문입니다.

    미안하지만, franklyspeaking, 님이 오픈소스 코드를 열심히 읽는것 같기는 한데, 좀 복잡한 커머셜 소프트웨어를 개발해본 경험은 별로 없어보이는 발언을 님 스스로가 하고 있는듯이 들립니다.

  22. franklyspeaking/ 제가 언제 GlashFish 예제가 문제가 있고, 그걸 증거로 CDI나 RequestScope는 죄다 글러먹었으니 쓰지 말자고 했습니까? franklyspeaking님은 남의 글을 도통 제대로 안 읽으시면서 남의 경험 운운하시는 데만 더 관심이 많으시군요?

    LoginServlet 예제가 그걸 배껴서 쓰라는 것도 아니고 RequestScope/SessionScope가 동작하는 걸 최대한 단순하게 보여주려는 HelloWorld수준인 걸 누가 모릅니까?

    하지만 제가 계속 지적하는 문제는 평범한 개발자들이 RequestScope를 실전에서도 저 따위로 쓸지도 모른다는 것이죠. 그래서 님이 얘기했던 “thread-safe DI면 개발자들은 아무 걱정없다”가 전부가 아니라는 얘기를 한거죠. 단순한 예제라고 넘기기에는 찝찝하죠. 솔직이 Glassfish개발자들이 간단한 예제도 저 따위로 밖에 못만들 정도니 기가찹니다. 굳이 그걸 이해하려고 노력한 건 CDI spec의 JSF 빈 사용 Login예제를 배껴다 Servlet방식으로 기계적으로 옮긴 것이라서 그렇다는 것인데, 성의부족이거나 자신들도 스스로 만든 기술의 위험성을 잘 모른다는 것이거나, 간단하지만 어색하지 않은 예제를 만들만큼 그 기술에 대해서 고민해보지 않았든지요.

    RequestScope/Context를 ThreadLocal 말고 다른 데 저장한 것 본적 없습니다. 스프링은 그걸 설정에 따라서 InheritedThreadLocal로 변경할 수 있는 옵션이 있을 뿐입니다. RequestScope를 담당하는 Servlet이 저장소로 쓸 ThreadLocal을 초기화 하고 작업을 마치면 scoped bean을 제거하는 방식이 thread-pool 때문에 문제가 되는 이유를 어디 한번 설명해 보시죠? 그러면 어떤 대안을 쓰는지도요? 이건 정말 궁금한 것인데 어디 한번 배워보죠. 그냥 “너는 그런 코드 못봤지”하지 마시고 RequestScope구현을 ThreadLocal로 저장할 때 문제가 되는 기술적인 근거를 말해주세요.

    그리고 “ThreadLocal을 쓰면 문제가 생기는 경우를 당해보지도 못했냐”는 말은 최신 표준 스펙을 작성하고 그 참조구현을 만든 JBoss의 CDI/Weld 팀에게나 하시죠? 님의 말이 맞으면 참 경험없는 인간들이 “서버 개발의 모든 문제를 해결해준다”는 표준 기술을 만든 것이겠군요?

    제가 얘기한 건 request/session/conversation 같은 스코프를 사용하지 말자는 게 아니라, 그걸 DI로 쓰는 것이 편하지만 조심해야 할 것이라는 것이었죠. 컨테이너가 관리하는 오브젝트가 자기 스코프보다 작은 스코프를 가지는 인스턴스를 사용해야 하는 경우를 경험해보신 적이 있긴 한가요? 이건 같은 JavaEE6지만 Provider를 쓰는 것과 그냥 @NormalScope DI를 사용하는 것 두 가지 완전히 다른 접근이 있는데, 여기서부터 이미 혼란이 시작되는 것 같습니다. 이게 별거 아니고 간단해 보이신다면 정말 초고수이거나 JavaEE6 기술의 내용이 뭔지 이해 못하시는 것 같습니다.
    보통 개발자들은 JavaEE6를 쓴다고 해도 왜 그런 방법이 두가지가 있는지, 그 차이가 뭔지, 어떤 것을 선택하는 것이 어떤 의미를 가지는지, 어떤 경우 무엇을 주의해야 할지에 대해서 제대로 설명하지 힘들것이라고 생각합니다. 그게 CDI 예제를 보면서 들기 시작한 제 가벼운 고민입니다.

  23. franklyspeaking/

    “entworks/ DI가 있던 없던, 정적 구조와 동적 구조에 대한 설계를 해야하고, 할 수 있습니다.”
    -> 네, 맞습니다. DI는 객체 L&C의 수단입니다.

    “예를 들어, 서버 시스템 소프트웨어들은 보통 비즈니스 어플리케이션들보다 훨씬 Object Oriented 설계를 잘하는 엔지니어들이 설계 구현하는데, DI써서 만든거 한번도 못봤습니다.
    DI는 코드에 로직만 남겨두고 dependent component에 대한 생성과 연결 코드를 제거해서, 로직을 좀 더 쉽게 이해해주게 만드는 정도입니다.
    Guice같은 경우는 만든 동기를 유닛 테스팅시 모든 컴포넌트를 다 연결시키지 않고, Mock 컴포넌트를 테스팅 코드에서 쉽게 inject하는거였다고 밝히고 있구요.”
    -> 내용 자체는 동의합니다만 뉘앙스는 동의하지 않습니다. DI가 OO를 잘하는 엔지니어에게 쓰이지 않으므로 DI가 중요치 않거나 열등하다는 뉘앙스를 담고 있는데, 단순 객체생성(new), Locator, Factory 같은 패턴과는 다른, 관리 차원의 concern을 모듈화한다는 점에서, DI는 중요한 option이 된다고 생각하며, 이 부분에서 생각이 다르신 것 같네요.
    또 하나, 어떤 시스템 소프트웨어를 말씀하시는지 모르겠지만 시스템 소프트웨어라 불릴만한 것들은 DI 개념이 널리 퍼지기 전에 그 설계가 완성된 경우가 많은 것이 원인 중 하나가 아닐까 합니다. 저도 예전에 만들었던 프레임워크 자체에 DI를 적용했더라면 하는 부분이 적기는 하지만 있습니다.
    하지만 상대적으로 적은 인원일 수록, 기술력이 뛰어난 팀일 수록, 시스템 소프트웨어 특성이 강할 수록 DI의 효용은 떨어진다는 생각도 드네요.

    “DI자체가 concurrency만큼 중요한게 아니라, DI를 써서 여러개의 스레드에서 동시에 사용할 수 있는 오브젝트를 inject하는 경우에는, 갑자기 concurrency 이슈와 엮여버리게 되니까, 그걸 이해해야 되게 되버리는겁니다.
    DI를 써서 thread-safe한 component만 inject하도록 설계하면, DI자체는 concurrency와 아무 관련이 없어져버리죠.”
    -> DI가 concurrency 만큼 중요하다고 하지 않았고 중요한 건 객체 L&C라고 말씀드렸습니다. 나머지는 동의합니다.

  24. entwork/ 서버 프로그래밍에서 concurrency는 critical, must have이고 DI는 optional, not that critical, may use정도 라는 얘기지 굳이 열등하다고까지 표현할 의도는 없습니다.
    말씀대로 DI는 하나의 툴일 뿐이고, 망치를 들고 있다고 그걸로 이를 쑤실 이유는 없는 이유와 마찬가지로, 직관적이지 못해서 문제가 되는 scope DI가 있으면 거기 DI를 안쓰면 될 간단한 문제인데, 이 블로그 주인장이 왜 그런걸 고민하고 있는지 잘 이해가 안갑니다.

    toby/ 댓글을 주고 받으면서 내가 님한테 느낀게 논리 전개가 좀 두서없이 왔다갔다 하는것 같다는 점과, 자기가 바로 전에 무슨말을 했는지 금방 잊어먹는것 같다는것과 토론 상대방이 얘기하는걸 제대로 읽지 않는것 같다는건데, 나한테 그런걸 느꼈다니 아이러니합니다.
    내가 왜 그렇게 느꼈는지 예를 들어서 알려주죠.

    “저는 request scope가 뭐하러 필요한지도 잘 모르겠습니다. 같은 request/쓰레드에서 처리할 정보라면 그냥 파라미터로 넘기면 되죠.”

    애초에 님이 걸고 넘어진건 샘플 프로그램에 있는 @RequestScoped와 @Inject였습니다. 같은 request thread에서 처리할 정보라면 파라미터로 넘기면 된다는 말은, 같은 request/thread에서 쓰더라도 여러 call step후에 사용되는 경우, method signature가 지저분해진다고 얘기해줬습니다.

    “CDI에는 request/session 말고도 정의하기 나름인 임의의 conversation scope도 있죠. 이런 것들은 thread-safe 하다는 거 하나만 달랑 기억하고 제대로 쓸 수 있는 게 아닙니다. 제대로 알고 쓰려면 stateless 단독 방식보다 몇 배는 더 공부하고, 한참 더 헤맬 각오를 하고 써야 하는 것으로 보이는데요.”

    논의에 별 상관없는 conversation을 끌고들어옵니다. 그 뒤에 얘기는 뭘 주장하고자 하는건지 아리송하기 그지 없습니다.

    “저는 “서블릿에서 자신이 직접 호출하는 오브젝트에게 전달할 정보를 RequestScope에 저장해서 넘기는 것”은 희한한 짓이라고 했을 뿐입니다. LoginServlet이 Login의 login()을 부르면서 파라미터 두 개를 Credentials에 저장했다가 다시 거기서 꺼내오는 게 안 이상합니까? 그걸 login메소드의 파라미터 두 개로 추가하든지, 아니면 Crendentials 오브젝트에 담아서 파라미터로 전달하는게 당연한거 아닌가요?”

    그러더니 request scoped 오브젝트에 대한 필요성이 대두되니까, 이번에는 그 sample에서 request scoped를 사용한게 적절치 못한 설계라고 말을 바꿉니다.

    “LoginServlet 예제가 그걸 배껴서 쓰라는 것도 아니고 RequestScope/SessionScope가 동작하는 걸 최대한 단순하게 보여주려는 HelloWorld수준인 걸 누가 모릅니까? ”

    RequestScoped 기능 보여주려고 만든 샘플에 디자인 운운하는게 우스운일 아니냐는 말에, 그게 샘플인걸 누가 모르냐고 합니다. 이때쯤이면 샘플에 디자인을 걸고 넘어지는게, Spring의 ugly hello world 샘플에 시비거는것 같은 우스운일이란걸 본인도 깨닫기 시작한듯이 보입니다.

    “RequestScope/Context를 ThreadLocal 말고 다른 데 저장한 것 본적 없습니다. 스프링은 그걸 설정에 따라서 InheritedThreadLocal로 변경할 수 있는 옵션이 있을 뿐입니다. RequestScope를 담당하는 Servlet이 저장소로 쓸 ThreadLocal을 초기화 하고 작업을 마치면 scoped bean을 제거하는 방식이 thread-pool 때문에 문제가 되는 이유를 어디 한번 설명해 보시죠? 그러면 어떤 대안을 쓰는지도요? 이건 정말 궁금한 것인데 어디 한번 배워보죠. 그냥 “너는 그런 코드 못봤지”하지 마시고 RequestScope구현을 ThreadLocal로 저장할 때 문제가 되는 기술적인 근거를 말해주세요.”

    나는 “transaction context”가 thread local에 저장되는 경우도 있지만, request context에 저장되는 경우도 있다고 얘기했는데, 님은 “request context”가 thread local에 저장되지않는 경우를 말해달라고 합니다. 제대로 읽지를 않은거죠.

    “제가 얘기한 건 request/session/conversation 같은 스코프를 사용하지 말자는 게 아니라, 그걸 DI로 쓰는 것이 편하지만 조심해야 할 것이라는 것이었죠.”

    request scope가 뭐하러 필요한지 모르겠다고 하더니, 갑자기 여기서 말이 또 바뀝니다.

    “컨테이너가 관리하는 오브젝트가 자기 스코프보다 작은 스코프를 가지는 인스턴스를 사용해야 하는 경우를 경험해보신 적이 있긴 한가요? 이건 같은 JavaEE6지만 Provider를 쓰는 것과 그냥 @NormalScope DI를 사용하는 것 두 가지 완전히 다른 접근이 있는데, 여기서부터 이미 혼란이 시작되는 것 같습니다. 이게 별거 아니고 간단해 보이신다면 정말 초고수이거나 JavaEE6 기술의 내용이 뭔지 이해 못하시는 것 같습니다.
    보통 개발자들은 JavaEE6를 쓴다고 해도 왜 그런 방법이 두가지가 있는지, 그 차이가 뭔지, 어떤 것을 선택하는 것이 어떤 의미를 가지는지, 어떤 경우 무엇을 주의해야 할지에 대해서 제대로 설명하지 힘들것이라고 생각합니다. 그게 CDI 예제를 보면서 들기 시작한 제 가벼운 고민입니다.”

    Provider를 사용하면 더 작은 스코프 오브젝트를 할당하는게 대부분 가능하고, DI를 쓰는게 직관적으로 지저분하면 거기는 DI를 안쓰면 그만입니다. 망치를 가지고 있다고 그걸로 이를 쑤실 필요는 없습니다.

    님의 글들을 보면 대부분 별로 critical하지 않은 주제에 대해, 별 상관없는 jargon들을 남발하면서, 클리어한 예제가 없고, 글이 두서없이 왔다갔다하기 때문에 사람들을 더 헷갈리게 만들것 같은 느낌이 듭니다.
    대단히 죄송한 말씀이지만, franklyspeaking, 개인적으로 님의 쓰신책 무료로 받더라도 읽을 일이 별로 없을것 같습니다.

  25. franklyspeaking/ 끝도 없는 꼬투리 잡기에 대해선 더 얘기하고 싶지도 않고.

    제 블로그 글은 그때 그때 제가 당시에 관심을 두고 있는 주제나 생각하고 있는 것들을 끄적이는 뎁니다. 때로는 정리된 생각도 있지만, 때로는 그저 당시에 하는 사소한 고민 같은 것들도 적습니다. 님 같은 분한테 관심갈만한 크리티컬한 주제를 가지고 체계적으로 정리해서 클리어한 예제를 곁들려고 블로그 쓰는 게 아니죠. 님은 블로그를 그렇게 쓰시기나 하는지 궁금하군요.

    죄송하지만 저는 앞으로도 이렇게 계속 나갈테니, 헷갈리는 블로그에 오셔서 “무료로 주더라도 읽지 않을 책”을 쓰는 사람의 글이나 읽는 데 시간 낭비하지 않으시는 것이 좋을 것 같습니다. 저도 스팸함에는 신경 안쓸 겁니다 . 세 번째 드리는 조언입니다.

  26. franklyspeaking/
    >>애초에 님이 걸고 넘어진건 샘플 프로그램에 있는 @RequestScoped와 @Inject였습니다. 같은 request >>thread에서 처리할 정보라면 파라미터로 넘기면 된다는 말은, 같은 request/thread에서 쓰더라도 여러 call >>step후에 사용되는 경우, method signature가 지저분해진다고 얘기해줬습니다.
    사용자가 많이 몰리는 시스템에서는 클래스에 잉여 속성을 추가하는 것은 바람직하지 않아 보입니다.

    – 덧붙이는 글–
    그러고 보니 @inject 같은 어노테이션 사용을 금지하는 코딩 규칙도 나올수 있겠군요?

  27. avanafil Individuals who take these label where you are low substituted hydroxypropylcellulose calcium. http://allbestedmeds.com/acheter-avana-france.html avana if you are the onset of action seems to be faster Buy button and wait or 200. Sexual stimulation that leads than your body actually of blood pressure. http://allbestedmeds.com/acheter-avana-france.html – avana Sexual stimulation that leads than your body actually of blood pressure.

  28. This could not psoislby have been more helpful!

  29. We have decided to open our POWERFUL and PRIVATE web traffic system to the public for a limited time! You can sign up for our UP SCALE network with a free trial as we get started with the public’s orders. Imagine how your bank account will look when your website gets the traffic it deserves. Visit us today: http://bag.sh/16M

  30. I discovered your page and noticed you could have a lot more traffic. I have found that the key to running a website is making sure the visitors you are getting are interested in your subject matter. There is a company that you can get traffic from and they let you try it for free. I managed to get over 300 targetted visitors to day to my website. Visit them today: http://nsru.net/fdse

  31. Hello there, I found your site by way of Google even as looking for a related subject, your site came up, it looks good. I’ve bookmarked to favourites|added to bookmarks.

  32. gucci mane ft future brick fair lyrics Dependecy Injection에는 Prototype Scope가 없다 » Toby’s Epril

  33. gucci outlet stores Dependecy Injection에는 Prototype Scope가 없다 » Toby’s Epril

  34. mbt usa shoes Dependecy Injection에는 Prototype Scope가 없다 » Toby’s Epril

  35. mbt world online shop Dependecy Injection에는 Prototype Scope가 없다 » Toby’s Epril

  36. free shipping skate shoes Dependecy Injection에는 Prototype Scope가 없다 » Toby’s Epril

  37. I noticed that it’s hard to find your website in google, i found it on 16th spot, you should
    create some social bookmarks to rank it in google and increase traffic. I had the same problem with my website, your should search in google for – Insane google ranking boost – it helped me a lot

  38. mbt kimondo shoes Dependecy Injection에는 Prototype Scope가 없다 » Toby’s Epril

  39. Website traffic doesn’t come easy these days. It’s hard and it usually takes a long time. In many cases, too much time… So much that you might be ready to give up. Someone shared a website traffic service with me on my site and I want to share it with you. I was skeptical at first but I tried their free trial period and it turns out they are able to get hundreds of visitors to your website every day. My sales revenue has increased tenfold. Check them out here: http://gmbal.com/1811l

  40. Nike Court Royale Womens
    When you have a serious case of acne, take into account talking with your medical professional about making use of anti-biotics to take care of your epidermis problem. Medicines target the germs within your epidermis, that helps to eliminate your acne leaving your skin layer hunting excellent. Remember that there could be side effects through the medication, such as dry skin and awareness to light.

    https://www.theunionbar.ca/imagess/the2/30915-nike-roshe-run-white-on-feet.jpg

    Don’t simply make 1 movie and provide up! Keep your guests involved and desiring to come back and enjoy a lot more by creating exciting episodes. Depart your visitors hanging after every episode to make sure they simply have to revisit and see what will happen. This can be a wonderful marketing plan and will be highly effective.

    https://www.vom-albtrauf.de/images/newvomrv/3497-reebok-classic-baby.jpg

  41. Kamagra Portugal
    Visit vino fairs! They may be affordable and provide you with the ability to consider a number of different wine whilst you’re there. This can provide you with an excellent possiblity to sample new tastes and vino without spending too much funds if you don’t like it! Most wineries offer you them routinely.
    cialis schweiz
    If you are going through hair loss, sentimentally the best option is usually to just take care of it. Know that it must be properly standard so you will not be on your own. While we all era, at some point, most of us encounter hair loss. Accept it, and love on your own for what you are about, not what you seem like.
    dapoxetin schweiz
    If you intend for taking your iPad in to the kitchen area, you absolutely should have a display screen protector, stylus and ranking case. You may by accident drop goo all over your iPad, and also the protector and circumstance will make sure it affirms away from the apple ipad itself. The stylus keeps tacky hands off of the monitor, too.
    cialis zonder voorschrift

Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

© 2017 Toby's Epril Suffusion theme by Sayontan Sinha