정상혁정상혁

(덧붙임: 이글을 쓰던 시점의 CloudFoundry는 지금의 CloudFoundry와는 다른 기술이였고, 이전 CloudFoundry는 http://classic.cloudfoundry.com/ 으로 옮기어 갔습니다. )

스프링, 클라우드를 내세우다.

스프링 프레임워크의 개발사인 스프링소스(SpringSource)와 VMWare는 최근 스프링이 클라우드 환경에 적합한 기술이라고 홍보를 하고 있다. 현재 스프링과 관련이 있는 클라우드 플랫폼은 아래와 같다.

vFabric

VMWare에서 제공하는 프라이빗 클라우드를 위한 솔루션이다. VMWare의 가상화 솔루션과 스프링소스의 미들웨어, 프레임웍, 개발도구 등을 합한 기술 스택을 제공한다.

Coludfoundry (http://www.cloudfoundry.com/ )

스프링소스가 인수해서 운영하는 클라우드 서비스이다. 아마존의 AWS 인프라를 이용하고, Tomcat 등의 미들웨어를 제공한다.

VMForce (http://www.vmforce.com/ )

VMWare와 세일즈포스닷컴이 제휴한 클라우드이다. force.com 데이터베이스를 저장소를 이용하고, 스프링,Tomcat, vSphere 같은 VMWare의 솔루션이 들어간다.

image

VMFoce 클라우드 (출처 vmforce.com)

Google App Engine

구글과 VMWare의 제휴로 Google App Engine에 대한 지원이 스프링소스의 개발도구에 들어가게 되었다. Spring-roo에서 Google App Engine의 저장소를 쓸 수 있도록 JPA의 Provider로 Datanucleus를 선택할 수 있다.

2010년 10월에 열린 스프링원 컨퍼런스에서도 클라우드에 대한 홍보는 두드러졌다. 자사의 클라우드 솔루션인 vFabric과 CloudFoundry는 물론, VMForce와 Google App Engine 과도 스프링을 묶어서 홍보했다. 스프링원 2010의 플레티엄 스폰서 세 곳 중 두 곳이 구글과 세일즈포스닷컴이였다는 것을 봐도 그 컨퍼런스의 초점은 알 수 있었다

스프링은 애플리케이션 프레임워크일 뿐인데, 과연 클라우드와 무슨 관련이 있다는 것일까? 클라우드의 핵심기술은 가상화나 분산 저장소 같은 기술이 아닐까? 클라우드 환경에서 JVM만 제대로 갖추어진다면 스프링이 아닌 스트럿츠나 구글쥬스라고 해도 안 돌아갈 이유는 없지 않은가? 요즘은 서버 여러 대만 쓰는 기술이면 다 클라우드라는 이름을 붙이고 싶어하던데, 스프링도 이런 유행에 묻어 가고 싶은 마음이 아닐까? 여러 가지 의구심이 들만도 하다.

그러나, 이를 억지 홍보 전략이라고만 생각하면서 그냥 넘어가는 것보다는 왜 VMWare ,구글, 세일즈포스닷컴이 스프링을 클라우드에 끼워 맞추면서 제휴를 하고 있는지를 분석해 본다면 기술의 흐름을 이해하는데 도움이 될 것이다.

지난 10년, 그리고 수익 모델

널리 알려 진 것처럼, 스프링은 EJB의 초기 시대에 Java EE 표준에 대한 대안 기술로 시작되었다. 스프링의 아버지 로드존슨은 초기 EJB의 어려움을 해결한 자신만의 프레임워크를 만들었고, 그 코드를 저서 “Expert one to one J2EE development”에 공개했다. 그 코드가 많은 개발자들의 호응을 얻어서 오픈소스 프로젝트가 되었다. 스프링 프레임워크는 세계 10대 은행 중 9개가 쓰고 있다고 할 정도로 인기를 끌었고[주1], 핵심 개발자들은 사업체를 차리고, 벤처 캐피탈의 투자를 받기에 이른다.

스프링소스는 창업 이후에 계속 수익 모델을 고심 했을 것이다. 과연 어플리케이션 프레임워크만으로 어떻게 수익을 창출할 것인가? 한 때 스프링소스에서는 엔터프라이즈 서비스라는 것을 만들어서 라이선스를 산 고객에게 좀 더 편하게 마이너패치 버전을 제공하는 정책을 고려하기도 했었다[주2].

그리고 인수 합병을 통해 프레임워크 이외의 제품군도 확보를 한다. 스프링소스가 처음으로 인수한 업체는 Tomcat과 Apache Httpd의 핵심개발자들이 있는 Covalent라는 업체였다[주3]. 프레임워크와 미들웨어를 통합한 서비스를 제공한다는 명분이였지만, 프레임워크만으로는 수익 창출에 한계가 있었기에 그런 결정을 했을 것이다.

더욱 놀랍게도 스프링소스 자체가 2009년 4억 2천만 불(당시 환율로 5천3백억원 정도[주4]) 의 가격에 VMWare에 인수된다. 00만원짜리 서버 53만대의 가격이니 그 가격도 놀랍지만 무엇보다 인수자가 의외였다. 오라클이나 IBM처럼 자바 개발자가 친숙한 미들웨어를 많이 파는 업체가 아니였고, 자바와는 멀리 떨어진 듯한 가상화 솔루션으로 유명한 업체인 VMWare였기 때문이다.

로드존슨은 확장성 있는 사업모델을 고민했다[주5]. 컨설팅과 교육만으로는 인건비를 바탕으로 하는 수익 구조가 된다. 그래서 제품과 서비스를 판매하는 사업 모델도 필요했다. 그런데 제품도 상용 버전과 오픈소스 버전의 차이를 지나치게 크게 둔다면 오픈소스 커뮤니티를 홀대한다는 비판을 받을 수도 있다. 스프링소스에서는 Tc server라는 Tomcat에 기능을 강화한 제품을 판매하고 있다. 그러나 Tc Server에는 없는 버그가 Tomcat에는 있다면 많은 비판이 쏟아질 것이다. 제품 판매에도 어느 정도 한계가 있다 보니 더 확장성 있는 사업 모델인 클라우드 서비스와 스프링을 연결시키려고 했을 것이다. 그래서 클라우드 서비스 업체인 CloudFoundry를 인수했고, 결국 VMWare와 손을 잡았다.

이러한 사업 배경과는 별도로 스프링과 클라우드를 연관시키는 것이 기술적으로 무리 수는 아닌지, 그 연결에 어떤 노력을 하고 있는지 살펴보아야 할 것이다.

스프링 포트폴리오의 확장과 클라우드

VMWare의 인수 이후로, 스프링 포트폴리오의 발전 속도는 더욱 빨라 지고 있다. 최근 Spring-Android, Spring-Hadoop같은 프로젝트를 보면 자바 기술 중 스프링이 건드리지 않은 영역이 바로 생각나지 않을 정도이다. 이 중 클라우드와 관련이 있는 기술들은 아래와 같이 나누어 정리해 볼 수 있다.

첫째, 대용량 처리 미들웨어를 직접 스프링에서 인수한 것들이다. AMQP(Advanced Message Queuing Protocol) 바탕의 메시징큐 솔루션인 RabbitMQ와 데이터그리드 기술인 GemFire가 여기에 해당한다. 비동기 처리와 데이터 캐쉬는 대용량 처리가 많은 클라우드 환경에서 더욱 많이 쓰이는 기술이 될 것이다.

둘째, 분산 저장소에 대한 API의 래핑(Wrapping)을 제공하는 것이다. Spring-data라는 프로젝트 아래에서 많은 저장소를 위한 프로젝트들이 진행되고 있다. 이미 Redis, Riak, CouchDB , MongoD, Neo4j등을 지원한다. 물론 꼭 스프링에서 지원해 주지 않아도 그런 저장소를 쓰는 데에는 문제가 없다. 그런 프로젝트의 의도는 JDBC를 바로 사용하는 것보다 Spring-jdbc를 사용하는 것처럼, 저장소 API도 스프링의 설정과 프로그래밍 방식으로 API를 편리하고 일관성 있게 사용하도록 도와 주는 것이다. 물론 저장소 API들이 JDBC만큼 불편하지는 않겠지만, Template-callback 패턴으로 반복된 Try-catch를 줄일 수 있는 부분 등 개선점이 없지는 않을 것이다.

그리고 스프링 3.1에 추가되는 캐쉬 추상화도 분산 캐쉬 솔루션을 편하게 활용하도록 해 준다. 트랜잭션 처리 방식과 유사하게 애노테이션으로 캐쉬할 대상과 키를 지정하는 기능이다. EhCache에 대한 구현체는 기본 제공되고 SPI(Service Provider Interface)에 맞추면 다양한 캐쉬가 이 스펙에 맞추어서 활용될 수 있다.

셋째, 모니터링 기술이다. 클라우드 환경에서는 물리적인 서버에 대해서 사용자가 신경을 쓰지 않더라도 실제로 많은 서버와 미들웨어 인스턴스를 쓰게 된다. 그리고 사용량으로 요금이 결정되므로, 리소스 사용량을 지속적으로 확인할 필요도 생길 수 있다. 사용자가 쓰는 패턴을 빨리 파악을 하는 것도 비용 대비 효과를 판단하는데 도움이 된다. 그래서 모니터링이 전통적인 시스템보다 더욱 중요하다. 스프링소스에서 모니터링 도구인 Hyperic을 인수하고 Spring-insight 같은 도구들을 만들고 있는 것이 이에 대한 대응으로 보여 진다. Spring-insight에서는 Spring MVC의 Controller 정보 등 스프링에만 특화된 정보도 제공하는데, 모니터링이 독립적인 영역이지만 스프링을 썼을 때에 이득을 더 부각시키려는 의도일 것이다.

메시징큐, 데이터 저장소와 캐쉬, 모니터링 기술들은 기존 환경에 설치해서 사용할 수도 있지만,클라우스 서비스에서 제공하는 기술 스택에 포함되기도 한다. 클라우스 서비스에서도 기본으로 제공되는 솔루션들은 중요한 경쟁력이다. 아마존 클라우드에는 메시징 큐로 SQS(Simple Queue Servcie), 저장소로 SimpleDB가 있고, Google App Engine에서는 캐쉬로 Memcache, 저장소로 빅테이블에 바탕을 둔 DataStore를 쓸 수 있다. VMWare가 제공하는 클라우드 솔루션인 VFabric에는 TcServer의 세션 클러스터링을 Gemfire로 쓰고, Hyperic으로 모니터링을 하도록 구성된다.

최근 스프링 포트폴리오의 확장 중 많은 부분은 클라우드 시대에 맞춘 기술 투자라고 볼 수 있다

스프링과 클라우드 이식성(Cloud Portability)

스프링원 2010 컨퍼런스에서는 VMWare의 클라우드에서 돌아가는 애플리케이션이 Google App Engine에서 똑같이 돌아가는 데모를 보여 줬다. JVM의 이식성을 생각한다면 어떻게 보면 당연한 결과일 수도 있는데, 이것이 어떤 의미가 있을까?

클라우드를 도입하려는 쪽에서는 미래에 일어날 수 있는 다양한 상황들을 감안해야 한다. 애플리케이션을 레거시 서버에서 클라우드로, 클라우드에서 다른 클라우드로, 클라우드에서 다시 기존 방식의 서버로의 이전하는 모든 경우가 충분히 일어날 수 있다. 그렇다면 애플리케이션이 특정 실행 환경에 종속적인 부분이 많아 지는 것은 애플리케이션의 소유자에게는 큰 짐이 된다. 그래서 특정 클라우드에 애플리케이션이 묶여 버린다는 것은 얼핏 생각하면 클라우드 사업자에게 유리한 것 같지만, 클라우드의 잠재 사용자에게는 초기의 클라우드 도입을 망설이게 해서, 사용자층이 넓어지는데 부정적인 요인이 된다. 클라우드로 이사하는데 드는 비용이 많다면 기존 애플리케이션을 올리지도 않을 것이다. 그리고 이사 한 후에도 빠져 나오기 힘들다면 사용자가 가격 정책 협상에 불리한 위치가 된다. 그래서 클라우스 사업자는 클라우드 사용자가 기존 애플리케이션을 작은 수정으로 클라우드에 올릴 수 있고, 이사 나갈 때도 쉽게 옮길 수 있다는 것은 강조하는 편이 초기에 시장을 넓히는 데에는 유리할 것이다.

그런데 클라우드 환경이 정말 기존 애플리케이션을 똑같이 받아줄 수 있을까? 우선 웹어플리케이션이 올라갈 WAS부터 그러기가 쉽지 않다. 클라우드 서비스에서는 한정된 종류의 WAS가 제공된다. Google App Engine은 Jetty를 수정해서 쓰고 있고, VMWare가 관여하는 클라우드인 CloudFoundry, VMForce, VFabric은 당연히 Tomcat의 상용판인 Tc Server를 제공하고 있다. 거기다 클라우드에 올라가는 JVM이나 WAS는 지원하는 스펙이 제약된다. Google App Engine에서는 파일을 직접 쓰지 못하고, 쓰레드나 소켓을 생성할 수 없다. 서블릿 스펙에서도 ServletContext.getNamedDispatcher 을 호출해서 디폴트 서블릿의 이름을 알아내는 메소드가 제대로 동작하지 않는다. 보안 문제나 남용의 여지가 있는 부분은 지원하지 않는 것이다. 레가시 시스템을 클라우드 환경으로 옮기는 상황이라면 기존에 레거시 시스템에서 쓰던 WAS와 클라우드 위의 WAS의 종류가 다를 가능성이 높고, 기존의 WAS가 Java EE Server라면 더욱 그렇다. 더욱이 WAS 자체 혹은 애플리케이션에서 호출하는 기능까지도 제약된다.

여기서 스프링이 클라우드 사업자들에게도 도움이 될 수 있다. 클라우스 소비자에게 지정된 WAS, 그것도 서블릿 스펙만 지원하는 WAS를 제공한다는 클라우스 서비스의 약점을 스프링이 상쇄해 줄 수 있다. 즉, JavaEE 스펙을 지원하는 서버가 없어도 Tomcat만으로도 객체의 라이프 싸이클 관리와 관계 주입, 선언적 트랜잭션 등을 쓸 수 있다. 그리고 JavaEE server를 쓰는 경우라도 서버가 제공하는 데이터 소스, 트랜잭션 서비스들을 스프링을 거쳐서 사용할 수 있다. 스프링을 통해 간접적으로 Java EE 스펙을 쓴다면, 나중에 Tomcat이나 Jetty로 WAS를 바꿀 때에도 어플리케이션의 적은 부분만 수정하면 된다. 예를 들면 JNDI로 데이터 소스를 찾아오는 부분은 DBCP로 바꾸고, JtaTransationManager를 쓰도록 선언된 Bean선언을 DataSourceTransactionManager으로 바꾸는 정도이다. 그렇게 때문에 스프링을 사용한 어플리케이션은 WAS간의 이식성이 높아지고, WAS선택의 폭이 넒어 진다. WAS의 완충 지대 역할이라 할 수 있다.

한편으로는 스프링을 활용했을 때 WAS 같은 미들웨어에 대한 종속성은 적어지지만 프레임워크 자체에 종속성이 다시 생기기 때문에, 그것 또한 이식성을 줄이는 일이 아니냐는 생각을 할 수 있다. 하지만 굳이 둘 중에 종속성을 가져야 한다면, WAS보다는 프레임워크에 종속되는 편이 더 낫다고 생각한다. 프레임워크는 하나의 WAS 위에서 여러 개가 공존할 수도 있어서 점진적으로 바꿔나가기도 쉽다. 그리고 애플리케이션이 의존하는 부분을 WAS보다는 프레임워크에 두는 것이 유연성 측면에서는 유리하다. 프레임워크의 버전 업그레이드나 특정 라이브러리 변경은 WAS에 대한 업그레이드보다 간편하기 때문이다. jar파일을 바꾸는 일만 생각한다면 프레임워크의 업그레이드는 Maven의 pom.xml에서 버전 선언 몇 줄만 바꿔 주면 된다. 반면 WAS는 설치 자동화가 되어 있다면 간편하게 모든 서버에 한꺼번에 복사할 수도 있겠지만, 아무래도 프레임워크 업그레이드 보다는 부담되는 일이다. 그리고 스프링은 스프링에 종속적이기 않게 코드를 작성하는 방법들을 많이 제공하고 있다. @Inject 같은 표준 애노테이션이 그 예이다. 이를 적절히 활용한다면 프레임워크에 대한 종속성도 다소 덜어낼 수 있다.

세일즈포스닷컴, 구글은 스프링소스를 소유한 VMWare와 함께 스프링을 통한 클라우드 이식성(Cloud Portability)을 강조하고 있다. 어떻게 보면 경쟁 관계에 있는 이들이 한 목소리를 내고 있는 것은 초기 시장 확대가 무엇보다 중요하기 때문일 것이다. 그리고 사용자들을 자신들의 플랫폼 만으로 가두는 전략보다는 원한다면 오갈 수도 있는 길을 열어 두는 것이 장기적으로는 이득이라는 믿음을 공유하고 있는 것 같다. 그렇게 해도 될 만큼 핵심 경쟁력인 인프라 기술 등에서는 자신이 있다는 해석도 할 수 있다.

기술 포털로서의 스프링

스프링과 클라우드가 연관되고 있는 또 하나의 측면은, 스프링이 자바 기술 생태계에서 일종의 ‘포털’(Portal) 역할을 하고 있어서라고 분석된다. 인터넷 포털은 많은 사용자들이 방문하고 여러 정보들을 모아서 사용자에게 일관된 UX를 제공한다. CP(Contents provider)사가 컨텐츠를 포털과 제휴하는 것은, CP사 입장에서는 자사의 컨텐츠를 알릴 수 있고, 포털 입장에서는 방문자에게 풍부한 컨텐츠를 제공해서 트래픽을 더 늘릴 수도 있다는 점에서 양측 모두에 이득이 된다. 그리고 사용자는 포털의 일관된 접근 경로와 UX로 다양한 컨텐츠를 접할 수 있다. 예를 들면 네이버의 휘발류 가격 정보는 석유공사에서 운영하는 Opinet에서 데이터를 가지고 오는 것이지만, 사용자는 네이버 검색창을 통해서 다른 컨텐츠를 볼 때와 같은 화면 스타일과 사용 방법으로 컨텐츠에 쉽게 접근할 수 있다.

포털의 UI 일관화

image

마찬가지로 스프링은 많은 개발자들이 사용하는 기술이고, 다양한 기술들을 조율해서 일관된 설정 방식과 명명 규칙, API 스타일을 제공한다. API는 Application Programming Interface이니 포털의 User interface가 최종 사용자가 보는 화면이라면 개발자들이 보는 interface는 프레임워크와 라이브러리의 API라 할 수 있겠다. 그리고 스프링과 제휴하는 요소 기술의 보유 업체들은 CP사와 같이 자사의 기술을 알려서 사용자를 늘릴 수 있는 기회를 얻는다. 그리고 스프링소스는 스프링과 연결되는 기술 생태계를 더 풍요롭게 만든다는 이득을 얻는다.

스프링은 다양한 기술을 같은 API로 추상화 시켜서 유연성을 주거나, 비슷한 스타일로 정리해서 개발자들에게 초기 학습 비용을 줄여 준다. 예를 들면 데이터그리드인 Gemfire에서 기존의 스프링의 DB 트랜잭션 관리 인터페이스에 맞춘 GemfireTransactionManager를 제공하는 것이 있다. 그리고 Spring-amqp 같이 최근 추가된 프로젝트도 클래스명, 인터페이스명, 메소드명은 스프링에 익숙한 사람이면 처음 보아도 친숙한 스타일을 느낄 수 있다.

VMWare가 스프링소스를 인수한 일이라던지, 세일즈포스닷컴과의 제휴나 Neo4j, Terracotta같은 저장소, 캐쉬 기술과 스프링이 연결되는 것은 기술적인 시너지를 기대한 측면도 있다. 그러나 그것도 스프링이 많은 사람들에게 익숙한 기술이고, 사람들을 모을 수 있기에 성사된 일들이다. 어느 새 VMWare가 자바 개발자들에게 이전보다 친숙한 기업이 되었으니 스프링소스 인수로 홍보 효과는 충분히 성공을 한 듯하다. 물론 그리고 단순한 홍보 수단 이상의 가치가 있으려면, 소비자들에게 시너지를 체감하게 하는 과제가 남아 있긴 하다.

비침범적인 설계과 클라우드 시대

스프링이 처음 만들어 졌을 때 클라우드 시대를 염두에 두었을 리는 없다. 급작스런 시대의 변화에 스프링도 적응을 해야 하는 상황인데, 현재까지는 클라우드 업체 사이에 활발한 제휴 대상이 되고 있다. 인기 있는 기술이라서 홍보를 위해서 제휴를 하는 측면도 있겠지만, 그래도 스프링이 주는 유연성과 이식성이 클라우드에서도 의미가 있다는 평가를 받아서 투자와 협업 대상이 되었을 것이다.

이런 현상의 가장 근본적인 이유는 인프라성 코드와 업무 로직 코드를 침범적이기 않게 한다는 스프링의 설계 철학에서 비롯된다고 생각한다. 스프링에서 강조하는 POJO(Plain Old Java Object) 방식의 개발은 특별한 규약에 의존이 없는 자바 코드가 핵심 로직을 담당해서 실행 환경에 덜 의존적인 코드를 만든다.

예를 들면 트랜잭션 처리 같은 인프라성 코드는 WAS가 제공하는 JTA(Java Transaction API) 같은 규약을 쓸 수도 있다. 그렇게 특정 미들웨어에 의존적인 코드는 최대한 한 곳으로 모으는 것이 향후 그 미들웨어가 바뀌었을 때 더 적은 수정을 유발한다. 스프링에서는 JTA에 중립적인 트랜잭션 API(PlatformTransactionManager)를 만들고, 이를 AOP를 통해서 사용해서 결국 JTA를 쓰는 코드를 한 곳에 모으고, 한 두줄 수정으로 다른 방식으로도 바꿀 수 있게 되었다. 다른 예로 Spring security가 Google App Engine의 로그인 인증에도 쓰일 수 있는 이유도 사용자 정보 저장소 인프라에 의존하는 부분이 잘 추상화되어 있기 때문일 것이다[주6].

거창하게 '클라우드 이식성 '을 위해서가 아니고, 시스템의 변화가 있을 때 적은 수정으로 대응할 수 있도록 고려를 하는 것은 설계의 기본이다. 역할과 책임이 잘 구분된 설계는 시대와 환경을 초월해서 의미가 있다. 결국 유연성, 이식성이라는 것은 잘된 모듈화의 일반적인 결과이지 꼭 특별한 기술을 적용해야 얻어지는 것은 아니다. 스프링의 AOP니 Dependency Injection이니 하는 기술들도 결국 그런 일을 돕기 위해서 존재하는 것일 뿐이다. 스프링 이전에도, 스프링 이후에도 이런 모듈화는 중요하고, 스프링이 클라우드 시대에서도 유행하고 있는 것은 이런 보편적인 설계 원리를 잘 지켰기 때문이라고 할 수 있다.

클라우드 시대에 애플리케이션 개발은 얼마나 달라질까? 사용하는 저장소나 미들웨어 같은 인프라는 많이 달라진다. 클라우드에 들어오는 새로운 구성요소들에 잘 적응을 하는 것이 처음에는 생산성을 결정하는 요인이 될 것이다. 그러나 그렇다고 애플리케이션을 개발하는 방식이 크게 달라진다고는 생각하지 않는다. 잘 모듈화되어서 역할과 책임이 잘 구분된 코드는 클라우드 시대까지 살아남을 것이고, 그런 코드는 클라우드 시대에도 수정, 추가 비용을 적게 하고, 클라우드 이후 시대까지도 남겨 질 것이다. 프레임워크의 코드이든, 응용 개발자가 짜는 애플리케이션의 코드이든 마찬가지로 말이다.

덧붙여서, 그렇게 관심과 역할이 잘 정리된 좋은 코드를 만들었다는 것을 무엇으로 증명할 것인가? 바로 테스트 코드를 짜 보는 것이다. 인프라를 관리하는 코드와 업무 규칙의 코드가 섞여있다면, 테스트 코드를 짜기가 힘들 것이고, 그런 코드는 앞으로의 변경에도 더 많은 비용이 드는 코드가 되고 살아남기 힘든 코드가 된다. 특정 프레임워크를 썼다고 좋은 설계가 당연히 바로 나오지는 않는다. 스프링을 쓰면서 테스트하기 쉬운 코드를 짜고 있는지를 돌아보는 것이 스프링을 잘 쓰고 있는지를 가장 잘 확인하는 방법이다.

정리

스프링소스가 클라우드와 관련한 활발한 활동들을 하는 것은 확장성 있는 사업 모델을 찾기 위한 돌파구였고, 포트폴리오와 강화와 각종 제휴로 현재까지는 클라우드를 지원하는 기술 쪽으로도 빠른 발전을 보이고 있다. 그리고 스프링이 제공하는 이식성 덕분에 제한된 WAS를 제공하는 클라우드에 유리한 점이 있고, 넓은 사용자층을 가진 기술 생태계의 포털 역할로 그 가치를 인정받은 것으로 분석된다. 그런데 스프링이 클라우드 시대에도 흥행하고 적응하고 있는 가장 근본적인 이유는 애플리케이션의 핵심 로직과 인프라를 담당하는 부분을 구분한 설계를 하는데 도움이 되는 기술이기 때문이다.

10년전 한 개인이 만들었던 코드조각이였을 뿐인 스프링이 이제는 업계 흐름을 좌우하는 기술이 되었다. 스프링의 예처럼, 오픈소스는 더 이상 잉여시간이 넘치는 개인들의 습작이 아니고, 기업이 전략적 협업을 하는 매개체이다.

올해에도 스프링의 소식들이 마구 쏟아질 것이고 그 중 상당 부분은 클라우드와 관련이 있을 것이다. 그들의 전략이 자바 생태계의 참여자 모두에게 혜택이 될 수 있는 방향으로 이어지기를 바란다.

[주1] 관련 내용이 인용된 기사 http://www.bloter.net/archives/15878 . 물론 스프링 기술 중 작은부분만 활용하고 있어도 스프링을 쓰는 것으로 집계되었을 것이라고 생각된다. [주2] 당시 논의 되었던 라이선스 정책에 대해서는 http://toby.epril.com/?p=440 에 자세히 설명되어 있다. [주3]로드존슨은 Covalent 인수 배경에 대해서 아래와 같이 밝히고 있다. http://blog.springsource.com/2008/01/29/some-decisions-are-easy-%E2%80%93-like-springsource-acquiring-covalent/ [주4] 인수 가격과 원화 환산 금액은 아래 링크를 참조했다 http://younghoe.info/1192

[주5]로드존슨의 사업 모델에 대한 고민은 아래에 발표자료에 언급되어 있다. http://gotocon.com/dl/jaoo-brisbane-2010/slides/RodJohnson_bKeynotebThingsIWishIdKnown.pdf [주6] http://blog.springsource.com/2010/08/02/spring-security-in-google-app-engine/ 참조

정상혁정상혁

작년 SpringOne에서도 Spring Roo에 대한 발표가 있었고, Google IO 등 다른 컨퍼런스에서도 꾸준히 Spring Roo는 홍보되었지만, 이번 SpringOne에서는 부쩍 그 비중이 높게 느껴졌습니다.

키노트가 있었던 주행사장에는 Spring Roo, Spring, SpringSource, Groovy, Grails의 5개의 로고가 조명으로 비추어져 있었습니다. Groovy-Grais의 관계처럼 Spring-SpringRoo의 관계를 연상시켜서, Spring의 대표 기술로 홍보하려는 전략으로 보였습니다.

_oJrmz3UkGJk/TMi7gUjZNII/AAAAAAAAC0A/hSU3s8E2XCk/s640/PA220055.JPG

_oJrmz3UkGJk/TMi7hDFNR_I/AAAAAAAAC0A/mWjWPk7bMPE/s912/PA220058.JPG

그리고 행사 기념품으로 나온 배찌에서도, Spring,SpringSource, Goorvy, Grails, Tomcat 등과 함께 Spring Roo의 로고가 박힌 것이 포함되었습니다. Security나 Batch같이 이미 현장에서 더 많이 쓰이고 있는 하위 프로젝트들도 있는데, Roo만 특별대우 한다는 느낌까지 들 정도였습니다. 다른 프레임웍 기술만과는 차별된 Spring만의 강점을 강조하기 위해서 Spring Roo가 전면에 나왔다고 생각됩니다. 스프링에서 지원하는 기술이 많아질 수록, API들을 전파하는 것도 쉽지 않을 것인데, Spring Roo를 통해서 사용할 수 있는 방법을 제공하면 코드가 자동생성 되므로 사용법이 더 간편해 보인다는 장점이 있을 것입니다. 그리고 Roo가 그렇게 새로운 API 전파 창구의 역할을 수행한다면 Roo를 직접 사용하지 않는 사람도 Roo가 생성해주는 코드를 샘플로 활용할 수도 있을 것입니다. Spring 3.0.4에 포함된 <mvc:default-servlet-handler/>가 Roo에 바로 반영된 것이나, Neo4j의 Roo addon등이 그 예입니다.

컨퍼런스가 끝나고 몇일 뒤에 바로 Spring Roo 1.1.0 버전이 발표되었는데, 이번 컨퍼런스에서 1.1.0에 포함된 기능을 소개하는 발표가 많았습니다.

OSGi, GWT, GAE-J 지원, 검색서버인 Apache Solr 지원, Database reverse engineering 등 많은 발전을 보여줍니다. 아래 포스트에 있는 지난 1년간의 Roo의 commit 내력을 시각화한 그림에서도 그런 변화가 표현되었습니다.

벤알렉스 아저씨가 열심히 개발을 하는 모습이 보이는군요. 이번 컨퍼런스에 벤알렉스는 참석하지 않았고, 벤알렉스가 진행하기로 한 발표의 일부는 로드존슨이 직접 진행했습니다. 아파서 못 왔다고는 말했는데, 1.1 출시를 얼마 안 앞두고 마무리 작업 때문에 못 온 것이 아닌가 하는 생각도 들었습니다.

저는 Roo 관련 세션 중에 Add-On 개발 관련 세션에 들어갔었습니다. 아래 URL에 있는 toString addon을 샘플소스로 보라고 했는데, toString을 Addon도 크게 쉬워보이지는 않았습니다.

가장 흥미로운 이야기는 Roo에서 앞으로 iBatis, Spring jdbc 같은 JPA 이외의 Persistence 기술도 지원하겠다는 것이였습니다.

그리고 Maven 멀티 프로젝트를 언제 지원할 수 있으냐는 질문이 세션 중에 나왔는데, 명확한 일정을 확답을 하지 못한 것으로 봐서는 가까운 시일 내에 가능해지지는 않을 것 같습니다.

Roo 관련 발표 자료들은 아래에 공개되어 있습니다.

정상혁정상혁
변경 이력
  • 2015/01/21 : Eclipse에서 Groovy를 쓰기위한 plugin과 Maven 선언 부분을 현행화

  • 2013/01/25 : http://www.dpriver.com/pp/sqlformat.htm 의 캡쳐화면 추가 등

  • 2012/11/06 : Eclipse에서 Groovy를 쓰기위한 plugin과 Maven 선언 부분을 더 편한 방식으로 수정

요약하면, Java의 여러 프레임웍은 XML안에 SQL을 넣는 방식을 지원하는데, 줄바꿈이 있는 문자열을 편하게 쓰게 해주는 따옴표 세 개문법 (""")만 Java에 추가된다면 XML을 사용하는 목적을 충족시키면서도 XML로 인한 여러 단점들을 겪지 않아도 된다는 것입니다. 따옴표 세개는 Java에서 추가될 예정이지만, Groovy등에서는 이미 지원합니다. 지금이라도 SQL관리에만 Groovy를 쓰면 쿼리편집이 조금 더 편리해질만도 합니다.

XML로 SQL을 관리할 수 있는 Java framework

많은 Java 프레임웍들이 SQL구문들을 XML파일 안에서 코딩하게 되어 있습니다. 가장 대표적인 것이 iBatis입니다. 아래와 같이 SQL 구문, 파라미터를 운반하는 클래스, 쿼리의 결과가 담길 클래스를 XML안에 선언합니다.

    <select id="findByIsbn13" parameterClass="string" resultClass="book">
    SELECT  title,    author,     isbn13,     isbn10,     pages, content, imageUrl
    FROM book
    WHERE isbn13 = #isbn13#
    </select>
    <select id="findByTitle" parameterClass="string" resultClass="book">
    SELECT  title,    author,     isbn13,     isbn10,     pages, content, imageUrl
    FROM book
    WHERE title = #title#
    </select>

그리고 Hibernate와 JPA에서도 "named query"라는 개념으로, SQL을 따로 XML파일로도 뺄 수 있습니다. 아래는 Hibernate에서 SQL을 XML 파일안에 설정한 예입니다.

<sql-query name="findBookByIsbn13">
    <return alias="book" class="tdd.edu.domain.Book"/>
   SELECT  title,    author,     isbn13,     isbn10,     pages, content,  imageUrl
   FROM book
    WHERE isbn13 = :isbn13
 </sql-query>

Navie SQL과 Hibernate가 쓰는 HQL을 모두 .xml파일 안에 선언하는 것이 가능합니다. JPA를 사용해도 마찬가지로 JPA-QL, Native SQL을 Java에서 String으로 선언할 수도 있지만, XML 파일 안에 넣어도 됩니다.

Spring JDBC에서는 Jdbctemplate.execute 등의 메소드에서 SQL내용을 직접 문자열로 넘기게 되어있지만, Applicaton context 안에 쿼리를 저장해두고, 이를 사용하는 쪽에서 java.util.Properties 같은 객체를 Dependency Injection 받아서 사용하면 iBatis처럼 XML로 쿼리가 관리됩니다.

<util:properties id="bookSqls">
    <prop key="findByIsbn13">
   SELECT  title,    author,     isbn13,     isbn10,     pages, content,  imageUrl
   FROM book
    WHERE isbn13 = :isbn13
    </prop>
</util:properties>

그런데, Spring-jdbc나 Hibernate, JPA에서는 XML에 SQL을 저장하는 방식이 선택일 뿐이지만, iBatis 2.x에서는 반드시 XML안에 쿼리를 넣어야합니다. myBatis라고 이제 이름이 갈라진 iBatis 3.x에서는 Annotation으로 쿼리를 지정할 수 있어서, .java파일 안에 문자열로 SQL에 넣어도 되기는 합니다.

final String PERSIST_INFO =
“INSERT INTO simple_information(info_id, info_content) VALUES (#\{infoId}, #\{infoContent})”;

@Insert(PERSIST_INFO)
public int persistInformation(SimpleInformationEntity simpleInfo) throws Exception;

(예제는 http://java.dzone.com/articles/mybatis-formerly-called-ibatishttp://java.dzone.com/articles/mybatis-formerly-called-ibatis 에서)

그런데, 이런식으로 쿼리까지 Annotation으로 지정하는 것에 대해서는 의견이 분분할 것 같고, 개인적인 생각으로는 Spring jdbc나 Hibernate처럼 필요하면 직접 메소드 시그니처에 직접 SQL을 문자열로 넘기는 방식이 훨씬 더 자연스럽다고 보여집니다.

문제점은?

iBatis에서는 파라미터에 따라서 SQL이 다르게 구성되는 다이나믹 쿼리를 아래와 같이 선언합니다.

<isEqual property="writerSelected" compareValue="false">
  <isNotNull property="writerList">
    <iterate prepend=" AND writer in" property="writerList"
       open="(" close=")" conjunction=",">#writerList[]#
    </iterate>
  </isNotNull>
</isEqual>

if, for문 처럼 조건,반복문들이 XML로 표현되어 있습니다. 이는 절차적 프로그래밍을 SQL로 하게 되어서 아래와 같은 단점이 있습니다.

  • 조건, 반복문에 해당하는 태그 문법을 별도로 배워야함

  • 괄호"\{}"대신 열고 닫는 태그가 단락을 구분하기 때문에, 같은 조건,만복문을 코딩해도 Java 같은 범용언어에서보다 긴 코드가 나오게됨

  • Compile time의 validation범위가 더 줄어들게 됨. getter, setter로 참조하게 될 속성명에 오타가 있어도 직접 실행해봐야지 오타를 알 수 있음.

  • Java파일 밖이므로, Emma와 같은 Coverage 확인 툴로 실제 해당 절이 실행되었는지 확인할 수도 없음.

왜 SQL이 XML에 들어가게 되었을까?

직접 JDBC를 쓰면 Connection 관리와 Exception처리 등이 불편합니다. 그리고 JDBC의 Prepared Statement에서는 파라미터를 "?"를 표시하기 때문에 거기에 넘어가는 변수를 위치의 순서로 파악을 해야 합니다. ":id"와 같이 named parameter를 넣을 수 있다면 훨씬 쿼리의 가독성이 높아집니다. 그래서 그러한 Jdbc의 미흡한 점들을 보완해주는 프레임웍들이 각광을 받았습니다.

그런데, Connection이나 Excpetion처리의 편의성, named parameter의 활용하고 싶다고 해서 반드시 XML로 SQL를 관리해야 하는 것은 아닙니다. XML을 안 써도 되는 Spring의 JdbcTemplate에서도 그런 기능은 다 제공을 합니다.

SQL이 한 파일에 모여있지 않으면 DBA한테 쿼리 검수를 맡기거나, 여러 SQL을 한번에 수정할 일이 있을 때 불편해 지기도 합니다. 그러나 그런 점도 SQL 내용을 상수로 선언하는 .Java 파일을 따로 분리하면 해결할 수 잇습니다. SQL을 보관하는 .java파일에 *SqlMap.java와 같은 명명규칙을 부여하고, SQL 검수를 맡길 때 그 파일만 넘기면 됩니다.

또, 과거에는 .java파일 밖에 SQL이 있으면 SQL만을 수정을 했을 때는 다시 컴파일을 안 해도 된다는 장점이 강조되었습니다. 그러나, 요즘은 개발 PC에서는 Eclipse로, 서버에 배포할 때는 Ant나 Maven으로 빌드과정이 간편해졌고, 설정파일을 수정해도 파일의 복사를 위해 그런 배포과정을 똑같이 거쳐야 하므로, 컴파일이 필요없다는 것도 더이상 장점이 되지 못합니다.

XML에 SQL을 썼던 가장 핵심적인 이유는 .java파일에서는 줄 바꿈이 들어간 문자열을 편집을 하는 것이 불편했기 때문입니다. Java 파일에서는 문자열이 한 줄이 넘어가면 아래와 같이 + 기호를 이용해서 이를 연결해주는 방법 밖에 없습니다.

public static final String SELECT_BY_ISBN13 =
    "SELECT name , id "
    + "FROM user "
    + "WHERE isbn13 = :isbn13 ";

보통 Toad와 같은 DB client 도구에서 SQL을 작성해서 프로그램에 붙여넣기도 하고, 디버깅 중에는 프로그램 내에 있는 SQL을 반대로 DB client 툴에 붙여넣어서 실행해보기도 하는데, 그 때마다 저렇게 줄바꿈마다 "+"가 있다면 쿼리 편집이 많이 번거로워집니다. 그래서 XML파일 안에 SQL이 있으면 줄바꿈이 있는 긴 문자열도 똑같이 붙여넣을 수 있기 때문에, SQL을 개발하는 작업이 훨씬 편해집니다. 이렇게 SQL이 XML안에 들어가다보니 동적쿼리를 만들기 위한 조건,반복문과 각종 파라미터 매핑 클래스등까지 다 XML에 포함되어 버렸고, 앞에서 말한 부작용들이 점점 드러나기시작했습니다.

물론 Eclipse의 설정으로 .java 파일에 붙여넣기를 할 때는 "+"를 넣는 것과 같이 줄을 바꿀 때 필요한 작업들을 자동으로 할 수도 있습니다.

Windows-Preference-Java-Editor-Typing란의 "Escape text When pasting into a string literal"을 선택하고, 큰 따옴표 하나를 연 채 여러줄을 붙여넣으면, 알아서 줄이 바뀔 때는 " + " 기호를 넣어줍니다.

typing.png

그리고 반대로 이런 여러줄의 String을 DB 접속 툴에 붙여 넣을 때도 Sql-Squirrel이나 Toad 같은 툴에서는 그런 "+"와 같은 기호를 제거해 주는 기능이 있기도 합니다. 그리고 웹으로 이런 변환을 해주는 사이트도 있습니다. http://www.dpriver.com/pp/sqlformat.htm는 여러줄로 된 SQL문장을 Java, C#, Delphi, PHP등 다양한 언어의 문자열 선언으로 변환해줍니다.

sql-formatter.png

이렇게 편집을 도와주는 설정이나 도구들을 쓰더라도 중간 변환과정에서 몇번의 키 입력과 클릭이 필요해서 아예 그런 과정이 없는 것보다는 번거롭게 느껴집니다. 그래서 문자열 전체를 중간 변환과정없이 편집할 수 있는 XML에 SQL을 선언하기 시작했다고 생각합니다.

대안으로 Groovy로 따옴표 3개 문법을 이용해서 SQL 관리하기

Python, Groovy, Scala, Ruby에서 이미 지원하고 있는 '따옴표 3개짜리 문자열 선언’이 Java에도 포함된다면 여러줄의 문자열을 따로 편집하는 불편함을 겪지 않아도 됩니다. 아래와 같이 중간에 줄바꿈이 있어도 전체 SQL 내용이 끊어지지 않고 들어갑니다.

 public static final String SELECT_BY_ISBN13 =    """

  SELECT  title,    author,     isbn13,     isbn10,     pages, content,  imageUrl
   FROM book
   WHERE isbn13 = :isbn13

""";

이 따옴표 3개는 이미 JDK7에 포함되는 것이 제안된 상태인데, JDK에 포함될 실험적인 내용을 구현해보는 "Kijaro"라는 프로젝트에서는 Enhanced String Handling for Java라는 이름으로 이 명세를 다루고 있습니다. 그러나, 내년 중반기 쯤에 JDK7에 포함되어 발표될 예정인, java의 문법 개선내용을 주로 담고 있는 project coin에서는 아직 이를 찾아볼 수 없어서, 언제 Java에 반영될지는 아직 미지수입니다.

그렇다면 Java에서 따옴표 3개를 지원해주기 전까지는 계속 XML의 불편함을 감수해야 할까요? 저는 이미 이 문법을 지원하는 Groovy를 SQL관리 용도로 사용해볼만 하다고 생각합니다.

Groovy를 사용하기 위해서는 Eclipse와 Maven에 아래 설정만 해주면 됩니다.

1.Eclipse에서 Groovy plugin 설치

Update site:

Groovy-Eclipse Configurator for M2Eclipse도 설치가 필요한데, 2번 과정에서 pom.xml에 빨간 줄이 뜨면 Ctrl +1 을 눌러서도 설치할수 있습니다.

2.pom.xml에 Groovy를 compile할 수 있는 plugin과 runtime dependency 추가

Groovy를 Compile하는 Maven plugin은 GmavenGroovy-Eclipse Compiler Plugin For Maven이 있습니다. 후자가 Eclipse 최신버전의 me2와 더 나은 궁합을 보여줘서 컴파일을 할 때는 후자를 선택했습니다.

(1)Dependencies에 선언 추가

<dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-all</artifactId>
    <version>2.4.5</version>
</dependency>

(2)build-plugins 에 아래 내용 추가

               <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <compilerId>groovy-eclipse-compiler</compilerId>
                    <meminitial>128m</meminitial>
                    <maxmem>512m</maxmem>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>utf-8</encoding>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.codehaus.groovy</groupId>
                        <artifactId>groovy-eclipse-compiler</artifactId>
                        <version>2.7.0-01</version>
                    </dependency>
                </dependencies>
            </plugin>

<plugin>

3.Groovy 사용

그리고 New→ groovy class를 선택하여서 java 파일 작성하듯이 클래스를 만듭니다.

new-groovy-class.png

Java 문법을 그대로 쓸 수 있으니 따옴표 3개를 쓸 수 있다는 점만 다르다고 생각해도 됩니다. 아래와 같이 .groovy 파일 안에 들어간 SQL이 색깔도 다르게 표시되어 비교적 가독성이 높게 표시되는 것을 확인할 수 있습니다.

roovy-sqls.png

그런 다음 DAO 등 SQL을 호출하는 쪽에서는 이 상수 문자열을 바로 참조합니다. 상수 선언이 되어 있으니 아래와 같이 오타를 쳐도 미리 알려주고, Ctrl + Space를 치면 자동완성도 됩니다.

typing-error.png

Dynamic SQL의 경우에도 직접 Java안에서 if문으로 써서 적어주면 됩니다. 아래와 같이 EclEmma 같은 도구로 coverage를 측정하면, 실제 실행되지 않은 조건분기도 눈으로 보입니다.

image

위의 코드를 Spring-JDBC를 사용했는데, 필요하다면 Hibernate나 apache commons DBUtils에서도 적용 가능한 방법입니다. 다만 Hibernate에서는 Criteria 같은 것을 이용하면 문자열로 길게 쓰는 쿼리가 많이 나오지는 않을 것으로 예상합니다. 그리고 myBatis(iBatis 3.0)의 Annotation으로 지정하는 쿼리 문자열에서도 똑같이 참조할 수 있습니다. static final String으로 선언된 문자열 상수만 쓰는 것이기 때문에 Groovy의 성능문제도 걱정할 필요가 없습니다.

단점과 꺼림직함도 물론 있습니다. 별도의 Eclipse plugin을 설치해야 하기 때문에, 이미 많은 수의 Plugin을 설치해서 Eclipse가 무겁다고 느껴지는 개발환경에서는 다소 부담이 될지 모른다는 점입니다. Groovy가 거의 java와 같은 문법을 지원하기는하지만, 이 문법 하나 때문에 새로운 언어를 도입하는 것이 과하다고 느끼시는 분들도 계실 것입니다. 이 문법을 위해서 Groovy의 다른 부분은 쓰지 않는데도 Runtime에 Groovy의 라이브러리를 올리는 것이 부담스러울 수도 있습니다. (따옴표 3개와 같은 Groovy만의 문법을 바이트코드로 변환하는 작업은 Compile time에 이루어지지만, Groovy로 선언한 객체는 groovy.lang.GroovyObject를 상속해야 하기 때문에, 다른 기능을 쓰지 않더라도 Runtime에서 추가 라이브러리가 필요합니다.) 그런 분들은 언제가 될지는 몰라도 Java에서 따옴표 3개를 지원하는 때까지 기다리는 것이 좋으실듯합니다.

SQL을 XML에 쓰는 것이 전혀 불편하지 않다고 느끼신다면 계속 하던대로 개발을 하면 되겠지만, 저는 위의 시도가 조금이라도 더 편한 개발환경을 만든다고 생각합니다.