Protected Variation : '보호된 변수?, 변경? 변화? 으로 부터의 보호', 어렵습니다. 설계에 대한 용어는 매번 모호함으로 시작되는 듯합니다. 대충 private 으로 변수나 메소드의 접근을 외부로 부터 숨기는 것. 이라는 감이 옵니다. Variation을 어떤 단어로 대응해야 하는지는 Protected Variation 의 진짜 의미를 이해한 후에나 가능할 것 같습 합니다. Protected Variation 보다  정보은닉( Information Hiding) 이라는 용어가 훨씬 많이 사용됩니다. 정보은닉도 대표적으로 잘 못 해석되고 있는 용어이죠. 소프트웨어 설계에서 제대로 해석되는 용어가 존재하는지 의문이 들 정도입니다.

PV 는 David Parnas 가 소개한 용어로써, GRASP 의 아홉번째 항목으로 등장합니다. 변화로 부터 보호하는 패턴 이라는 것으로 말이죠.  Craig Larman 이 Protected Variation: The Importance of Being Closed (May/June 2001 IEEE SOFTWARE) 의 제목으로 PV를 설명하는 글을 기고 하였는데요, PV의 개념을 잘 이해시키는 글 입니다.

요약하자면 :
Protected Variation , Information Hiding, OCP는 같은 개념이다. 외부 모듈로 부터 '설계 결정' 을 감추어서 변화의 충격을 최소화 하는 것이 PV 이며, Data Encapsulation 과는 다른 의미이다. 유연성(flexibility)은 PV 로 얻어지는 산물중 하나이다.

Protected Variation 또는 Information Hiding 은  field 와 메소드를 private 으로 설정한다 정도의 지엽적이기 보다는 , 설계 결정 또는 설계 정보를 감추어서 외부의 변화로 부터 내부가 변경되지 않도록 보호한다 는 큰 개념. 으로 생각하면 이해하기 쉬울 듯 합니다.

보호는 그냥 되는 것이 아니다. 사소한 필드 부터 적절한 전략을 취해야 한다.



번역 :

변화로 부터의 보호 : 닫힘의 중요성.

Protected Variation: The Importance of Being Closed

by Craig Larman , May/June 2001 IEEE SOFTWARE

The Pattern Almanac 2000 (Addison-Wesley, 2000) 에는 소프트웨어와 관련된 패턴이 500여개 넘게 담겨져 있습니다. 호기심 많은 개발자는 프로그램을 작업할 시간이 없을 정도죠!
물론 이렇게 많은 패턴들은 개발자들이 오랜 시간동안 고민하고 논쟁해오던 주제와 원칙들을 단순화 할 목적을 가지고 있습니다.


Larry Constantine 의 coupling 과 cohesion 가이드라인 ("Structured Design," IBM Systems J., vol. 13, no. 2, 1974) 을 예로 들수 있듯이, 이 원칙들은 새로운 세대의 개발자와 아키텍트들이 무수히 많은 디자인 아이디어와 통합을 달성할 수 있도록  지속적으로 재 탐구 되어야 함이 당연 합니다.

Bertrand Meyer 가 Object-Oriented Software Construction (IEEE Press, 1988)에 기술한  Open–Closed Principle : 모듈은 확장(extention)과 적응(adaptation) 에는 열려(open) 있어야 하고, 클라이언트에 의한 변경 에는 닫혀 있으야 한다.
, 이 바로 그런 것입니다.

OCP는 본질적으로 Protected Variation pattern 과 동일 합니다. : 변경이 예측되는 지점을 판별하고 , 그것들을 위한 안정된 인터페이스를 생성하는 것.

Alistair Cockburn 은 PV("Prioritizing Forces in Software Design," Patterns Languages of Program Design, vol. 2, Addison-Wesley,1996)를 최초 기술할 때 OCP에 대해 알지 못했습니다.
David Parnas 의 OCP는 information hiding 을 뜻 하는 것이었습니다.("On the Criteria to Be Used in Decomposing Systems into Modules" Comm. ACM, vol.12, no. 2, Dec. 1972).

OCP 와 PV 는 많은 형태로 묘사되는 기반 설계 원칙을 형식화, 일반화 합니다. OCP 와 PV 는 작은 차이를 강조하는 것이 다를 뿐, 같은 원칙을 다르게 표현 한 것 이죠.-변화와 진화로 부터 기존의 코드와 디자인의 변경을 보호 하는 것.


저는 protected variation을 일반적 용어로 사용 하기를 제안합니다.개념을 짧고 명확하게 만드는 용어로 말이죠.

OCP 에서는 모듈에 포함된 소트프웨어의 모든 추상적인 요소를 칭하는 용어입니다. 메소드 , 클래스, 서브시스템, 어플리케이션, 기타 등등 말이죠.
또한 "X에 대해서 닫혀있다"라는 문구는 X의 변경이 클라이언트에 영향을 주지 않는다는 뜻입니다. 예를 들어 "클래스는 인스턴스 필드 정의에 대해 닫혀있다." PV 에서는 접근 관점으로의 광의적 표현으로 interface (java 나 COM의 인터페이스를 특정 하는 것은 아닙니다.) 라는 용어를 사용합니다.


정보은닉(information hiding)은 PV 이지 data encapsulation 이 아닙니다.


고전인 "On the Criteria To Be Used in Decomposing Systems Into Modules" 는 많이 참조 되지만 많이 읽혀지지는 않았습니다.
Parnas 는 거기에서 information hiding 을 소개 했습니다. 많은 사람들은 이 용어를 data encapsulation으로 잘 못 해석하고 있고, 몇몇 책에서는 유사어 개념으로 잘못 정의하고 있습니다.
Parnas 는 다른 모듈 내부의 어려운 것 또는 변경되기 쉬운 것들의 설계로 부터 정보은닉을 의미하려고 의도하였습니다.


정보은닉에 대한 설계 원칙 가이드로서 그의 논의를 빌자면 : 우리는 어려운 설계 결정의 목록으로써의 시작점, 변경되기 쉬운 설계 결정  대신에 제안하였습니다. 각각의 모듈은 다른 것에 대하여 그러한 결정을 감추도록 설계 되어야 합니다. Parnas의 정보은닉은 PV 나 OCP의 표현과 같은 원칙입니다. - 단순히 data encapsulation 이 아니라 설계 정보를 감추는 많은 기술중의 하나 입니다.
어쨋든, 이 용어는 data encapsulation 의 유사어 인 것 처럼 너무 광범위 하게 사용되어져서, 이제는 원래 의미로 사용 될 수 조차 없습니다.
Parnas의 PV 원칙에 대한 존경을 표시하자면 이 글을 "정보은닉의 중요성"이라고 불러야 마땅 합니다.
Dijkstra는 일찍이 이 원칙을 "THE" 프로젝트에서 암시했습니다. 하지만 Parnas 는 이것을 중요하게 생각하고 형태를 만들었죠. (Dijkstra, "The Structure of the 'THE' Multiprogramming System," Comm. ACM, 1968).


PV에 의해 동기를 얻은 메커니즘들 Mechanisms motivated by PV


PV는 수많은 프로그래밍 패턴 과 메커니즘들이 변화로 부터 설계의 유연성과 보호성을 제공하도록 동기를 부여한 근원 원칙 입니다.
여기에 몇가지 예가 있습니다. 데이터 캡슐화, 인터페이스, 다형성, 간접성, 표준성은 PV 메커니즘과 유사하며 PV가 동기를 부여한 것들 입니다.
브로커(broker)와 가상머신(virtual machine)과 같은 컴포넌트는 간접성의 복잡한 예 입니다.


통일된 접근 Uniform access

Ada, Eiffel, C# 과 같은 언어는 메소드와 필드에 대해 동일한 접근을 지원합니다. 예를 들어 aCircle.radius 는 radius() 를 실행합니다 :
클래스 정의에 기반한 public 필드에 대해 유동적인 메소드나 직접적인 참조를 의미.
여러분은 클라이언트 코드의 변경없이 public 필드가 메소드에 접근하도록 바꿀수 있습니다.


데이터-드리븐 디자인 Data-driven designs

데이터-드리븐 디자인은 코드, 값, 클래스 파일 경로, 클래스 이름 등 넓은 기술을 커버합니다. 다른 종류로는 외부 코드의 행위를 변경, 런타임에 "파라미터화" 를 위한 것, 객체-관계 매핑을 위한 meta-data, style sheet, 속성 파일 같은 것, 창 레이아웃을 읽는 것을 포함해서 말이죠.
시스템은 데이터, 메타데이터, 외부화된 변수의 선언을 읽는 행동 영향으로 부터 보호되어야 합니다.


서비스 룩업 Service lookup

서비스 룩업은 네이밍 서비스(예:JNDI), 서비스를 찾기 위한 트레이더(예: Jini) 기술을 포함합니다. 이 접근 방식은 클라이언트에게 안정적인 인터페이스를 제공함으로써 지역서비스에서의 변경으로부터 서비스를 찾는 것을 보호합니다. 이것은 데이터-드리븐 디자인의 특수한 경우 입니다.


인터프리터-드리븐 디자인 Interpreter-driven designs

인터프리터-드리븐 디자인은 외부의 소스,스크립트 또는 프로그램을 읽고 실행하는 규칙 자체를 해석하는 규칙을 포함합니다.
넷을 실행시키는 신경망 엔진. 이러한 접근은 외부 로직을 통하여 시스템을 변경시키는 파라미터화된 시스템을 가능케 합니다.
시스템은 외부 로직 표현의 변화로 부터 보호됩니다.

 

Reflective or metalevel designs

reflective, metalevel design 은 자바에서 bean 객체의 정보를 조회하기 위한 beans.Introspector 를 포함합니다.
bean 속성 X 를 얻기 위해 getter 메소드를 이용합니다(getXXX). 그리고 Method.invoke를 호출 합니다. introspection 과 metalanguage 서비스를 이용하는 Reflective는 외부 코드 변화의 충격으로 부터 시스템을 보호합니다.
우리는 이것 또한 데이터-드리븐 디자인이 포함하고 있는 특별한 경우라고 생각합니다.

Pick your battles

PV 어플리케이션의 예로써, 클라이언트에게 항공운항 논리를 설명하는 것은 머리아픈 일 입니다. 물류 비즈니스 로직을 지원하기 위한  변경이 매우 빈번하게  발생하기 때문이죠.
이런 변화에 대해 어떻게 시스템을 보호 할까요? PV를 지원하는 메커니즘(데이터 캡슐화, 인터페이스, 간접성)을 이용한 룰-기반 디자인(Rule-Based design)이 선택됩니다  :
룰 엔진은 시스템 소스 코드의 변경을 요구하지 않고도 룰을 업데이트 할 수 있게 합니다. 

Low coupling 과 protection

변화에 대항하는 것은 그냥 되는 것이 아닙니다. macro-architectural 레벨과 사소한 인스턴스 필드에서 부터 여러분은 설계에 적절한 전략을 취해야 합니다.
좋은 설계자는 변화와 불안전성이 존재하는 곳에는 PV 를 적용합니다. 그렇지 않으면 고생은 수포로 돌아가고, 복잡성은 증가할 것입니다. 또는 결함이 발생할 가능성이 높아지죠.
예를 들어 자바의 static public final field의 빈번한 사용으로 인해 놀랐던 경험을 회상합니다. 어떤 사람들은 잘 상상하지 못할 것입니다.
red, black, white등의 Color 로서의 static field 를 사용하는 것은 매우 안정합니다. 비슷하게 객체 순혈주의 입장에서 그것들을  private 또는 접근하는 메소드를 별도로 만들면 불안정하게 됩니다.
반대되는 경우로 유연성을 제공하기 위해 예쁜 스크립트 언어와 인터프리터를 추가한  pager-message-handling 시스템 아키텍트를 알고 있는데, 버전 향상 작업 동안에  복잡성과 비효율성을 이유로 스크립팅 부분은 제거 돼야만 했습니다.

 

현명한 PV 와 금강반야바라밀경 Judicious PV and the Diamond Sutra

low coupling 에 대한 Constantine의 설계 가이드라인은 설계의 핵심 원칙 이며, PV 는 여기에서 출발 했다고 말할 수 있습니다.
우리는 다음의 목표와 전락에 따라 우선순위를 정할 수 있습니다:
1. 우리는 시간과 비용을 줄이길 바랍니다. 새로운 결함을 줄이고, 중노동의 고통으로 부터 개발자를 구하길 희망합니다.
2. 이를 달성하기 위해 변경의 충격을 최소화 하도록 설계 해야 합니다.
3. 변경의 충격을 최소화 하기 위해 low coupling 이 달성되도록 목표해야 합니다.
4. low coupling을 달성하기 위해 PV로 설계 해야 합니다.

 Low coupling 과 PV 는 시간, 비용을 줄이기 위한 융합된 메커니즘 입니다. 이 목표를 달성하기 위한 불확실한 미래 방어 비용은 매우 높습니다.
highly couple 된 "깨지기 쉬운" 설계는 언제나 변화에 의한 압박으로 재작업이 요구됩니다. 진화 단계에서의 보호 엔지니어링 작업 비용은 단순한 설계를 재작업 하는 것보다 높습니다.


제 주장은 재작업과 깨지기 쉬운 설계를 변호할 목적이 아닙니다. 유연성이 필요하고, PV가 즉시 적용 가능하다면 PV를 적용하는 것이 옳습니다. 그러나, 불확실한 미래를 방어 하려거나, 재사용을 위해 이 전략을 사용하려는 것은 현명한 행동이 아닙니다. 풋내기 개발자는 깨지기 쉬운 설계를 하려는 경향이 있습니다. 예쁘고 일반화 시킨 유연성을 중간에 삽입하려 하죠(전혀 사용되지 않을 텐데도 말이죠).
전문가는 통찰력을 이용하여 단순하고, 깨지기 쉬운 디자인의 변경 비용 사이의 균형점을 찾습니다. 이는 잘 알려진 금강반야바라밀경을 수도하는 것과 같습니다:
선(zen, 禪) 을 수행하기 전에는 산은 산이요, 강물은 강물이더라.
선을 수행하는 동안에는 산은 더이상 산이 아니오, 강물은 더이상 강물이 아니다.
깨우친 후에는 또다시 산은 산이오, 강물은 강물이로다.

### 끝.


더 읽을 꺼리 :
Information Hiding : 이터너티 님의 블로그 포스트

The Difference Between Encapsulation and Information Hiding by stefanoricciardi

신고

이 글을 Twitter / Facebook 에 공유하기
이 글이 유익하다면 아래의 트위터 버튼을 눌러 공유해 주시거나, 페이스북 "좋아요" 버튼을 눌러 주세요.

   


Posted by 반더빌트
객체지향설계에 있어서 맨 처음 하는 일은 도메인 분석에 의해서 객체를 뽑아 내는 작업 입니다.

명사 는 객체로, 동사는 메소드로, 상태는 객체의 속성으로 구별해 내는 것이지요. 하지만 이 작업이 말처럼 쉽지는 않습니다. 어떤 명사는 명확하게 객체로 구별이 되는데, 어떤 명사는 모호하며, 더 어려운 일은 메소드가 어느 객체에 할당 되어야 하는지 구별하는 것입니다. 또한, 도메인 분석에 의해 구별된 객체 이외에도  관계 및 로직을 구현하기 위해서는 부가 객체들도 필요 합니다. 


어떤 객체가 어떤 책임을 질것 이며, 그 책임에 따라 객체에 할당할 메소드를 찾고, 다른 객체와 공유해야 하는 정보를 구별해 내는 방법론이 Rebecca Wirfs-Brock 와 Brian Wilkerson 이 제안한 Responsibility-driven design, RDD 입니다.

Responsibility-driven design 은 client/server 모델에서 영감을 얻었는데요, 질의에 의한 계약에 집중합니다 : 

1. 이 객체가 책임질 액션은 무엇인가?
2. 이 객체가 공유(Share) 해야할 정보(Information)는 무엇인가?


객체에 책임을 할당 해야 하는데 그 할당하는 패턴 또는 원칙이 General Responsibility Assignment Software Patterns , GRASP 패턴, 또는 원칙 입니다.

객체의 책임을 부여하는 일은 항상 어려운 일 입니다. 마틴 파울러은 '리팩토링 Refactoring' 에서 책임부여의 어려움을 이렇게 말하고 있습니다.

객체 디자인에서 가장 기본이 되는 것 중의 하나(원칙은 아닐지라도)는 책임을 어디에 둘지를 결정하는 것이다. 나는 십년 이상 객체를 가지고 일했지만 처음 시작할 때는 여전히 적당한 위치를 찾지 못한다. 늘 이런 점이 나를 괴롭혔지만, 이제는 이런 경우에 리팩토링을 사용하면 된다는 것을 알게 되었다.
- "리팩토링", 마틴 파울러 , 윤성준 역, 대청미디어, 2002, p.169


GRASP은 이 어려움을 돕기 위한 책임 부여 원칙인 것이지요.

GRASP 은 Information Expert, Creator, Controller, Low Coupling, High Cohesion, Polymorphism, Pure Fabrication, Indirection, Protected Variations. 의 9가지 항목이며, 객체지향디자인 5원칙의 각론으로 볼수 있습니다.

책임은 매우 중요하다. 책임 진다고 하면 의외로 쉽게 해결되는 것도 있다.




9가지 항목에 대한 기술은 김대곤님의 글로 대체 합니다.

김대곤 님의 GRASP 패턴 에서 발췌

GRASP 패턴은 아홉 가지로 구성되어 있다. 사실 각 패턴들이 너무 간단해서 싱거울 정도이다.
  1. Information Expert: 역할을 수행할 수 있는 정보를 가지고 있는 객체에 역할을 부여하자. 단순해 보이는 이 원칙은 객체지향의 기본 원리 중에 하나이다. 객체는 데이터와 처리로직이 함께 묶여 있는 것이고, 자신의 데이터를 감추고자 하면 오직 자기 자신의 처리 로직에서만 데이터를 처리하고, 외부에는 그 기능(역할)만을 제공해야 하기 때문이다.

  2. Creator: 객체의 생성은 생성되는 객체의 컨텍스트를 알고 있는 다른 객체가 있다면, 컨텍스트를 알고 있는 객체에 부여하자. A 객체와 B 객체의 관계의 관계가 다음 중 하나라면 A의 생성을 B의 역할로 부여하라.
    - B 객체가 A 객체를 포함하고 있다.
    - B 객체가 A 객체의 정보를 기록하고 있다.
    - A 객체가 B 객체의 일부이다.
    - B 객체가 A 객체를 긴밀하게 사용하고 있다.
    - B 객체가 A 객체의 생성에 필요한 정보를 가지고 있다.

  3. Controller: 시스템 이벤트(사용자의 요청)를 처리할 객체를 만들자. 시스템, 서브시스템으로 들어오는 외부 요청을 처리하는 객체를 만들어 사용하라. 만약 어떤 서브시스템안에 있는 각 객체의 기능을 사용할 때, 직접적으로 각 객체에 접근하게 된다면 서브시스템과 외부간의 Coupling이 증가되고, 서브시스템의 어떤 객체를 수정할 경우, 외부에 주는 충격이 크게 된다. 서브시스템을 사용하는 입장에서 보면, 이 Controller 객체만 알고 있으면 되므로 사용하기 쉽다.

  4. Low Coupling: 객체들간, 서브 시스템들간의 상호의존도가 낮게 역할을 부여하자. Object-Oriented 시스템은 각 객체들과 그들 간의 상호작용을 통하여 요구사항을 충족시키는 것을 기본으로 한다. 그러므로, 각 객체들 사이에 Coupling이 존재하지 않을 수는 없다. 이 패턴은 요구사항은 충족시키면서도 각 객체들, 각 서브시스템 간의 Coupling를 낮은 수준으로 유지하는 방향으로 디자인하라고 말하고 있다. Low Coupling은 각 객체, 서브시스템의 재 사용성을 높이고, 시스템 관리에 편하게 한다.

  5. High Cohesion: 각 객체가 밀접하게 연관된 역할들만 가지도록 역할을 부여하자. 이 패턴은 Low Coupling 패턴과 동전의 양면을 이루는 것으로, 한 객체, 한 서브시스템이 자기 자신이 부여받은 역할만을 수행하도록 짜임새 있게 구성되어 있다면, 자신이 부여 받은 역할을 충족시키기 위해 다른 객체나 시스템을 참조하는 일이 적을 것이고, 그것이 곧 Low Coupling이기 때문이다.

  6. Polymorphism: 객체의 종류에 따라 행동양식이 바뀐다면, Polymorphism 기능을 사용하자. Object-Oriented 시스템은 상속과 Polymorphism(다형성)을 지원한다. 만약 객체의 종류에 따라 행동이 바뀐다면 객체의 종류를 체크하는 조건문을 사용하지 말고, Object-Oriented 시스템의 Polymorphism 기능을 사용하라.

  7. Pure Fabrication: Information Expert 패턴을 적용하면 Low Coupling과 High Cohesion의 원칙이 깨어진다면, 기능적인 역할을 별도로 한 곳으로 모으자. 데이터베이스 정보를 저장하거나, 로그 정보를 기록하는 역할에 대해 생각해 보자. 각 정보는 각각의 객체들이 가지고 있을 것이다. 이 때 Information Expert 패턴을 적용하면, 각 객체들이 정보를 저장하고, 로그를 기록하는 역할을 담당해야 하지만, 실제로 그렇게 사용하는 사람들은 없다. 이것은 그 기능들이 시스템 전반적으로 사용되고 있기 때문에 각 객체에 그 기능을 부여하는 것은 각 객체들이 특정 데이터베이스에 종속을 가져오거나, 로그을 기록하는 매커니즘을 수정할 경우, 모든 객체를 수정해야 하는 결과를 가져온다. 즉 Low Coupling의 원칙이 깨어지게 된다. 이럴 경우에는 공통적인 기능을 제공하는 역할을 한 곳으로 모아서 가상의 객체, 서브시스템을 만들어라.

  8. Indirection: 두 객체 사이의 직접적인 Coupling을 피하고 싶으면, 그 사이에 다른 객체를 사용하라. 여기서 말하는 다른 객체란 인터페이스가 될 수 있고, 주로 인터페이스인 경우가 많다. 그런 특별한 경우는 아래에 설명된 Protected Variations 패턴이라고 부를 수 있다.

  9. Protected Variations: 변경될 여지가 있는 곳에 안정된 인터페이스를 정의해서 사용하자. JDBC에 대해서 생각해 보자. JDBC는 일련의 인터페이스들로 구성되어 있으며, 각 데이터베이스 벤더들이 인터페이스를 구현한 Concrete 클래스를 제공하고 있다. 데이터베이스 기능을 사용하는 시스템의 입장에선 각 벤더들이 구현방식을 바꾸었을 때, 자신의 코드를 수정하고 싶지 않을 것이다. 그래서 Driver를 로딩하는 코드를 제외하고는 모두 인터페이스를 사용함으로서 데이터베이스의 변경시에도 Driver 로딩만 바꾸어 주면 되도록 데이터베이스 관련 작업이 필요한 곳에는 안정된 JDBC 인터페이스를 사용한 것이다.


http://en.wikipedia.org/wiki/GRASP_(object-oriented_design)
http://scottlee.tistory.com/13
http://blog.naver.com/eatist/10013301919
http://davidhayden.com/blog/dave/archive/2005/03/27/895.aspx
신고

이 글을 Twitter / Facebook 에 공유하기
이 글이 유익하다면 아래의 트위터 버튼을 눌러 공유해 주시거나, 페이스북 "좋아요" 버튼을 눌러 주세요.

   


Posted by 반더빌트
TAG GRASP, OOD, RDD


티스토리 툴바