본문 바로가기

프로그래밍(TA, AA)/JVM 언어

[스프링] 스프링이란 무엇인가?

스프링은 기본적으로 IoC와 DI를 위한 컨테이너로서 동작하지만 그렇다고 "스프링은 단지 IoC/DI 프레임워크다"라고는 말할 수 없습니다. 스프링은 단순히 IoC/DI를 편하게 적용하도록 돕는 단계를 넘어서 엔터프라이즈 애플리케이션 개발의 전 영역에 걸쳐 다양한 종류의 기술에 관여합니다.


그렇다면 과연 스프링이란 무엇이고 어떻게 설명할 수 있을까요? 스프링 프레임워크가 만들어진 이유와 존재 목적, 추구하는 가치는 무엇일까요? 스프링의 사상과 가치, 그리고 적용된 원칙을 깊이 있게 생각하는 과정을 통하면 스프링이란 도대체 무엇이고 왜 존재하는지를 좀 더 체계적으로 이해할 수 있다면 앞으로 스프링을 더 쉽게 이해하는 데 도움이 될 것입니다.



1. 스프링의 정의


스프링이란 이런 것이다라고 한마디로 정의하기는 쉽지 않습니다. 스프링은 간단한 몇 단어로 규정하기에는 쉽지 않은 독특한 특징이 있기 때문입니다. 게다가 스프링에 대한 여러가지 정의를 본다고 해서 스프링이 무엇인지 간단히 이해되는 것도 아닙니다. 그렇다고 스프링을 그때그때 필요한 API 사용 방법 위주로만 공부하면 스프링을 오해하거나 그 가치를 충분히 누리지 못할 수 있습니다.


그래서 한번쯤은 스프링의 정의를 통해 스프링이 어떤 것인지 큰 그림으로 이해해보려고 노력할 필요가 있습니다. 정의란 원래 사물의 본질적인 뜻을 담고 있습니다. 따라서 정의를 이해하려는 노력은 스프링을 깊이 이해하고 그 가치를 파악하는 데 도움이 될 것입니다. 또, 스프링의 정의 하나쯤은 기억해두면 유용합니다. 스프링을 잘 모르는 고객이나 상사가 어느 날 "스프링이 도대체 뭐야?"라고 질문했는데 간단명료하게 대답을 못하는 것도 곤란할 테니까 말입니다.


스프링에 대해 가장 잘 알려진 정의는 아래와 같습니다.


자바 엔터프라이즈 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크


정의를 봐도 스프링이 무엇인지 감이 바로 오지는 않을 것입니다. 하지만 이 정의에는 스프링의 중요한 특징이 잘 담겨 있습니다.



1-1. 애플리케이션 프레임워크

일반적으로 라이브러리나 프레임워크는 특정 업무 분야나 한 가지 기술에 특화된 목표를 가지고 만들어집니다. 예를 들면 웹 계층을 MVC 구조로 손쉽게 만들 수 있게 한다거나, 포맷과 출력장치를 유연하게 변경할 수 있는 애플리케이션 로그 기능을 제공한다거나, 간단한 설정만으로 관계형 DB와 자바오브젝트를 매핑해주는 ORM 기술을 제공하는 것들입니다. 그래서 프레임워크는 애플리케이션의 특정 계층에서 주로 동작하는 한가지 기술 분야에 집중됩니다. 하지만 스프링은 이와 다르게 '애플리케이션 프레임워크'라는 특징을 갖고 있습니다.


애플리케이션 프레임워크는 특정 계층이나, 기술, 업무 분야에 국한되지 않고 애츨리케이션의 전 영역을 포괄하는 범용적인 프레임워크를 말합니다. 애플리케이션 프레임워크는 애플리케이션 개발의 전 과정을 빠르고 편리하며 효율적으로 진행하는데 일차적인 목표를 두는 프레임워크입니다.


스프링이 자바 엔터프라이즈 개발의 전 영역을 포괄하는 애플리케이션 프레임워크가 된 데는 스프링의 탄생배경과 밀접한 관련이 있습니다. 스프링은 처음부터 독자적인 프레임워크로 개발된 것이 아닙니다. 재미있게도 스프링의 기원은 J2EE 기술서적에 딸린 예제 코드입니다. 로드 존슨은 2003년에 [Expert One-on-One J2EE Design and Development]라는 책을 출간했습니다. 자바 엔터프라이즈 개발에 관한 자신의 풍부한 경험을 바탕으로 J2EE 애플리케이션 설계와 개발의 모든 영역에 대한 개발 전략을 다룬 책입니다. 이 책에 소개된 독창적인 개발 전략과 기존 기술에 대한 대안은 설명으로만 그치지 않고, 그 개념을 증명할 수 있도록 만들어진 3만 라인가량의 샘플 애플리케이션 형태로 제공됐습니다. 이 책에서 강조한 중요한 전략의 하나는 "항상 프레임워크 기반으로 접근하라"는 것이었습니다. 당연히 책의 예제 애플리케이션도 프레임워크를 먼저 만들고 나서, 프레임워크를 이용하는 코드를 만드는 방식으로 작성됐습니다. 바로 이 예제에 포함된 프레임워크가 스프링 프레임워크의 기원입니다. 이 책에서 주장하는 자바 엔터프라이즈 개발의 이상적인 프로그래밍 모델을 추구하는 데 필요한 기반이 돼주는 코드, 즉 프레임워크가 지금 스프링의 원시 버전이라고 보면 됩니다.


J2EE Design and Development PDF


이 책의 내용과 예제로 제공된 프레임워크에 매료된 개발자들이, 책의 독자들이 토론하는 출판사 포럼에 모이기 시작했습니다. 그리고 그중 의욕 있는 일부 개발자는 책에 나오는 프레임워크를 단지 예제 수준으로 두기에는 아깝다는 생각을 했고, 그것을 발전시켜서 지속적으로 개발하자는 의견을 냈습니다. 그런 열의를 가진 몇몇 개발자와 그들에게 설득당한 저자인 로드 존슨도 참여하면서 정식으로 스프링 프레임워크라는 이름의 오픈소스 프로젝트가 시작돼서 오늘날에 이르게 된 것입니다.


스프링의 기원이 된 예제 애플리케이션의 프레임워크는 책에서 설명한 각종 자바 엔터프라이즈 개발 전략의 핵심을 담아서 개발했습니다. 이 책 자체가 자바 엔터프라이즈 개발의 전 계층에 등장하는 기술과 애플리케이션의 전 영역에 대한 효과적인 설계와 개발 기법을 다루고 있었기 때문에 예제 프레임워크 또한 애플리케이션 전반에 걸친 모든 분야를 포괄하고 있었습니다. 결과적으로 이 예제 프레임워크로부터 시작된 스프링은 자연스럽게 애플리케이션의 전 영역을 지원하는 종합적인 애플리케이션 프레임워크가 된 것입니다.


단지 여러 계층의 다양한 기술을 그저 한데 모아뒀기 때문에 애플리케이션 프레임워크라고 불리는 건 아닙니다. 애플리케이션의 전 영역을 관통하는 일관된 프로그래밍 모델과 핵심 기술을 바탕으로 해서 각 분야의 특성에 맞는 필요를 채워주고 있기 때문에, 애플리케이션을 빠르고 효과적으로 개발할 수가 있습니다. 바로 이것이 스프링이 애플리케이션 프레임워크라고 불리는 이유입니다.


스프링 MVC 프레임워크 또는 JDBC/ORM 지원 프레임워크라고 생각하는 것은 스프링이 다루는 일부 영역만 봤기 때문입니다. 또, 스프링을 IoC/DI 프레임워크나 AOP 툴이라고 보는 이유는 스프링이 제공하는 핵심 기술에만 주목했기 때문입니다. 스프링의 일차적인 존재 목적은 핵심 기술에 담긴 프로그래밍 모델을 일관되게 적용해서 엔터프라이즈 애플리케이션 전 계층과 전 영역에 전략과 기능을 제공해줌으로써 애플리케이션을 편리하게 개발하게 해주는 애플리케이션 프레임워크로 사용되는 것임을 기억해 두는 것이 좋습니다.



1-2. 경량급

스프링 정의의 다음 항목은 경량급(lightweight)입니다. 스프링이 경량급이라는 건 스프링 자체가 아주 가볍다거나 작은 규모의 코드로 이뤄졌다는 뜻은 아닙니다. 오히려 스프링은 20여 개의 모듈로 세분화되고 수십만 라인에 달하는 코드를 가진 매우 복잡하고 방대한 규모의 프레임워크입니다.


그럼에도 스프링이 가볍다고 하는 이유는 무엇일까요? 그것은 불필요하게 무겁지 않다는 의미입니다. 아는 스프링의 기원이 된 책에서 비판하는 자바 엔터프라이즈 기술의 불필요한 복잡함에 반대되는 개념입니다. 특히 스프링이 처음 등장하던 시절의 자바 주류 기술이었던 예전의 EJB 같은 과도한 엔지니어링이 적용된 기술과 스프링을 대비시켜 설명하려고 사용됐던 표현입니다.


당시 EJB는 기술에 대한 과도한 욕심으로 인해 개발환경과 운용서버, 개발과 빌드, 테스트 과정, 작성된 코드 모두를 매우 무겁고 복잡하게 만들었습니다. EJB가 동작하려면 고가의 느리고 무거운 자바 서버(WAS)가 필요했습니다. 또한 툴의 도움 없이는 다루기 힘든 난해한 설정파일 구조와 까다로운 패키징, 불편한 서버 배치(deploy) 등으로 인한 부담 때문에 고가의 제품으로 구성된 제대로 된 개발환경을 갖추지 않고는 개발하기가 힘들었습니다.


그에 반해 스프링은 가장 단순한 서버환경인 톰캣(Tomcat)이나 제티(Jetty)에서도 완벽하게 동작합니다. 단순한 개발툴과 기본적인 개발환경으로도 엔터프라이즈 개발에서 필요로 하는 주요한 기능을 갖춘 애플리케이션을 개발하기에 충분합니다. 서블릿 컨테이너만으로 충분하니 EJB 컨테이너를 비롯해 복잡한 기능이 잔뜩 포함된 고급 WAS를 굳이 사용하지 않아도 됩니다. 그만큼 개발 과정도 단순해집니다. 스프링의 장점은 그런 가볍고 단순한 환경에서도 복잡한 EJB와 고가의 WAS를 갖춰야만 가능했던 엔터프라이즈 개발의 고급 기술을 대부분 사용할 수 있다는 점입니다. 코드는 더 단순하고 개발 과정은 편리하면서도 EJB에서조차 불편했던 고급 기능을 세련된 방식으로 적용할 수 있습니다.


결과적으로 스프링은 EJB를 대표로 하는 기존의 많은 기술이 불필요하게 무겁고 복잡했음을 증명한 셈이고, 그런 면에서 스프링은 군더더기 없이 깔끔한 기술을 가진 '경량급' 프레임워크라고 불린 것입니다.


스프링의 이런 특징은 개발환경과 서버에만 국한된 게 아닙니다. 경량급이라는 의미는 스프링을 기반으로 제작되는 코드가 기존 EJB나 여타 프레임워크에서 동작하기 위해 만들어진 코드에 비해 상대적으로 작고 단순하다는 뜻이기도 합니다. 같은 기능을 수행하는 코드인데도 스프링 기반의 코드가 가벼운 이유는 코드에 불필요하게 등장하던, 프레임워크와 서버환경에 의존적인 부분을 제거해주기 때문입니다. EJB와 WAS 같은 기술과 환경을 지원하기 위해 군더더기처럼 우겨넣어야 했던, 판에 박힌 듯이 반복되던 코드가 제거되고 나니 가장 단순하고 가벼운 코드만 남게 됐습니다.


다시 말하자면 스프링이 가볍다는 건 기술수준이 가볍다거나, 스프링이 유치하고 용도가 제한적이라는 의미는 결코 아닙니다. 고성능이면서 내구성도 좋은 스포츠카가 그저 덩치만 크고 성능은 떨어지는 차에 비해 오히려 중량은 가볍고 차체도 작다는 것과 마찬가지 개념이라고 생각해도 좋을 것입니다. 만들어진 코드가 지원하는 기술수준은 비슷하더라도 그것을 훨씬 빠르고 간편하게 작성하게 해줌으로써 생산성과 품질 면에서 유리하다는 것이 바로 경량급이라는 말로 표현되는 스프링의 특징입니다.



1-3. 자바 엔터프라이즈 개발을 편하게

이번에 살펴볼 정의 내용은 '자바 엔터프라이즈 개발을 편하게 해주는'입니다. 스프링 뿐 아니라 기존에 등장했던 대부분의 자바 엔터프라이즈 기술과 프레임워크는 저마다 '개발을 편하게 해준다'고 주장하고 있습니다. 하지만 스프링이 말하는 '엔터프라이즈 개발을 편하게'라는 말은 그 무게가 다릅니다. 스프링은 근본적인 부분에서 엔터프라이즈 개발의 복잡함을 제거해내고 진정으로 개발을 편하게 해주는 해결책을 제시합니다. 단순히 편리한 몇 가지 도구나 기능을 제공해주는 차원이 아닙니다. 엔터프라이즈 개발의 근본적인 문제점에 도전해서 해결책을 제시한다는 것이 기존 기술의 접근 방법과 스프링의 접근 방법의 차이점입니다.


흥미롭게도 이 문구는 EJB가 처음 등장했을 때도 사용됐습니다. 엔터프라이즈 개발을 위한 본격적인 자바 기술로 세상에 처음 등장했던 EJB 버전 1.0의 스펙문서를 살펴보면 EJB의 목표를 다음과 같이 이야기하고 있습니다.


EJB를 사용하면 애플리케이션 작성을 편하게 할 수 있다. 로우레벨의 트랜잭션이나 상태 관리, 멀티스레딩, 리소스 풀링과 같은 복잡한 로우레벨의 API 따위를 이해하지 못하더라도 아무런 문제 없이 애플리케이션을 개발할 수 있다.

 - Enterprise JavaBeans 1.0 Specification, Chapter 2 Goals


이 목표에서 볼 수 있듯이 편리한 애플리케이션 개발이란 개발자가 복잡하고 실수하기 쉬운 로우레벨 기술에 많은 신경을 쓰지 않으면서도 애플리케이션의 핵심인 사용자의 요구사항, 즉 비즈니스 로직을 빠르고 효과적으로 구현하는 것을 말합니다.


EJB의 비전과 목표는 바로 이것이었습니다. EJB의 약속대로 일정 부분에서는 엔터프라이즈 개발의 고민거리와 부담을 덜어줬습니다. 문제는 이 과정에서 다른 차원의 더 큰 복잡함을 애플리케이션 개발에 끌고 들어오는 실수를 저질렀다는 점입니다. 이 때문에 거의 대부분의 EJB 개발자는 처음 기대와는 달리 이전보다 더 어렵고 불편해진 애플리케이션 개발에 지쳐갔고, 결국 EJB의 접근 방법은 잘못됐음을 깨닫고 다른 대안을 찾게 됐습니다. 스프링도 당시 EJB의 잘못된 접근 방법에 대한 대안을 모색하는 중에 등장한 것입니다.


따라서 스프링은 EJB가 궁극적으로 이루고자 했던 이 목적을 제대로 실현하게 해주는 프레임워크입니다. 스프링은 애플리케이션 개발자들이 스프링이라는 프레임워크가 제공하는 기술이 아니라 자신이 작성하는 애플리케이션의 로직에 더 많은 관심과 시간을 쏟게 해줍니다. 초기에 스프링의 기본 설정과 적용 기술만 잘 선택하고 준비해두면, 이후로 애플리케이션 개발 중에는 스프링과 관련된 코드나 API에 대해 개발자가 거의 신경 쓸 일이 없습니다. 스프링이 '엔터프라이즈 개발을 편하게 해준다'라는 EJB와 동일한 목적을 추구하지만 그 과정에서 다른 불편함을 추가하지 않아도 되게 만들었기 때문에 가능한 일입니다.


스프링은 또한 엔터프라이즈 개발의 기술적인 복잡함과 그에 따른 수고를 제거해줍니다. 여기서 제거한다는 건 그런 기술적인 필요를 무시한다는 의미는 아닙니다. 엔터프라이즈 개발에서 필연적으로 요구되는 기술적인 요구를 충족하면서도 개발을 복잡하게 만들지 않는다는 점이 스프링의 뛰어난 면입니다. 과연 어떻게 해서 스프링이 개발을 편하게 만들어주는지는 뒤에서 계속 이야기 하겠습니다.



1-4. 오픈소스

스프링은 오픈소스 프로젝트 방식으로 개발돼왔습니다. 지금도 여전히 오픈소스 개발 모델과 오픈소스 라이선스를 가지고 개발되는 중이며, 이 사실은 앞으로도 바뀌지 않을 것입니다.


오픈소스란 말 그대로 소스가 모두에게 공개되고, 특별한 라이선스를 취득할 필요없이 얼마든지 가져다 자유롭게 이용해도 된다는 뜻입니다. 소스를 자유롭게 열람하고 자신의 목적에 맞게 사용할 수 있을 뿐만 아니라, 필요하면 맘대로 수정할 수 있고, 수정된 제품과 소스를 다시 공개적으로 배포하는 자유도 허용됩니다. 물론 오픈소스도 저작권이 있기 때문에 원 저작자에 대한 정보와 라이선스는 유지한 채로 사용하거나 배포해야지, 자신이 만든 것처럼 슬며시 가져다 사용해도 좋다는 뜻은 아닙니다.


스프링에 적용된 오픈소스 라이선스는 오픈소스 라이선스 중에서도 비교적 제약이 적고 사용이 매우 자유로운 편인 아파치 라이선스 버전 2.0(Apache)입니다. 아파치 라이선스에 따르면 스프링을 상업적인 목적의 제품에 포함시키거나 비공개 프로젝트에 자유롭게 이용해도 됩니다. 다만 스프링을 사용한다는 점과 원 저작자를 밝히고 제품을 패키징할 때 라이선스 정보를 포함시키는 등의 기본적인 의무사항을 따르면 됩니다. 또, 필요하다면 스프링 소스코드를 가져와 수정해서 사용할 수도 있습니다. 수정을 했더라도 수정한 소스를 공개해야 하는 의무는 없습니다.


대부분의 오픈소스 프로젝트처럼 스프링도 오픈소스 개발과 사용자를 위한 온라인 커뮤니티가 있습니다. 커뮤니티를 통해 자유롭게 개발에 관한 의견을 공유하거나 토론할 수도 있고 자신이 발견한 버그를 신고하거나 새로운 기능을 추가해달라고 요청할 수도 있습니다. 그런 요청이나 버그 신고가 어떻게 처리되고 있는지도 이슈트래커 시스템을 통해 공개적으로 확인이 가능하며, 수정된 코드도 언제든지 살펴볼 수 있습니다.


이렇게 개발 과정에 많은 사람이 자유롭게 참여한다는 것이 오픈소스 프로젝트로서 스프링이 가진 장점입니다. 그러나 스프링의 개발 과정은 공개되어 있지만 공식적인 개발은 제한 인원의 개발자에 한정됩니다. 원한다고 아무나 개발팀에 들어와 스프링 프레임워크 코드 개발에 참여할 수는 없습니다. 실제로 스프링은 대형 IT 기업의 사업부인 스프링소스(SpringSource)가 그 개발을 전적으로 책임지고 전담하고 있습니다. 비록 개발 과정이 공개되어 있고, 간접적으로 개발에 영향을 줄 수 있는 의견 제시나 패치 제공, 버그 신고, 공개적인 토론 등이 가능하다고 할지라도 직접적으로 스프링을 개발하는 일은 특정 조직에 소속된 개발자로 한정되 었다는 것입니다. 이렇게 개발팀이 폐쇄적으로 운영되고 있다는 사실은미션크리티컬한 시스템 개발에도 사용되는 엔터프라이즈 프레임워크인 스프링 입장에서는 중요한 의미가 있습니다.


모든 것이 다 그렇겠지만 오픈소스라는 것도 장단점이 있습니다.


오픈소스의 장점은 공개된 커뮤니티의 공간 안에서 투명한 방식으로 다양한 참여를 통해 개발되기 때문에 매우 빠르고 유연한 개발이 가능하다는 것입니다. 오픈소스 제품의 사용자는 소스코드를 다운받아서 품질과 기능을 얼마든지 검증하고 분석해볼 수 있습니다. 발견한 버그를 신고하거나 기능 개선을 제안했다면 그것이 어떻게 처리되는지도 지켜볼 수 있습니다. 개발 중인 경우에도 소스코드까지 투명하게 공개되기 때문에 다양한 현장에 있는 사용자의 피드백이 그만큼 빨리 전달되고 반영됩니다. 인기있는 오픈소스 제품이라면 베타 버전임에도 전 세계의 수많은 개발자가 자발적으로 다운받아서 사용해보고 다양한 방식으로 피드백을 주기도 합니다.


오픈소스 개발 모델을 사용하는 스프링 역시 전 세계의 많은 엔터프라이즈 시스템 개발자의 참여를 통해 발전해왔습니다. 때로는 새로운 기능에 대한 아이디어나 만들어진 코드를 제공받아서 적용하기도 했습니다. 포럼이나 이슈트래커를 통해 제안된 기능이나 요청사항 등이 다음 버전에 적용되는 사례를 꼽자면 끝도 없을 정도입니다. 자바 엔터프라이즈 환경이라는 게 워낙 다양하기 때문에 개발팀이 모든 환경과 기술 조합에 대해 일일이 테스트해보기는 불가능합니다. 하지만 다양한 환경에서 개발하는 개발자가 자신이 경험한 문제점이나 발견한 버그 등을 그때마다 커뮤니티를 통해 개발팀에 전달하기 때문에 잠재적인 버그와 문제점이 빠르게 발견되고 해결될 수 있습니다.


물론 오픈소스 제품을 사용하는 기업이나 사용자 입장에서 보자면 라이선스 비용에 대한 부담이 없다는 것도 큰 장점으로 꼽을 수 있습니다.


이런 여러 가지 장점이 있기 때문에 오픈소스 개발 모델은 이제 비영리 개발그룹에서만이 아니라 상용 제품을 만들고 영리를 추구하는 일반 기업에서도 적극적으로 이용합니다. 대형 소프트웨어 개발업체가 자신이 만든 제품의 일부 또는 전체 소스코드를 오픈소스 커뮤니티에 기증하거나 기업 웹사이트 등을 통해 공개하는 일도 적지 않게 일어나고 있습니다.


하지만 오픈소스 개발 모델에는 단점도 있습니다. 오픈소스 개발 방식의 가장 큰 취약점은 지속적이고 안정적인 개발이 계속될지가 불확실하다는 것입니다. 상당수의 오픈소스 제품은 핵심 개발자의 여가시간을 이용해 일종의 취미활동으로 만들어집니다. 그런데 개발자의 개인적인 사정으로 인해 개발을 더 진행할 수 없거나, 개발자가 중간에 교체되거나, 개발팀에 불화가 생겨서 개발을 정상적으로 진행하기가 힘들 때도 종종 있습니다. 어떤 때는 단순한 버그 하나가 수정되기까지 몇 년씩 걸리거나 개발자들이 다 떠나서 프로젝트 자체가 사장되는 최악의 상황까지도 갈 수 있습니다. 개발 프로젝트라는 게 대부분 그렇긴 하지만, 오픈소스 프로젝트는 특히 개발자 개개인에게 극히 의존적입니다.


스프링 같은 프레임워크는 기업의 가장 중요한 핵심 업무를 관장하는 엔터프라이즈 시스템의 개발에 사용됩니다. 오류가 발생하거나 문제가 생기면 치명적일 수 있는 미션크리티컬한 시스템의 개발에도 사용됩니다. 그런 데서 기반이 되는 프레임워크가 버그가 있는 채로 방치된다거나, 지속적으로 안정적인 개발이 진행되지 못한다는 건 심각한 문제입니다. 그런 이유 때문에 엔터프라이즈 시스템 개발자는 언제 개발이 중단되거나 지연될지 모르는 오픈소스 프레임워크의 도입을 부정적으로 생각할 수 밖에 없었습니다.


스프링 개발자는 이런 오픈소스의 문제점과 한계를 잘 알고 있었습니다. 그래서 오픈소스 개발이라는 방법을 선택하기는 했지만 프레임워크 사용자에게 지속적인 신뢰를 줄 수 있도록 개발을 책임지고 진행할 수 있는 전문 기업을 만들었습니다. 이를 통해 스프링의 핵심 개발자가 파트타임이나 여가시간 대신 정규 업무시간에 풀타임으로 오픈소스 개발에 전념할 수 있었고, 덕분에 안정적이고 전문화된 개발과 품질관리가 가능해졌습니다. 기존 오픈소스 개발 방식의 단점을 극복할 수 있는 대안은 기업이나 기가관의 지원을 받는 전문 개발자가 오픈소스 개발을 책임지게 하는 것입니다.


스프링을 개발하고 있는 스프링소스는 스프링의 창시자인 로드 존슨을 비롯해 스프링이 오픈소스화되는 데 가장 큰 역할을 한 유겐 횔러와 자바 엔터프라이즈 세계에서 손꼽히는 최상급 개발자들이 주축이 돼서 만든 회사입니다. 이 회사는 스프링에 대한 전문적인 기술지원과 컨설팅 그리고 스프링을 기반으로 개발된 시스템을 안정적으로 운용할 수 있도록 돕는 상용 제품을 제공함으로써 수익을 얻고, 한편으로는 오픈소스 프로젝트로서 스프링이 효율적으로 개발되도록 지원하고 있습니다.


엔터프라이즈 영역에서 사용되는 대표적인 오픈소스 제품의 경우는 이렇게 특정 기업이 주도하거나 지원하는 방식으로 개발되는 일이 상당히 보편화됐습니다. 사용자는 개발이 중단될까봐 염려하지 않아도 되고, 필요한 경우에는 비용을 지불하고 개발팀의 전문적인 기술지원 서비스나 컨설팅을 받을 수도 있기 때문입니다.


스프링 개발업체인 스프링소스는 2009년에 세계적인 IT 기업인 VMWare에 전략적으로 합병됐습니다. 그 덕분에 이전보다 더욱 안정된 환경과 조직의 지원을 통해 오픈소스 스프링의 개발에 더욱 전념할 수 있었습니다.


스프링은 오픈소스의 장점을 충분히 취하면서 동시에 오픈소스 제품의 단점과 한계를 잘 극복하고 있는, 전문적이고 성공적인 오픈소스 소프트웨어라고 할 수 있습니다.



2. 스프링의 목적


지금까지 스프링의 정의를 살펴봄으로써 스프링의 기본적인 특징을 알아보았습니다. 이번에는 좀 더 구체적으로 스프링의 개발 철학과 궁극적인 목표가 무엇인지를 생각해보겠습니다. 모든 기술이나 지식이 다 그렇지만, 스프링은 더더욱 그 목표를 분명히 알고 사용하지 않으면 그 가치를 제대로 얻기 힘듭니다. 그저 스프링을 가져다가 어떻게든 사용해서 개발만 하면 스프링을 적용한 것이고, 스프링의 장점이 개발에 반영됐다고 할 수 있을까요? 결코 그렇지 않습니다. 스프링을 사용하기는 해도 스프링이 주는 혜택을 전혀 누리지 못하고 오히려 사용하지 않느니만 못한 경우도 적지 않습니다.


스프링을 제대로 사용하는 건 생각보다 쉽지 않습니다. 이런 식으로 만들면 된다는 표준 샘플이 있는 것도 아닙니다. 스프링의 개발 표준 따위가 존재하지도 않지만, 스프링 적용 베스트 프랙티스를 모아다가 그대로 따른다고 해도 스프링을 잘 사용하고 있다고 확신할 수는 없습니다. 레퍼런스 매뉴얼을 착실히 읽고 관련 서적을 여러 권 공부한다고 해도 스프링을 사용해 어떻게 개발해야 할지 막막할 수도 있습니다.


스프링은 그 기능과 API 사용 방법을 잘 안다고 해서 잘 쓸 수 있는게 아닙니다. 이 말이 이상하게 들릴지도 모르겠지만 자바를 처음 배울 때를 생각해보면 이해가 될 것입니다. 자바 언어 문법과 JDK의 API 사용법이 자세히 설명된 두꺼운 자바 입문서를 읽고, 더 욕심을 내면 웬만한 철학서적보다도 더 지루한 자바 언어 스펙까지도 공부했다고 자바로 개발을 잘할 수 있을까요? 자바의 장점을 잘 살려 애플리케이션을 개발할 수 있을 까요? 그렇지 않다는 것은 자바로 개발을 해온 개발자라면 누구나 잘 알 것입니다. 자바 언어와 JDK 라이브러리는 모두 일종의 편리한 도구로서 자바 언어의 특징인 객체지향 프로그래밍을 좀 더 손쉽게 할 수 있도록 돕고 있을 뿐입니다. 자바로 개발을 잘하려면 결국 근본적인 프로그래밍 실력이 필요합니다. 자바의 근본적인 목적은 객체지향 프로그래밍을 통해 유연하고 확장성 좋은 애플리케이션을 빠르게 만드는 것입니다. 자바를 가져다가 절차지향 언어처럼 사용한다면 자바를 사용하는 가치를 얻을 수 없습니다.


마찬가지로 스프링도 목적을 바로 이해하고, 그 목적을 이루는 도구로 스프링을 잘 활용해야만 스프링으로부터 제대로 된 가치를 얻을 수 있습니다. 어떤 기술이든 그 자체로는 도구에 불과합니다. 그것을 용도에 맞게 잘 활용해서 궁극적으로 이루고자 하는 목표를 이루는 것이 중요하지, 도구의 사용법만 열심히 익힌다고 결과를 저절로 얻을 수 있는 것은 아닙니다.


그렇다면 스프링의 목적은 무엇일까요? 스프링이 만들어진 이유는 무엇이고, 스프링을 통해 궁극적으로 이루려고 하는 것은 무엇일까요? 그것은 정의를 통해 살펴봤듯이 '경량급 프레임워크인 스프링을 활용해서 엔터프라이즈 애플리케이션 개발을 편하게' 하는 것입니다. 그렇다면 굳이 스프링을 사용해서 엔터프라이즈 개발을 편하게 하려는 이유는 뭘까요? 원래 엔터프라이즈 개발이란 편하지 않기 때문입니다.



2-1. 엔터프라이즈 개발의 복잡함

2000년대 초반 각종 자바 컨퍼런스에서 자주 논의됐던 주제는 '왜 자바 엔터프라이즈(JavaEE) 프로젝트는 실패하는가?'였습니다. 당시 IT 리서치기업의 조사에 따르면 80% 이상의 자바 엔터프라이즈 프로젝트가 실패했다고 합니다. 프로젝트가 아예 중단되고 취소된 것까지는 아니더라도, 원래 정해진 기간과 계획된 예산을 맞추지 못한 경우가 그만큼 많다는 뜻입니다. 또는 원하는 만큼의 기능과 완성도를 갖춘 시스템을 못 만들고 적당히 마무리하기도 했을 것입니다. 아무튼 자바 엔터프라이즈 개발이 실패하는 이유에 대해 많은 논의가 있었습니다. 그 과정에서 밝혀진 여러 가지 원인이 있었지만, 그중 가장 대표적인 게  '엔터프라이즈 시스템 개발이 너무 복잡해져서'였습니다.


복잡함의 근본적인 이유

그렇다면 엔터프라이즈 시스템 개발은 왜 복잡할까요? 크게 두 가지 원인을 생각해볼 수 있습니다.


첫번째는 기술적인 제약조건과 요구사항이 늘어가기 때문입니다.

엔터프라이즈 시스템이란 서버에서 동작하며 기업과 조직의 업무를 처리해주는 시스템을 말합니다. 엔터프라이즈 시스템은 많은 사용자의 요청을 동시에 처리해야 하기때문에 서버의 자원을 효율적으로 공유하고 분배해서 사용할 수 있어야 합니다. 또한 중요한 기업의 핵심 정보를 처리하거나 미션 크리티컬한 금융, 원자력, 항공, 국방 등의 시스템을 다루기도 하기 때문에 보안과 안정성, 확장성 면에서도 뛰어나야 합니다. 따라서 뛰어난 성능과 서비스의 안정성이 요구되고 그런 점을 고려한 개발 기술이 필요합니다. 즉 엔터프라이즈 시스템을 개발하는 데는 순수한 비즈니스 로직을 구현하는 것 외에도 기술적으로 고려할 사항이 많다는 뜻입니다. 또 웹을 통한 사용자의 인터페이스뿐만 아니라, 타 시스템과의 자동화된 연계와 웹 이외의 클라이언트와의 접속을 위한 리모팅 기술도 요구됩니다. 기업의 시스템이 복잡함에 따라 다중 데이터베이스를 하나의 트랜잭션으로 묶어서 사용하는 분산 트랜잭션의 지원도 필요합니다. 문제는 이러한 엔터프라이즈 시스템의 기술적인 요구사항은 단순히 고가의 애플리케이션 서버(WAS)나 툴을 사용한다고 충족될 수 있는게 아니라는 점입니다. 따라서 이런 종류의 기술적인 문제를 고려하면서 애플리케이션을 개발해야 하는 부담을 안게됩니다.

엔터프라이즈 시스템이 기업 업무를 처리하는 데 핵심적인 역할로 등장하고 중요해지면서 점점 더 기술적인 요구는 심화되고 그에 따른 복잡도는 증가합니다. 이전에는 그다지 신경쓰지 않았던 보안에 관한 부분도 갈수록 중요해지고, 그에 따라 시스템 설계자와 개발자 개개인이 져야 할 기술적인 부담은 점점 더 커져갔습니다.


두번째는 엔터프라이즈 애플리케이션이 구현해야 할 핵심기능인 비즈니스 로직의 복잡함이 증가하기 때문입니다.

예전에는 기업 업무 중 회계처럼 복잡한 계산이나 빠른 분석 작업이 필요한 영역에서만 IT 시스템을 활용했습니다. 하지만 갈수록 엔터프라이즈 시스템을 이용해 기업의 핵심 업무를 처리하는 비율이 늘어갔고, 점차 대부분의 업무 처리는 컴퓨터를 이용하지 않고는 아예 진행하기 힘들 만큼 엔터프라이즈 시스템에 대한 업무 의존도가 높아졌습니다. 그만큼 다양하고 복잡한 업무 처리 기능을 엔터프라이즈 시스템이 구현해야 했다는 뜻입니다. 원래 기업 업무란 그 자체로 복잡한데다, 다양한 예외상황도 많고, 처리해야 하는 정보의 규모도 상당합니다. 엔터프라이즈 시스템이 관여하는 업무의 비율이 급격하게 커지고 있으니 당연히 애플리케이션 개발도 힘들도 복잡해져 가는 것입니다.


더 큰 문제는 2000년 전후로 전 세계에 불어 닥친 경제위기가 기업의 체질을 크게 바꿨다는 사실입니다. 한번 업무 프로세스와 정책이 결정되면 제법 오랫동안 유지하던 전통적인 기업조차도 경제 흐름과 사회의 변화, 업계의 추이에 따라서 수시로 업무 프로세스를 변경하고 조종하는 것을 상시화할 만큼 변화의 속도가 빨라졌습니다. 결국 이런 업무구조와 프로세스의 변화는 이를 뒷받침해줘야 하는 엔터프라이즈 시스템의 변경을 요구할 수 밖에 없습니다. 버그나 오류가 있어서가 아니라, 기능 요구사항과 업무 정책 등이 바뀌기 때문에 애플리케이션을 자주 수정해줘야 하는 시대가 된 것입니다. 그만큼 이전과 다르게 시스템 개발과 유지보수, 추가 개발 등의 작업에 대한 부담은 커지고 그에 따른 개발의 난이도는 더욱 증가한 것입니다.



복잡함을 가중시키는 원인

엔터프라이즈 애플리케이션 개발이 실패하는 주요 원인은 비즈니스 로직의 복잡함과 기술적인 복잡함입니다. 복잡하다는 건 단지 양이 많고 어렵다는 뜻이 아닙니다. 세부 요소가 이해하기 힘든 방식으로 얽혀 있고, 그 때문에 쉽게 다루기 어렵다는 의미입니다. 자칫 잘못 손을 댔다가는 더 엉망이 되기 쉬우며, 들인 노력과 시간이 허사가 될 수도 있습니다. 자바 엔터프라이즈 시스템 개발이 어려운 가장 큰 이유는 근본적인 비즈니스 로직과 엔터프라이즈 기술이라는 두 가지 복잡함이 한데 얽혀 있기 때문입니다. 하나씩 놓고 봐도 만만치 않은데, 그 두가지를 한 번에 다뤄야 하니 복잡함이 몇 배로 가중되는 것입니다.


예를 들면 이런 경우입니다. 고객의 기존 거래내역을 분석하고 그 특성을 파악해서 그에 따른 적절한 추천상품을 선정하는 로직을 담당하는 코드를 작성한다고 생각해보겠습니다. 그런데 그 작업 요청을 XML 문서를 통한 리모팅 서비스로 받기 때문에 그것을 파싱해서 고객 ID를 추출하기 위해 XML 파서 라이브러리를 사용해야 하고, 고객의 최신 정보를 얻기 위해 DB를 조회할 때 캐시를 먼저 점검하려고 캐시 API를 호출하고, 없으면 서버가 제공하는 DB 풀에서 커넷션을 가져와서 JDBC API를 이용해 다양한 타입의 필드로 된 정보를 가져와야 합니다. 그대 가져온 정보를 분석한 내용을 만일을 위해 로그로 남겨놓도록 분산 파일 시스템을 이용하는 로그 라이브러리를 매번 호출한다. 현재 요청을 보낸 사용자의 정보를 보안 API를 통해 가져와 요청한 작업에 대한 권한이 있는지도 파악해야 하고, 권한이 없으면 그에 따른 예외를 발생시켜야 합니다. 최종적으로 추천상품으로 선정한 내역을 로컬 DB에 저장하고 메시지로도 전송해야 하는데, 반드시 하나의 트랜잭션 안에서 동작하도록 하기 위해 JTA를 이용해야 한다고 생각해보겠습니다.


고객에 대한 추천제품 선정이라는 비즈니스 로직을 제대로 구현하는 일도 만만치 않은데 동시에 이런저런 다양한 기술적인 문제도 함께 신경 써야 한다면 어떨까요? 각종 엔터프라이즈 기술 서비스를 적용하기 위한 코드와 각종 기술적인 API의 호출 코드를 비즈니스 로직에 대한 구현 코드와 함께 덕지덕지 붙여서 만드는 것은 매우 어렵습니다. 더 큰 문제는 그렇게 기술과 비즈니스 로직의 복잡함에 엉켜있는 코드를 유지보수하는 일입니다. 만약 적용한 기술을 변경해야 한다면? 또는 특정 로직을 수정해야 한다면? 하나의 수정 요구를 적용하기 위해 복잡하게 얽혀 있는 코드를 헤매다 보면 정작 수정할 대상이 아닌 부분에까지 영향을 줘서 새로운 버그를 만들 수도 있습니다.


일반적으로 사람은 성격이 다른 두 가지 종류의 일을 동시에 생각하고 처리하는 데 매우 취약합니다. 그럼에도 전통적인 자바 엔터프라이즈 개발 기법은 대부분 비즈니스 로직의 복잡한 구현 코드와 엔터프라이즈 서비스를 이용하는 기술적인 코드가 자꾸 혼재될 수 밖에 없는 방식이었습니다. 결국 개발자가 동시에 그 두 가지를 모두 신경 써서 개발해야 하는 과도한 부담을 줬고, 그에 따라 전체적인 복잡함은 몇 배로 가중됐습니다.



2-2. 복잡함을 해결하려는 도전


제거될 수 없는 근본적인 복잡함

엔터프라이즈 개발의 근본적인 복잡함의 원인은 제거할 대상은 아닙니다. 물론 구현해야할 비즈니스 로직의 적용범위를 줄이고, 기술적인 요구조건을 일부 생략한다면 그만큼 개발은 편해질 것이고 적어도 실패하지 않을지는 모릅니다. 하지만 현실적으로는 불가능합니다. 기술적인 복잡함을 해결하고자 보안을 취약하게 방치한다거나, 사용자가 늘어나도 더 이상 확장이 불가능한 시스템을 만들 수는 없습니다. 기업의 업무 처리에서 IT가 차지하는 비중을 생각해볼 때 업무의 일부를 다시 수작업으로 가져가서 시스템 개발의 부담을 줄이겠다는 것도 말이 되지 않습니다.


결국 근본적으로 엔터프라이즈 개발에 나타나는 복잡함의 원인은 제거 대상이 아닙니다. 대신 그 복잡함을 효과적으로 상대할 수 있는 전략과 기법이 필요합니다. 문제는 비즈니스 로직의 복잡함을 효과적으로 다루기 위한 방법과 기술적인 복잡함을 효과적으로 처리하는 데 적용되는 방법이 다르다는 점입니다. 따라서 두 가지 복잡함이 코드에 한데 어우러져 나타나는 전통적인 개발 방식에서는 효과적으로 복잡함을 다루기가 힘듭니다.


따라서 가장 먼저 할 일은 성격이 다른 이 두가지 복잡함을 분리해내는 것입니다.


실패한 해결책: EJB

EJB가 처음 등장했을 때 내세웠던 목표를 봐도 알 수 있듯이 EJB의 기본 전략도 이 두가지 종류의 복잡함을 분리하는 것이었습니다. 개발자가 로우레벨의 기술적인 복잡함에 신경 쓰지 않고 비즈니스 로직을 효과적으로 개발하는 데 더 집중할 수 있게 하자는 목표가 있었습니다.


하지만 기존 EJB는 결과적으로 그런 목표를 달성하는 데 실패했습니다. EJB는 기술적인 복잡함을 애플리케이션의 핵심 로직에서 일부분 분리하는 데 성공하긴 했습니다. 선언적 트랜잭션이나 선언적 보안, 컨테이너를 통한 리모팅 기술의 적용, 컴포넌트 단위의 배치, JNDI를 통한 서비스 검색 지원, 서비스 오브젝트의 풀링, 컴포넌트 생명주기 관리 등은 EJB의 목표를 어느 정도 충족시켰습니다. 반면에 EJB 환경에서 동작하기 위해 특정 인터페이스를 구현하고, 특정 클래스를 상속하고, 서버에 종속적인 서비스를 통해서만 접근하고 사용이 가능하게 만드는 등의 EJB 개발 방식은 잘못된 선택이었습니다. 애플리케이션 로직을 담은 핵심 코드에서 일부 기술적인 코드가 제거된 건 사실이지만, 오히려 EJB라는 환경과 스펙에 종속되는 코드로 만들어져야 하는 더 큰 부담을 안게 됐습니다.


EJB는 결국 일부 기술적인 복잡함을 덜어주려는 시도를 하다가 오히려 더 큰 복잡함을 추가하는 실수를 범했습니다. 가장 치명적인 건, EJB라는 틀 안에서 자바 코드를 만들게 강제함으로써 자바 언어가 원래 갖고 있던 장점마저 잃어버렸다는 사실입니다. EJB의 특정 클래스를 상속하게 함으로써 더 이상 상속구조를 적용하지 못하게 만들거나, 다형성 적용을 근본적으로 제한한다거나 하는 것들입니다. EJB는 결국 객체지향적인 특성을 잃어버린 밋밋한 서비스 스크립트성 코드로 변질돼갔습니다. 별다른 장점은 없는데다 개발 방식은 너무 불편했기 때문에 개발자에게 점점 외면당하는 신세가 돼버렸습니다.


물론 스프링이 처음 등장했을 때 EJB와는 달리, 그 후에 등장한 EJB는 훨씬 개선되긴 했지만 여전히 서버환경에 의존적인 기능을 요구하는 등의 단점이 남아 있는데다, 한번 인식이 나빠진 이후로는 개발자에게 점차 외면되고 있는 것이 현실입니다. 게다가 EJB의 발전주기는 너무 느려서 엔터프라이즈 개발 기술의 발전을 따라잡지 못하는 것도 문제점입니다.



비침투적인 방식을 통한 효과적인 해결책: 스프링

스프링은 EJB의 실패를 교훈으로 삼아서 출발했습니다. EJB의 처음 목표와 마찬가지로 기술적인 복잡함을 애플리케이션 핵심 로직의 복잡함에서 제거하는 데 목표를 뒀습니다. 하지만 그 과정에서 EJB처럼 개발자의 코드에 난입해서 지저분하고 복잡한 코드를 만들어버리는 실수를 하지는 않았습니다. EJB처럼 어떤 기술을 적용했을 때 그 기술과 관련된 코드나 규약 등이 코드에 등장하는 경우를 침투적인 기술이라고 합니다. 물론 꼭 필요한 기능을 사용해야 하기 때문에 특정 기술의 API를 이용하게 되는 건 어쩔 수 없습니다. 그런데 꼭 필요한 기능을 사용하는 것도 아니면서 단지 어떤 기술을 바탕으로 만들어진다고해서 특정 클래스나 인터페이스, API 등의 코드에 마구 등장한다면 그것은 침투적인 기술이 되며 복잡함을 가중시키는 원인이 됩니다. 


반면에 비침투적인(non-invasive) 기술은 기술의 적용 사실이 코드에 직접 반영되지 않는다는 특징이 있습니다. 어딘가에는 기술의 적용에 따라 필요한 작업을 해줘야 하겠지만, 애플리케이션 코드 여기저기에 불쑥 등장하거나, 코드의 설계와 구현 방식을 제한하지는 않는다는 게 비침투적인 기술의 특징입니다.


스프링이 성공할 수 있었던 비결은 바로 비침투적인 기술이라는 전략을 택했기 때문입니다. 스프링을 이용하면 기술적인 복잡함과 비즈니스 로직을 다루는 코드를 깔끔하게 분리할 수 있습니다. 중요한 점은 그 과정에서 스프링 스스로가 애플리케이션 코드에 불필요하게 나타나지 않도록 하는 것입니다. 꼭 필요한 것 같은 경우조차도 기술 코드가 직접 노출되지 않도록 만들어줬습니다.


결과는 성공적이었습니다. 물론 스프링을 적용한다고 해서 근본적인 복잡함의 원인이 사라지는 건 아닙니다. 하지만 스프링을 통해 성격이 다른 복잡함들을 깔끔하게 분리해줬기 때문에 각각을 효과적으로 상대할 수 있는 기반이 마련됐습니다. 동시에 스프링이 코드에 불필요하게 등장해서 부가적인 복잡함을 가져오지도 않았습니다. 이러한 전략 덕분에 많은 프로젝트를 실패로 몰아가고 비효율적인 개발로 개발자를 고생시켰던 문제를 공략할 수 있게 된 것입니다.



2-3. 복잡함을 상대하는 스프링의 전략

스프링의 기본적인 전략은 비즈니스 로직을 담은 애플리케이션 코드와 엔터프라이즈 기술을 처리하는 코드를 분리시키는 것입니다. 이 분리를 통해 두 가지 복잡함의 문제를 효과적으로 공략하게 해줍니다.


기술적 복잡함을 상대하는 전략

기술적인 복잡함을 분리해서 생각하면 그것을 효과적으로 상대할 수 있는 적절한 전략을 발견할 수 있습니다. 스프링은 엔터프라이즈 기술을 적용했을 때 발생하는 복잡함의 문제를 두가지로 분류하고 각각에 대한 적절한 대응 방법을 제공합니다.


첫번째 문제: 기술에 대한 접근 방식이 일관성이 없고, 특정 환경에 종속적이다.

환경이 바뀌고, 서버가 바뀌고, 적용되는 조건이 바뀌면 적용하는 기술이 달라지고 그에 따라 코드도 바뀐다는 건 심각한 문제다. 비록 동일한 목적으로 만들어졌지만 API의 사용방법이 다르고, 접근 방식이 다른 기술로 난립하는 것이 현실입니다. 그래서 목적이 유사하지만 호환이 안 되는 표준, 비표준, 오픈소스, 상용 제품 등이 제공하는 각기 다른 API를 사용하도록 코드를 일일이 변경해야 하는 번거로움이 발생한다.


이렇게 일관성 없는 기술과 서버환경의 변화에 대한 스프링의 공략 방법은 바로 서비스 추상화다. 앞에서 살펴봤던 트랜잭션 추상화나 OXM 추상화, 데이터 액세스에 관한 일관된 예외변환 기능, 데이터 액세스 기술에 독립적으로 적용 가능한 트랜잭션 동기화 기법 등이 그런 대표적인 예다. 기술적인 복잡함은 일단 추상화를 통해 로우레벨의 기술 구현 부분과 기술을 사용하는 인터페이스를 분리하고, 환경과 세부 기술에 독립적인 접근 인터페이스를 제공하는 것이 가장 좋은 해결책이다.


때론 자바메일과 같이 해당 기술을 사용하는 코드의 테스트를 어렵게 만드는, 그럼에도 표준으로 떡 하니 자리 잡은 기술에 대해서도 서비스 추상화를 적용할 필요가 있다. 이를 통해 테스트 편의성을 증대시키고 기술에 대한 세부 설정과 환경으로부터 독립적인 코드를 만들 수 있다.


데이터 액세스 예외에 대한 추상화는 비즈니스 로직을 담은 서비스 레이어의 코드가 특정 기술이 발생시키는 예외에 종속되지 않고, 불필요하게 예외를 잡아야 하거나 throws를 선언해야 하는 것을 방지해준다.


스프링이 제공하는 템플릿/콜백 패턴은 판에 박힌 반복적인 작업 흐름과 API 사용 코드를 제거해준다. 이를 통해 기술을 사용하는 코드도 최적화된 핵심 로직에만 집중하도록 도와준다.



두번째 문제: 기술적인 처리를 담당하는 코드가 성격이 다른 코드에 섞여서 등장한다.

앞에서도 살펴봤듯이 비즈니스 로직 전후로 경계가 설정돼야 하는 트랜잭션, 비즈니스 로직에 대한 보안 적용, 계층 사이에 주고받는 데이터와 예의 일괄 변환이나 로깅이나 감사 기능 등이 대표적인 예다. 책임에 따라 계층을 구분하고 그 사이에 서로의 기술과 특성에 의존적인 인터페이스나 예외처리 등을 최대한 제거한다고 할지라도 근본적으로 엔터프라이즈 서비스를 적용하는 한 이런 문제를 쉽게 해결할 수 없다. 이런 기술과 비즈니스 로직의 혼재로 발생하는 복잡함을 해결하기 위한 스프링의 접근 방법은 바로 AOP다.


AOP는 최후까지 애플리케이션 로직을 담당하는 코드에 남아 있는 기술 관련 코드를 깔끔하게 분리해서 별도의 모듈로 관리하게 해주는 강력한 기술이다. AOP를 적용하지 않았을 때는 기술과 비즈니스 로직이 지저분하게 얽혀서 다루기 힘들다는 문제도 있지만, 기술적인 코드가 여기저기 중복돼서 나타난다는 것도 심각한 문제점이다. 이 때문에 기술적인 작업을 처리하는 방식이 변경될 경우 많은 곳을 수정해야 한다. AOP는 기술을 다루는 코드로 인한 복잡함을 기술 그 자체 이상으로 불필요하게 증대되지 않도록 도와주는 가장 강력한 수단이다.


비즈니스와 애플리케이션 로직의 복잡함을 상대하는 전략

기술적인 코드, 침투적인 기술이 가져온 불필요한 흔적 등을 제거하고 나면 순수하게 애플리케이션의 주요 기능과 비즈니스 로직을 담은 코드만 독립적으로 존재하게 됩니다. 이 중에서 기술적인 부분과 느슨하게나마 연관되는 데이터 처리 코드나 웹이나 리모트 인터페이스 코드 등을 제외하면 비즈니스 로직 코드를 다루는 코드가 남게 됩니다. 비즈니스 로직을 담은 코드는 애플리케이션에서 가장 중요한 핵심이 되는 부분입니다. 또한 업무의 변화에 따라 자주 변경되거나 수정되는 부분이기도 합니다. 따라서 대체로 복잡합니다. 자주 바뀌는 업무 정책, 비즈니스 규칙, 업무 흐름을 담고 있을 뿐만 아니라 복잡한 데이터를 분석하고 그에 따른 작업을 수행하고, 클라이언트가 필요한 결과를 만들어내야 하기도 합니다. 기술적인 부분이나 사용자 인터페이스에 관한 오류가 발생했을 겨우에는 시스템을 복구하거나 빠르게 대응해주면 당장에 큰 문제가 발생하지는 않습니다. 반면에 비즈니스 로직을 다루는 핵심 코드에 오류가 있으면 엔터프라이즈 시스템을 사용하는 업무 자체에 큰 지장을 주거나 치명적인 손실을 끼칠 수도 있습니다. 


증권사의 거래 사이트가 사용자가 늘어났지만 확장성이 떨어져서 가끔 서비스가 느려지는 문제라면 시스템을 리셋하든, 서버를 증설하든 어떻게든 대응을 하면 됩니다. 기술적인 문제도 방치할 수는 없지만 대부분은 심각한 상황까지 가지는 않습니다. 반면에 비즈니스 로직에 오류가 발생하면 엄청난 사고로 이어질 수 있습니다. 증권사 사이트를 통해 주식거래를 분명히 완료했는데도 실제로는 체결이 되지 않았다거나 계좌의 잔액이 이유도 없이 줄어든다면 어떻게 될까? 아마 당장에 성난 고객들이 몰려와서 난동을 부리고, 자칫하면 회사 문을 닫아야 할지도 모릅니다.


그래서 비즈니스 로직은 가장 중요하게 다뤄져야 하고 가장 많이 신경써야 합니다. 예전에는 비즈니스 로직의 상당 부분을 DB에 두는 것이 유행이었습니다. SQL을 통해 비즈니스 로직을 표현하고, DB에서 동작하는 저장 프로시저를 통해 핵심 로직을 처리하는 경우도 많았습니다. 하지만 엔터프라이즈 시스템의 규모가 커지고, 복잡함이 증가하면서 DB에 비즈니스 로직을 두는 건 매우 불편할뿐더러 위험한 일이라고 여겨지기 시작했습니다.


가장 확장하기도 힘들고 확장하더라도 많은 비용이 드는 공유 자원인 DB에 커다란 부담을 주는 것도 문제고, 데이터 액세스를 중심으로 로직을 다루면 개발과 유지보수는 물론이고 테스트도 매우 어렵게 됩니다.


따라서 엔터프라이즈 시스템 개발의 흐름은 점차로 비즈니스 로직은 애플리케이션 안에서 처리하도록 만드는 추세입니다. DB는 단지 데이터의 영구적인 저장과 복잡한 조건을 가진 검색과 같은 자체적으로 특화된 기능에만 활용하고, 데이터를 분석하고 가공하고 그에 따라 로직을 처리하는 부분은 확장하기 쉽고, 비용도 싼 애플리케이션 서버 쪽으로 이동하는 것입니다. 오브젝트에 담긴 로직은 테스트하기도 쉽습니다. 목 오브젝트 등을 이용하면 심지어 DB가 없어도 테스트를 할 수 있습니다. 게다가 CBD를 비롯한 최신 설계와 개발 기법, 모델링을 중심으로 한 개발 방법은 오브젝트 기반의 설계와 구현에 잘 들어맞습니다.


자바는 객체지향 언어의 장점을 잘 살려서 설계된 언어입니다. 객체지향 프로그래밍 기법과 언어가 주는 장점인 유연한 설계가 가능하고 재상용성이 높다는 점을 잘 활용하면 자주 바뀌고 조건이 까다로운 비즈니스 로직을 효과적으로 구현해낼 수 있습니다. 객체지향 분석과 설계(OOAD)를 통해서 작성된 모델을 코드로 구현하고 지속적으로 발전시킬 수도 있습니다.


환경에 종속적인 기술과 침투적인 기법으로 인해 추가된 군더더기에 방해만 받지 않는다면 객체지향 언어로서의 장점을 잘 살려 비즈니스 로직의 복잡함을 최대한 효과적으로 다룰 수 있는 깔끔한 코드를 만드는 건 어렵지 않습니다.


물론 이 영역은 스프링조차 관여하지 않습니다. 비침투적인 기술인 스프링은 핵심 로직을 다루는 코드에는 스프링의 흔적조차 찾을 수 없을 만큼 자신을 드러내지 않습니다. 다만 뒤에서 비즈니스 로직을 담당하는 오브젝트들에게 적절한 에터프라이즈 기술 서비스가 제공되도록 은밀히 도와줄 뿐입니다.


결국 비즈니스 로직의 복잡함을 상대하는 전략은 자바라는 객체지향 기술 그 자체입니다. 스프링은 단지 객체지향 언어의 장점을 제대로 살리지 못하게 방해했던 요소를 제거하도록 도와줄 뿐입니다.



핵심 도구: 객체지향과 DI

기술과 비즈니스 로직의 복잡함을 해결하는 데 스프링이 공통적으로 사용하는 도구가 있습니다. 바로 객체지향(OO)입니다. 스프링 개발자는 자바 엔터프라이즈 기술의 가장 큰 장점은 바로 객체지향 설계와 프로그래밍을 가능하게 해주는 자바 언어라고 생각했습니다. 그런데 EJB 등이 등장해서 자바 언어의 객체지향 프로그램의 장점을 취하지 못하게 하면서, 특정 기술의 스펙에 종속된 설계 방식을 강요했다는 점에 불만을 가졌습니다.


스프링의 모토는 결국 "기본으로 돌아가자"입니다. 자바의 기본인 객체지향에 충실한 설계가 가능하도록 단순한 오브젝트로 개발할 수 있고, 객체지향의 설계 기법을 잘 적용할 수 있는 구조를 만들기 위해 DI 같은 유용한 기술을 편하게 적용하도록 도와주는 것이 스프링의 기본 전략입니다.


지금까지 살펴봤듯이 기술적인 복잡함을 효과적으로 다루게 해주는 기법은 모두 DI를 바탕으로 하고있습니다. 서비스 추상화, 템플릿/콜백, AOP와 같은 스프링의 기술은 DI없이는 존재할 수 없는 것들입니다.


그리고 DI는 객체지향 설계 기술이 없이는 그 존재의미가 없습니다. DI란 특별한 기술이라기보다는 유연하게 확장할 수 있는 오브젝트 설계를 하다 보면 자연스럽게 적용하게 되는 객체지향 프로그래밍 기법일 뿐입니다. 스프링은 단지 그것을 더욱 편하고 쉽게 사용하도록 도와줄 뿐입니다. 


객체지향 언어를 쓴다고 해서 자연스럽게 객체지향 설계가 되고 객체지향 프로그래밍을 할 수 있는 것은 아닙니다. 그래서 많은 개발자는, 심지어는 EJB의 설계자와 같은 세계적인 전문가도 그 가치를 놓칠 때가 있습니다. 그런 면에서 DI는 자연스럽게 객체지향적인 설계와 개발로 이끌어주는 좋은 동반자입니다. DI가 자연스럽게 확장성이 좋은 설계로 이끄는 과정을 생각해보겠습니다. DI를 의식하다 보면 오브젝트를 설계할 때 자주 DI를 적용할 후보가 더이상 없을까를 생각해보게 됩니다. 여기서 바뀔 수 있는 것은 무엇일까? 여기서 성격이 다르고, 변경의 이유가 다른 기능은 무엇일까? 그리고 그런 후보를 찾을 수 있다면 DI를 적용해서 오브젝트를 분리하고, 인터페이스를 도입하고, DI로 관계를 연결해줄 것입니다. 결국 DI는 좋은 오브젝트 설계의 결과물이기도 하지만, 반대로 DI를 열심히 적용하다 보면 객체지향 설계의 원칙을 잘 따르고 그 장점을 살린 설계가 나올 수도 있습니다.


그런 면에서 객체지향과 DI는 서로 떼놓고는 생각할 수 없습니다. 만약 스프링을 사용하고 DI를 적용했다고 하지만, 기계적인 방법으로 항상 사용하는 틀에 박힌 구조의 빈만 정의하고 나머지 코드에는 DI를 적용해볼 생각조차 안한다면 DI를 잘못 사용하고 있는 것입니다.


기술적인 복잡함을 해결하는 문제나 기술적인 복잡함이 비즈니스 로직에 침범하지 못하도록 분리하는 경우에도 DI가 바탕이 된 여러가지 기법이 활용됩니다. 반면에 비즈니스 로직 자체의 복잡함을 해결하려면 DI보다는 객체지향 설계 기법이 더 중요합니다. 왜 스프링이 힘들게 비즈니스 로직 자체에 기술적인 코드와 특정 기술의 스펙이 침범하지 않는 코드로 만들어주는 데 그토록 힘을 썼을까 생각해보겠습니다. 단지 좋은 코드가 좀 더 단순해지고 명확해지기 때문만은 아닙니다. 그보다는 순수한 비즈니스 로직만을 담고 있는 코드에는 객체지향 분석과 설계에서 나온 도메인 모델을 쉽게 적용할 수 있기 때문입니다. 객체지향적인 특성을 잘 살린 설계는 상속과 다형성, 위임을 포함해서 많은 객체지향 디자인 패턴과 설계 기법이 잘 녹아들어 갈 수 있습니다. 기술적인 코드에 침범당하지 않았다면 이런 설계를 비즈니스 로직을 구현하는 코드에 그대로 반영할 수 있습니다. 그래서 객체지향 기술의 장점을 최대한 활용해서 복잡하고 자주 변하는 업무를 지원하는 시스템을 만들 때도 손쉽게 대응이 가능해지는 것입니다.


결국 모든 스프링의 기술과 전략은 객체지향이라는 자바 언어가 가진 강력한 도구를 극대화해서 사용할 수 있도록 돕는 것이라고 볼 수 있습니다. 스프링은 단지 거들 뿐입니다. 현장의 업무를 잘 지원하고 유연하게 대응할 수 있는 뛰어난 애플리케이션을 만드는 것은 객체지향을 잘 활용해서 복잡한 문제를 풀어나갈 줄 아는 개발자의 능력에 달려 있다는 사실을 잊지 말아야 합니다. 스프링만 잘 공부하면 자바 언어 자체나 객체지향 설계와 개발 실력 따윈 별로 신경 쓰지 않아도 복잡한 엔터프라이즈 시스템을 잘할 수 있을 거라고 생각하면 오산입니다.



POJO 프로그래밍


스프링의 목적은 애플리케이션 개발의 복잡함을 줄여주는 것 또는 효과적으로 대응하게 해주는 것이라고 하면 맞는 말이긴 하지만 좀 추상적입니다. 좀 더 기술적으로 스프링이 지향하는 목적이 무엇인지 정의해보겠습니다.


스프링의 핵심 개발자들이 함께 쓴 Professional Spring Framework라는 책이 있습니다. 이 책에서 스프링 핵심 개발자들은 "스프링의 정수는 엔터프라이즈 서비스 기능을 POJO에 제공하는 것"이라고 했습니다. 엔터프라이즈 서비스라고 하는 것은 보안, 트랜잭션과 같은 엔터프라이즈 시스템에서 요구되는 기술을 말합니다. 이런 기술을 POJO에 제공한다는 말은, 뒤집어 생각해보면 엔터프라이즈 서비스 기술과 POJO라는 애플리케이션 로직을 담은 코드를 분리했다는 뜻이기도 합니다. "분리됐지만 반드시 필요한 엔터프라이즈 서비스 기술을 POJO 방식으로 개발된 애플리케이션 핵심 로직을 담은 코드에 제공한다"는 것이 스프링의 가장 강력한 특징과 목표입니다.



스프링의 핵심: POJO

스프링의 핵심이 POJO 프로그램이이라는 사실은, 스프링의 핵심을 가장 나타내고 있다고 알려진 아래 스프링 삼각형을 통해서도 잘 알 수 있습니다. 이 그림은 스프링 소스의 CTO인 아드리안 콜리어가 스프링의 핵심 개념을 설명하기 위해 만들었습니다.



스프링으로 개발한 애플리케이션의 기본 구조를 보여줍니다. 스프링 애플리케이션은 POJO를 이용해서 만든 애플리케이션 코드와, POJO가 어떻게 관계를 맺고 동작하는지를 정의해놓은 설계정보로 구분됩니다. DI의 기본 아이디어는 유연하게 확장 가능한 오브젝트를 만들어두고 그 관계는 외부에서 다이나믹하게 설정해준다는 것입니다. 이런 DI의 개념을 애플리케이션 전반에 걸쳐 적용하는 것이 스프링의 프로그래밍 모델입니다. 


스프링의 주요 기술인 IoC/DI, AOP와 PSA(Portable server abstractions)는 애플리케이션을 POJO로 개발할 수 있게 해주는 기능기술(enabling technology)이라고 불리웁니다.



POJO란 무엇인가?

스프링 애플리케이션 개발의 핵심인 POJO를 좀 더 자세히 알아보겠습니다. POJO는 Plain Old Java Object의 첫 글자를 따서 만든 약자입니다. 최근 몇년간 자바에서 유행어처럼 사용되고 있는 이 단어는 마틴 파울러가 2000년에 컨퍼런스 발표를 준비하다가 만들어낸 용어라고 합니다. 그런데 POJO라는 용어를 만들어낸 이유가 재미있습니다. 마틴 파울러는 당시 인기를 끌고 있던 EJB처럼 복잡하고 제한이 많은 기술을 사용하는 것보다는 자바의 단순한 오브젝트를 이용해 애플리케이션의 비즈니스 로직을 구현하는 편이 낫다고 생각했습니다. 그럼에도 왜 개발자는 자바의 단순한 오브젝트를 사용하길 꺼리는지 궁금했습니다. 그 이유를 찾아보니 평범한 자바오브젝트에는 EJB와 같은 그럴싸한 이름이 없기 때문이었습니다. 그래서 뭔가 있어 보이도록 만든 이름이 바로 POJO였습니다. 같은 설명이지만 그냥 "간단한 자바오브젝트를 사용하는데요"라고 말하는 것보다 "POJO 방식의 기술을 사용합니다"라고 하면 왠지 세련되고 첨단기술을 쓰는 것처럼 느껴진다는 심리를 이용한 것입니다. 평범한 자바오브젝트에 멋진 이름을 붙여줬던 시도는 기대 이상으로 성공적이었습니다.


단지 POJO라는 폼 나는 이름 때문만은 아니겠지만, 아무튼 그 이후로 POJO 프로그래밍에 관한 개발자들의 관심이 높아졌고 POJO를 지원한다는 걸 장점으로 내세우는 많은 프레임워크 기술이 쏟아져 나오기 시작했습니다. 심지어 EJB조차 3.0에서는 기존의 문제점을 반성하고 POJO 프로그래밍의 장점을 적극 도입하려고 했습니다.



POJO의 조건

그렇다면 이 POJO 프로그래밍이란 무엇일까요? 그저 EJB를 사용하지 않으면 POJO일까요? 특정 프레임워크의 클래스를 상속하지 않으면 POJO일까요? 단순하게 보자면 그냥 평범한 자바오브젝트라고 할 수 있지만 좀 더 명확하게 하자면 적어도 다음의 세 가지 조건을 충족해야 POJO라고 불리울 수 있습니다.


특정 규약(Contract)에 종속되지 않는다

POJO는 자바 언어와 꼭 필요한 API 외에는 종속되지 않아야 합니다. 따라서 EJB2와 같이 특정 규약을 따라 비즈니스 컴포넌트를 만들어야 하는 경우는 POJO가 아닙니다. 스트럿츠 1과 같이 특정 클래스를 상속해서 만들어야 하는 규약이 있는 경우도 마찬가지입니다. 특정 규약을 따라 만들게 하는 경우는 대부분 규약에서 제시하는 특정 클래스를 상속하도록 요구합니다. 그럴 경우 자바의 단일 상속 제한 때문에 더 이상 해당 클래스에 객체지향적인 설계 기법을 적용하기가 어려워지는 문제가 생깁니다. 또한 규약이 적용된 환경에 종속적이 되기때문에 다른 환경으로 이전이 힘들다는 문제점이 있습니다.


스트럿츠 1의 ActionForm을 상속한 폼 정보를 담는 객체는 스트럿츠의 규약에 독립적이어야 하는 서비스 레이어로 전달하기에 적합하지 않기 때문에 거의 비슷한 구조를 가진 DTO를 만들어 복사해줘야 하는 번거로움이 있습니다. 당연히 객체지향적인 설계로 만든 POJO 도메인 모델 오브젝트를 그대로 웹 레이어에서 사용할 수는 없습니다. EJB2 또한 비즈니스 컴포넌트가 EntityBean 클래스를 상속해야만 합니다. 별다른 가치를 주지도 못하는 규약 따위에 종속되지 않아야 하고, 객체지향 설계의 자유로운 적용이 가능한 오브젝트여야만 POJO라고 불리울 수 있습니다.


특정 환경에 종속되지 않는다

특정 환경에 종속적이어야만 동작하는 오브젝트도 POJO라고 할 수 없습니다. EJB 3는 분명 이전 버전의 문제점이던 규약에 따라 오브젝트를 만들어야 한다는 단점은 극복했습니다. 어떤 면에서 POJO에 가가운 설계와 구현이 가능해졌습니다. 하지만 여전히 JNDI라는 서버 서비스를 필요로 합니다. EJB 3 빈의 의존 오브젝트 정보는 JNDI를 통해 가져와야 하기 때문입니다. 따라서 JNDI가 없는 환경에서는 그대로 사용하기가 힘듭니다. 이렇게 JNDI와 같은 특정 환경이 의존 대상 검색 방식에 종속적이라면 POJO라고 할 수 없습니다.


어떤 경우는 특정 벤더의 서버나 특정 기업의 프레임워크 안에서만 동작 가능한 코드로 작성되기도 합니다. 또 환경에 종속적인 클래스나 API를 직접 쓴 경우도 있습니다. 예를 들면 WebLogic 서버에서만 사용 가능한 API를 직접 쓴 코드를 갖고 있거나 특정 OS에서 제공하는 기능을 직접 호출하도록 만들어진 오브젝트 등이 존재합니다. 이런 식으로 순수한 애플리케이션 로직을 담고 있는 오브젝트 코드가 특정 환경에 종속되게 만드는 경우라면 그것 역시 POJO라고 할 수는 없습니다. POJO는 환경에 독립적이어야 합니다.


특히 비즈니스 로직을 담고 있는 POJO 클래스는 웹이라는 환경정보나 웹 기술을 담고 있는 클래스나 인터페이스를 사용해서는 안됩니다. 설령 나중에는 웹 컨트롤러와 연결돼서 사용될 것이 뻔하다고 할지라도 직접적으로 웹이라는 환경으로 제한해버리는 오브젝트나 API에 의존해서는 안됩니다. 그렇게 하면 웹 외의 클라이언트가 사용하지 못하게 됩니다. 또 웹 서버에 올리지 않고 독립적으로 테스트하기도 힘들어집니다. 기술적인 내용을 담은 웹정보가 비즈니스 로직과 얽혀 있으니 이해하기도 힘들고 수정하기도 어렵습니다. 비즈니스 로직을 담은 코드에 HttpServletRequest나 HttpSession, 캐시와 관련된 API가 등장하거나 웹 프레임워크의 클래스를 직접 이용하는 부분이 있다면 그것은 진정한 POJO라고 볼 수 없습니다.


요즘은 소스코드에 직접 메타정보를 추가해주는 애노테이션을 많이 사용합니다. 그렇다면 애노테이션을 사용했을 경우에는 POJO일까 아닐까요? 이전에 XML에 담겨있던 설정정보를 자바 코드로 가져왔으니 이는 POJO가 아니라고 할지 모르겠지만 꼭 그런건 아닙니다. 애노테이션이 단지 코드로 표현하기는 적절치 않은 부가적인 정보를 담고 있고, 그 때문에 환경에 종속되지만 않는다면 여전히 POJO라고 할 수 있습니다. 하지만 애노테이션이나 엘리먼트 값에 특정 기술과 환경에 종속적인 정보를 담고 있다면 그때는 POJO로서의 가치를 잃어버린다고 할 수 있습니다.


그럼 특정 기술규약과 환경에 종속되지 않으면 모두 POJO라고 말할 수 있을가요? 많은 개발자가 크게 오해하는 것 중의 하나가 바로 이것입니다. 그저 평범한 자바 클래스를 써서 개발했다고 해서 POJO 방식으로 개발했다고 생각합니다. 단지 자바의 문법을 지키고, 순순하게 JavaSE API만을 사용했다고 해서 그 코드를 POJO라고 할 수는 없습니다. POJO는 객체지향적인 자바 언어의 기분에 충실하게 만들어져야 하기 때문입니다. 그것이 POJO라는 이름을 붙이면서까지 단순한 자바오브젝트에 집착하는 이유입니다. 자바는 객체지향 프로그래밍을 가능하게 해주는 언어이지만, 자바 언어 문법을 사용했다고 해서 자동으로 객체지향 프로그래밍과 객체지향 설계가 적용됐다고 볼 수는 없습니다.


책임과 역할이 각기 다른 코드를 한 클래스에 몰아넣어 덩치 큰 만능 클래스로 만드는 경우, 재사용이 불가능할 정도로 다른 레이어와 영역의 코드와 강한 결합을 가지고 만들어지는 경우, 상속과 다형성의 적용으로 처리하면 깔끔한 것을 if/switch문이 가득 찬 길고 긴 메소드로 작성해놓은 경우라면 과연 그것이 객체지향적인 자바오브젝트라고 할 수 있을지 의문입니다. 그런 식으로 설계되고 개발된 오브젝트라면 단지 특정 기술과 환경에 종속적이지 않다고 해서 POJO라고 부르기 힘듭니다.


진정한 POJO란 객체지향적인 원리에 충실하면서, 환경과 기술에 종속되지 않고 필요에 따라 재활용될 수 있는 방식으로 설계된 오브젝트를 말합니다. 그런 POJO에 애플리케이션의 핵심 로직과 기능을 담아 설계하고 개발하는 방법을 POJO 프로그래밍이라고 할 수 있습니다.



POJO의 장점

그렇다면 POJO 프로그래밍의 장점은 무엇일까요? 바로 POJO가 될 수 있는 조건이 그대로 POJO의 장점이 됩니다.


특정한 기술과 환경에 종속되지 않는 오브젝트는 그만큼 갈끔한 코드가 될 수 있습니다. 로우 레벨의 기술과 환경에 종속적인 코드가 비즈니스 로직과 함께 섞여 나오는 것만큼 지저분하고 복잡한 코드도 없습니다. 그런 코드는 개발하기도 힘들고, 오류를 찾고 디버깅하기는 더더욱 힘듭니다. 코드를 읽고 이해기도 어려울뿐더러 검증이나 테스트 작성에도 한계가 있으므로 유지보수는 큰 부담이 됩니다.


또 POJO로 개발된 코드는 자동화된 테스트에 매우 유리합니다. 환경의 제약은 코드의 자동화된 테스트를 어렵게 합니다. 컨테이너에서만 동작을 확인할 수 있는 EJB 2는 테스트하려면 서버의 구동 및 빌드와 배치 과정까지 필요합니다. 자동화된 테스트가 불가능한건 아니지만 매우 복잡하고 번거로우므로 대부분 수동 테스트 방식을 선호합니다. 간단한 코드 수정에도 빌드, 배치, 수동 확인이라는 번거로운 사이클을 따라 작업하기가 얼마나 힘든지는 EJB 개발자들이 경험적으로 잘 알고 있습니다. 그에 반해 어떤 환경에도 종속되지 않은 POJO 코드는 매우 유연한 방식으로 원하는 레벨에서 코드를 빠르고 명확하게 테스트할 수 있습니다.


객체지향적인 설계를 자유롭게 적용할 수 있다는 것도 큰 장점입니다. 개발자들이 자바와 객체지향 프로그래밍, 모델링과 설계에 대해 배울 때 그려봤던 도메인 모델과, 오랜 경험을 통해 쌓여온 재활용 가능한 설계 모델인 디자인 패턴 등은 POJO가 아니고는 적용하기 힘듭니다. 로드 존슨은 특정 기술과 규약, 환경보다 자바 언어와 객체지향 기술이 더 중요하다는 사실을 끊임없이 강조했습니다. 그저 로드 존슨이 객체지향 기술의 광적인 팬이기 때문일까? 아닙니다. 로드 존슨은 대규모 자바 엔터프라이즈 시스템을 개발해온 수많은 경험을 통해 자바 언어의 객체지향적인 설계와 구현 방식이야말로 그 어떤 새로운 기술과 환경, 툴보다 더 실제 프로젝트를 성공시키는 데 중요한 요소임을 알고 있기 때문입니다.


객체지향 프로그래밍은 지금까지 나온 프로그래밍 패러다임 중에서 가장 성공했고, 가장 많은 언어에서 적용됐으며, 무엇보다도 엔터프라이즈 시스템에서와 같이 복잡한 문제 도메인을 가진 곳에서 가장 효과적으로 사용될 수 있다는 사실이 이미 오랜 시간을 통해 증명되었습니다.


그렇다면 왜 이런 장점이 있는 POJO 방식, 어쩌면 가장 기초적이라고 할 수 있는, 자바의 초기부터 애용되던 이러한 POJO를 이용한 개발 방식이 왜 EJB처럼 제약이 심하고 특정 기술에 종속적인 코드를 강요하고 자바의 객체지향적인 특징을 무시해버리는 기술에 밀려버렸던 것일까요? 그것은 앞에서 살펴봤듯이 엔터프라이즈 시스템의 개발이라는 복잡한 과제에 대해 잘못된 접근 방법을 선택했기 때문입니다.



POJO 프레임워크

스프링은 POJO를 이용한 엔터프라이즈 애플리케이션 개발을 목적으로 하는 프레임워크라고 했습니다. POJO 프로그래밍이 가능하도록 기술적인 기반을 제공하는 프레임워크를 POJO 프레임워크라고 합니다. 스프링 프레임워크와 하이버네이트를 대표적인 POJO 프레임워크로 꼽을 수 있습니다. 주로 DB 이용 기술에 POJO를 적용하는 것을 목적으로 하는 하이버네이트와 달리, 스프링은 엔터프라이즈 애플리케이션 개발의 모든 영역과 계층에서 POJO 방식의 구현이 가능하게 하려는 목적으로 만들어졌습니다.


스프링을 이용하면 POJO 프로그램의 장점을 그대로 살려서 엔터프라이즈 애플리케이션의 핵심 로직을 객체지향적인 POJO를 기반으로 깔끔하게 구현하고, 동시에 엔터프라이즈 환경의 각종 서비스와 기술적인 필요를 POJO 방식으로 만들어진 코드에 적용할 수 있습니다.



스프링이 엔터프라이즈 시스템의 복잡함을 어떻게 다루는지를 보여주는 그림입니다. 하지만 자신은 기술영역에만 관여하지 비즈니스 로직을 담당하는 POJO에서는 모습을 감춥니다. 데이터 액세스 로직이나 웹 UI 로직을 다룰 때만 최소한의 방법으로 관여합니다. POJO 프레임워크로서 스프링은 자신을 직접 노출하지 않으면서 애플리케이션을 POJO로 쉽게 개발할 수 있게 지원해줍니다.



이제 스프링이 어떤 목적으로 만들어졌고, 스프링을 사용하면 개발자가 어떤 혜택을 누릴 수 있는지 어느 정도 이해할 수 있을 것입니다. 물론 객체지향적 POJO 프로그래밍을 어떻게 효과적으로 적용할지는 개발자에게 또 하나의 숙제이고 부담입니다. 이를 위해 객체지향 분석과 설계에 대한 지식을 습득하고 훈련해야 합니다. 당연히 자바 언어와 JVM 플랫폼 그리고 JDK API 사용법도 잘 알아야 합니다. 객체지향 기술의 선구자들이 잘 정리해놓은 디자인 패턴과 구현 패턴, 좀 더 나은 코드 구조를 만들기 위한 리팩토링 기술 또한 필요합니다.


스프링을 사용한다고 해서 이런 부담이 줄어드는 건 아닙니다. 대신 스프링은 개발자들이 복잡한 엔터프라이즈 기술보다는 이러한 객체지향적인 설계와 개발의 원리에 좀 더 집중할 수 있도록 기회를 줍니다. 동시에 스프링이 제공하는 기술과, 프레임워크 API 및 확장 포인트는 그것을 이용하는 코드가 자연스럽게 객체지향적인 설계원리를 따라가도록 이끌어주기도 합니다. 좋은 코드와 좋은 프레임워크의 특징은 그것을 사용해서 만들어지는 코드가 나쁜 코드가 되기 어렵다는 점입니다. 스프링은 매우 자연스럽게 개발자가 좋은 코드를 만들게 해주는 특별한 재주가 있습니다. 이게 바로 스프링이 전 세계적으로 그토록 많은 개발자에게 인정받고 인기를 누리는 이유입니다.