헐리웃의 영화 관계자들 사이에서 격언처럼 사용되는 말이 있다고 합니다. 그것은 바로 "Don't call us, we'll call you." 인데요. 번역하면 "우리가 연락할테니 연락하지 마" 정도가 되겠죠.

눈치채셨겠지만 이 말이 그 바닥에서 유명하게 된 이유는, 바로 스타 지망생들의 전화공세 때문이라죠. 자신이 오디션에 합격했는지 확인하려는 지망생들의 전화 때문에, 관계자들이 업무를 볼 수 없을 정도가 되었던 것입니다. 그래서 생각해 낸 것이 바로, "네가 필요할 일이 있으면 우리가 연락할거야"라는 전략인 것이죠.


참으로 귀찮아 보이기까지 하는 이 짧은 말에는, 몇 가지 사전 조건이 포함되어 있습니다. 다음과 같은 조건들 말이죠.

- 영화 관계자는 지망생들의 목록을 관리하고 있다. (만난 적이 있다, 혹은 오디션을 본 적이 있다 등등)

- 영화 관계자에게는 지망생에게 연락해야 하는 특정 이유가 있다. (주연/조연/엑스트라/스텝 등 어떤 이유로든)

- 영화 관계자는 지망생의 연락처를 알고 있다. 혹은 연락할 수 있는 방법이 있다. (직접방문/전화/우편/지인을 통해 등등)


디자인 패턴 중 관찰자 패턴(Observer Pattern)은, 이 전략을 프로그래밍 영역으로 끌어온 것이라 할 수 있습니다. 개념적으로 간단하고 구현이 간편하기 때문에 수 많은 영역에서 이미 사용되고 있죠. 많은 프로그래밍 언어들이 언어 내에 관찰자 패턴의 기본적인 골격을 포함하고 있는 경우도 많이 있습니다.

그럼 이제, 관찰자 패턴에 대해 다룬 포스트 하나를 보면서 Java 프로그래밍 언어에서 관찰자 패턴이 어떻게 사용되고 어떻게 구현되는지 살펴보도록 하겠습니다. 


이 포스트의 원문 주소는 http://www.vogella.com/articles/DesignPatternObserver/article.html 입니다.


관찰자 패턴 (Observer Pattern)

1) 정의

관찰자 패턴은, 여러 객체 간의 일대다(one-to-many) 의존관계를 정의하는 디자인 패턴으로, 한 객체의 상태가 변경되었을 때 그 객체에 의존하고 있는 나머지 객체들이 변경 사항을 통보받고 자동적으로 어떤 동작을 수행하도록 하기 위해 사용됩니다.

여기서 관찰이 되는 객체를 대상(subject)이라 하고, 대상의 상태 변화를 주시하고 있는 객체를 관찰자(observer) 혹은 리스너(listener)라고 합니다.

 

2) 사용 예

관찰자 패턴은 Java 내에서 이미 흔하게 사용되고 있습니다. 예를 들어 사용자 인터페이스(UI)에서 사용되는 버튼(button)을 위해 리스너(listener)를 정의하는 것이 관찰자 패턴의 입니다. 버튼이 클릭되면 리스너가 그 내용을 통지받아 특정 동작을 수행하게 됩니다.

하지만 관찰자 패턴이 사용자 인터페이스 컴퍼넌트에서만 사용될 수 있는 것은 아닙니다.

예를 들어 어플리케이션 내에 현재 온도를 표시해주는 partA라고 하는 부분이 있다고 가정해봅시다. 그리고 partB는 현재 온도가 20도가 넘으면 녹색 불빛을 표시하기로 했다고 하면, partA의 상태 변화를 감지하기 위해 partBpartA에 자기 자신을 리스너로 등록해야 할 것입니다.

partA에서 기온이 변경되면 이벤트가 발생(trigger)될 것입니다. 그리고 이 이벤트는 등록되어 있는 모든 리스너들에게 전달될 것인데, 위의 경우에서는 partB가 전달을 받습니다. 이제 partB는 이벤트와 같이 전달된 정보를 얻어 화면을 갱신할 것입니다.

다음은 버튼에 리스너를 설정하는 예제 코드입니다.


Button button = new Button(shell, SWT.PUSH); 
button.addSelectionListener(new SelectionAdapter() {   
    @Override   
    public void widgetSelected(SelectionEvent e) {     
        // Handle the selection event         
        System.out.println("Called!");
    } 
}); 


3) 예제 코드

다음 예제는 Person 객체 내의 List 정보의 변경을 확인하는 관찰자를 만들 것입니다. 이를 위해 com.vogella.java.designpattern.observer.MyObserver 클래스와 그 외의 몇 가지의 클래스들을 이용할 것입니다.


package com.vogella.java.designpattern.observer;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;

public class MyModel {

    private List persons = new ArrayList();
    private List listeners = 
            new ArrayList();

    public class Person {

        private String firstName;

        private String lastName;

        public Person(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }

        public String getFirstName() {

            return firstName;
        }

        public void setFirstName(String firstName) {
            notifyListeners(this, "firstName", 
                    firstName, 
                    this.firstName = firstName);
            
        }

        public String getLastName() {
            return lastName;
        }

        public void setLastName(String lastName) {
            notifyListeners(this, "lastName", 
                    lastName, 
                    this.lastName = lastName);
        }
    }

    public List getPersons() {
        return persons;
    }

    public MyModel() {
        // Just for testing we hard-code the persons here:
        persons.add(new Person("Lars", "Vogel"));
        persons.add(new Person("Jim", "Knopf"));
    }

    private void notifyListeners(Object object, 
            String property, String oldValue, String newValue) {
        for (PropertyChangeListener listener : listeners) {
            listener.propertyChange(new PropertyChangeEvent(this, 
                            property, 
                            oldValue, 
                            newValue));
        }
    }

    public void addChangeListener(PropertyChangeListener newListener) {
        listeners.add(newListener);
    }
} 


package com.vogella.java.designpattern.observer;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

public class MyObserver implements PropertyChangeListener {
    public MyObserver(MyModel model) {
        model.addChangeListener(this);
    }

    @Override
    public void propertyChange(PropertyChangeEvent event) {
        System.out.println("Changed property: " + event.getPropertyName() + " old:"
                + event.getOldValue() + " new: " + event.getNewValue());
    }
}


package com.vogella.java.designpattern.observer;

import com.vogella.java.designpattern.observer.MyModel.Person;

public class Main {


  public static void main(String[] args) {
    MyModel model = new MyModel();
    MyObserver observer = new MyObserver(model);
    // We change the last name of the person, observer will get notified
    for (Person person : model.getPersons()) {
        person.setLastName(person.getLastName() + "1");
    }
    // We change the  name of the person, observer will get notified
    for (Person person : model.getPersons()) {
        person.setFirstName(person.getFirstName() + "1");
    }
  }
}


4) 평가

관찰자 패턴은 객체 지향 프로그래밍의 원칙 중 하나인 OCP(Open Closed Principle)을 가능케 합니다. 이 원칙은, 클래스들은 확장에는 열려(Open)있어야 하나 변경에는 닫혀(Closed) 있어야 함을 의미합니다.

관찰자 패턴을 이용하면, 대상(subject)은 관찰자를 숫자에 제한 없이 등록할 수 있게 됩니다. 새로운 리스너가 대상 객체를 관찰하려 한다 하더라도 대상 클래스의 코드에는 아무런 변경도 필요하지 않습니다.

, 관찰자 패턴은 대상 클래스를 관찰자 클래스로부터 분리(decouple)하도록 해 줍니다. 관찰자만이 대상 클래스의 존재를 인식할 뿐입니다.



아래는 관찰자 패턴의 UML 입니다.위의 내용을 잘 이해했다면 UML에 익숙하지 않은 분이라 하더라도 쉽게 이해가 되시리가 생각합니다. 위에서 이미 설명된 내용을 그저 UML로 표기한 것 뿐이니(UML이란 원래 그런 겁니다.) 더 이상의 자세한 설명은 생략하....


UML of Observer Design Pattern (출처 : Wikipedia)



지금까지 관찰자 패턴에 대해 간략하게 알아보았습니다. 

위 포스트에서 얼핏 소개가 된 내용이 있는데요, 객체 지향 프로그래밍의 원칙에는 크게 다섯 가지 원칙이 있습니다. 이른바, [SOLID principles] 라고 불리는 것인데요, 나중에 기회가 된다면 이에 대해 다뤄 보도록 하겠습니다.


여기까지 보신 분들 중, EDA라고 불리는 Event Driven Architecture와 관찰자 패턴은 어떻게 다른가 하는 의문이 드신 분들이 있을 것입니다. 실제로 특정 이벤트에 대한 처리를 위해 관찰자 패턴을 이용하여 구현한 경우가 많기에, 많은 개발자들이 이러한 질문을 해 오고 있습니다. 


과연 관찰자 패턴과 EDA는 완전히 같은 것일까요? 엇비슷한 것일까요? 아니면 혹시 포함 관계에 있는 것일까요? 이에 대한 내용은 다음에 EDA에 대해 다루면서 다시 한 번 살펴보도록 하겠습니다. 성격이 급한 분이라면, [Observer Pattern vs Event Driven Architecture]로 구글링하여 먼저 확인해 보실 수 있겠죠?

신고
Posted by Layered 트랙백 0 : 댓글 0

댓글을 달아 주세요

이 글은 Atomikos라고 하는 오픈소스 JTA 라이브러리 사이트에서 제공하는 JTA와 XA에 대한 설명을 번역한 것입니다. 

사내 교육용으로 번역했었는데, 교육 효과는 개뿔, 읽어본 아이들이 손에 꼽을 정도내요. 이대로 사장(?)되는 것이 아쉬워 올려봅니다. 원문 주소는, http://www.atomikos.com/Documentation/GettingStarted 입니다. 

Atomikos는 스프링 프레임워크가 더 이상 JOTM(Java Open Transaction Manager)를 정식으로 지원하지 않으면서 더욱 각광을 받고 있는 듯 합니다. 나중에 기회가 되면 [Atomikos를 이용한 Spring 분산 Transaction처리]와 [Tomcat/Glassfish에 Atomikos 적용하기] 등을 다뤄볼까 합니다.


What is JTA

JTA(Java Transaction API)은 플랫폼마다 상이한 트랜잭션 매니저들과 어플리케이션들이 상호작용할 수 있는 인터페이스를 정의하고 있다. Java에서 제공되는 대부분의 API와 마찬가지로, JTA는 실제 구현은 다르지만 어플리케이션이 공통적으로 사용할 수 있는 하나의 인터페이스를 제공한다. 이 말은 트랜잭션 처리가 필요한 어플리케이션이 (API의 사용 방식 그대로만 사용한다면) 특정 벤더의 트랜잭션 매니저에 의존할 필요가 없음을 의미한다. Atomikos와 같이 JTA 구현체들을 오픈소스로 제공하는 벤더들도 있고, IBM 같이 JTA 구현체를 어플리케이션 서버의 한 부분으로 제공하는 벤더들도 있다.

JTA의 구현체를 사용할 때에는 주의를 기울여야 한다: 자세히 들여다 보면 뭔가 잘 못 되어 있는 것처럼 보이기 때문이다. 믿기 어렵겠지만, J2EE 호환됨이라고 검증을 받은 어플리케이션 서버들도 트랜잭션 관리를 제대로 지원하지 않거나 가상적으로만 지원할 수도 있다.

 

What is XA

XA(eXtended Architecture)는 동일한 전역 트랜잭션(Global Transaction) 내에서 몇 개의 백엔드 데이터 저장소에 접근하기 위한 X/Open 그룹 표준의 하나이다. XA 표준 규격은 하나의 트랜잭션 매니저가 어떤 트랜잭션의 한 부분으로 어떤 작업이 수행되고 있는지를 데이터베이스에 통보하는 방식과, 각 트랜잭션이 완료될 때 2단계 커밋(2 Phase Commit)을 수행되는 방식을 관장한다. 또 데이터 저장소에서 지연되고 있는 트랜잭션을 회복시키는 방법도 포함하고 있다.

XA의 장점

XA 역시 하나의 표준이기 때문에, 모든 호환되는 데이터 저장소(혹은 드라이버)들이 전역 (분산) 트랜잭션의 부분으로서의 트랜잭션 매니저와 연동할 수 있다. 다른 말로, 2단계 커밋이 고려되어야 하는 상황이라면 XA는 트랜잭션 매니저와 데이터 저장소를 연결해 주는 역할 담당한다는 말이다. 이것이 Atomikos와 같은 솔루션들이 Oracle이나 Sybase와 같은 데이터베이스와 연동하여 커밋과 롤백 등의 모든 작업을 수행할 수 있는 이유이다.

 

When to use JTA / XA

JTA XA는 데이터가 오염되는 것(그리고 그로 인한 사업상의 손실)을 막아주는 일종의 보험 시스템 같은 것이다. 가장 흔한 경우는 다음과 같다.

l  (Queue)로부터 JMS 메시지를 받아 처리한 뒤 그 결과를 데이터베이스에 저장하는 경우: 데이터베이스에 대한 저장이 실패한 경우에도 JMS 메시지가 유실되어서는 안 된다.

l  두 개 이상의 레거시 백엔드 시스템에 대해 동일 트랜잭션으로 업데이트 해야 하는 경우

일반적으로 하나 이상의 백엔드 시스템에 대해 동일 트랜잭션으로 여러 작업을 수행해야 하는 경우에 JTA/XA의 사용을 강하게 권고한다. 그렇지 않으면 데이터의 유실이나 오염의 위험이 매우 커질 수 있다. (그리고 그것을 확인할 방법이 없을 수도 있다.)

많은 프로그래머들이 JTA/XA의 오버헤드를 피하기 위해 어플리케이션에 특정 복구 코드를 프로그래밍 하기도 한다. (예를 들어, 중복 요청 처리라던가, 데이터베이스에 부가 상태 정보를 저장하는 것과 같은) 그러나 이 방법들은 모두 (재사용 불가능하고, 어플리케이션에 종속적이고 테스트하기 어렵기 때문에) 불완전하다. 결과적으로, 모두가 예측할 수 있는 JTA/XA의 오버헤드가 같은 작업을 하지만 버그를 내포하고 있는 어플리케이션 레벨의 오버헤드로 대체된 것과 같다.

간단한 계산으로 JTA/XA의 이점을 보여줄 수 있다: 은행이 하나 있고, 일반적으로 하루에 백만 트랜잭션을 처리하며 평균적으로 트랜잭션 당 100$가 처리된다고 가정해 보자. 즉 하루에 총 100,000,000$가 처리되는 것이다. 만약 시스템에 문제가 발생하여 1%의 데이터가 유실된다면, 한 번의 문제로 전체 1,000,000$의 손실을 입게 되는 것이다. JTA/XA는 명백하게 이런 문제를 미연에 방지해준다.

 

When NOT to use JTA / XA

아래 표는 JTA/XA를 사용하지 말아야 할 경우와 몇몇 기회비용들을 보여주고 있다. 이 외의 경우에서는 JTA/XA가 신뢰성과 간결함이라는 측면에서 엄청난 혜택을 줄 수 있다.

시나리오

JTA/XA 없이 실행

JTA/XA 혜택

최대 하나의 리소스에 접근

안전함.
(
시스템 락이 트랜잭션 지연을 유지할 수 있음)

락이 무한정 걸리는 것을 방지함

하나의 백엔드 시스템 내에서 여러 자원에 접근

각 접근에 대해 동일한 커넥션을 이용하면 안전함. 서로 다른 접근 간에 데이터를 공유해야 할 경우에는 공유 커넥션 처리를 위해 Thread-local 조작이 필요할 수 있으며, 커밋 처리가 매우 복잡해 짐

데이터 공유가 XA에 의해 처리됨

상이한 백엔드 시스템들에 대한 다중 쿼리

가능함, 하지만 정확성은 보장되지 않음

모든 경우에 있어 정확한 데이터를 읽을 수 있음

다중 백엔드 시스템

안전하지 않음. 시스템 장애로 인해 데이터 손실이 발생해도 상관 없는 경우에만 사용할 것

데이터 손실이나 오염이 발생하지 않음

 

Getting Started with TransactionsEssentials

배경

Atomikos는 모듈화를 감안하여 설계되었다. icatch라고 하는 독점적인 API를 제공하는 트랜잭션 커널이 있는데, 이것을 바탕으로 수많은 트랜잭션 서비스들이 만들어졌다. 그 중 하나가 JTA 구현체이다: icatch의 상위 계층으로 JTA API 구현체가 존재한다.

수많은 다른 서비스들이 있긴 하지만 Atomikos TransactionsEssentials 배포에서 사용할 수 있는 것은 JTA가 유일하다. Atomikos ExtremeTransactions RMI와 웹서비스 인터페이스들을 포함하고 있다.

Atomikos를 이용하여 JTA 프로그래밍

일반적으로는 icatch API는 신경 쓸 필요 없이 JTA 인터페이스만 사용하면 된다.

트랜잭션 매니저를 초기화하려면, com.atomikos.icatch.jta.UserTransactionManager 인스턴스를 생성하고 생성된 인스턴스의 init () 메소드를 호출하면 된다. 어플리케이션이 종료될 때 close() 메소드를 호출하는 것을 잊어서는 안 된다.

이 클래스는 javax.transaction.TransactionManager 인터페이스를 구현했는데, 이 인터페이스에는 JTA 트랜잭션을 제어하기 위한 모든 작업 begin(), commit() 그리고 rollback()과 같은 메소드들이 정의되어 있다.

초기화하는 과정에서 이 클래스는 클래스패스의 루트 디렉토리에 있는 jta.properties 파일을 읽는다. 이 파일에 대한 설정 방법은 JTA Properties를 참고하기 바란다.

간단한 JTA 예제

이제 JTA API를 이용하여 트랜잭션 매니저를 초기화하고 시작하고 커밋 한 뒤 적절하게 셧다운 하는 예제 코드를 확인해 보도록 하겠다. 간결하게 설명하기 위해 예외 처리는 생략하였다.

JDBC JMS 자원을 설정하고 사용하는 상세한 방법은 JDBC와 TransactionsEssentials 사용하기JMS와 TransactionsEssentials 사용하기를 참고하기 바란다. 온라인에서 제공되는 Atomikos ExtremeTransactions 인증 코스를 통해 JDBC JMS에 대해 학습할 수도 있다.

import com.atomikos.icatch.jta.UserTransactionManager; 
import com.atomikos.jdbc.AtomikosDataSourceBean; 
 
import javax.jta.TransactionManager; 
import javax.sql.DataSource; 
 
public class AtomikosExample { 
 
  // Atomikos implementations 
  private static UserTransactionManager utm; 
  private static AtomikosDataSourceBean adsb; 
 
  // Standard interfaces 
  private static TransactionManager tm; 
  private static DataSource ds; 
 
  // initialize resources 
  private static void init() { 
    UserTransactionManager utm = new UserTransactionManager(); 
    utm.init(); 
    tm = utm; 
 
    adsb = ...; // omitted for clarity 
    ds = adsb; 
  } 
 
  // release resources 
  private static void shutdown() { 
    adsb.close(); 
    utm.close(); 
  } 
 
  public static void main(String[] args) { 
    init(); 
 
    tm.begin(); 
 
    Connection c = ds.getConnection(); 
    // use connection to execute SQL 
    c.close(); 
 
    tm.commit(); 
 
    shutdown(); 
  } 
 
} 

 

신고
Posted by Layered 트랙백 0 : 댓글 0

댓글을 달아 주세요

다소 도발적으로 들리는 제목이고, 실제로 도발적이지만, 사실 이 글은 작성한지 2년이나 지난 포스트를 '이제서야'보고 작성하는 글입니다. 먼저 그 문제의 글부터 보시죠.


ORM is an anti-Pattern

원문 : http://seldo.com/weblog/2011/08/11/orm_is_an_antipattern


그리 긴 포스트가 아님에도 불구하고, 친절하게 11줄 요약(... 이게 요약인지)까지 해 주었습니다. (참고 : TL; DR은 Too Long, Didn't Read의 약자입니다. 한 마디로 '너무 길어 읽지 않음' 이랄까요..

  • ORM is initially simpler to understand and faster to write than SQL-based model code
       ORM은 SQL기반 모델 코드에 비해 최초에는 쉽게 이해할 수 있고 빠르게 작성할 수 있다.
  • Its efficiency in the early stages of any project is adequate
       대부분의 프로젝트의 초기에는 ORM을 사용하는 것이 꽤 효율적이다.
  • Unfortunately, these advantages disappear as the project increases in complexity: the abstraction breaks down, forcing the dev to use and understand SQL
       불행히도, 프로젝트의 복잡성이 커질 수록 이러한 장점은 사라진다: 추상화는 무너지고, 개발자들은 SQL을 직접 사용해야하고 이해해야 한다.
  • Entirely anecdotally, I claim that the abstraction of ORM breaks down not for 20% of projects, but close to 100% of them.
       정말 개인적인 경험에 따르면, ORM의 추상화는 프로젝트의 20%에서만 사용될 수 없는 것이 아니라 거의 100%에서 사용할 수 없게 된다.
  • Objects are not an adequate way of expressing the results of relational queries.
       객체는 관계형 쿼리들의 결과를 표현하는 데 좋은 방식이 아니다.
  • The inadequacy of the mapping of queries to objects leads to a fundamental inefficiency in ORM-backed applications that is pervasive, distributed, and therefore not easily fixed without abandoning ORM entirely.
       쿼리 결과를 객체로 매핑하는 것이 적절치 않기 때문에, 여기저기서 마구 존재하는, ORM을 사용하는 어플리케이션들은 근원적으로 비효율적이다. 또 그러므로, ORM을 완전히 포기하지 않는 이상 고치기도 쉽지 않다. 
  • Instead of using relational stores and ORM for everything, think more carefully about your design
       모든 상황에 대해 관계형 저장소와 ORM을 사용하는 대신 설계에 대해 좀 더 주의 깊게 생각해보라.
  • If your data is object in nature, then use object stores ("NoSQL"). They'll be much faster than a relational database.
       사용하는 데이터가 본질적으로 객체형이라면, 객체 저장소("NoSQL")를 이용하라. 객체 저장소들이 관계형 데이터베이스보다 훨씬 빠르다.
  • If your data is relational in nature, the overhead of a relational database is worth it.
       사용하는 데이터가 본질적으로 관계형이라면, 관계형 데이터베이스에 오버헤드가 있다고 해도 쓸만한 가치가 있다.
  • Encapsulate your relational queries into a Model layer, but design your API to serve the specific data needs of your application; resist the temptation to generalize too far.
       관계형 쿼리들을 모델 레이어 내에 캡슐화하라. 하지만 특정 데이터에 대한 어플리케이션의 요구에 맞게 API를 설계하라. 과도하게 일반화하려는 유혹을 견뎌내라.
  • OO design cannot represent relational data in an efficient way; this is a fundamental limitation of OO design that ORM cannot fix.
       객체지향 설계는 관계형 자료를 효율적으로 표현할 수 없다. 이것은 ORM도 해결할 수 없는 객제지향 설계의 근원적인 한계이다.

  • 이마저도 길다고 하시는 분들을 위해 이 11줄 요약을 다시 한 번 요약해보면 다음과 같습니다.

    1. ORM은 개발 초기에만 쓸만하다. 

    2. 어플리케이션이 조금만 복잡해져도 HELL이 된다. 해 본 사람은 알 거다.

    3. 관계형 데이터베이스와 ORM을 쓰지 말라는 게 아니라, 관계형 데이터의 모든 것을 객체지향 설계에 주입하려고 하지 말라는 거다.


    어떤 분은 이 글을 읽고 ORM의 사용에 대해 찬성하기도, 혹은 반대하기도 할 것입니다. 하지만 ORM에 대한 절대적인 반대, 반감을 이끌어 내려는 것이 원 저자의 의도는 아니라고 생각합니다. 원 저자가 얘기하려고 하는 것, 그리고 제가 받아들인 바는, '객체 지향 설계라는 것이 지고지순한 선인 것은 아니다. 필요에 따라 우회할 줄 알아야 한다.' 라는 것이라고나 할까요.

    개인적으로 이런 글을 좋아합니다. 어떤 문제에 대한 '해결책'이라 불리는 것이 나왔을 때, 기계적으로 그것을 대입하는 것이 아니라, 똥인지 된장인지 알고 쓰자는 그런 류의 글 말이지요. 

    과거 JavaWorld에 이런 류의 글이 나와 논란이 된 적이 있었습니다. 바로 그 유명한 "Why extends is evil" 입니다. 수 많은 독자들이 이 글에 문제를 제기했고 급기야 '당신이 뭔데 OOP의 기본을 부정하냐?'라는 비난섞인 댓글까지 난무했었습니다.(한때, JavaWorld는 엄청 활동적인 사이트였었죠...) 하지만 이 글의 저자는, 이 도발적인 제목 아래, '클래스 상속, 제대로 설계하지 않고 쓰면 독이 된다. 그리고 상속보다는 인터페이스를 이용해라.'라는, 지금에와서는 지극히 상식적인 내용을 다뤘던 것이었습니다.  나중에 이 저자는 다시 글을 작성하여 본래의 의도를 다시 설명하기에 이릅니다. .... 나중에 기회가 되면 이 글에 대해서도 언급해보기로 하죠.


    그래서 저의 입장은 뭐냐구요? "애매"합니다. 하지만 확실한 것은, ORM을 사용한다 하더라도 결과적으로 Native SQL 혹은 ORM specific Query Language를 사용할 수 밖에 없다는 것입니다. 비즈니스의 복잡성으로 인해, 성능 이슈로 인해, DBMS에 특화된 기능을 사용하기 위해 등등. 결국 ORM이 어떤 문제를 해결해 주지만 또다른 많은 문제들을 야기함을 경험적으로 알고 있습니다. (이에 대해 CQRS - Command Query Responsibility Segregation을 주장하는 사람도 있습니다.) 저의 입장은 결국, '상황을 명확히 이해한 뒤에 결정해야 할 듯요?'가 되겠네요... 무책임하게도 말이죠.


    이 부분은 마치, 정규 표현식에 대한 이 미친듯한 센스를 가진 명언(?)을 생각나게 할지도 모르겠습니다. 이 명언을 처음 접하고 미친듯이 웃었었는데 말이죠..

    Some People, when confronted with a problem, think "I know, I'll use regular expressions". 
    Now they have two problems.


    여담입니다만, 외산 솔루션들을 보면(제가 하는 일의 성격상 외산 솔루션들을 분석하는 작업을 많이 하게 됩니다...), ORM을 적극적으로 사용하면서 그로 인한 성능 문제를 해결하기 위해 External Cache를 적극적으로 사용하는 것을 많이 봅니다. 이것이 해결책이 될 수 있을까요? 역시 어떤 부분에서는 해결책이, 또 다른 부분에서는 또다른 문제점을 야기할 수 있을 것입니다. 어쨌든 나중에 기회가 되면 External Cache에 대해서도 다뤄보기로 하죠.


    아참! 혹시나 오해하실까봐 말씀드립니다만, iBatis/MyBatis는 엄밀히 말해 ORM이 아닙니다. 이에 대한 수많은 글들을 찾아보실 수 있을 겁니다.


    무엇이든 객관적인 시각에서, 장점과 단점을 명확히 파악하고, 장점은 취하고 단점은 최소화하는 노력을 기울여야 함을, 우리 모두 알고 있지만 결코 쉬운 일이 아닌 듯 합니다. 인간은, 특히 저는 그다지 객관적이지 않거든요.

    신고
    Posted by Layered 트랙백 0 : 댓글 0

    댓글을 달아 주세요


    티스토리 툴바