IT_Architecture/Design Pattern

Framework

JJun ™ 2014. 3. 31. 13:50


 

 [출처]

 http://aeternum.egloos.com/2630624

 http://aeternum.egloos.com/2635171

 http://aeternum.egloos.com/2640343

 


 

 

 

재사용과 프레임워크

 

가장 이상적인 재사용 방법은 추가적인 프로그래밍 작업 없이 이미 존재하는 컴포넌트(component)를 조립하여 시스템을 구축하는 것이다. 그러나 이와 같은 컴포넌트 기반의 레고 블록(LEGO block, 또는 집적 회로IC) 접근 방법에는 분명한 한계가 있다.

 

다양한 컨텍스트 내에서 컴포넌트를 재사용하기 위해서는 조립 시 다양한 매개변수와 옵션을 설정할 수 있어야 한다. 설정 가능한 파라미터와 옵션의 종류가 적을수록 컴포넌트를 재사용할 수 있는 컨텍스트의 범위가 줄어든다. 반대로 설정 가능한 파라미터와 옵션의 종류가 많을수록 재사용을 위해 기억해야 하는 정보의 양이 늘어나기 때문에 프레임워크를 사용하기가 복잡해진다. 컴포넌트와 관련된 역설은 컴포넌트를 재사용 가능하게 만들려고 하는 모든 노력은 컴포넌트의 재사용 가능성을 감소시킨다는 것이다.

 

보다 본질적인 문제는 비즈니스 컴포넌트와 같은 대규모의 재사용 가능한 컴포넌트를 개발하는 것이 거의 불가능하다는 사실이다. 설정 가능한 파라미터와 옵션이 다양해야 한다는 것은 소프트웨어가 수용해야 하는 요구사항의 스펙트럼이 다양해야 한다는 것을 의미한다. 여러 애플리케이션에 대해 코드를 수정하지 않고도 재사용 가능할 정도로 유사한 요구사항을 발견하는 것은 예외에 가깝다.

이 논쟁의 핵심은 소프트웨어 다양성이라 불리는 주제에 있을 것이다. 만약 여러 프로젝트나 애플리케이션 도메인 사이에 비슷한 문제가 충분히 많이 존재한다면 컴포넌트 기반의 접근방법은 결국 효과가 있을 것이다. 그러나 많은 사람들이 의심하는 바와 같이, 애플리케이션과 도메인의 다양성으로 인해 두 가지 문제가 아주 비슷한 경우가 거의 없다면, 가장 기본이 되는 공통적 작업만이 일반화될 수 있을 것이고, 이것이 프로그램 코드에서 차지하는 비율 또한 매우 작을 것이다.

- Robert L. Glass, 우리가 미처 알지 못한 소프트웨어 공학의 사실과 오해

 

 

컴포넌트 재사용이 비현실적인 접근방법이라면 컴포넌트를 개발하는 동안 축적된 경험과 지식을 재사용하는 방법을 생각해 볼 수 있다. 컴포넌트 자체를 재사용하는 것은 코드 재사용(code reuse)을 의미한다.

이에 비해 경험과 지식의 재사용은 설계의 재사용(design reuse)을 의미한다. 언어나 플랫폼과 같은 다양한 제약으로 인해 적용 범위가 제한되는 코드 재사용에 비해 설계를 재사용할 수 있는 범위는 무한대에 가깝다. 또한 설계의 재사용은 프로젝트 초반부터 적용 가능하기 때문에 코드 재사용보다 투자 대비 효과가 더 크다.

설계를 재사용하는데 있어 가장 큰 어려움은 재사용 가능하도록 설계를 표현하고 커뮤니케이션할 수 있는 효과적인 방법을 찾는 것이다. UML을 중심으로 한 그래픽적인 표기법과 패턴을 통해 일정 수준의 의사소통은 가능할 지 몰라도 설계에 담긴 모든 휴리스틱과 근거, 대안을 모호하지 않도록 전달하는 것은 쉽지 않은 일이다.

 

패턴의 목적은 설계 의도나 근거를 설명하는 것이지 구현 결과를 제공하는 것이 아니다. 따라서 패턴이라는 형식을 통해 표현된 설계를 재사용하기 위해서는 패턴을 구성하는 각 부분에 대응되는 코드를 재작성하는 반복적인 작업이 요구된다. 또한 패턴은 어떤 애플리케이션에라도 적용 가능해야 하므로 언어나 구현 방법에 독립적이며 추상적이어야 한다. 디자인 패턴을 효과적으로 적용하기 위해서는 트레이드오프를 통해 상황에 적합한 패턴을 선택하고 가공해야 한다. 우리는 항상 TEMPLATE METHOD와 STRATEGY 패턴의 갈림길에서 고민해야 한다.

 

가장 이상적인 형태의 재사용 방법은 설계 재사용과 코드 재사용을 적절한 수준으로 조합하는 것이다. 코드 재사용만을 강조하는 컴포넌트는 실패했다. 추상적인 수준에서의 설계 재사용을 강조하는 패턴은 설계를 재사용하기 위해 매번 유사한 코드를 작성해야만 한다. 패턴과 유사하게 기존 설계를 재사용할 수 있으면서도 패턴을 반복적으로 구현하는 문제를 피하기 위해 이미 존재하는 코드를 재사용할 수 있는 방법은 없을까?

프레임워크에서 해답을 찾을 수 있다. 프레임워크란 “추상 클래스 집합과 추상 클래스 인스턴스 간의 상호작용을 통해 시스템 전체나 일부를 표현하는 재사용 가능한 설계”, 또는 “애플리케이션 개발자가 현재의 요구사항에 맞게 커스터마이즈할 수 있는 애플리케이션의 골격(skeleton)”을 의미한다. 첫 번째 정의가 프레임워크의 구조적인 측면에 초점을 맞추고 있는 반면 두 번째 정의는 프레임워크를 사용하는 목적인 코드와 설계의 재사용에 초점을 맞추고 있다.

 

프레임워크는 애플리케이션의 아키텍처를 제공하며 문제 해결에 필요한 설계 결정과 이에 필요한 기반 코드 모두를 포함하고 있다. 프레임워크는 애플리케이션이 확장할 수 있도록 부분적으로 구현된 추상 클래스와 추가적인 작업 없이도 재사용 가능한 다양한 종류의 컴포넌트 라이브러리를 제공한다. 설계 아이디어를 재사용하기 위한 수단으로 프레임워크를 이용할 경우 패턴에서 살펴본 설계의 전달 방안에 대해 고민할 필요가 없다. 프레임워크에서는 코드가 곧 설계 재사용을 위한 표기법이다.

 

프레임워크에서 설계를 재사용 가능하도록 지원해 주는 핵심 구성요소는 추상 클래스(abstract class)다. 추상 클래스의 경우 인스턴스를 생성할 수 없기 때문에 서브 클래스를 생성하기 위한 템플릿의 용도로 사용된다. 프레임워크를 사용해서 애플리케이션을 구축할 경우 추상 클래스를 상속 받은 서브 클래스를 추가하여 애플리케이션에 특화된 기능을 구현하게 된다. 따라서 프레임워크에 속한 추상 클래스는 애플리케이션에 속한 서브 클래스의 인터페이스를 정의한다.

 

인터페이스의 정의가 프레임워크에 속하기 때문에 자연스럽게 애플리케이션의 제어 흐름 역시 프레임워크에 의해 결정된다. 프레임워크의 핵심은 추상 클래스가 아니라 추상 클래스의 인터페이스에 의해 정의되는 상호작용 방식이다. 서브 클래스는 추상 클래스가 사용되는 문맥 내에서 추상 클래스와 동일한 방식으로 상호작용할 수 있어야 하며 리스코프 치환 원리(LSP, Liskov Substitution Principle)에 따라 대체 가능해야 한다. 

 

프레임워크는 애플리케이션에 대한 아키텍처를 제공한다. 즉, 프레임워크는 클래스와 객체들의 분할, 전체 구조, 클래스와 객체들 간의 상호작용, 객체와 클래스 조합 방법, 제어 흐름에 대해 미리 정의한다. 프레임워크는 설계의 가변성을 미리 정의해 두었기 때문에 애플리케이션 설계자나 구현자는 애플리케이션에 종속된 부분에 대해서만 설계하면 된다. 프레임워크는 애플리케이션 영역에 걸쳐 공통의 클래스들을 정의하여 일반적인 설계 결정을 미리 내려 둔다. 비록 프레임워크가 즉시 업무에 투입할 수 있는 구체적인 서브 클래스를 포함하고 있기는 하지만 프레임워크는 코드의 재사용보다는 설계 자체의 재사용을 중요시 여긴다.

 

 


 

 

 

 

의존성 역전(Dependency Inversion)과 프레임워크


앞에서 살펴 본 바와 같이 프레임워크의 핵심은 추상 클래스라고 할 수 있다.

그렇다면 추상 클래스(또는 인터페이스)의 어떤 특징이 프레임워크의 재사용성을 향상시키는 것일까?

 

객체-지향 이전의 구조적 분석/설계와 같은 전통적인 소프트웨어 개발 방법의 경우 상위 레벨 모듈이 하위 레벨 모듈에, 그리고 상위 정책이 구체적인 세부적인 사항에 의존하도록 소프트웨어를 구성한다. 이해를 돕기 위해 핸드폰 과금 시스템에서 가입자가 문자 서비스를 사용할 경우의 요금 계산 로직을 떠올려 보자.

 

여기에서의 상위 정책은 DOMAIN EVENT의 타입에 따라 DISPATCHER AGREEMENT에서 POSTING RULE을 선택하는 일련의 흐름이다. 실제 요금을 계산하는 DOMAIN EVENT, ACCOUTING ENTRY, POSTING RULE 타입은 구체적인 세부 사항에 속한다.

 

<그림1>은 통화 요금을 계산하는 상위 정책인 PeriodicServiceContract가 세부적인SmsStandardPostingRule, SmsSendingEvent, MonetaryEntry와 강하게 결합되어 있는

전통적인 의존 관계를 표현한 것이다.


 

 

<그림 1> 정책이 세부적인 사항에 의존하는 전통적인 의존 관계

 

 

<그림 1>의 설계에 나타난 가장 큰 문제점은 다양한 종류의 POSTING RULE과 DOMAIN EVENT, ACCOUNTING ENTRY를 처리해야 하는 PeriodicServiceContract가 문자 메시지에 특화된 구체적인 클래스들에게 의존한다는 점이다. 따라서 통화 요금 계산을 위해 새로운 POSTING RULE, DOMAIN EVENT, ACCOUNTING ENTRY 타입을 사용해야 할 경우 PeriodicServiceContract를 재사용할 수 없다.

 

즉, 상위 레벨의 정책이 하위 레벨의 구체적인 세부사항에 의존하도록 구조를 설계할 경우 다양한 컨텍스트에서의 재사용이 불가능해진다.

 

이와 같은 의존성 문제를 문제를 해결할 수 있는 방법이 없을까? 방법은 의외로 간단하다.

상위 레벨의 정책을 재사용하기 위해서는 상위 레벨의 정책이 하위 레벨에 대해 독립적이어야 한다.

즉, 정책이 상세에 의존하지 않도록 의존성을 역전시켜야 한다.

 

상위 레벨의 정책이 의존하고 있는 세부적인 클래스들로부터 EXTRACT INTERFACE를 한다.

이제 상위 레벨 정책이 하위 레벨의 구체적인 클래스에 직접적으로 의존하지 않게 되며 상세와 정책 모두

추상적인 인터페이스에 의존하게 된다.

 

이와 같은 방법은 전통적인 분석/설계 방법에서 다루는 의존성의 방향을 역전시킨다.

이처럼 재사용 가능한 객체 지향 설계를 만들기 위해 인터페이스 또는 추상 클래스를 사용해서 의존성의

방향을 바꾸는 것을 의존성 역전 원리(DIP, Dependency-Inversion Principle)라고 한다.

 

<그림 2>는 의존성을 역전시킨 후의 핸드폰 과금 시스템의 구조를 표현한 것이다.

 

<그림 2> 정책과 상세 모두 인터페이스에 의존하도록 의존성을 역전

 

 

이제 <그림 3>과 같이 상위 정책인 PeriodicServiceContract와 추출된 인터페이스를 별도의 패키지로

묶어 보자. DOMAIN EVENT와 ACCOUNTING ENTRY의 인터페이스는 상위 정책의 필요에 의해 결정되기 때문에 상위 정책에 속한다. 즉, 인터페이스와 구현 클래스를 별도의 패키지로 분리해야 한다.

 

이처럼 재사용을 위해 인터페이스와 구현 부를 별도의 패키지로 분리하는 것을 SEPARATED INTERFACE 패턴이라고 한다. 상위 정책과 인터페이스를 포함하는 패키지는 전체 애플리케이션에 있어 프레임워크로서의 기능을 제공한다.

 

<그림 3> 상위 정책과 인터페이스를 포함하는 프레임워크

 

 

<그림 4>와 같이 상위 정책을 표현하는 패키지에 속한 인터페이스 또는 추상 클래스를 구현하는 새로운 POSTING RULE, DOMAIN EVENT, ACCOUNTING ENTRY를 추가해서 상위 정책의 설계를 재사용할 수 있다. 이것이 애플리케이션이 프레임워크의 설계와 코드를 재사용하는 방법이다.

 

<그림 4> 프레임워크를 재사용하는 애플리케이션

 


사실, 좋은 객체 지향 설계의 증명이 바로 이와 같은 의존성의 역전이다. 프로그램이 어떤 언어로 작성되었는가는 상관없다. 프로그램의 의존성이 역전되어 있다면, 이것은 OO 설계를 갖는 것이다. 그 의존성이 역전되어 있지 않다면, 절차적 설계를 갖는 것이다. 의존성 역전의 원칙은 객체 지향 기술에서 당연하게 요구되는 많은 이점 뒤에 있는 하위 수준에서의 기본 메커니즘이다. 재사용 가능한 프레임워크를 만들기 위해서는 이것의 적절한 응용이 필수적이다. 이 원칙은 또한 변경에 탄력적인 코드를 작성하는 데 있어 결정적으로

중요하다. 추상화와 구체적인 사항이 서로 고립되어 있기 때문에, 이 코드는 유지보수하기가 훨씬 쉽다.

- Robert C. Martin, 소프트웨어 개발의 지혜

 

 

 

제어 역전(Inversion of Control)과 프레임워크


의존성 역전은 의존성의 방향뿐만 아니라 제어 흐름의 주체 역시 역전 시킨다. 앞서 설명한 것처럼 상위 정책이 구체적인 세부사항에 의존하는 전통적인 구조에서는 상위 정책의 코드가 하부의 구체적인 코드를 호출한다. 즉, 애플리케이션의 코드가 재사용 가능한 라이브러리나 툴킷의 코드를 호출한다. 그러나 의존성을 역전 시킨 객체 지향 구조에서는 반대로 프레임워크가 애플리케이션에 속하는 서브 클래스의 메소드를 호출한다. 따라서 프레임워크를 사용할 경우 개별 애플리케이션에서 프레임워크로 제어 흐름의 주체가 이동된다. 즉, 의존성을 역전시키면 제어 흐름의 주체 역시 역전된다. 이를 제어 역전(Inversion of Control)의 원리,

또는 할리우드(Hollywood) 원리라고 한다.


설계 수준의 재사용은 애플리케이션과 기반이 되는 소프트웨어 간에 제어를 바꾸게 한다.

툴킷을 사용하여 애플리케이션을 작성하면, 애플리케이션은 재사용하는 툴킷의 코드를 호출한다.

그러나 프레임워크를 재사용할 때는 프레임워크가 제공하는 주(main) 프로그램을 재사용하고

이 주 프로그램이 호출하는 코드를 애플리케이션 개발자가 작성하는 것이다.

이미 특정 이름과 호출 방식이 결정된 오퍼레이션을 작성해야 하지만 결정해야 하는 설계 개념은

줄어들고 애플리케이션 별 구체적인 오퍼레이션의 구현만 남게 된다.

-  GOF, 디자인 패턴

 


프레임워크에서는 일반적인 해결책만 제공하고 애플리케이션에 따라 달라질 수 있는 특정한 동작은

비워둔다. 그리고 이렇게 완성되지 않은 채로 남겨진 동작을 훅(hook)이라고 하며, 훅의 구현은

애플리케이션의 컨텍스트에 따라 달라진다. 훅은 프레임워크 코드에서 호출하는 프레임워크의 특정 부분이다. 재정의된 훅은 제어 역전 원리에 따라 프레임워크가 원하는 시점에 호출된다.

 

만약 프레임워크를 처음 사용한다면 제어 흐름이 손가락 사이로 스멀스멀 빠져나가는 듯한 느낌에 불안해질 수도 있다. 그러나 이러한 제어의 역전이 프레임워크의 핵심 개념인 동시에 코드의 재사용을 가능하게 하는 힘이라는 사실을 이해해야 한다.

 

 

<그림 5> 프레임워크에 정의된 제어 흐름에 따라 호출되는 애플리케이션 객체

 

 

 

 


 

 

 

 

프레임워크의 진화

 

재사용 가능한 프레임워크는 실제로 재사용되었을 때에만 재사용 가능하다고 말할 수 있다. 의존성 역전과 제어 역전의 원리를 통해 확장 가능하도록 프레임워크를 구축했다고 해도 요구사항의 변화와 도메인 규칙의 확장을 수용하지 못하는 프레임워크는 재사용되기 어렵다. 그러나 프레임워크의 사용 패턴을 예견하고 변화에 대응하기 위해서는 실제적으로 프레임워크를 적용한 애플리케이션이 필요하다. 따라서 프레임워크를 개발을 위해 가장 필요한 것은 구체적인 애플리케이션 개발을 통한 피드백이다.

 

재사용 가능한 프레임워크를 개발하기 위해 피드백을 증폭시킬 수 있는 가장 핵심적인 방법은 반복(iteration)이다. 프레임워크의 초기 버전을 사용해서 애플리케이션을 구축하고, 구축된 애플리케이션을 통해 얻어진 피드백을 통해 반복적으로 프레임워크를 정제하고 확장하라.

 

프레임워크를 구축하기 위해 반복적인 접근 방법을 적용할 경우 다음과 같은 사항에 주의해야 한다.

 

첫째, 프레임워크는 실제로 애플리케이션을 구축하기 위해 반복적으로 적용 가능해야 한다. 여기에 언급할 가치가 있는 두 가지 ‘3의 법칙’이 있다. 재사용 가능한 컴포넌트를 만드는 것은 단일 목적의 컴포넌트를 만드는 것보다 세배는 어렵다. 컴포넌트는 재사용 라이브러리로 인정할 만큼 일반적이라 생각하기 전에 서로 다른 세 가지 애플리케이션에 적용해 봐야 한다. 이처럼 세 가지 예제 애플리케이션을 통해 프레임워크를 개발하는 방식을 THREE EXAMPLES 패턴이라고 부른다.

 

둘째, 대부분의 사람들의 예상과 달리 성공적인 프레임워크를 만들기 위한 최선의 접근 방법은 프레임워크를 염두에 두지 않는 것이다. 애플리케이션을 개발하기 전에 프레임워크부터 개발할 경우 재사용과 확장이 어렵고 불필요한 기능과 복잡도로 인해 사용이 어려운 프레임워크를 개발하게 될 확률이 높다. 따라서 개발이 완료된 애플리케이션 간의 공통 부분을 기반으로 프레임워크를 개발하는 것이 효과적이다.
 

셋째, 프레임워크가 갖추어야 할 가장 기본적인 필요조건은 적절한 추상화다. 다양한 컨텍스트에 대한 가장 최적의 추상화를 구축하는 방법은 실제 애플리케이션의 공통적인 부분을 식별하고 이를 프레임워크를 구성하는 아키텍처의 근간으로 삼는 것이다. 따라서 프레임워크의 추상 클래스 및 인터페이스의 목록, 이들 간의 관계는 사전 설계가 아닌 경험을 기반으로 해야 한다. 경험이 추정을 향상시킨다는 XP의 슬로건과 유사하게 경험은 프레임워크의 추상화 역시 향상 시킨다.

 

성공적으로 재사용되는 프레임워크는 적용 과정에서 발생하는 다양한 피드백을 통해 지속적으로 진화하게 된다. 프레임워크가 변경되지 않는 시점은 프레임워크가 더 이상 사용되지 않게 되었을 때뿐이다. Ralph Johnson은 성공적으로 재사용되는 프레임워크는 적어도 동일한 도메인에 포함된 3개 이상의 애플리케이션의 공통적인 추상화를 기반으로 하며, 화이트 박스 프레임워크에서 블랙박스 프레임워크로, 그리고 최종적으로 잘 구축된 도메인 특화 언어(DSL, Domain-Specific Language)의 형태로 진화한다고 보았다.

 

  • Three Examples
    - 프레임워크는 적어도 동일한 도메인에 포함된 3개 이상의 애플리케이션에서 공통적인 부분을
       사용해서 추상화를 이끌어 내야 한다.
  • White Box Framework
    - 두 번째 애플리케이션을 개발하는 경우 상속을 사용해서 프레임워크의 기능을 확장하는
      화이트 박스 프레임워크를 구축한다.
  • Component Library
    - 세 번째 프레임워크를 개발하는 경우 반복적인 코드 작성을 피하기 위해 공통적으로
      사용되는 클래스들을 프레임워크에 포함시킨다.
  • Hot Spots
    - 프레임워크를 사용해서 애플리케이션을 사용하는 과정에서 유사한 코드들이 나타날 경우
       반복되는 코드와 반복되지 않는 코드를 분리한 후 변경되는 부분을 캡슐화해서 상속이 아닌
       조합을 통해 애플리케이션을 작성할 수 있도록 한다.
  • Pluggable Objects
    - 변경의 범위가 어느 정도 예측할 수 있게 되었다면 변경 가능성을 파라미터화할 수 있도록
       객체에 유연성을 추가한다.
  • Fine-grained Objects
    - 컴포넌트 라이브러리의 재사용성을 향상시키기 위해 문제 도메인 내에서 더 이상 
      분해하는 것이 의미가 없을 정도로 객체를 분해한다.
  • Black-Box Framework
    - 컴포넌트 라이브러리를 구축하는 경우에만 상속을 통해 프레임워크를 확장하고, 
      애플리케이션에서는 단순히 컴포넌트들을 조합해서 사용할 수 있는 블랙박스 프레임워크를
      구축한다.
  • Visual Builder
    – 조합을 통해 애플리케이션을 개발할 수 있는 블랙 박스 프레임워크를 가지게 되었으므로
       이를 시각적으로 조합할 수 있는 그래픽 에디터를 제공한다. 
       이것은  DSL의 Language-Workbench를 개발하는 것을 의미한다.
  • Language Tools
    – Visual Builder를 사용해서 조합된 객체의 정합성을 검증하고 디버깅할 수 있는 도구를 
      제공한다.

 

<그림 5> 프레임워크의 진화 패턴

 

프레임워크를 효과적으로 재사용하기 위해서는 프레임워크의 최종 모습뿐만 아니라 현재의 모습을 띠게

되기까지 진화한 과정을 살펴 보는 것이 가장 효과적이다. 프레임워크의 진화 과정 속에는 프레임워크의

구성 원리 및 설계 원칙, 재사용 가능한 컨텍스트와 변경 가능성에 관련된 다양한 정보가 들어 있기 때문이다.

 

그렇다면 프레임워크 진화 속에 담겨 있는 다양한 정보를 효과적으로 전달할 수 있는 방법이 없을까?

패턴과 패턴 언어에서 그 해답을 찾을 수 있다.

 

 


패턴 언어와 프레임워크


프레임워크의 진화 과정은 유사한 애플리케이션들을 일반화를 통해 공통적인 추상화를 식별하고 변경 지점을 캡슐화 시켜 블랙 박스 프레임워크로 개선시키는 과정으로 요약할 수 있다. 이러한 진화 과정을 거치면서 자연스럽게 변경이 빈번하게 발생하는 “핫 스팟(Hot Spot)”을 식별하게 된다.

 

다양한 요구사항을 수용할 수 있도록 핫 스팟을 유연하게 만들고 코드 중복을 제거하는 가장 보편적인 방법은 디자인 패턴을 사용하는 것이다. 객체의 알고리즘이 빈번하게 변경된다면 STRATEGY 패턴을 적용해 알고리즘을 객체로 캡슐화시키고 실행시간에 알고리즘을 교체할 수 있도록 만든다. 객체의 행위가 특정 상태에 따라 변경되어야 한다면 STATE 패턴을 사용해서 상태 변경에 유연해지도록 만든다. GOF에 소개된 23개의 디자인 패턴 중 대다수는 다양한 변이를 캡슐화시키고 애플리케이션을 유연하기 만들기 위해 적용될 수 있다. 대부분의 프레임워크는 진화 과정 속에서 리팩토링을 통해 다양한 패턴을 적용하는(또는 제거하는) 과정을 통해 유연하고 확장성 있는 구조를 갖추게 된다.

지금까지 언급한 재사용 가능하고 확장 가능한 유연한 설계는 프레임워크 설계에는 매우 필수적이다. 디자인 패턴을 이용하는 프레임워크는 그렇지 않은 프레임워크보다 설계와 코드 재사용의 수준을 높일 수 있다. 성숙한 프레임워크는 일반적으로 여러 개의 디자인 패턴을 사용하는데, 이런 디자인 패턴은 프레임워크의 아키텍처를 재설계하지 않고도 다른 많은 애플리케이션에 재사용할 수 있도록 도와준다.

- GOF,디자인 패턴

 

 

하나의 프레임워크는 다양한 분석 패턴, 디자인 패턴, 아키텍처 패턴의 조합으로 표현할 수 있다.

예를 들어 전통적인 Smalltalk MVC 프레임워크의 경우 MODEL-VIWE-CONTROLLER 아키텍처 패턴을

사용하여 구축되었으며, OBSERVER, COMPOSITE, STRATEGY 디자인 패턴을 포함한다.

패턴은 반복적으로 발생하는 문제와 해결책뿐만 아니라 언제(when), 어떤 방식으로(how) 패턴을 적용해야 하는지에 대한 규칙과 패턴의 구조에 이르게 된 이유(why)까지도 포함한다. 따라서 패턴의 형식을 빌어 설계를 설명할 경우 언제(when), 어떻게(how) 설계를 확장할 지에 대한 지침을 전달하고 설계 원리(why) 및 근거를 효과적으로 설명할 수 있다.

 

변화나 요구사항과 같은 다양한 원인을 설계로 변경하여 아키텍처를 유도하기 위해 적용할 수 있는 패턴을 “생성적인 패턴(generative pattern)”이라고 부른다. “생성적인 패턴”의 핵심은 변화의 요인을 설계로 변형시키기 위해 패턴에 포함된 언제(when)와 어떻게(how)라는 측면을 사용한다는 점이다. “생성적인 패턴”을 적용한 경우 설계의 최종 모습만이 아니라 설계가 그런 구조를 가지게 된 이유(why)까지도 쉽게 전달할 수 있다. 따라서 프레임워크를 가장 효과적으로 문서화할 수 있는 방법은 패턴을 사용하는 것이다. 프레임워크 문서에는 프레임워크의 목적, 프레임워크 사용 방법, 프레임워크의 세부 설계가 포함되어야 한다. 언제(when), 어떻게(how), 왜(why)와 관련된 패턴의 3가지 측면은 프레임워크 문서화의 3가지 요구사항을 만족시킬 수 있는 최고의 도구를 제공한다.

 

프레임워크의 전반적인 구조를 설명하고 이를 문서화하기 위해서는 개별 패턴이 아닌 패턴 언어(pattern language)에 초점을 맞추어야 한다. 패턴 언어는 특정한 애플리케이션 도메인의 본질적인 설계 지식을 표현한다. 패턴 언어와 마찬가지로 프레임워크 역시 특정 도메인을 대상으로 하며 도메인 문제를 해결하기 위해 필요한 연관성 높은 패턴들의 집합을 포함한다. 화이트 박스 프레임워크에서 블랙 박스 프레임워크로의 진화 과정을 거치면서 추가되는 다양한 패턴들은 상호 연관되어 있으며 이들이 모여 패턴 언어를 구성한다. 패턴과 패턴 간의 관계에 초점을 맞춤으로써 프레임워크의 진화 과정과 설계 원리, 사용 방법을 좀 더 높은 개념에서 조망하고 이해할 수 있다.

 

개별적인 디자인 패턴이 애플리케이션 설계에 있어서의 의사 결정 지점이라면, 패턴 언어는 개별 패턴이 일련의 다른 패턴으로 연결되는 트리 또는 그래프 형태로 구성될 수 있다. 이런 구조는 완전한 애플리케이션을 설계하기 위해 필요한 시간에 따른 일련의 의사 결정을 표현하며, 애플리케이션은 프레임워크를 사용해서 구현된다. 따라서, 패턴 언어는 프레임워크를 애플리케이션으로 변환하기 위해 필요한 구체적인 방법(method)이 된다. … 특정한 애플리케이션 도메인을 위한 패턴 언어와 프레임워크를 사용할 수 있다면 프레임워크가 패턴과 패턴 언어의 재사용 가능한 구현을 제공하기 때문에 아무 것도 없는 상태에서 새로운 애플리케이션을 개발할 필요가 없다.

- Davide Brugali,Frameworks and pattern languages: an intriguing relationship

 

 

지금까지 살펴본 바와 같이 패턴 언어는 아키텍처와 설계 측면의 의사소통과 재사용성 향상, 공통 용어의 제공, 개념적 무결성 확립을 위한 메타포의 제공뿐만 아니라, 구체적인 코드 재사용을 위한 프레임워크의 근간으로 활용할 수 있다. 패턴을 적용하기 위한 패턴에는 한계가 없다.

 

 

 

참고자료

  • Kent Beck, Ralph Johnson, “Patterns Generate Architectures”, European Conference on Object-Oriented Programming, 1994
  • Andreas Birrer, Thomas Eggenschwiler, “Frameworks in the Financial Engineering Doman: An Expert Report”, European Conference on Object-Oriented Programming, p21-35, 1993
  • Davide Brugali, Katia Sycara, “Frameworks and pattern languages: an intriguing relationship”, ACM Computing Surveys, 32(1), p12-42, 2000
  • Frank Buschmann, 패턴 지향 소프트웨어 아키텍처: 패턴 시스템 Volume 1, 지앤선, 2008
  • Martin Fowler, “Language Workbenches: The Killer-App for Domain Specific Languages?”, http://martinfowler.com/articles/languageWorkbench.html
  • Martin Fowler, FoundationFramework, http://martinfowler.com/bliki/FoundationFramework.html
  • Martin Fowler, HarvestFramework, http://martinfowler.com/bliki/HarvestedFramework.html
  • Martin Fowler, 엔터프라이즈 애플리케이션 아키텍처 패턴, 피어슨 에듀케이션 코리아, 2003
  • Martin Fowler, Refactoring, 대청, 2002
  • Robert L. Glass, 우리가 미처 알지 못한 소프트웨어 공학의 사실과 오해, 인사이트, 2004
  • Erich Gamma, Richard Helm, Ralph Johnson, John M. Vlissides, GOF의 디자인 패턴, 피어슨에듀케이션 코리아, 2007
  • Ralph E. Johnson, “Components, Frameworks, Patterns”, http://st-www.cs.illinois.edu/users/johnson/cs329/2003/framework97.pdf, 1997
  • Ralph E. Johnson, “Documenting Frameworks using Patterns”, ACM SIGPLAN Notices 27, p63-76, 1992
  • Ralph E. Johnson, “Evolving Frameworks-A Pattern Language for Developing Object-Oriented Frameworks”, http://st-www.cs.uiuc.edu/users/droberts/evolve.html
  • Ralph E. Johnson, “FRAMEWORKS=(COMPONENTS+PATTERNS)”, Communications of the ACM, Vol. 40, No. 10, 1997
  • Robert C. Martin, 소프트웨어 개발의 지혜, 야스미디어, 2004
  • Rebecca Wirfs-Brock, 오브젝트 디자인, 인포북, 2004