Aspected Oriented Programming(AOP)을 가장 잘 지원하고 있는 언어를 꼽으라면, 숨도 쉬지않고 Java를 선택할 수 있겠다. Java의 경우에는 주로, VM코드를 직접 수정하는 방식으로 구현하는 모양인데, C++에서 기계어를 고치고 있을 수는 없는 것 아닌가.. 상상만 해도 우울하다.
그렇다고 해서 C++에서 AOP를 포기할 수는 없는 노릇! 고민을 해보았다.
생각해보니, AOP의 가장 큰 개념concept은 실행중인 로직과 수직이 되는 코드를 삽입하는 것이다. 즉, AspectJ에서 이야기하는 pointcut(그중에서도 특히 함수가 실행되기 전의 point인 before와 함수 실행 후인 after)이 가장 큰 개념이라고 보여진다.
그렇다면! C++에서도 로직의 중간에 어떤 코드를 강제로 삽입할 수 있으면 되는 것 아닌가? 라는 생각이 들었다. 하지만, 애석하게도 C++에서 코드를 삽입할 방법은 보이지 않았다. 물론, Macro와 Preprocesor를 과도하게 사용하면 가능하겠지만, 이는 C++의 순수성을 훼손하는 일이라 생각되므로 일단 제외하였다.
그러던 찰나, 다음과 같은 코드가 눈에 들어왔다.
{ SpinLock::guard g(info_set_guard_); info_set_.insert(data); }
그때 디버깅 하던 코드에서 사용하던 부분인데, info_set_의 멀티쓰레딩 안정성을 위해 SpinLock을 guard를 이용해 블럭내에서 자동으로 획득acquire/해제release를 해주는 코드다. 물론, 명시적으로 획득/해제를 해주는 코드는 없다! guard에 의해 자동으로 수행된다. 자동으로.
“Eureka!”
라고 외치고, 담배를 한대 피워물며 고민해보았다. guard를 잘 사용하면, 특정 코드 블럭에 대해서 AOP(혹은 그와 유사한 무엇)을 적용할 수 있지 않을까? 라는 생각.
다음과 같이 말이다.
class logging_guard
{
public:
logging_guard(const char* block_name)
: block_(block_name)
{
std::cout << "entering block = " << block_ << std::endl;
}
~logging_guard()
{
std::cout << "leaving block = " << block_ << std::endl;
}
private:
const char* block_;
};
void test()
{
logging_guard lg("test()");
std::cout << "running test" << std::endl;
}
[/cpp]
확실히 이런 식으로 작성하면 block에 대한 수직적 코드 삽입이 가능해진다. 하지만, 이런 방식은 코드를 삽입할 point와 삽입할 코드가 명확히 구분되지 않는다는 점에서 좀 모자라다. 그렇다면, tagging 기법을 적용해보자.
[cpp]
class test_tag{};
template
class cut
{
public:
void before(const char* block)
{
}
void after(const char* block)
{
}
};
template<>
class cut
{
public:
void before(const char* block)
{
std::cout << "entering block = " << block << std::endl;
}
void after(const char* block)
{
std::cout << "leaving block = " << block << std::endl;
}
};
template
class cut_guard
{
public:
cut_guard(const char* block_name)
: block_(block_name)
{
cut
}
~cut_guard()
{
cut
}
private:
const char* block_;
};
void test()
{
cut_guard
std::cout << "running test" << std::endl;
}
[/cpp]
이러면(이런 개념을 이용하면), cut_guard
물론, 위의 경우는 해당 포인트에 한종류의 코드만 넣을 수 있다는 엄청난 단점이 존재한다. 그리고, 각 포인트에서 인수parameter를 넘길 수도 없다. 이런 문제는 singleton, boost::mpl, boost::preprocessor를 사용하면 쉽게 해결할 수 있다. 이 해결책들은 Flowcut!의 소개글이 될지도 모르는 다음 글에 나올 예정이다. 🙂
to be continued…
RAII를 가지고 뭔가 만드셨군요. AOP를 공부한 적이 없는데 이번 기회에 좀 해야겠네요. 🙂
Flowcut! 소개 글 빨리 올려주세요~ @_@
java 에서건 c++ 에서건 제가 테스트해본것으로는 새로운 소스 코드를 생성해서 컴파일 하는 것으로 보였습니다. (로그가 그렇게 나와요.. 코드생성… 컴파일… 식으로.. )
AOP 를 스터디하고 느낀건…
모든 부분에서는 아니고 적정한 부분에서는 굉장한 방법이 될 수 있겠다는 생각…
실제로 디버깅이 어케될까는 젤 큰 궁금점이였습니다. -.-;;
iwongu//
네. RAII를 가지고 뭔가 이상한걸 만들어버렸습니다. 🙂
문제는, mpl을 이해하지 못하면 상당히 어려운 코드가 되어버리는 녀석이 있어서, 이걸 어찌 쉽게 설명하나 고민중이네요. 🙂
zoops//
Source to Source컴파일 방식이죠. 하지만, Source to Source방식은 범용IDE에 적용하는게 꽤나 까다로워지고 이리저리 귀찮아서…
아마 Flowcut!의 디버깅은 일반 c++디버깅과 별 차이가 없을걸로 생각합니다. (별도로 컴파일을 안하거든요! 우훗!)