Plain Old Java Object, 간단히 POJO는 말 그대로 해석을 하면 오래된 방식의 간단한 자바 오브젝트라는 말로서 Java EE 등의 중량 프레임워크들을 사용하게 되면서 해당 프레임워크에 종속된 "무거운" 객체를 만들게 된 것에 반발해서 사용되게 된 용어이다. 2000년 9월에 마틴 파울러, 레베카 파슨, 조쉬 맥킨지 등이 사용하기 시작한 용어로서 마틴 파울러는 다음과 같이 그 기원을 밝히고 있다.
“ 우리는 사람들이 자기네 시스템에 보통의 객체를 사용하는 것을 왜 그렇게 반대하는지 궁금하였는데, 간단한 객체는 폼 나는 명칭이 없기 때문에 그랬던 것이라고 결론지었다. 그래서 적당한 이름을 하나 만들어 붙였더니, 아 글쎄, 다들 좋아하더라고. ”
— 마틴 파울러
POJO라는 용어는 이후에 주로 특정 자바 모델이나 기능, 프레임워크 등을 따르지 않은 자바 오브젝트를 지칭하는 말로 사용되었다. 스프링 프레임워크는 POJO 방식의 프레임워크이다.
이상적으로, POJO는 Java 언어 규약에 의해 강제된 것 이외의 제한에 구속되지 않는 Java 오브젝트 이다
따라서 POJO는 다음과 같은 것을 해선 안된다.
미리 지정된 클래스를 extends 하는 것.
public class Foo extends javax.servlet.http.HttpServlet { ... }
미리 정의된 인터페이스를 implement 하는 것.
public class Bar implements javax.ejb.EntityBean { ... }
미리 정의된 Annotation을 포함하는 것.
@javax.persistence.Entity
public class Baz { ... }
그러나 기술적 어려움과 다른 이유로 인해, POJO-compliant라고 기술된 많은 소프트웨어 제품이나 프레임워크들(persistence와 같은)은 실제로 미리 정의된 Annotation을 제대로 동작하는 기능을 구현하기 위해 필요로 한다.
이와같은 것들의 특징은 Annotation을 추가하기 전에 POJO이고 Annotation을 제거했을 때, POJO 상태로 되돌아간다면 POJO로 간주할 수 있다는 것 이다.
이는 특정 라이브러리나 모듈에서 정의된 클래스를 상속 받아서 구현하지 않아도 된다는 것을 의미한다. 앞서 언급한 것처럼 POJO 가 되기 위해서는 외부의 의존성을 두지 않고 순수하게 Java 로 구성이 가능해야한다.
만약 특정 비즈니스 로직을 처리하는 과정에서 외부 종속적인 것(http request, session 등)을 사용하는 것은 POJO를 위반했다고 간주한다. 또한 현재 스프링에서도 사용하고 있는 어노테이션(@Annotation) 기반으로 설정하는 부분도 엄연하게는 POJO라고 볼 수는 없다.
그렇다면 POJO 를 지향하는 프레임워크에는 어떤 것이 있는지 알아보자. 대표적으로는 현재 우리가 사용 중 Spring 이 있고, 그 외에 Hibernate 가 있다.
일반적으로 하나의 서비스를 개발하기 위해서는 서비스가 동작하는 시스템의 복잡함, 구현해야될 비즈니스 로직의 복잡함 등 다양한 어려움에 직면할 수 있다. 예를 들어, 대출 시스템을 개발한다고 하면, 사용자의 신용도나 이용 한도 등 비즈니스 로직을 챙기는 동시에, 시스템이 원할하게 동작하는 지도 체크해야된다는 것이다. 이는 오른쪽을 보면서, 동시에 왼쪽을 보라는 말과도 같다. 이를 극복하기 위해서 우리는 프레임워크(Framework) 라는 것을 사용하게 된다.
그 중에서도 Spring 과 Hibernate 는 모두 객체지향적인 설계를 하고 있으며, POJO 를 지향하고 있다. 결과적으로 개발자가 서비스 로직에 좀 더 집중할 수 있고, 이를 POJO로 쉽게 개발하도록 지원해주고 있다.
그렇다면, 어떻게 특정 기술에 종속적이면서 동시에 POJO를 지향할 수 있을까? 해답은 스프링에서 정한 표준 인터페이스가 있기 때문이다. 스프링 개발자들이 ORM 이라는 기술을 사용하기 위해서 "JPA" 라는 표준 라이브러리를 생성했으며, 이 후 여러 종류의 ORM 프레임워크들은 JPA 에 기반하여, 구현되고 실행된다.
public class ExampleListener implements MessageListener {
public void onMessage(Message message) {
if (message instanceof TextMessage) {
try {
System.out.println(((TextMessage) message).getText());
}
catch (JMSException ex) {
throw new RuntimeException(ex);
}
}
else {
throw new IllegalArgumentException("Message must be of type TextMessage");
}
}
}
위는 POJO 개념을 사용하지 않았다.
위 코드는 MessageListener 인터패이스를 상속받았다.
이렇게 POJO 기반의 코드를 작성하지 않게 되면, 이후 JMS와 같은 기능을 비슷하지만 다른 솔루션을 사용하고자 할 때, 교체하기가 굉장히 힘들어진다.
아래는 POJO 기반으로 작성한 예시이다.
@Component
public class ExampleListener {
@JmsListener(destination = "myDestination")
public void processOrder(String message) {
System.out.println(message);
}
}
위 예제는 JmsListener를 상속받지 않고 어노테이션을 통해 객체를 주입받은 상황이다.
이런 식으로 코드를 작성하게 되면 해당 클래스와의 결합도가 낮아져 다른 솔류션으로 변경할 경우 @JmsListener를 @다른 솔루션으로 코드만 수정하면 되므로 유지 보수에 있어 좀 더 유용하게 활용 가능하다.
POJO프로그래밍의 진정한 가치는 "자바의 객체지향적인 특징을 살려 비즈니스 로직에 충실한 개발이 가능하도록 하는 것 입니다." 그러면서 복잡한 요구조건을 가진 엔터프라이즈 개발의 필요조건을 충족시킬 수 있도록 POJO 기반의 프레임워크를 적절히 사용하는 것이 요구됩니다. 단순히 POJO프레임워크로 알려진 제품을 사용한다고, POJO 개발을 자동으로 하는 것은 아니라는 것입니다.
POJO의 자바 오브젝트라는 것은 단순히 자바 언어 문법을 지켜 만든 것이 아니라, 객체지향언어로서의 자바 오브젝트의 특징을 가지고 있는지가 중요합니다. 끊임없이 반복적으로 등장하는 템플릿 코드와 테스트하기 힘든 구조, 확장이나 재활용의 어려움이 그대로 남아있다면 EJB의 문제점을 여전히 안고있는 것이죠.
수정-빌드-배포-테스트의 사이클을 벗어나지 못하고 있다면, EJB로 개발했던 시절과 대체 무엇이 다른지 생각해봐야합니다. 잘 만들어진 POJO 애플리케이션은 자동화된 테스트 코드 작성이 편리합니다. 코드 작성이 편리하면 좀 더 자주 꼼꼼하게 만들게 되고, 반복적으로 실행할 수 있으므로 코드 검증과 품질 향상에 유리해집니다. 또한, 잘 만들어진 테스트 코드베이스가 있다면, 리팩토링할 여유가 생겨 POJO 코드를 좀 더 나은 설계구조로 변경할 가능성도 높아지게 됩니다.
출처
https://blog.naver.com/slykid/222573604177
https://blog.naver.com/youbeen2798/222896388246
https://velog.io/@dion/what-is-POJO