태그 : framework

프레임워크 = 디자인 패턴 + 라이브러리?

어제 어쩌다가 프레임워크 관련 문서를 하나 읽었다. 더글라스 C. 슈미트의 Object-Oriented Application Frameworks와 랄프 존슨의 Evolving Frameworks를 잘 요약해 놓은 문서였는데 이 문서 중에 이런 식이 적혀 있었다.
프레임워크 = 디자인 패턴 + 라이브러리

이 식을 보는 순간 뭔가 억지스럽다는 느낌이 들었다. 별다른 설명없이 이 식만 적혀 있었기에 글에서 (그리고 위의 두 문서에서도) 단서를 찾을 수는 없었다. 식을 보고 든 생각은 대략 이런 것들이었다.
  • 디자인 패턴과 라이브러리를 합한 게 프레임워크라고?
  • 디자인 패턴이 GoF의 디자인 패턴이나 그에 준하는 설계 패턴들을 말하는 건가?
  • 디자인 패턴이 프레임워크를 만들 때 중요한 역할을 하지만 프레임워크의 두 구성 요소 중 하나라고 할 수 있나?
  • 혹시 디자인 패턴을 아키택처 패턴까지 포함한 넒은 의미로 사용했나?
  • 그렇다고 해도 특정 애플리케이션 영역의 지식과 추상화가 프레임워크 제작에서 디자인 패턴보다 더 중요하지 않나?
  • 라이브러리가 그걸 말하는 걸까?
  • 라이브러리란 표현도 좀 어색한데? 어떤 의미로 사용한 거지? 보통은 상위 로직의 추상화가 아닌 하부 로직 모음을 라이브러리라고 하지 않나? 프레임워크에 유용한 클래스 라이브러리가 포함되기는 하지만 필수요소라고 볼 수는 없을 듯 한데... 뭐 이거야 얼마든지 다양하게 쓸 수 있는 여지가 많으니 일단 패스...
무엇보다 그냥 무시하지 못할 것이, 글 자체가 다른 유명한 논문을 요약한 글이기에 작성자가 자의로 이런 식을 쓰지는 않았으리라는 생각이 들었기 때문이다.
대략 이런 단상들이 복잡하게 섞여 떠오르다가 미투데이에 글을 썼다.
프레임워크 = 디자인 패턴 + 라이브러리 이란 공식의 근거는 뭘까? 논리적 비약이 있다고 보는데 혹시 권위 있는 논문이나 책에 근거를 두고 있다면 보고 싶구나
그랬더니 이일민씨가 댓글로 몇가지 단서가 될만한 얘기를 해 줬고 이 식의 원전일 수도 있는 문서를 하나 소개해줬다. ACM에 제출한 논문이라 돈을 주고 사야하나 했는데 간단한 구글 검색으로 구할 수 있었다. (-O-);
이일민씨는 계속 토론을 하고 싶어했지만 내가 배경지식이 없어 오해를 하고 있는 상황일 수도 있으니 일단 문서를 읽고 토론을 계속하거나 내 생각을 정리하기로 했다. (그래서 이 글을 쓴다).
이일민씨가 소개해준 문서는 GoF 중 한 사람인 랄프 존슨의 문서였고 문서 제목이 문제의 식과 비슷했다.
프레임워크 = 컴포넌트 + 패턴 (Frameworks = (Components+Patterns))

회사 업무 때문에 문서 읽을 시간이 없어서 퇴근길에 아이폰에 담아 두었는데 읽기 전까지 제목만 보고는 대략 이런 생각이 들었다.
  • 문제의 식과는 달리 디자인 패턴이 아니라 그냥 패턴이라고 했군.
  • 혹시 이 패턴은 애플리케이션의 문제 영역에 대한 해법을 패턴화한다는 뜻 아닐까? 아니면 그런 의미까지 포함한 더 넓은?
  • 컴포넌트라... 재사용 가능한 클래스를 컴포넌트라고 한 건가?
  • 프레임워크를 사용해 컴포넌트를 만든다고 말한다면 모를까 프레임워크의 두 구성요소 중 하나가 컴포넌트라니... 어떤 의미로 컴포넌트란 단어를 쓴 걸까?
  • 프레임워크, 패턴, 컴포넌트가 복수다. (정확히는 모르겠지만 뭔가 느낌이 달라!)
참고로 내가 컴포넌트라는 말을 쓸 때의 의미는 대략 이렇다.
  • 클래스를 하나 이상 사용해 구현한 기능 단위
  • 소스 코드가 아닌 바이너리 상태로 배포/재사용된다.
  • 경계 객체가 외부와의 인터페이스 역할을 한다.
  • 여러 속성을 외부에서 설정해서 작동 방식을 조정할 수 있지만 일반 클래스 라이브러리보다는 응집도가 높아서 기능을 확장하기엔 한계가 있다.
아무튼 시간은 흘러 퇴근 시간이 됐고 문서를 읽었다. 피곤한 가운데 (10시 퇴근) 흔들리는 버스 안에서 읽었기에 정독하지는 못했기에 바로 이해했는지 모르겠지만 문서의 내용은 대략 이랬다.
  • 프레임워크는 객체지향 재사용 기술이다.
  • 프레임워크는 다른 전통적인 재사용 기술과 비슷한 부분도 있지만 차이점도 있다.
  • 프레임워크는 장점도 있지만 단점도 있다.
  • 프레임워크가 컴포넌트라고 말하는 사람이 있는데 비슷한 부분이 있음에도 프레임워크는 컴포넌트보다 더 (확장해서 애플리케이션의 특별한 상황에 맞추기에) 유연하고 (배우고 사용하기) 복잡고 어렵다.
  • 프레임워크가 설계 재사용이라고 볼 수도 있지만, 다른 설계 재사용 기술이 별도의 설계 표현 방법을 사용하는 한편 프레임워크는 코드로 설계를 표현했다는 점에서 다르다. 프레임워크는 언어에 종속적이다.
  • 프레임워크는 애플리케이션 생성기나 도메인 전용 아키텍처와도 유사하지만 다르다.
  • 프레임워크는 패턴을 표현하기도 하고 패턴을 활용하기도 한다. 하지만 코드로 표현했다는 면에서 더 구체적이고 일부 구현을 했다는 점에서 유연성이 떨어진다.
 글에서 다른 재사용 기술과 프레임워크의 차이를 비교하면서 프레임워크의 성격을 정의한 문장은 이렇다.
Frameworks are firmly in the middle of reuse techniques. They are more abstract and flexible than components, but more concrete and easier to reuse than a pure design (but less flexible and less likely to be applicable). Although they can be thought of as a more concrete form of a pattern, frameworks are more like techniques that reuse both design and code, such as application generators and templates. Patterns are illustrated by programs, but a framework is a program.

 프레임워크는 분명히 재사용 기술들 중심에 있다. 프레임워크는 컴포넌트보다 추상적이고 유연하지만 순수한 설계보다는 구체적이고 재사용하기 쉽다(반면에 유연성이나 적용 가능성이 떨어진다). 프레임워크를 패턴을 구체화한 형태로 볼 수 있다. 그럼에도, 프레임워크는 애플리케이션 생성기과 템플릿처럼 설계와 코드 모두를 재사용하는 기술에 더 가깝다. 패턴을 설명할 때 프로그램을 사용하는 반면에 프레임워크는 프로그램 자체다.
 그럼 문서를 읽고 나서의 내 생각은 뭘까?
 일단 프레임워크 = 패턴 + 컴포넌트라는 식에 대한 생각은 이렇다.
  • 이 식을 수식으로 보면 안 된다. 프레임워트가 단순히 하나 이상의 패턴과 컴포넌트의 "조합"이란 의미는 아니다.
  • 그럼 이렇게 보면 어떨까? Pattern < Framework < Component. 어느 정도 문서의 내용과 비슷하지만 이것도 아니다. 프레임워크가 추상화 관점에서 패턴과 컴포넌트 중간 정도에 있는 건 맞지만 패턴이 컴포넌트로 구체화 되는 중간에 생기는 것은 아니다.
  • 이 식을 변증법적으로 읽으면 어떨까? 즉 "+" 기호를 "종합"으로 읽으면? 비록 패턴과 컴포넌트가 정과 반의 관계는 아니지만 둘을 "종합"한 결과로 전혀 다른 성격의 합이 나왔다는 식으로 읽으면 어느 정도 글의 내용과도 일치하고 내 직관과도 어긋나지 않는다.
원래의 식인 프레임워크 = 디자인 패턴 + 라이브러리에 대한 내 생각은 이렇다.
  • 일단 글에서 자세한 설명을 하지 않았기에 추측 이상은 어렵다.
  • 랄프 존슨의 글이 원전이라면 패턴을 디자인 패턴으로 바꾼 건 오류에 가깝다. 흔히 디자인 패턴은 GoF의 디자인 패턴을 말할 때 사용하는데 이 디자인 패턴은 패턴이라는 도구를 객체 설계 영역에 적용한 결과며 랄프 존슨의 글에서는 디자인 패턴에 제한해서 패턴을 말하지는 않는다. 물론 디자인 패턴은 프레임워크 제작에 아주 중요한 역할을 한다.
  • 컴포넌트를 라이브러리로 바꾼 부분도 오해의 소지가 크다. 흔히 라이브러리는 작은 하위 기능 요소의 묶음을 의미하며 컴포넌트 같이 덩어리가 큰 코드를 묶었다고 라이브러리라고 부르지는 않는다. (적어도 내 단어 사전에 의하면... 하지만 Evolving Framework에서는 컴포넌트 라이브러리란 말을 쓴다).
하지만 마음을 곱게 써야 성장한다고 하니 이 글 덕에 좋은 글을 읽을 수 있어서 고맙다고 해야겠고 오해의 소지가 있어 보임에도 아주 틀렸다고도 할 수 없으니 뭐... 그렇다. (응?)
다시 확인한 교훈 한가지는 가능하면 원전 또는 고전을 읽어야 한다. 사실 랄프 존슨의 논문은 여러 글에서 인용된 글이라서 어느 정도 부분적으로는 접했던 내용이다. 하지만 원문을 읽으니 확실히 이해의 깊이와 폭이 다르다.
나 같은 삼거리 개발자가 스프링 덕에 별 복에도 없는 좋은 지식을 익히게 된다는 생각이 든다. 좋은 API는 좋은 코드를 유도할 뿐 아니라 좋은 지식을 쌓게 하고 좋은 사람들을 만나게 한다. (갑자기 왠 뚱딴지 같은 결말?)

------

추가

여러 말을 했지만 내 논점은 딱 두 가지다.
  1. 문제의 식에서 디자인 패턴이 뭘 말하는 걸까? 내 생각에 디자인 패턴이란 단어는 고유명사에 가깝다고 생각한다. 그러니 식에서 사용한 디자인 패턴이 GoF의 디자인 패턴을 말할 때 사용하는 디자인 패턴과 의미가 다르다면 표현을 바꾸거나 따로 설명을 해야 한다고 본다. 그리고 만약 정말 GoF의 디자인 패턴과 같은 의미로 사용했다면 디자인 패턴의 의미를 너무 강조한 것 아니냐는 생각이 든다. 프래임워크 제작에 디자인 패턴이 중요하지 않다는 말이 아니다. 비 본질적이라는 의미다. 내 말은 좋은 객체지향 코드 중에 디자인 패턴이랑 관계 없는 코드가 어디 있냐는 말이다.
  2. 문제의 식이 자의적으로 만들어낸 식인지, 아니면 어떤 권위있는 원전에 근거를 두고 있는지 아직 모르겠다. 적어도 랄프 존슨의 글은 아니라고 본다.

by 박성철 | 2011/07/21 10:17 | 프로그래밍 이야기 | 트랙백(2) | 핑백(1) | 덧글(4)

프레임워크를 사용하는 이유

* 써 놓고 보니 서론은 정말 읽을 필요 없겠습니다. 본론으로 점프 하세요. ^^;;

블로그를 개설한 이후 아침마다 습관처럼 하는 것이 방문 통계 보는 것입니다. 몇 사람이 방문했는지를 먼저 보기는 하지만 검색 키워드를 가장 유심히 보게 됩니다. 어떤 이유로 이 어둠의 장소까지 흘러 들어오셨는지 참 궁금하더라구요. 그런데 어제 어떤 분이 '프레임워크를 사용하는 이유' 라는 키워드로 제 블로그를 방문해 주셨더군요.

사실 많은 분들이 이런 질문을 한 번 쯤은 하셨을 것 같습니다. 저도 물론 그랬구요. 굳이 프레임워크가 아니더라도 어떤 기술을 써야 할지 말아야 할지 늘 고민을 하게 되죠. 그래서 저 나름대로의 기준을 가지고 Lost In space of technology라는 글을 쓰기도 한 것 입니다.

사실 어떤 기술을 채용한 이유를 순전히 객관적으로 설명하라고 하면 과연 얼마나 많은 사람이 그걸 논리적으로 설명해서 반대자들을 설득 할 수 있을까요? 어떻게 설명이야 하겠지요. 그러나 수 많은 논란만 일으킬 뿐 결론이 나지는 않을거라고 생각합니다. 그 사람이 하는 설명이 어느 정도의 합리적인 형태를 갖추기야 하겠지만 저는 기술적인 결정의 지배적인 요인은 현실적으로 정치적인 타협 또는 신념의 관철이라고 봅니다. 한마디로 취향인거죠. 다행히 팀의 취향이 동일하다면 별 문제 없이 그 기술이 적용되겠지만 누군가 불만이 있다면 팀장이나 일부 어떤 오피니언 리더의 고집과 평화주의자들의 침묵 가운데 어쩔 수 없이 쓰게 되는 경우가 될 겁니다.

저도 몇 번은 어거지로 기술을 도입하게 했던 범죄를 저지른 경험이 있고... 또 투덜거리면서 맘에 들지 않는 기술을 억지로 사용했던 적도 있습니다. 잘 진행이 안될 때 그 기술을 도입하자고 했던 사람을 공격하는 것은 물론 잊지 않았죠. ㅎㅎ

요즘은 어떤 기술을 쓸지 결정하는 과정에서 권위 있는 발언을 하는 사람은 보통 '이해관계자'라고 번역되는 Stakeholder들이라고 생각합니다. 한마디로 돈줄을 쥐고 있는 사람들이죠. 고객이 될 수도 있고 투자자가 될 수도 있고... 사장이 되기도 하고... 이 사람들은 어디선가 봤던 기술 단신 또는 식사를 같이 했던 영업사원의 감언이설에서 그 기술에 대한 환상을 갖게 되고 이것을 기술진들에게 강요하곤 합니다.

프레임워크를 사용하는 이유


서두가 길어졌는데 제가 프레임워크를 쓰는 이유를 간단히 생각나는 대로 적어보았습니다.
  1. 코드 품질을 보장하기 위해
  2. 백지의 압박이 싫어서
  3. 언어의 표준화
  4. 유지보수성
  5. 개발 편의
  6. 뒤쳐지지 않고 있다는 위안
하나씩 간단히 설명을 해볼까요?

코드 품질을 보장하기 위해

저희 개발팀에 프레임워크라는 것을 처음 도입한 유일한 이유는 코드 품질 때문이였습니다. 품질을 향상 시키려는 게 아니고 품질을 떨어트리지 않으려고...;;;

저랑 한두 명이 일할 때는 제가 모든 사람의 코드를 살펴 보고 문제가 있는 부분은 지적해서 고치게 했었습니다. 작동만 하면 된다는 것은 저한테 통하지 않았기 때문에 저 때문에 많이 힘들어 했었을 겁니다. 다른 사람이 자기 코드를 한줄한줄 짚어가면서 잘못을 지적한다면 무척 기분 나쁘겠죠. 하지만 남의 돈을 받아가면서 일을 하는 이상 일정한 품질은 반드시 유지해야 한다고 생각했습니다. 저도 사회 초년생일 때에 저희 상사에게서 그렇게 배웠구요. 저도 기분 나빴지만 솔직히 배우는게 더 많았습니다.

그런데 사람들이 더 늘어나면서 품질에 문제가 생기기 시작했습니다. 저도 제가 맡은 분량이 있으니 모든 사람의 코드를 다 살펴보는 것이 사실상 불가능해진 것이죠. 문제는 여기저기서 생기고... 이미 그렇게 하면 안된다는 것을 다른 사람들은 알고 있었지만 신입사원에게 그것이 전달되는 시스템은 없었던 것입니다.

개발팀이 체계적으로 잘 만들어져서 운영된다면 따로 교육기간도 있고 품질 관리나 개발 방법론 같은 것도 정립되어야 할 것 같지만 저희 같이 작은 회사에서 그런 것을 다 만든다는 게 힘들 뿐 아니라 솔직히 오히려 부작용만 있을 수 있다는 생각이 있습니다. 오히려 문화를 만들고 공유하는 것이 더 효과적이지요.

같은 언어를 쓰고 같은 방식으로 설계하고 구축하는 것이 정착된다면 품질 때문에 문제가 되는 일이 많이 줄어들 것이라 생각했고 그래서 적당한 프레임워크를 도입하거나 만들어 쓰게 되었습니다.

혼자 일한다면야 이런 부분에서 문제를 별로 느끼지 못하시겠지만 팀의 품질을 일정 수준으로 유지해야만 하는 상황, 더구나 특별히 누군가가 그 일을 위해서 시간을 투자해 신경을 쓸 수 없는 상황에서 적절한 프레임워크를 도입하게 되면 많은 효과가 있는 듯 합니다.

그러나 외부의 프레임워크를 그대로 가져다 쓰면 이것이 자연스럽게 해결되지는 않더군요. 오히려 이 프레임워크를 더 다듬어서 다양한 사례에 적용해보고 그 결과를 공유하는 작업이 필요했습니다. 저 같은 경우는 이 부분에서 신경을 쓰지 못해서 수년 동안 문제 있는 코드가 회사 내에 유령처럼 떠돌아다니는 상황을 목격했습니다.

이런 코드는 사실 제가 투입되지 않았던 프로젝트에서 대부분 생산이 되었는데 이것을 없애기가  바퀴 벌래 박멸 보다 더 힘들어 보입니다. 사실 제가 포기하고 말았지요. 결국 아키텍처는 그 프레임워크로 어플리케이션을 개발하는 사람 중 하나가 만들어야 한다는 말은 진짜 옳은 말입니다.

백지의 압박이 싫어서

무슨 일을 할 때에 일을 하는 순서가 정해진 것과 매번 백지에서 하는 것과는 심리적으로 느끼는 부담감이 다릅니다. 프레임워크는 이런 부담을 많이 줄여줍니다. 일의 순서가 정해져 있으니 그것을 따라 하면 되는 것이죠. TDD가 주는 부수적인 이점도 비슷하다고 생각합니다. 일단 돌려서 결과를 볼 수 있다는 게 개발의 지루함을 많이 줄여주게 되니까요.

프레임워크를 사용한 다양한 예제가 있다면 더욱 좋다고 생각합니다. 저도 대부분 예전에 작업했던 코드를 가져다 수정하는 방식으로 개발을 많이 하는데 프레임워크가 사용하지 않았다면 이런 일은 어렵겠죠. 매번 새로운 프레임워크를 써야 하는 상황이라면 조금 다르다고 생각하는 분이 계시겠지만 같은 방식의 프레임워크 간의 포팅은 완전히 새로 짜는 것 보다 쉽게 느껴지더군요. 예를 들어 struts로 개발한 코드를 struts2나 spring mvc로 포팅하는 것은 쉬운데 tapestry나 jsf로 포팅하는 것은 비용이 많이 들겠죠. 저는  struts의 코드를 spring mvc로 포팅해서 구축한 경험이 있었는데 그리 어렵지 않았습니다. 처음부터 다시 짠 것 보다 더 빨리 작업했는지는 모르겠지만 적어도 맘은 편했습니다. ^^

언어의 표준화

앞의 코드 품질과 관계되기도 하는데 개발 할 때에 프레임워크를 도입하게 되면 자연히 그 개발 철학과 언어도 같이 들어오게 됩니다. 그러면서 자연히 언어가 통일되게 되죠. 서로 대화도 편해지고 명확해집니다. 자연히 사고 방식도 맞춰지구요.

유지보수성

다른 사람이 만든 코드를 들여다 보는 게 얼마나 힘든 일인지 개발자들이라면 다 알겁니다. 그걸 수정하느니 다시 만드는 게 낫다고들 하죠. 그런데 그게 타사의 개발자가 만든 코드가 아닌 같은 회사의 개발자가 만든 코드라면 좀 문제가 심각한 것이겠죠.

저는 기본적으로 같은 회사의 개발자들은 큰 부담 없이 서로의 코드를 이해 할 수 있어야 한다고 생각합니다. 그래야 품질도 어느 수준에서 보장되는 것이고 유지보수 비용도 적게 들게 되는 것이고 재사용도 할 수 있게 되죠.

프레임워크를 사용하면 그런 면에서 많은 도움을 받을 수 있습니다. 저는 어떤 일을 하게 되면 동료들에게 비슷한 경우가 있었는지 물어보고 그 코드를 가져다 수정하는 식으로 작업을 합니다. 물론 이렇게 하려면 프레임워크를 어떻게 사용 할지에 대한 것도 시간이 지남에 따라 어느 정도 정형화 되어야 하겠지요.

개발 편의

대부분의 프레임워크들은 개발을 편하게 하기 위한 다양한 기능들을 가지고 있습니다. 이런 것은 제가 따로 만들 수도 있겠지만 제 경험상 프레임워크에서 제공해주는 코드가 제가 만든 것 보다 훨씬 낫더군요. 저 보다 똑똑한 사람이 만든 게 분명해 보였습니다. ^^

뒤쳐지지 않고 있다는 위안

개발자라면 늘 최신 기술 흐름에서 떨어지지 않으려는 욕심이 있을 겁니다. 모든 것을 외부의 도움 없이 스스로 해결 할 수도 있겠지만 어느 한 순간 우물 안 개구리가 되는 경우도 있지요. 꼭 트렌드를 따라야 한다고 말하고 싶지는 않구요. 오히려 남들이 안하는 특수 분야를 파고 드는 것이 장점이 될 수도 있다는 것은 인정합니다. 하지만 전 좀 남들에게 개발자로 인정 받고 싶은 욕심이 있어서 그런지 외골수로 파고들기 보다는 약간은 흐름을 타고 싶더라구요.

실패를 방지하기 위한 어설픈 조언

이왕 글을 쓴 것... 프레임워크를 사용하면서 쓰라린 경험을 가지고 계신 분이 있다면 몇 가지 조언을 드려볼까 합니다. 대부분 제가 실패한 경험을 기초로 적었습니다.
  1. 그 프레임워크의 철학과 해법에 동의하지 않는다면 절대 도입하지 마십시오. 혹시 그 철학이 이해되지 않는다면 더욱 도입해서는 안됩니다.
  2. 한번만 쓸 생각이라면, 그리고 그 코드가 계속 유지보수 되어야 할 성질의 것이 아니라면 그냥 하던 대로 하십시오. 프레임워크뿐 아니라 대부분의 신기술 도입은 생각보다 ROI 주기가 상당히 긴 것 같더군요.
  3. 개발 일정이 빡빡하고 개발자들이 그 프레임워크에 익숙하지 않다면 포기하십시오.
  4. 그 프레임워크를 소개만하고 도입하는데 헌신 할 생각이 없다면 포기하십시오. 그것이 성공적으로 정착 되도록 남들 보다 더 연구하고 미리 고민하여 문제를 해결해둬야 합니다.
  5. 풍성한 사례별 예제를 준비하십시오.
  6. 단계별로 도입하는 방법을 찾아보세요. 순식간에 100% 새로운 프레임워크 환경으로 이전하는 것은 비용이 너무 많이 들고 실패 할 확률이 높습니다. 아주 기본적인 것만 적용해서 프로젝트 진행 했더라도 대부분의 개발자들은 '아직도 이해 못하겠어'라고 말 할겁니다. 개발하는 것도 정신 없어 죽겠는데 프레임워크를 따로 신경 쓰면서 공부 할 사람이 몇이나 있겠어요. 그냥 하라니까 하는거죠.
아... 일해야 하는데 내가 뭐하는 것인지...ㅠ.ㅠ

by 박성철 | 2007/12/17 17:18 | 프로그래밍 이야기 | 트랙백(2) | 덧글(8)

What's New in Spring 2.5: Part 1


스프링 2.5가 드디어 릴리즈 되었네요.
좀 천천히 관심 둘 여유있을 줄 알았는데... 플젝 투입되어 있어서 정신이 없습니다.

19일, 인포큐에 스프링 2.5의 새로운  부분에 대한 글이 올라왔었습니다.
 
http://www.infoq.com/articles/spring-2.5-part-1

그냥 이런게 올라왔었구나... 나중에 읽어야지.. 하고 미뤄두었었는데 릴리즈도 된 마당에 대충이라도 읽어봤습니다.

2.0에서 XML 스키마 지원으로 스프링을 즐겁게 쓰도록 만들어 주었었는데... 이번에는 더욱 단순하고 강력한 스프링이 되었다고 하네요. 2.0은 2.5로 가기 위한 맛보기...ㅎㅎ

개인적으로 어노테이션을 통한 설정이 생각 만큼 생산성을 높여줄지에 대해서는 의문이지만 XML를 끔찍하게 여기는 사람들이 많기 때문에 매우 환영할만 하다고 생각합니다.

이왕 글을 쓴거 위 글의 내용을 약간 요약해보겠습니다. infoq에 기고된 글의 저작권이 어찌되는지 모르지만 요약 정도는 상관 없겠죠?

이 글은 총 3회에 나눠서 쓰여질 기고문의 첫번째에 해당합니다. 주로 어노테이션과 관련된 부분에 대해서 설명하고있구요.두번째 글은 Web Tier 쪽을, 마지막 글은 통합과 테스팅에 관련된 기술을 논하려고 한답니다. 아마도 두번째는SpringMVC를 마지막은 JUnit 4 지원과 OSGi가 될 듯 하네요.

JSR-250 어노테이션 지원

스프링 2.5에 새로 지원하는 어노테이션은 다음과 같다고 합니다.
  • @Resource
  • @PostConstruct
  • @PreDestroy
@Resource

DI를 위해서 사용합니다.
빈 컨테이너 안의 빈들 중에서 지정된 이름의 빈을 찾아서 DI를 해줍니다. 아래 예에서라면 스프링은 관라하는 빈들 중 이름이 dataSource인 놈을 가지고 setDataSource()를 호출하는거죠.
@Resource(name="dataSource")
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
직접 맴버 변수에 지정할 수도 있는데 이렇게 하면 setter 없이도 DI가 된다네요. 요거 맘에 듭니다.

@Resource
private DataSource dataSource; // inject the bean named 'dataSource'

위의 예에서 처럼 이름을 지정하지 않으면 변수 이름이 자동으로 사용되네요. 아래처럼 setter 메소드에 이름 없이 지정 할 수도 있다고 합니다.
private DataSource dataSource;
@Resource
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
이름으로 빈을 찾았는데 없으면 타입으로 찾아서 인젝션 해준답니다. 원하지 않으면 이 기능을 끌 수도 있습니다.

Lifecycle 어노테이션 @PostConstruct와 @PreDestory

기존에 빈 생성시 빈을 초기화하고 소멸시 정리하는 작업을 하려면 InitializingBean과 DesposableBean 인터페이스를 상속하거나 빈설정시 명시적으로 초기화 메소드와 정리 메소드를 지정해 주었어야 합니다.
인터페이스를 사용하면 자동화 되어 좋기는 하지만 스프링 디펜던시가 생기고 - 솔직히 이 빈을 다른 곳에서 쓸 일이 얼마나 있겠냐만 늘 결벽증 때문에 사용안하게 된다죠 - 그래서 설정을 주로 사용하곤 했습니다.

사용은 간단합니다. 초기화 메소드와 정리 메소드 위에 각 어노테이션을 표기만 하면 되는거죠.

public class FilePoller {

@PostConstruct
public void startPolling() {
...
}
...

@PreDestroy
public void stopPolling() {
...
}
...
}
늘 XML 설정 할 때 마다 빼먹을까봐 신경 썼었는데 좋네요.

정밀한 오토와이어링

2.5 이전에도 여러가지 오토와이어링 방법을 제공했습니다. 컨스트럭터, 셋터의 타입, 셋터의 이름, 자동인식.... 하지만 전체적으로어떤 것을 선택할지 설정 할 수는 있어도 어떤 경우에는 타입으로 찾고 어떤 경우에는 이름으로 찾을지 정밀하게 제어 할 수는 없었습니다.

위에서 말한 것 처럼 2.5에서는 @Resource 어노테이션으로 메소드별 필드별로 이름 기반의오토와이어링을 지정 할 수 있게 되었습니다. 하지만 이건 제약이 있어 스프링 2.5에서는 @Autowired 어노테이션을추가했다고 합니다. 이건 비표준인거죠. 스프링 디펜던시가 생깁니다.

@Autowired 어노테이션은 컨스트럭터, 메소드, 필드에 사용하며 타입으로 오토와이어링 하도록 지정하는 기능을 가지고 있습니다. 그런데 메소드가 꼭 셋터일 필요는 없습니다. 심시어 패러미터가 여러개인 경우도 상관 없답니다. 오호...
@Autowired
public void setup(DataSource dataSource, AnotherObject o) { ... }

기본적으로 이 어노테이션으로 표시된 항목은 필수인 것으로 처리되지만 required 옵션을 false로 하면 빈을 못 찾아도 그냥 넘어갑니다. 예를 들어 다음에서 빈을 못찾으면 그냥 하드코딩한 DefaultStrategy가 사용되는거죠.

@Autowired(required=false)
private SomeStrategy strategy = new DefaultStrategy();

이렇게 타입으로 빈을 찾는데 해당 타입의 빈이 하나 이상일 경우 스프링은 오토와이어링이 실패한 것으로 처리합니다. 이 문제를 해결하기 위한 몇가지 방법이 있습니다. 우선 빈 설정에서 primary 속성을 사용하는 방법이 있다.

<bean id="dataSource" primary="true" ... />

이번 2.5에는 보다 정밀한 제어가 가능한데 @Qualifier 어노테이션을 사용하면 빈 이름을 지정할 수 있다. 타입이 아닌 이름으로 찾게 됩니다.

@Autowired
@Qualifier("primaryDataSource")
private DataSource dataSource;

이 어노테이션을 별도로 만든 이유는 다음 처럼 사용할 수 있게 하려는 것이라네요. 머리도 좋아요. 이 어노테이션은 컨스트럭터 매개변수, 필드, 메소드 매개변수 어디에도 쓸 수 있답니다.

@Autowired
public void setup(@Qualifier("primaryDataSource") DataSource dataSource, AnotherObject o) { ... }

이 뿐 아니라 커스텀 어노테이션을 사용한 인젝션에도 사용될 수 있다는데요. 요건 읽기 귀찮아서 일단 PASS...

스프링 컴포넌트 자동 인식

스프링 2.0부터 스테레오 타입 개념의 어노테이션이 도입되었습니다. @Repository는 데이타 억세스 코드라는 표시를 하는 어노테이션으로 사용된 것이죠.
2.5에는 일반적인 3-Tier 아키택쳐에서의 역활을 표기하기 위해 @Service와 @Controller라는 어노테이션을 추가했습니다. 이와 함께 제너릭 어노테이션인 @Component도 추가...

이들 어노테이션들은 객체에 역할을 부여해서 AOP나 후처리기가 뭔가 추가적인 작업을 하도록 해줍니다.

이 어노테이션들로 사용할 수 있는 새 기능 중 하나가 컴포넌트 자동 인식 기능... 오토와이어링을 쓰더라도 기본적인 빈 설정을 해주었어야 했지만 이 컴포넌트 자동 탐색 기능을 쓰면 이 기본적인 빈 설정 조차 필요없게 됩니다.

2.5의 PetClinic 샘플을 보면 하부구조에 해당하는 컴포넌트들은 XML에 설정이 되어 있지만 Web Tier 컨트롤러들은 자동 인식 기능을 사용하도록 되어 있다는군요. 저도 처음 이 기능을 들었을 때에 Web Tier에 적용하면 좋겠다고 생각되더군요. XML의 명시적이고 중앙집중적인 특징도 무시는 못하죠. 개발할 때에는 편의상 오토와이어링을 쓰더라도 운영환경에서는 XML이 역시... 혹시 새로 생긴 자동 탐색 기능과 오토와이어링 기능으로 구성된 빈 컨테이너의 내용을 XML로 생성해주는 방법이 있다면 좀 알려주세요.

<context:component-scan base-package="org.springframework.samples.petclinic.web"/>

이렇게 지정된 패키지 안의 클래스들을 탐색해서 스테레오타입이 지정된 클래스들을 찾아냅니다. 예를 들면 이런 Spring MVC 컨트롤러...

@Controller

public class ClinicController {

private final Clinic clinic;

@Autowired
public ClinicController(Clinic clinic) {
this.clinic = clinic;
}
...

탐색 규칙을 커스터마이제이션 할 수도 있습니다. 다음과 같이 하면 스테레오 타입을 찾는 기본 룰은 사용하지 않고 Stub로 시작하는 클래스들과 Mock 어노테이션이 되어 있는 클래스들을 스프링 객체로 인식하게 할 수 있습니다.

<context:component-scan base-package="example" use-default-filters="false">
<context:include-filter type="aspectj" expression="example..Stub*"/>
<context:include-filter type="annotation" expression="example.Mock"/>
</context:component-scan>

기본 탐색 규칙을 조정 할 수도 있습니다. 아래 예는 탐색시 @Repository 어노테이션을 제외시킵니다.

<context:component-scan base-package="example">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>

 물론 커스텀 어노테이션을 탐색에 사용하게 할 수도 있습니다. @Generic 제넥릭 어노테이션으로 다음과 같이 커스텀 어노테이션에 @Generic 어노테이션을 사용하면

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface BackgroundTask {
String value() default "";
}

이 어노테이션이 지정된 객체들은 모두 스프링 객체로 인식이 됩니다.

@BackgroundTask
public class FilePoller {

@PostConstruct
public void startPolling() {
...
}

@PreDestroy
public void stopPolling() {
...
}
...
}

이렇게 자동 인식된 빈들은 클래스 이름으로 등록이 됩니다. 위의 예에 나오는 FilePoller 클래스는 filePoller라는 이름으로 스프링에 등록되는거죠. 만약 다른 이름을 원하면 이렇게 합니다.

@Service("petClinic")
public class SimpleJdbcClinic {
...
}

기본적으로 스프링은 빈을 싱글톤으로 관리하지만 다른 스코프를 써야 할 경우도 있습니다. 이 경우는 요렇게...

@Component
@Scope("session")
public class ShoppingCart {
...
}

전 지금 진행중인 프로젝트에 2.5를 적용할 예정입니다. 원래 아발론으로 만들어진 서버 프로그램인데 스프링으로 바꾸고 있거든요.

프로그래밍이 즐거워지네요. ㅎㅎ

아! 아시겠지만 제가 잘못 이해해서 생긴 오류에 대해서는 책임 안집니다. ;;;

by 박성철 | 2007/11/21 18:20 | 프로그래밍 이야기 | 트랙백(2) | 핑백(1) | 덧글(2)

◀ 이전 페이지다음 페이지 ▶