마커 애노테이션과 디자인을 위한 리플렉션
지난 번에 한 생각을 좀 더 정리해보려고 자바의 까칠대마왕 조쉬 블록이 뭐라고 했는지 좀 찾아봤다.
조쉬는 자바JDK의 핵심 개발자이고 Java5+의 개발에도 깊이 관여한 만큼 애노테이션에 관해선 전반적으로 긍정적인 입장이다. CoC스타일의 이름을 이용한 패턴보다는 애노테이션을 쓰는 게 낫다고 한다. 예를 test로 시작하는 메소드 이름을 찾아내는(JUnit2.0에 등장한 기법이다) 방식보다는 @Test를 붙이는게 낫다는 것을 예로 들기도 한다. 사실 그동안은 없으니까 못썼지.
그러나 마커 애노테이션의 타입이 ElementType.TYPE이라면 대신 마커 인터테이스가 낫지 않은지 곰곰히 따져보라고 한다. Marker Interface는 타입을 정의해주지만 Marker Annotation은 그렇지 않기 때문이다. 물론 리플렉션 API로 확인은 가능하지만, 사용편의성에서 보자면 차이는 크다. 인터페이스 vs 읽기편한 XML 수준이다. @List list = new ArrayList() 이런건 안되니깐.
타입(Class, Interface)이 아닌 메소드, 필드에는 애노테이션을 어쩔 수 없이 사용해야겠지만 말이다.
일단 여기서 인터페이스 +1.
그러나 부가정보가 들어가면 애노테이션 승리.
만약 스프링의 @Component에 bean name을 지정하는 것만 없었다면 Component인터페이스를 마커로 달게 하고 이를 가지고 컴포넌트 스캔을 하도록 했을지도 모르겠다.
타입에 붙는 마커 애노테이션이 어짜피 마커 인터페이스처럼 메소드 추가도 안하는데, 그냥 타입으로 사용할 수 있게 해주면 안되나하는 아쉬움도 있지만, 어짜피 태생이 메타 정보니 따로 놀아야겠지. 이쯤에서 아주 아주 오래전에 아드리안 콜리어가 말한 APOJO(Annotated POJO)도 POJO냐라는 얘기가 생각난다. 나는 A를 떼도 문제없이 동작하면 POJO라고 생각한다. A가 없으면 뭔가 기능에 절름발이가 된다면 POJO가 아닌 뭔가 다른 것이다. 왜냐면 그 A를 처리해주는 툴(프레임워크)의 도움이 필요할테니, 그게 독립된 오브젝트라고 말하기는 좀 이상하니깐.
어쨌든 내 불만이라면 애노테이션이 붙어있다고 마치 타입이 선언된 것처럼 취급을 해버리는 방식이다. 애노테이션 기반의 절름발이 다형성?
다음은 리플렉션. 당연한 얘기지만 리플렉션의 과용은 CoC, 메타프로그래밍를 위해서는 필수이지만, 그만큼 단점이 있다.
조쉬는 리플렉션에 대해서는 이렇게 단언하고 있다. "리플렉션 보다는 인터페이스를 선호해라" IoR이라고 해야 하나. 그 이유로
- 컴파일 타임의 타입 체킹 불가능 (뭘 언제 어떻게 호출할지 모르니깐)
- 리플렉션을 사용하는 코드의 지저분해짐 (한번만 개발해보면 온몸으로 느낄 수 있다)
- 성능 (이건 뭐 많이 개선되었다고 하긴 하는데.. 그래도 많이 쌓이면 차이가 크겠지)
그러다 이런 얘기가 나온다.
"코드 리플렉션 기능은 원래 컴포넌트베이스 애플리케이션 개발 툴을 위해서 만들어진 것이다."
그렇구나. 리플렉션은 원래 CoC적용하고 메타 프로그래밍 하라고 만든 것은 아니고, 개발이나 설계도구에서 클래스 정보를 읽어오거나 setter를 호출해서 프로퍼티 값을 넣는 등등에서 사용하기 위해서 만들어진 것이다.
따라서 당연하게도 리플렉션을 이용한 방법보다는 정상적인 코드에 의해서 호출되는 방법을 선호해야 한다. 아무리 루비 사용자들이 자바의 스태틱 타이핑은 꾸졌고, 메타 프로그래밍도 안되는 저급 OOP 바보언어라고 놀려도 "우리도 리플렉션API도 있고 할 거 다 한다"라고 비굴하게 굴 건 없다.
물론 다이나믹프록시라든가 RPC를 위한 스텁기능등을 지원하기 위해서 꼭 필요할 때가 있다. 프레임워크 또한 필요하다. 리플렉션 API가 없었다면 JUnit의 플러거블 셀렉터는 어찌 만들었을까. 그럼 JUnit 0.9쯤에서 끝나고, 아마 매 테스트마다 클래스 하나씩 새로 정의해서 써야 했을 거다. 템플릿 메소드 패턴이 있으니까 setUp, tearDown쯤은 공유했겠지만.
결론은 적절한 사용이 어디까지냐인데.. 한참 더 생각해볼 일이고. 분명한 것은 폼나는 CoC등에 너무 욕심내지 말고, 과도한 사용은 득보다 실이 클 수 있다는 상식을 가지면 좋다는 것. 계속 생각해보자.
참, 우리의 최고수는 연락이 없다. 잠적했나? 삐졌나? 내일이 세미나 날인데…
잠적은 무슨… 070 전화해도 안 받는 사람이 누군데
오늘 밤 비행기로 북경 가.
층을 옮기니까 구글톡 접속 불가야.. ㅡㅡ;
영회/ 새벽 한시 반에 skype로 전화한 게 너였구만. 그때 받을리가 있나.
CoC가 뭔가요? (구글 검색했더니 이상한 것만 잔뜩…)
초보님,
저도 약어에 약해서 제가 생각한게 맞는지 확신은 안 섭니다만,
Convention over Configuration 을 말씀하시는거 같습니다…
http://en.wikipedia.org/wiki/Convention_over_Configuration
초보/ Convention over Configuration 맞습니다. 관례를 설정보다 많이 쓰자는 얘기입니다.
예를 들어 MVC에서 UserController의 add메소드라면 구지 매핑 설정을 하지 않아도 “Controller를 뺀 컨트롤러이름/메소드이름+표준확장자” 관례를 따라서 /user/add.do 라는 URL에 매핑을 해주게 할 수 있죠. 이러면 매번 일일히 설정해줘야 하는 번거로움을 상당히 제거해줄 수 있습니다. 대신 관례가 복잡해지고 이를 정확히 알지 못하면 예상하지 않았던 방식으로 동작할 수 있어서 깜짝 놀랄 수도 있습니다.
대체로 관례가 네이밍룰과 파라메터 종류, 순서 같은 것의 조합을 가지고 만들어지는데, 그래서 이를 지원하려면 애노테이션과 Reflection API등을 써서 분석해줘야 하는 부담이 있습니다.
답변 감사합니다. 저게 레일즈부터 시작하여 유행한 스타일맞죠?
초보/ 비슷한 시도는 많이 있었지만 이름을 널리 알린 것은 아마 레일즈가 맞을 겁니다.
그런데 사실 JavaBean 에서 사용하는 getter & setter accessors 도 결국 CoC 아닌가요?
JSP 에서는 그냥 jsp:getProperty / jsp:setProperty 만써서 getName이 아니라 name만 써주면 되고,
EL을 써도 user.name 이나 user['name'] 이런식이니 이것도 CoC가 아닌가 싶습니다만…@_@;
Kevin/ EL과 같은 것들은 그 언어/기술스펙 자체의 정의에 따라 동작한다고 볼 수 있기 때문에 CoC라고 하기는 좀 곤란하다고 생각합니다. Configuration을 사용할 가치가 없는 것들이죠. 보통 설정을 만드는 것은 기술을 응용하는 개발자입장이고, 그것까지 관례를 만들어서 접근하게 한다면 그때 CoC라고 부르는 것이 일반적이라고 생각합니다.
만약 EL을 써서 value=”${user.name}”이라고 구지 설정해줘야 하지만, 그게 없어도 input 태그에 있는 id=”" 애트리뷰트와 form 태그의 id를 조합해서 ${user.name}이라는 EL로 자동으로 해석하게 해준다고 하면 그땐 CoC라고 할 수 있겠죠. HTML과 EL 자체의 기술적인 정의에는 존재하지 않고, 구지 그런 기능을 만들어준다면 설정을 만들어서 정의해주어야 하겠지만, 그것을 관례를 새로운 방식으로 정의해서 언어나 기술 자체에는 원래 없는 방식의 설정을 가정하고 동작한다면 그때 CoC라고 부르는 것이 적합할 듯 싶습니다.
아… 그렇군요. jsp property도 그렇고, EL도 그렇고 따로 설정해줄수 있는게 아니라
정의되어 있어서 그렇게 밖에 못 쓰는거죠…
RoR을 사용해 본적이 없으니 CoC는 좀 생소합니다.
기껏해야 SpringMVC 에서 조금 써본 정도라…