관점 지향 프로그래밍

컴퓨팅에서 관점 지향 프로그래밍(, AOP)은 횡단 관심사(cross-cutting concern)의 분리를 허용함으로써 모듈성을 증가시키는 것이 목적인 프로그래밍 패러다임이다. 코드 그 자체를 수정하지 않는 대신 기존의 코드에 추가 동작(어드바이스)을 추가함으로써 수행하며, "함수의 이름이 'set'으로 시작하면 모든 함수 호출을 기록한다"와 같이 어느 코드가 포인트컷(pointcut) 사양을 통해 수정되는지를 따로 지정한다. 이를 통해 기능의 코드 핵심부를 어수선하게 채우지 않고도 비즈니스 로직에 핵심적이지 않은 동작들을 프로그램에 추가할 수 있게 한다. 관점 지향 프로그래밍은 관점 지향 소프트웨어 개발의 토대를 형성한다.

관점 지향 소프트웨어 개발은 온전한 엔지니어링 분야를 가리키는 반면에 관점 지향 프로그래밍은 소스 코드 레벨에서 관심사들의 모듈화를 지원하는 프로그래밍 메서드들과 도구들을 포함하고 있다.

관심 지향 프로그래밍은 프로그램 로직을 명확한 부분들(이른바 "관심사")로 나누는 것을 수반한다. 거의 모든 프로그래밍 패러다임들은 관심사들을 별도의 독립적인 엔티티로 그룹화하고 캡슐화하는 것을 어느 정도는 지원하며, 이는 이러한 관심사들을 구현, 추상화, 합성하기 위해 사용할 수 있는 추상화(예: 함수, 프로시저, 모듈, 클래스, 메서드)를 제공함으로써 수행된다. 일부 관심사들은 프로그램 내의 여러 추상적 개념들에 영향을 미치며 이러한 형태의 구현체를 거역한다. 이러한 관심사들을 크러스 커팅 관심사(cross-cutting concerns)라고 부른다.

횡단 관심사의 전형적인 예로 로깅을 들 수 있는데 로깅 전략이 필연적으로 시스템 상에서 로그되는 모든 부분에 영향을 미치기 때문이다. 그러므로 로깅은 로그가 되는 모든 클래스들과 메서드들을 횡단한다.

모든 AOP 구현체들은 각각의 관심사를 한 자리에 캡슐화하는 횡단 표현식들을 일부 보유하고 있다. 구현체들 간의 차이점은 제공되는 생성자들의 권한, 보안, 사용성에 기인한다.

 역사 
AOP에는 여러 선행자 A1, A2가 있다: 반영, 메타오브젝트 프로토콜, 주체 지향 프로그래밍, 컴포지션 필터(Composition Filters), 적응형 프로그래밍(Adaptive Programming)."Adaptive Object Oriented Programming: The Demeter Approach with Propagation Patterns" Karl Liebherr 1996  presents a well-worked version of essentially the same thing (Lieberherr subsequently recognized this and reframed his approach).

제록스 PARC의 Gregor Kiczales와 동료들은 명시적 개념의 AOP를 개발하였으며 AspectJ AOP 확장 기능을 자바로 가져왔다. IBM의 연구팀은 언어 설계 접근으로 도구 접근을 추구하였으며 2001년에 Hyper/J와 관심 조작 환경(Concern Manipulation Environment)을 제안하였으나 널리 사용되지는 않았다.

마이크로소프트 트랜잭션 서버가 최초의 주요 AOP 애플리케이션으로(이후에는 엔터프라이즈 자바빈즈) 간주된다.

 동기와 기본 개념 
일반적으로 애스펙트(aspect)는 코드로서 분산되거나 얽혀있으며 이해하고 유지보수하기를 어렵게 만든다. 잠재적으로 서로 완전히 관련이 없는 시스템, 각기 다른 원본 언어 등에서 수많은 비관련 함수들에 로깅과 같은 함수가 분산된다. 즉, 로깅을 바꿀 경우 영향을 받는 모든 모듈의 수정이 필요하다. 애스펙트는 표현이 되는 시스템의 핵심 기능에만 얽혀있는 것이 아니라 서로에게도 얽혀있다.

이를테면, 개념적으로 매우 단순한 메소드가 있는 은행업 애플리케이션을 생각해 보자. 아래는 하나의 계정에서 다른 계정으로 송금하는 것이다:Note: The examples in this article appear in a syntax that resembles that of the 자바 language.
void transfer(Account fromAcc, Account toAcc, int amount) throws Exception {
  if (fromAcc.getBalance() < amount)
      throw new InsufficientFundsException();

  fromAcc.withdraw(amount);
  toAcc.deposit(amount);
}

그러나 이러한 송금 방식은 디플로이된 애플리케이션이 다음을 필요할 것만 고려하고 있다: 현재 사용자가 이 작업을 수행하기 위한 권한이 있는지를 검사하는 보안 검사 기능이 없다. 데이터베이스 트랜잭션은 우연한 데이터 손실을 예방하기 위해 작업을 캡슐화하는 것이 좋겠다. 진단을 위해 이 작업은 시스템 로그에 기록하는 것이 좋겠다. 등등...

이러한 새로운 관심사들의 버전은 이를테면 다음과 같이 보일 수 있다:

void transfer(Account fromAcc, Account toAcc, int amount, User user,
    Logger logger, Database database) throws Exception {
  logger.info("Transferring money...");

  if (!isUserAuthorised(user, fromAcc)) {
    logger.info("User has no permission.");
    throw new UnauthorisedUserException();
  }

  if (fromAcc.getBalance() < amount) {
    logger.info("Insufficient funds.");
    throw new InsufficientFundsException();
  }

  fromAcc.withdraw(amount);
  toAcc.deposit(amount);

  database.commitChanges();  // Atomic operation.

  logger.info("Transaction successful.");
}

이 예에서 다른 관심사들은 기초적인 기능(비즈니스 로직 관심사)과 함께 뒤얽혀있다. 트랜잭션, 보안, 로깅은 모두 횡단 관심사를 가리킨다.

이를테면 우리가 갑자기 애플리케이션에 대한 보안 고려사항을 변경해야 한다면 일어나는 일에 대해서 생각해 보자. 프로그램의 현재 버전에서 보안 관련 기능들은 수많은 메소드를 가로질러 분산되어 있는 것으로 나타나며 이러한 변경은 상당한 노력이 요구된다.

AOP는 프로그래머가 횡단 관심사를 애스펙트라는 독립적인 모듈로 표현할 수 있게 함으로써 이 문제의 해결을 시도한다. 애스펙트는 어드바이스(프로그램 내의 특정 포인트와 결합되는 코드)와 인터타입 선언(다른 클래스에 추가되는 구조적인 멤버)을 포함할 수 있다. 이를테면 보안 모듈에는 은행 계좌에 접근하기 전에 보안 검사를 수행하는 어드바이스를 포함할 수 있다. 포인트컷은 누군가가 은행 계정에 접근하는 시점(조인 포인트)을 정의하며 어드바이스 몸체 내의 코드는 어떻게 보안 검사를 구현하는지를 정의한다. 이러한 방식으로 검사와 장소를 한 자리에서 유지보수할 수 있게 된다. 게다가 양호한 포인트컷은 나중의 프로그램 변경을 예측할 수 있으므로 다른 개발자가 은행 계정에 접근하기 위한 새로운 메소드를 만든다면 어드바이스는 실행 시 새로운 메소드에 적용이 가능하다.

그러므로 위의 예제에 애스펙트에 로깅을 구현하면 다음과 같이 된다:

aspect Logger {
  void Bank.transfer(Account fromAcc, Account toAcc, int amount, User user, Logger logger)  {
    logger.info("Transferring money...");
  }

  void Bank.getMoneyBack(User user, int transactionId, Logger logger)  {
    logger.info("User requested money back.");
  }

  // Other crosscutting code.
}

AOP를 디버깅 도구나 사용자 수준의 도구로 생각하는 사람이 있을 수 있다. 어드바이스는 함수 변경을 취할 수 없는 경우에 대비하여 (사용자 레벨)Emacs documentation, 또 운영 모드(디버깅)에서 함수를 변경하고 싶지 않을 때 예비해 두는 것이 좋다.

 구현 
다음의 프로그래밍 언어들은 언어 자체적으로, 또는 외부 라이브러리를 통해 AOP를 구현하고 있다:
 닷넷 프레임워크 언어 (C# / VB.NET)Numerous:
Afterthought, LOOM.NET, Enterprise Library 3.0 Policy Injection Application Block, AspectDNG, DynamicProxy, Compose*, PostSharp, Seasar.NET, DotSpect (.SPECT) , Spring.NET (as part of its functionality), Wicca and Phx.Morph, SetPoint 
 PostSharp는 상용 AOP 구현체이다.
 유니티: API를 제공.
 액션스크립트
 에이다Ada2012 Rationale
 오토핫키Function Hooks{{ 
 C / C++Several: AspectC++, FeatureC++, AspectC, AspeCt-oriented C , Aspicere{{ 
 코볼Cobble
 코코아 오브젝티브-C 프레임워크
 어도비 콜드퓨전ColdSpring{{ 
 커먼 리스프
 델파이
 옥시즌
 e (IEEE 1647)
 Emacs LispEmacs Advice Functions
 그루비
 하스켈monad (functional programming) () and Aspect-oriented programming with type classes. A Typed Monadic Embedding of Aspects
 자바Numerous others: CaesarJ , Compose*, Dynaop , JAC , Google Guice (as part of its functionality), Javassist , JAsCo (and AWED), JAML , JBoss AOP , LogicAJ , Object Teams, PROSE, The AspectBench Compiler for AspectJ (abc) , 스프링 프레임워크 (as part of its functionality), Seasar, The JMangler Project , InjectJ, GluonJ , Steamloom 
 AspectJ
 자바스크립트Many: Advisable , Ajaxpect, jQuery AOP Plugin , Aspectes , AspectJS, Cerny.js , Dojo Toolkit, Humax Web Framework, Joose, 프로토타입 - Prototype Function#wrap, YUI 3 (Y.Do) 
 로그토크Using built-in support for categories (which allows the encapsulation of aspect code) and event-driven programming (which allows the definition of before and after event handlers).
 루아
 make
 MATLAB
 ML
 펄
 PHPSeveral: PHP-AOP (AOP.io) , Go! AOP framework, PHPaspect, Seasar.PHP, PHP-AOP{{ , TYPO3 Flow , AOP PECL Extension
 프롤로그 (프로그래밍 언어)
 파이썬Several: PEAK , Aspyct AOP{{ , Lightweight Python AOP , Logilab's aspect module , Pythius, Spring Python's AOP module , Pytilities' AOP module , aspectlib
 래킷
 루비
 스퀵 스몰토크
 UML 2.0WEAVR
 XML

 같이 보기 
 프로그래밍 패러다임
 데코레이터 패턴

 각주 


분류:프로그래밍 패러다임
분류:관점 지향 소프트웨어 개발