AOP가 대체 뭐냐?

OOP

객체 지향이라는 것은 엄밀하게 말하자면 컴퓨터에 관한 이야기가 아니다. 일종의 세상을 바라보고 이해하는 인식의 방법론이라고 할 수 있다. 객체지향에서는 모든 삼라만상(사건, 사물, 관념)을 별개의 독립된 개체로 본다. 각각의 개체는 속성행위를 가지며, 이 개체들은 인터페이스란 것을 통해서 서로 의사소통한다.

이 과정에서 협력이란 것이 발생하고, 특정 목적의 범주에 포함되는 객체들을 묶어 패키지라고 부르며, 이것이 좀더 거시적인 수준에서 나타날 경우 시스템이라고 한다. 이것이 OOP가 세상을 인지하는 방식이다.

OOP적 설계란 지금까지 설명한 내용을 거꾸로 적용하는 과정이다. 전체 시스템의 목적을 상정하고, 시스템이 목적을 달성하기 위해 협력해야할 패키지들을 정의하고, 패키지의 목적을 달성하기 위한 구성원들을과 이 구성원들이 서로에게 가진 역할(인터페이스)를 정의하는 과정이다.

이로서 프로그래밍은 한결 간단해졌다. 마치 현실문제를 다루듯 설계하고 프로그래밍 하는 것은 철학적으로도 아름다울뿐만 아니라, 설계와 물리적 구현을 거의 일치시킴으로써 생산성의 극대화를 가져올 수 있었다. 하지만 좋던 시절은 끝나버리고 말았다. 씨발

OOP의 한계

이러한 접근 방법의 문제점은 오늘날 고도로 복잡해진 사회처럼, 객체들도 너무나 많은 영역에 속해가고 있다는 점이다. 예를 들어 김씨는 영어 강사인 동시에 바이올리니스트 이며, 피트니스 클럽의 VIP회원이다. 게다가 5살 철수의 아버지이기도 하며, 최씨의 남편이기까지 하다.

좀더 개발자에 가까운 예를 들어 보이자면, 액션은 키보드를 통해 이뤄지기도 하지만, 버튼의 클릭, 메뉴의 선택에 의해 유발되기도하며, 특정 상태에 도달 할 때 발생하기도 한다. 따라서 본래의 단순한 액션은 수많은 GUI 처리 코드와 연결되고, 상태를 모니터링 하는 이벤트 리스너 시스템에까지 참여하게 된다. 따라서 액션 본연의 임무와는 무관한 부가적인 코드들이 상당수 발생하게 되고, 이들의 위치 역시 제각각이라 일목요연하게 통제하는 것에 어려움이 생기게 된다.

객체들은 여러개의 영역에 참가하기 위해, 많은 수의 인터페이스를 구현해야 하며, 결과적으로 그러한 영역들에 참가하기 위한 비용이 높아지게 된다. 보통 이것을 인프라 스트럭쳐 구현 비용이라고 한다.

복잡한 문제를 좀 더 효율적으로 다루어보고자 수 많은 디자인 패턴과 모델들이 탄생했다. 각자의 패턴과 모델은 깔끔하고 아름다우며 각자의 장점들을 자랑한다. 하지만 오늘날의 시스템은 한가지 모델과 패턴으로 구현될 리 만무하다. 바로 이러한 것들이 뒤섞이기 시작하면서 우리는 비명을 지르기 시작한다. 갸흥! 이 빌어먹을 패턴과 모델들이 서로 목청을 높혀대는 통에, 개발자들의 죽음의 레이스가 시작되어 버리고 말았다. 우리는 밤하늘의 별처럼 많은 모델과 패턴을 익혀야 하며, 재사용을 위해 도입한 라이브러리는 각자 나름의 모델과 패턴을 가지는 통에, 우리 프로젝트의 아름다움은 저 멀리 안드로메다로 가버리고 만다. 우리에게 필요한 것은 라이브러리의 비즈니스 로직이지 그들의 철학이 아니다. 다시 한 번 더 씨발. 갸흥!

그 중에서도 가장 큰 문제는 여러개의 영역이 존재하는 시스템에서, 각자의 영역에 따라 객체들을 분류하는 것이 불가능해진다는 점이다. 왜냐하면 객체들이 하나의 영역에만 참가한다는 보장이 없기 때문이다. 따라서 앞서 말한 패키지는 제 기능을 발휘하지 못하게 되어버린다. 이렇게 여러 객체에 걸쳐 발생하는 공통적인 관심사를 전역적 관심사(Cross-concerned)라고 한다. 이 놈들은 보통 여기저기 엉망으로 걸쳐져 발생하기 때문에, 하나의 관심사를 수정하거나 유지보수하는데에 매우 높은 비용이 들어가게 된다.

예를 들어 모든 get과 set을 모니터하기 위해서는 모든 getter와 setter의 내부에 로그 코드를 집어 넣어야 하는데, 이렇게 단순한 아이디어 조차 쉽게 변경할수도 없고, 소스를 한군데 모아 모듈화 할 수도 없다.

웹 프로그래밍 분야에서는 이 문제를 해결하기위해 XML의 도입에 적극적이었다. XML은 원래는 코드가 하던일을 상당부분 XML로빼 내어, 여러군데 산발적으로 흩어진 코드를 수정하지 않고도 몇몇 관심 영역의 행동을 변경할수 있게 했다. 하지만 각각의 솔루션마다 중구난방으로 이러한 XML을 정의한 탓에, 개발자들은 언제나 자기가 만들고 싶은 것 보다 더 많은 것을 공부해야만 하게 되었다.결국 자바 어노테이션 기술의 등장과 함께 오늘날 다시 POJO로 돌아가는 웃기는 현상마저 나타나게 되었다. 물론 단순한 시스템에서는 POJO가 유리하다. 하지만 이러한 시도들은 OOP가 가진 문제점을 직시했던 것이 아니라, 단순히 생산성의 차원에서 발전되어온 것일 뿐이다. 관리의 측면에선 여전히 XML이 유리하다.

AOP(Aspect-Oriented Programming)

영역지향은 모듈지향과 객체지향의 특징을 반반정도씩 섞은 것이라고 할 수 있다. 객체들과 그들의 소스코드들에게는 핵심 임무 만을 맡기고, 그들이 특정 영역에 참가하는데에 필요한 코드들은 별도의 단일한 영역 내에서 구현하게끔 하는 것이다. 핵심 아이디어는 다음과 같다:

객체가 주체인 활동이라 할지라도, 그것이 어떤 영역내에서만 의미가 있다면, 객체의 코드가 아닌 영역의 코드에 작성되어야 한다.

Aspect

AspectJ는 Java에 새로운 타입 키워드인 aspect를 제공한다. 이를 이용하여, 특정 영역의 문제를 다루는 코드들을 작성 할 수 있다. 하지만 객체들은 서로 유기적인 활동을 통하여 목적을 달성하므로, 이곳에다 코드들을 기술한다 해도, 결국 비즈니스 코드는 객체들이 가져야 할 것이다. 그렇다면 Aspect는 별 의미가 없게 된다.

Inter-Type Declaration

이미 존재하는 클래스가 특정 영역에서 어떠한 역할을 수행하려면, 그 영역에서 요구하는 인터페이스나 필드, 메서드등을 가져야 할 필요가 있다. 대부분의 현존하는 라이브러리들은 이러한 인프라스트럭쳐 구현 비용을 요구한다. 하지만 우리는 이를 위해 원본 클래스의 깔끔한 모델을 훼손하지 않고 싶지 않고, AOP의 개발자들 역시 같은 생각을 했다. 따라서 AspectJ는 이러한 필드나 메서드들이 영역 내에서 선언되고, 영역에서만 보일 수 있도록 만들어졌다. (가시성은 변경할수 있지만 사용하지 않을 것을 권장한다) 이것을 Inter-Type Declaration이라고 하는데, 이용 방법에 따라 프로그래머는 인터페이스에 구현이 되어있는 메소드나, 변경이 가능한 필드를 첨부할 수도 있다. 이러한 기법들을 이용하면 특정 영역에서 객체들이 작동하는데 필요한 코드들을 하나의 소스 파일로 모아둘수 있다. 하지만 여전히 객체들이 유기적인 상호 작용그 자체를 통제하거나 수정할 방법은 없다.

Joint Point Model

대부분의 개발자들은 OOP가 현실의 모든 문제를 추상화 할 수 있다고 확신한다. 과연 그럴까?

  • 대학생 아들이 용돈을 달라고 할 때와, 유치원생 딸이 용돈을 달라고 할 때, 즉 메시지를 발송한 객체의 타입이나 상태에 따라 다른 금액을 주는 아빠의 용돈주기 메소드를 구현할 방법이 있는가?
  • 자원을 비정상적으로 많이 소유한 스레드가 메소드 호출하면, 이를 거부할 방법이 있을까?

위의 나열한 것들이 간단하지 않은 이유는, 결국 OOP의 구현 단위가 객체이기 때문에, 객체 바깥에서 그들 사이에 벌어지는 일을 규정하거나 조작하기 쉽지 않다는 점에 있다. 극단적인 예로 메시지를 수신한 객체는 메시지를 보낸 객체가 무엇인지조차 알지 못한다. 단순한 살인자가 방아쇠를 당기건 뼛속까지 애국심 사무친 군인이 방아쇠를 당기건 총알은 발사 되버린다. 객체 지향에서 가시성은 객체의 내부(private)이냐 외부(public)이냐 하는 수준밖에 없기 때문에, 외부는 외부일뿐 누구라고 특정지을 수 있는 방법이 없다. 즉 객체지향의 가치가 협력에서 오는데도 불구하고 우리가 그 협력 자체에 간섭할 기회가 많지 않다는 점이다.

때문에 저러한 비객체적인 요소들을 우리는 Meditation 패턴과 같은 중계 객체를 이용해서 제어해야만 한다. 단순히 메시지 흐름을 제어하기 위해 패턴이 도입되야 한다는 것은 너무 비싼 비용이 든다고 생각된다. 게다가 유지 보수나, 변경의 비용도 엄청나게 상승하고말 것이다.

그래서 AOP의 선구자들은 객체간의 메시지 흐름을 통제하고 관리할 수단이 필요하다고 생각했고, Joint Point Model이라는 것을 만들어냈다. 조인트 포인트 모델이란 PC(Process Counter)가 메소드 사이를 옮겨다니는 것을 추상화하고 다룰수 있도록 해준다.

Joint Point란, 한 모듈을 수행하던 스레드가 다른 모듈로 연결되는 점(Point)를 말한다. goto코드일 수도 있고, 메소드 호출일 수도 있으며, return코드와 같은 것이 될 수 있다. AOP에서는 이러한 Joint Point들을 통제할 수 있도록 해 준다. 개발자가 관심을 가지는 메시지 전송만을 제어하기 위해 AOP는 Pointcut이라는 도구를 제공한다. 이것을 이용하여 원하는 Joint point들을 감시할 수 있고, 이 Pointcut에 어드바이저를 제공하여 해당 조인 포인트에 대해 적절한 처리를 수행할 수 있게 한다. 어드바이저는 종류에 따라, 메소드 호출과 같은 작업을 상황에 따라 취소하거나 예외를 던질수도 있고, 흐름을 감시 / 제어할 수 있다.

도입은 현명한 일?

AOP의 도입을 꺼리는 가장 대표적인 이유가, AOP가 OOP의 개념에 정면으로 맞서는 여러가지 도구들을 단지 “생산성”을 이유로 허용하기 때문이다. 앞서 말한 Inter-Type Declaration 역시 인터페이스가 구현이나 필드를 가지게 하는 등의 OOP에서 보기에는 이상한 모습을 보여준다. 오늘날의 AOP역시도 OOP를 기본으로 하고 영역을 도구의 개념으로 추가 확장한 것에 불과하기 때문에 “영역 지향”이라는 것은 OOP와 동등한 수준의 대체 개념이 될수는 없다. 어쨌든 AOP를 도입하면 생산성이 전과는 비교할 수 없을정도로 높아진다. 코드의 분량은 심한경우 수백배 이상 줄어들기도 한다. 그러니 단순히 결정할 만한 문제는 아니다. 우선 팀원의 OOP, AOP를 잘 이해하고, 그 한계도 알고 있어야한다. 그리고 생산비용을 감소시키고 싶다면 도입은 시도해 볼만한 일이다.

다른 대안들

  • MS의 선택
    MS 역시 이문제를 잘 알고 있었고, 좀 허탈할 정도로 간단한 방법으로 이문제를 해결했다. Partial Class라는 키워드를 만들어 클래스가 여러개의 소스에서 따로 나뉘어질 수 있도록 했다.이 경우 클래스는 하나 이지만, 영역에 따라 Partial Class들을 모아둘 수 있으므로, 재사용성 같은것은 기대할 수 없다 치더라도, 적어도 같은 영역 문제를 다루는 코드들을 한 개의 폴더에 넣어 둘 수는 있다. 하지만 뭔가 속고 있는 듯한 기분이 드는건…?
  • Eclipse 선택
    Eclipse는 영역에 대한 문제를 어댑터 패턴을 이용하여 해결했다. MVC가 각자 깔끔함을 유지하되 중개 객체인 Adapter를 두어 이들의 유기적인 활동성을 보장한다.

결론

AOP를 도입하는 것은 아직은 시기상조라고 본다. AspectJ는 자바 5.0까지 대응하고 있으며, 이 과정에서 많은 문법이 Annotation으로 대체되거나 혼용되고 있어 예전처럼 쉽게 배울수 없는 것이 되버렸다. AspectC는 자바에 비해 C++이 워낙 동적인 기능들이 제한되다보니 여전히 지지부진이다. 근본적으로 오늘날의 AOP는 새로운 패러다임이 아니라 OOP에 기능을 덧 대는 형이다 보니, OOP의 기준에 반하는 형상이 많이 드러나는 자폭에 가까운 모순이 노출되는것도 문제점 중 하나이다. 이미 SpringAOP같은 웹개발에서의 AOP는 비교적 자리를 잡긴 했으나, 변화의 속도가 너무 빠르다. 근본적으로 새로운 패러다임이 태동할 시기가 왔다고 생각하지 않는가?

(가끔… 거의 별다른 변화가 없는 Embeded 개발자들이 부러워질 때가 있다. 하지만 걔네들은 항상 RichUI 개발자들을 부러워한다는거! ㅋㅋㅋ)

Tags: ,

Leave a Reply

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word