스프링의 본질은 엔터프라이즈 서비스 기능을 POJO에 제공하는 것이다
- Professional Spring Framework, 2005
EJB와 POJO 프로그래밍
POJO의 등장
EJB(Enterprise Java Bean)란 엔터프라이즈 개발을 단순화하기 위해 Sun 사에서 만들어낸 Java 스펙이다. 스프링이 등장하기 이전에는 EJB가 자바 엔터프라이즈 애플리케이션 개발 시장을 독점하고 있었다. 하지만 EJB에는 치명적인 단점이 있었는데, 바로 코드들이 EJB 기술에 지나치게 종속되어야 한다는 것이다. 아래의 코드는 EJB 기반으로 작성된 것으로, 특정 서비스 계층에 EJB라는 기술이 마구 침투하는 모습을 확인할 수 있다. import 선언문부터 implenets, 인스턴스 변수까지 코드가 EJB에 완전히 종속된다.
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public class OrdersService implements SessionBean {
private SessionContext ctx;
public Orders placeOrder(String menuName) {
Orders orders = new Orders(menuName);
orders.init()
return orders;
}
@Override
public void setSessionContext(SessionContext ctx) throws EJBException {
this.ctx = ctx;
}
@Override
public void ejbRemove() throws EJBException {
}
@Override
public void ejbActivate() throws EJBException {
}
@Override
public void ejbPassivate() throws EJBException {
}
}
마틴 파울러는 당시 인기를 끌던 EJB처럼 복잡하고 제한적인 기술보다는 자바의 단순 오브젝트를 이용해 비즈니스 로직을 구현하는 편이 낫다고 생각했다. 그럼에도 개발자는 왜 자바의 단순한 객체를 사용하길 꺼리는지 궁금해했는데, 그 이유를 찾아보니 그럴싸한 이름이 없기 때문이였다. 그래서 2000년에 마틴 파울러가 컨퍼런스 발표를 준비하다가 뭔가 있어보이도록 만든 이름이 바로 POJO(Plain Old Java Object)였고, 이는 기대 이상으로 성공적이였다.
스프링 프레임워크의 탄생
스프링 프레임워크의 탄생
2000년대 초반 각종 자바 컨퍼런스에서 자주 논의됐던 주제는 “왜 자바 엔터프라이즈 프로젝트는 실패하는가?” 였다. 밝혀진 여러 가지 원인이 있었지만, 그 중 가장 대표적인게 “엔터프라이즈 시스템 개발이 너무 복잡해져서”였다.
엔터프라이즈 시스템 개발이 복잡한 이유는 비즈니스 자체의 복잡함과 기술적인 복잡함이 결합되기 때문이다. 비즈니스 자체의 복잡함은 우리가 구현해야 할 로직으로 제거 대상이 아니다. 대신 기술적 복잡함을 비즈니스 로직으로부터 분리해내는 것이 필요했다. 이러한 분위기 속에서 2002년에 로드 존슨(Rod Johnson)은 EJB의 문제점을 지적한 책(J2EE Design and Development)을 출간했다.
로드 존슨은 EJB의 문제점을 지적하면서 EJB 없이도 고품질의 애플리케이션 개발할 수 있다는 내용과 예제 코드를 선보였다. 그리고 이 책을 읽은 개발자 유겐 휠러(Uergen Hoeller)와 얀 카로프(Yann Caroff)가 로드 존슨에게 오픈 소스 프로젝트를 제안했고, 2004년에 탄생한 것이 바로 스프링 프레임워크이다. 실제로 해당 책의 내용을 보면 BeanFactory, ApplicationContext 등 스프링의 기본이 되는 코드들이 모두 담겨있다고 한다. 참고로 Spring은 EJB에 종속되던 겨울이 끝나고 봄이 왔다는 의미에서 붙여졌다고 한다.
스프링 프레임워크의 목표: 비침투적인 해결책
스프링은 EJB의 처음 목표와 마찬가지로 기술적인 복잡함을 애플리케이션 핵심 로직에서 제거하는데 목표를 뒀다.
어떤 기술을 적용했을 때 그 기술과 관련된 코드나 규약 등이 코드에 등장하는 경우를 침투적인 기술이라고 한다. 물론 꼭 필요한 기능을 위해 특정 기술의 API를 이용하는건 어쩔 수 없지만, 꼭 필요한 기능이 아닌데도 특정 클래스나 인터페이스, API 등이 코드에 마구 등장한다면 그것은 침투적인 기술이 되며 복잡함을 가중시키는 원인이 된다.
반면에 비침투적인 기술은 기술의 적용 사실이 코드에 직접 반영되지 않는다는 특징이 있다. 어딘가에서는 기술의 적용에 따라 필요한 작업을 해줘야 하겠지만, 애플리케이션 코드 여기저기에 등장하거나, 코드의 설계와 구현 방식을 제한하지는 않는다.
스프링이 성공할 수 있었던 비결은 바로 비침투적인 기술이라는 전략을 택했기 때문이다. 스프링을 이용하면 기술적인 복잡함과 비즈니스 로직을 다루는 코드를 깔금하게 분리할 수 있다. 스프링 스스로는 애플리케이션 코드에 불필요하게 나타나지 않도록 도와주며, 꼭 필요할 것 같은 경우조차도 기술 코드가 직접 노출되지 않도록 만들어졌다.
그리고 이런 문제를 해결하는데 스프링이 공통적으로 사용하는 도구가 바로 객체지향이다. 기술적인 복잡함을 효과적으로 다루게 해주는 기법은 모두 DI를 바탕으로 한다.
서비스 추상화, 템플릿/콜백, AOP와 같은 스프링의 기술은 DI 없이 존재할 수 없다. 그리고 DI는 객체지향 기술 없이 그 존재 의미가 없다. DI는 특별한 기술이라기보다는 유연하게 확장할 수 있는 오브젝트 설계를 하다 보면 자연스럽게 적용하게 되는 객체지향 프로그래밍 기법일 뿐이며 스프링은 단지 그것을 더욱 편하고 쉽게 사용하도록 도와줄 뿐이다.
결국 모든 스프링의 기술과 전략은 객체지향이라는 자바 언어가 가진 강력한 도구를 극대화해서 사용할 수 있도록 돕는 것이며 스프링은 단지 거들 뿐이다.
물론 최근에는 Spring 3.1에 등장한 어노테이션 기반의 프로그래밍 방식이 상당한 인기를 끌고 있어서 우리의 코드는 프레임워크에 꽤나 침투되고 있다. 하지만 이것은 개발자인 우리의 선택일 뿐이며, 비침투적인 코드 작성도 가능하다.
POJO 프로그래밍과 Spring프레임워크
스프링의 핵심 개발자들이 함께 쓴 ”Professional Spring Framework”라는 책에서 스프링 핵심 개발자들은 “스프링의 정수(essence)는 엔터프라이즈 서비스 기능을 POJO에 제공하는 것”이라고 했다. 엔터프라이즈 서비스라고 하는 것은 보안, 트랜잭션과 같은 엔터프라이즈 시스템에서 요구되는 기술을 말한다.
이런 기술을 POJO에 제공한다는 말은 엔터프라이즈 서비스 기술과 POJO 애플리케이션 로직을 담은 코드를 분리했다는 뜻이다.
“분리됐지만 반드시 필요한 엔터프라이즈 서비스 기술을 POJO 방식으로 개발된 애플리케이션 핵심 로직을 담은 코드에 제공한다”는 것이 스프링의 가장 강력한 특징과 목표이다.
스프링의 핵심이 POJO라는 사실은 스프링의 핵심을 가장 나타내는 스프링 삼각형을 통해서도 알 수 있다. 이 그림은 스프링 소스의 CTO인 아드리안 콜리어가 스프링의 핵심 개념을 설명하기 위해 만들었다. 스프링의 주요 기술인 Ioc/DI, AOP, PSA는 애플리케이션을 POJO로 개발할 수 있게 해주는 가능 기술들이며, 이것들은 모두 스프링이 있기 전에도 여러 가지 형태로 시도됐고 발전하던 기술이었다.
시간이 지나면서 스프링은 모던한 웹 프레임워크들과 비교하여 한계점을 갖게 되었습니다. 어느 개발자는 이러한 부분을 지적하고 개선해달라는 요구를 하였는데, 그것이 바로 스프링 부트(Spring Boot)의 탄생이 되었습니다.
POJO(Plain Old Java Object, 단순한 자바 오브젝트)란?
아래 내용은 위키 백과에 나와있는 POJO에 대한 설명이다.
Plain Old Java Object, 간단히 POJO는 말 그대로 해석을 하면 오래된 방식의 간단한 자바 오브젝트라는 말로서 Java EE 등의 중량 프레임워크들을 사용하게 되면서 해당 프레임워크에 종속된 "무거운" 객체를 만들게 된 것에 반발해서 사용되게 된 용어이다. 2000년 9월에 마틴 파울러, 레베카 파슨, 조쉬 맥킨지 등이 사용하기 시작한 용어로서 마틴 파울러는 다음과 같이 그 기원을 밝히고 있다.
“ 우리는 사람들이 자기네 시스템에 보통의 객체를 사용하는 것을 왜 그렇게 반대하는지 궁금하였는데, 간단한 객체는 폼 나는 명칭이 없기 때문에 그랬던 것이라고 결론지었다. 그래서 적당한 이름을 하나 만들어 붙였더니, 아 글쎄, 다들 좋아하더라고. ”
— 마틴 파울러
근데 오래된 방식의 간단한 오브젝트가 뭘까? 오래된 방식이 있다면 새로운 방식도 있는걸까? 좀 더 풀어서 쉽게 말해보자면, 특정 '기술'에 종속되어 동작하는 것이 아닌 순수한 자바 객체를 말하는 것이다.
예를들어, ORM(Object Relationship Mapping)이 새롭게 등장 했을 때를 생각해보자. ORM 기술을 사용하고 싶었다면 ORM을 지원하는 ORM 프레임워크를 사용해야 한다. (대표적으로 Hibernate라는 프레임워크가 있다.) 만약 자바 객체가 ORM 기술을 사용하기 위해서 Hibernate프레임워크를 직접 의존하는 순간! POJO라고 할 수 없다. 특정 '기술'에 종속되었기 때문이다.
즉, 진정한 POJO란, 객체 지향적인 원리에 충실하면서 환경과 기술에 종속되지 않고 필요에 따라 재활용될 수 있는 방식으로 설계된 오브젝트를 말한다. 그러한 POJO에 애플리케이션의 핵심로직과 기능을 담아 설계하고 개발하는 방법을 POJO 프로그래밍이라고 할 수 있다.
왜 POJO를 지향해야 하는가?
스프링 프레임워크 이전에는 원하는 엔터프라이즈 기술이 있다면 그 기술을 직접적으로 사용하는 객체를 설계했다. 그리고 이러한 개발 방식이 만연하고 있었다. 특정 기술과 환경에 종속되어 의존하게 된 자바 코드는 가독성이 떨어져 유지보수에 어려움이 생겼다. 또한, 특정 기술의 클래스를 상속받거나, 직접 의존하게 되어 확장성이 매우 떨어지는 단점이 있었다. 이 말은 객체지향의 화신인 자바가 객체지향 설계의 장점들을 잃어버리게 된 것이다.
그래서 POJO라는 개념이 등장했다. 본래 자바의 장점을 살리는 '오래된' 방식의 '순수한' 자바객체 말이다.
그럼 특정 기술을 사용하고 싶다면? (스프링이 POJO를 유지하면서 Hibernate를 사용할 수 있는 이유) - PSA
하지만 Hibernate는 스프링 개발에서 많이 사용하고 있는 기술이다. 특정 기술에 종속적이면 POJO가 아니라면서 스프링에서는 어떻게 가능한 걸까?
바로 스프링에서 정한 표준 인터페이스가 있기 때문이다. 스프링 개발자들은 ORM이라는 기술을 사용하기 위해서 'JPA'라는 표준 인터페이스를 정해두었다. 그리고 이제 여러 ORM 프레임워크들은 이 JPA라는 표준 인터페이스 아래, 구현되어 실행된다. 이것이 스프링이 새로운 엔터프라이즈 기술을 도입 하면서도 POJO를 유지하는 방법이다. (그리고 이런 방법을 스프링의 PSA라고 얘기한다.)
POJO의 조건
1. 특정 규약에 종속되지 않는다.
자바언어와 꼭 필요한 API외에는 종속되지 말아야한다. EJB2와 같이 특정 규약을 따라 만들게 하는 경우는 대부분 규약에서 제시하는 특정 클래스를 상속하도록 요구한다. 그럴 경우 자바의 단일 상속 제한 때문에 더이상 해당 클래스에 객체지향적인 설계 기법을 적용하기가 어려워지는 문제가 생긴다.
2. 특정 환경에 종속되지 않는다.
특정 기업의 프레임워크나 서버에서만 동작가능한 코드라면 POJO라 할 수 없다. POJO는 환경에 독립적이여야한다. 특히 비지니스 로직을 담고 있는 POJO 클래스는 웹이라는 환경 정보나 웹 기술을 담고 있는 클래스나 인터페이스를 사용해서는 안된다. 설령 나중에는 웹 컨트롤러와 연결되서 사용될 것이 분명하더라도 직접적으로 웹이라는 환경으로 제한해버리는 오브젝트나 API에 의존해서는 안된다. 그렇게 되면 웹 외의 클라이언트가 사용하지 못하기 때문이다.
기술적인 내용을 담은 웹 정보가 비즈니스 로직과 얽혀있으니 이해하기도 어렵다. 때문에 비지니스 로직을 담은 코드에 HTTPServletRequest, HttpSession, 캐시에 관련된 API가 등장한다면 진정한 POJO라고 할 수 없다.
3. 객체 지향적 원리에 충실해야한다.
POJO는 객체지향적인 자바언어의 기본에 충실하게 만들어져야한다. 자바 언어 문법을 사용했다고해서 자동적으로 객체지향 프로그래밍과 객체지향 설계가 적용됬다고 볼 수는 없다. 책임과 역할이 각기 다른 코드를 한 클래스에 몰아넣어 덩치큰 만능 클래스를 만들고 상속과 다형성의 적용이 아닌 if/switch문으로 가득 설계된 오브젝트라면 POJO라고 부르기 힘들다.
POJO 프로그래밍이 필요한 이유
- 특정 환경이나 기술에 종속적이지 않으면 재사용이 가능하고, 확장 가능한 유연한 코드를 작성할 수 있다.
- 저수준 레벨의 기술과 환경에 종속적인 코드를 제거하여 코드를 간결해지며 디버깅하기에도 상대적으로 쉬워진다.
- 특정 기술이나 환경에 종속적이지 않기 때문에 테스트가 단순해진다.
- 객체지향적인 설계를 제한 없이 적용할 수 있다. (가장 중요한 이유)
POJO 프레임워크
POJO 프레임워크란 POJO 프로그래밍이 가능하도록 기술적인 기반을 제공하는 프레임워크이다. 스프링 프레임워크와 하이버네이트를 대표적인 POJO 프레임워크로 꼽을 수 있다.
스프링을 이용하면 POJO 프로그래밍의 장점을 그대로 살려서 엔터프라이즈 애플리케이션의 핵심로직을 객체지향적인 POJO를 기반으로 깔끔하게 구현하고, 동시에 엔터프라이즈 환경의 각종 서비스와 기술적인 필요를 POJO방식으로 만들어진 코드에 적용할 수 있다.
스프링의 핵심 : POJO
Spring은 POJO 프로그래밍을 지향하는 프레임워크이다.
최대한 다른 환경이나 기술에 종속적이지 않도록 하기 위한 POJO 프로그래밍 코드를 작성하기 위해 Spring 프레임워크에서는 IoC/DI, AOP, PSA를 지원하고 있다.
스프링 애플리케이션은 POJO를 이용해서 만든 애플리케이션 코드와 POJO가 어떻게 관계를 맺고 동작하는지를 정의해놓은 설계 정보로 구분된다.
즉, 스프링의 주요기술인 IoC/DI, AOP, PSA는 애플리케이션을 POJO로 개발할 수 있게 해주는 가능 기술이다. DI는 유연하게 확장가능한 오브젝트를 만들어두고 그 관계는 외부에서 다이내믹하게 설정해준다. 이런 DI의 개념을 스프링은 애플리케이션 전반에 걸쳐 적용한다.
참고