오상우
오상우

Categories

  • java
  • spring

스프링이란 무엇인가

8장은 개인적으로 가장 짧았지만, 토비책에서 가장 인상적이었던 장이었다. 지금까지 실제로 스프링의 핵심 가능기술인 DI/IoC, PSA, AOP에 대해 실습 위주로 필요성과 적용에 대해 학습했다면, 체득한 내용을 바탕으로 실제로 이 기술들이 모여서 어떻게 스프링의 POJO 프로그래밍을 구현하는지를 이론적으로 설명하는 장이다. 1~7장과는 달리 코드를 단 한줄도 작성하지 않는 장이기도 하다.

1. 스프링의 정의

스프링은 자바 엔터프라이즈급 어플리케이션 개발을 쉽게 할 수 있도록 도와주는 경량급 오픈소스 어플리케이션 프레임워크이다.

스프링을 단 한 줄로 정의한다면, 위와 같이 정의할 수 있다. 이제 위 정의에 나와 있는 개념들을 하나 하나 살펴보자.

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

혹시 아직 라이브러리와 프레임워크의 차이를 모르는 사람을 위해 설명하자면, 둘 다 미리 정의되어 있는 로직들을 가져다 사용하는 것은 같으나 라이브러리는 어플리케이션의 제어권이 사용자에게 있는 반면에 프레임워크는 제어권이 프레임워크에게 있다. 대표적인 프레임워크로는 파이썬 웹 어플리케이션 프레임워크인 장고, 루비의 인기를 이끈 일등 공신 ror 등이 있다.

하지만 스프링은 그냥 프레임워크가 아닌 ‘어플리케이션 프레임워크’이다. 일반 프레임워크는 특정 기술 영역에 특화된 기능을 제공한다. 위에서 말한 장고나 ror은 웹 기술에 특화된 프레임워크이고, 요즘 핫한 쿠버네티스는 컨테이너를 사용한 배포/운영 부분에서 활약하는 프레임워크라고 볼 수 있다. 하지만 스프링은 이런 일반 프레임워크와는 달리, 자바 어플리케이션의 전 영역에 사용되는 범용적인 프레임워크이다. 당장 스프링 홈페이지를 가보면, 스프링이라는 이름 아래 다양한 어플리케이션 영역(웹, 데이타, 매세지 큐, CI, 배치 , 모바일 어플리케이션 등) 21개의 프로젝트들이 존재함을 알 수 있다.

스프링이 이렇게 전 영역을 포괄하는 어플리케이션 프레임워크가 된 것은, 스프링의 기원과 관련이 있다. 스프링은 로드 존슨의 책 “Expert One-on-One J2EE Design and Development”라는 책에서, J2EE 어플리케이션 개발의 전 영역에 대한 설계와 개발 전략을 다룬 책이다. 그가 이 책에세 강조한 것은 “항상 프레임워크를 기반으로 접근하라”였다. 그는 단순히 말로 강조하는 것에서 그치지 않고, 실제 책에 3만 줄 가량의 프레임워크 코드를 제공했다. 이 책을 읽고 감명받은 많은 개발자들이 포럼에서, 해당 프레임워크 코드를 단순히 예제로만 남기기에는 너무 아깝다는 의견을 냈고, 여러 자바 개발자들과 로드 존슨이 합심하여 스프링이라는 이름의 오픈 소스 프로젝트를 시작한 것이다. 애초에 책 자체가 자바 어플리케이션 개발 전 영역에 걸쳐 진행되었기에, 스프링 역시 모든 영역에 대한 어플리케이션 프레임워크로 개발되었다.

스프링은 단순히 자바 어플리케이션 개발의 전 영역에 프레임워크를 제공해줄 뿐 아니라, 이런 20가지가 넘는 프레임워크들이 공유하는 핵심 기술을 가지고 있기에 스프링 프레임워크라고 불리고 있다.

2. 경량급

스프링이 경량급이라는 것은 절대적으로 가벼운 프레임워크라는 의미가 아니다. 위해서 언급했듯, 스프링은 21개의 프레임워크들이 모여있는 거대한 프로젝트이다. 여기서 경량급이라고 말한 것은, 처음 스프링이 등장했을 때 스프링이 바판했던 기존 기술인 EJB와 같은 기술들에 비해 상대적으로 가볍고 심플하다는 의미다.

EJB는 구동하기 위해 고가의 복잡한 WAS 서버가 필요했으며, 제대로 동작시키기 위해 복잡한 설정 등이 요구되었고 자바 코드 내에서도 EJB 종족적인 코드들이 계속해서 등장했다. 반면 스프링은 가장 간단한 WAS인 톰캣이나 제티 기반으로도 아주 잘 동작했고, 상대적으로 설정도 간단했으며 비즈니스 로직에 스프링이 전혀 등증하지 않았다.

3. 오픈소스

스프링은 1번에서 말했듯, 태생이 자발적인 자바 개발자들의 참여로 탄생한 오픈소스 프로젝트이다. 오픈소스 프로젝트는 장점과 단점을 모두 가지고 있다. 우선 장점은, 여러 환경/상황에 따른 테스트를 수 많은 개발자들의 도움으로 빠르고 방대하게 진행 가능하며, 사용 비용이 없고, 발전의 속도나 변화 역시 빠르다. 하지만 오픈소스 프로젝트는 개발자들의 보수가 없이 자발적으로 진행되는 만큼 안정성/사후지원이 부족하다는 점이 단점으로 꼽힌다. 하지만 스프링은 스프링소스라는 회사에서 근무하는 정규직 개발자들이 보수를 받으며 개발했고, 현재는 국제적 IT 기업 VMWare에 전략적으로 합병되어 해당 기업에서 개발하며, 돈을 지불하고 사후지원을 받거나 추가적인 소프트웨어를 구매하는 등의 사용도 가능하다.

스프링 프로젝트는 오픈소스의 장점을 유지하면서, 단점을 보완한 좋은 사례인 것이다.

4. 자바 엔터프라이즈 개발을 편하게

‘자바 엔터프라이즈 개발을 편하게’는 2000년대 초반에, 다른 여러 자바 엔터프라이즈 개발 프레임워크들이 가지고 나온 프레이즈였다. 그 이유는 당연하게도, 자바 엔터프라이즈 개발이 본질적으로 편하지 않고, 무척 복잡하고 까다로운 일이었기 때문이다.

대표적으로 EJB가 있는데, 역시 자바 엔터프라이즈 개발을 편하게 해주겠다는 목표로 등장한 J2EE 개발 프레임워크였다. EJB 도 일정 부분 자바 엔터프라이즈 개발을 편하게 해 주었으나, 그 해결책을 적용하는 과정에서 오히려 자바/객체 지향 개발의 장점을 잡아먹어 버리는 단점이 새로이 등장했다. 이 때문에 자바 개발자들은 차츰 EJB를 쓰지 않게 되었다.

자바 엔터프라이즈 개발을 스프링이 어떻게 편하게 만들었는지는 스프링의 핵심을 꿰뚫는 지점이므로, 추가적으로 더 이야기 해 보자.


2. 스프링의 목적

스프링을 사용하는 것은 그리 어렵지 않다. 빈 설정 파일, 애노테이션 몇개만 붙여서 실행하기만 해도 어플리케이션 컨텍스트는 동작하며 빈들이 주입되어 작동한다. 그만큼 프레임워크이지만 개발자에게 높은 자유도를 제공한다.

다시 말하면, 스프링을 제대로 사용하는 것이 그만큼 어렵다는 이야기이기도 하다. 스프링을 제대로 사용하려면 스프링의 목적을 분명히 알아야 한다. 위에서도 말했듯, 스프링은 결국 자바 엔터프라이즈 어플리케이션 개발을 편하게 해주기 위한 목적으로 등장했다.

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

엔터프라이즈 개발은 왜 복잡할까? 근본적으로 두가지 이유가 있다.


A. 기술적 복잡함

늘어나는 트래픽 처리, 트랜젝션, 분산처리, 데이터 분석과 로깅, 보안 등 여러 기업들의 업무에서 IT 시스템이 차지하는 비중이 커지면서, IT 시스템에 요구되는 기술적 기능들이 점점 많아지고, 복잡해진다. 이는 일반적으로 비지니스 로직과는 상관이 없는 경우가 많다.


B. 비즈니스 로직 자체의 복잡함

점점 더 많은 서비스들이 IT를 기반으로 제공되면서, 기술적 요구사항 뿐 아니라 서비스/비즈니스 자체의 요구사항도 복잡해져 간다. 우버와 같이 실시간으로 두 모바일 기기 사용자간 위치를 공유하고, 최단거리에 있는 소비자들을 매칭하며 예약을 걸고 해지해주고 거리에 따라 결제까지 해 줘야 하는 비즈니스 모델은 그 자체로 몹시 복잡하고 예외도 많은 비즈니스 로직이다.


사실 위 두 복잡함은 어떤 지름길이 존재하지 않는 복잡함이다. IT가 비즈니스에서 점점 핵심적인 역할을 함에 따라, 필연적으로 개발자들이 다루어야 하는 문제인 것이다. 하지만 위 두 복잡함이 서로 혼재되어 나타나면서 복잡함은 두배가 아니라 세배, 네배로 증가한다.

자바 엔터프라이즈 개발의 복잡함은 저렇게 성격이 다른 두 복잡함이 한데 섞이고 서로 결합되어 나타나면서 개발자들을 힘들게 했고, 유지보수가 어려운 어플리케이션이 양산되었다.

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

스프리의 기본적인 전략은, 기술적인 복잡함과 비즈니스의 복잡함을 분리하는 것이다. 지금까지 사용했던 PSA와 AOP가 이 두 복잡함을 분리하는 스프링의 대표적 방법이다.

  • 기술에 대한 접근 방식을 일관성 있게, 특정 기술에 종속적이지 않게

PSA가 위 문제를 해결하는 스프링의 방식이다. 서비스 추상화를 통해 여러 다른 구체 기술을 하나의 추상적 기술 인터페이스로 접근해, 일관성있고 독립적 구현을 가능하게 한다.

  • 기술적 처리를 담당하는 코드와 비즈니스 로직 코드를 분리

특정 기술 코드와 비즈니스 로직 코드는 실행시에 몹시 가깝게 결합되어야 하는 경우가 많다(트랜젝션, 성능 모니터링, 로깅 등). 이 경우, 런타임에는 한데 합쳐지더라도 소스 코드 레벨에서는 서로 분리하는 기술이 바로 AOP이다. 기술적 코드가 여기저기 중복해서 나타나는 것을 막아주는 AOP는 기술적인 부분이 필요 이상으로 복잡해지는 것을 막아주는 강력한 수단이다.


이렇게 기술적인 복잡함을 분리하고 나면, 오롯이 비즈니스 로직의 복잡함만이 남는다. 그리고 스프링은 순수한 비즈니스 로직의 복잡함을 다루는 것을 오롯이 자바와 객체 지향 프로그래밍에 맡긴다.

사실 객체 지향은 정말 오랫동안 수많은 소프트웨어 엔지니어들에게 인정받고, 발전해 온 복잡한 현실 문제를 다루는 프로그래밍 방법론이다. 실제로 수많은 디자인 패턴, 여러 방법론들이 객체 지향을 기반으로 발전해 왔다. EJB의 가장 큰 패인은 이런 객체 지향이라는 자바의 장점을 EJB 의존적 코드들이 등장하며 방해했기 때문이다. 스프링은 기술적인 코드를 깔끔하게 분리하며, 비즈니스 로직에 일절 스프링 코드가 등장하지 않는 비침투적 방식을 고수해 객체 지향 언어인 자바의 장점을 100% 활용할 수 있도록 한다. 결국 스프링을 잘 사용하려면 자바/객체지향 프로그래밍에 대해서도 잘 알아야한다.

그리고 DI/IoC는 이런 객체지향을 잘 쓸수 있게 해주는 스프링의 기본 전략이다. DI를 잘 사용하려고 노력하다 보면 자연스럽게 클래스에서 어떤 부분을 분리해서 DI해 적용할 수 있을지, 어떤 부분이 미래에 변경될 수 있는 부분인지 생각하게 되고, 인터페이스를 통해 OCP에 맞는 프로그래밍을 하다 보면 자연스럽게 객체지향 프로그래밍을 하게 된다.

3. POJO 프로그래밍

image

지금까지 우리가 배운 3가지 스프링 핵심 기술을 흔히 가능 기술(enabling technology) 라고 부른다. 무엇을 가능하게 해주는 기술일까? 바로 자바 어플리케이션을 POJO로 개발할 수 있게 해주는 가능 기술이라는 의미다.

POJO : Plain Old Java Object

POJO는 여러 복잡한 기술들이 섞여 있는 솔루션과는 달리, 그냥 단순한 자바 객체를 이용해 프로그래밍하는 방법이다.

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

image

스프링은 결국

  1. 기술적 복잡함을 비즈니스 로직에서 PSA / AOP 로 분리하여 다루고
  2. 비즈니스 로직의 복잡함은 POJO 프로그래밍 방식으로 해결하며
  3. 전체적인 어플리케이션을 DI/IoC로 관리하는

방식으로 설계된다.

그럼 마지막으로 스프링의 3가지 가능 기술들에 대해 좀 더 자세히 정리해보자.

4. 스프링의 가능 기술

1. IoC / DI

IoC/DI는 스프링의 가장 기본이 되는 기술이자, 스프링의 핵심 개발 원칙이기도 하다. 결국 나머지 2개의 기술도 IoC/DI에 기반을 두고 있다.

왜 우리는 두개의 오브젝트를 분리해서 인터페이스에 의존하게 만들고, 외부에서 실제 사용할 대상을 수동적으로 주입받는 것일까? 결국 그 이유는 OCP 원칙을 지키기 위해서이다. A -> B의 의존 관계가 존재할때, A의 입장에서는 B 인터페이스를 구현하는 실제 구현체가 무엇으로 변하든 자신은 변하지 않고(변경에 닫혀있는), B의 입장에서는 B 인터페이스만 구현하면 B1, B2, B3등 실제 구현체가 어떻게 변경되어도 괜찮은(확장에 열려있는) 설계로 만드는 것이다.

2. AOP

AOP는 관점 지향 프로그래밍이다. 객체 지향 프로그래밍과 같은 수준의 개념으로 오해할 수 있지만, AOP는 OOP의 대체제라기 보다는 보완해주는 보조적 개념에 가깝다.

POJO 만으로 엔터프라이즈 어플리케이션을 개발하면서 맞닥뜨리는 한계를, 기술적 서비스를 선언적으로 제공할 수 있는 것이 바로 AOP의 도움 덕분이다.

  • 자바 다이나믹 프록시
  • AspectJ의 바이트코드 수정

크게 위 두가지 방식으로 스프링에 AOP를 적용할 수 있다.

3. PSA

자바 엔터프라이즈 개발에는 여러 로우레벨 기술들이 들어갈 수 밖에 없다. PSA는 해당 로우레벨 기술을 쓰지 않는 것이 아니다. 그런 기술들을 직접 사용하지 않고, 추상화된 인터페이스를 사용하는 것이다. 실제로 스프링에는 대부분의 로우레벨 기술을 추상회시킨 객체들이 이미 존재한다(JDBC, 트랜젝션 등). 서비스 추상화를 위해 실제 필요한 기술은 DI 뿐이다. 결국 DI를 적극 활용해서 개발한다면 서비스 추상화는 자연스럽게 만들어진다. 서비스 추상화는 기술 독립적 코드 뿐 아니라 테스트에도 유용하게 활용 될 수 있다.