-
프레임워크 - 2부 [끝][옛날 글들] 설계 이야기 2024. 5. 30. 23:24728x90
이전 글 : 프레임워크 - 1부
제어 역전(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를 사용해서 조합된 객체의 정합성을 검증하고 디버깅할 수 있는 도구를 제공한다.
<그림 6> 프레임워크의 진화 패턴프레임워크를 효과적으로 재사용하기 위해서는 프레임워크의 최종 모습뿐만 아니라 현재의 모습을 띠게 되기까지 진화한 과정을 살펴 보는 것이 가장 효과적이다. 프레임워크의 진화 과정 속에는 프레임워크의 구성 원리 및 설계 원칙, 재사용 가능한 컨텍스트와 변경 가능성에 관련된 다양한 정보가 들어 있기 때문이다. 그렇다면 프레임워크 진화 속에 담겨 있는 다양한 정보를 효과적으로 전달할 수 있는 방법이 없을까? 패턴과 패턴 언어에서 그 해답을 찾을 수 있다.
패턴 언어와 프레임워크
프레임워크의 진화 과정은 유사한 애플리케이션들을 일반화를 통해 공통적인 추상화를 식별하고 변경 지점을 캡슐화 시켜 블랙 박스 프레임워크로 개선시키는 과정으로 요약할 수 있다. 이러한 진화 과정을 거치면서 자연스럽게 변경이 빈번하게 발생하는 “핫 스팟(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지금까지 살펴본 바와 같이 패턴 언어는 아키텍처와 설계 측면의 의사소통과 재사용성 향상, 공통 용어의 제공, 개념적 무결성 확립을 위한 메타포의 제공뿐만 아니라, 구체적인 코드 재사용을 위한 프레임워크의 근간으로 활용할 수 있다. 패턴을 적용하기 위한 패턴에는 한계가 없다.
728x90'[옛날 글들] 설계 이야기' 카테고리의 다른 글
Information Hiding (0) 2024.05.31 테스트 커버리지에 현혹되지 말자 (2) 2024.05.31 프레임워크 - 1부 (0) 2024.05.30 의존성 끊기와 단위 테스트 – 2부 [끝] (0) 2024.05.30 의존성 끊기와 단위 테스트 - 1부 (0) 2024.05.30