Extremely Agile/UML2007.10.29 11:01
I. 컴포넌트와 클래스 라이브러리

컴포넌트가 인터페이스를 갖도록 다이어그램을 그리는 것은 간단합니다만, 그것을 실제로 구현하는 것은 조금 어렵습니다. 컴포넌트는 잘 구현하면 그야말로 컴포넌트가 되지만, 제대로 구현하지 못하면 컴포넌트인지 클래스 라이브러리인지 알수가 없는 지경이 되거든요.

짐작하시겠습니다만 컴포넌트와 클래스 라이브러리는 많이 다릅니다. 클래스 라이브러리는 그 라이브러리를 쓰는 쪽에서 deploy의 방법을 결정하는 반면, 컴포넌트는 이미 고정되어 있는 상태라는 것이죠. 클래스 라이브러리의 경우에는 쓰는 쪽에서 어떻게 쓰느냐에 따라서 그 인스턴스들이 어떻게 만들어지고 이용되는지가 굉장히 달라질 가능성이 있습니다만, 컴포넌트의 경우에는 그 컴포넌트 단위로 배치가 이루어지기 때문에 컴포넌트 안에 속한 객체들이 만들어지고 이용되는 과정이 정형적입니다. 그리고 대부분의 경우, 컴포넌트 내부에서 무슨 일이 벌어지고 있는지는 클라이언트 코드 쪽에서는 전혀 알 필요가 없지요.


II. 인터페이스의 구현

그런데 어떤 코드 집합이 컴포넌트가 될 것인지 아니면 클래스 라이브러리가 될 것인지를 결정짓는 가장 핵심적인 요소는 무엇일까요? 제 생각에, 그것은 그 인터페이스를 어떻게 구현할 것이냐, 하는 문제인 것 같습니다. 다음과 같이 설계된 컴포넌트가 있다고 칩시다.

 component.JPG

이 컴포넌트가 외부에 제공해야 하는 인터페이스는 Request Admission Interface 하나뿐입니다. (앞선 글에서도 언급했었습니다만, 이 인터페이스는 반드시 하나의 Java Interface로 구현될 필요는 없습니다. 필요하다면 여러 개의 인터페이스로 구성될 수 있지요.) 예제 구성을 편하게 하기 위해, 우선은 이 인터페이스가 단 하나의 Java Interface 'RequestAdmissionInterface'로 구현된다고 치겠습니다. 그리고 이 인터페이스를  RequestrAdmissionInterfaceImpl 클래스로 구현했다고 해 보죠. 이렇게 구현된 인터페이스를 클라이언트 코드 안에서 다음과 같이 사용해야 한다면 어떨까요?

RquestAdmissionInterface o = new RequestAdmissionInterfaceImpl(); 
o.foo(); 

클라이언트 코드 안에서 RequesutAdmissionInterface의 구현에 사용된 클래스의 이름에 대해서 알아야 하는데, 그렇게 되면 클라이언트 코드 안에 불필요한 종속성이 발생하게 됩니다. 이런 종류의 종속성은 클래스 라이브러리를 사용할 때에는 흔히 발생하는 일입니다. (List 인터페이스를 구현하는 Concrete List 클래스들을 사용하는 경우들을 생각해보시기 바랍니다.) 위의 코드는 RequestAdmissionInterfaceImpl 이외의 다른 Implementation 클래스를 사용해야 하는 경우 반드시 변경되어야 합니다. (물론 new 를 해 주는 부분의 코드만 변경되면 충분하겠지만 말입니다.) 그러니, 저린 식의 사용방법을 강제하는 컴포넌트는 '그다지 컴포넌트 스럽지 않은' 컴포넌트라고 할 수도 있겠습니다. 컴포넌트를 사용하는 사람은 컴포넌트의 내부구조가 어떻게 변경되느냐에 무관하게 클라이언트 코드를 작성할 수 있어야 하기 때문이죠.

그렇다면 '단순히 인터페이스 클래스들을 만든 다음 그 인터페이스들을 구현하는 것 만으로는' 컴포넌트가 가져야 하는 요건을 충족하는 코드를 작성할 수 없겠군요. 그렇다면 이 문제를 해결하기 위해 참고할만한 기존의 사례는 없나요?

있습니다. RMI쪽이 그 대표적인 사례이죠. RMI는 외부에서 참조할 인터페이스를 구현하는 클래스에 의해 생성된 객체를 모종의 Repository에 등록하게 한 다음, 필요한 순간에 그 객체에 대한 레퍼런스를 가져와서 쓰도록 강제합니다. 이런 구현 방법의 장점은 '아무도 어떤 인터페이스의 실제 구현에 대해서는 알 필요가 없다'는 것이고, 단점은 '해당 인터페이스를 쓰려면 언제나 중앙의 repository를 한 번은 거쳐야 한다'는 것입니다. 물론 이 단점은 단점이라고 보기에는 좀 사소하죠. repository 개념 덕분에, RMI는 그 단순성을 네트워크-wide 하게 확장해 나갈 수 있었으니까요.

그렇다면, 우리도 RMI와 비슷하게 인터페이스 repository 객체를 만든 다음에 나중에 특정한 컴포넌트의 인터페이스가 필요할 때는 거기서 레퍼런스를 가져와서 쓰도록 하면 될 것 같군요. 어차피 컴포넌트는 deploy가 되는 순간에 그 컴포넌트를 대표하는 객체가 생성되어 있다고 봐도 좋을테니, 레퍼런스를 가져오는 것에 큰 문제는 없어 보입니다.

물론 중앙에 repository를 두는 것이 맘에 안 들 수도 있습니다. 그럴 경우에는 어떻게 해야 하나요? 컴포넌트의 외피를 적절한 클래스에 의해 모델링 한 다음, 그 클래스에 인터페이스 객체의 레퍼런스를 가져오기 위한 메소드를 구현하는 것을 생각할 수 있습니다.  

class DecisionSupportComponent {
   ...
   RequestAdmissionInterface getRequestAdmissionInterface() {
      ... 
   }
   ...
}

이렇게 하면 DecisionSupportComponent 객체를 사용하는 쪽에서는 인터페이스의 구현이 어떤 클래스에 의해 만들어지는지는 알 수가 없겠습니다. 그 코드는 getRequestAdmissionInterface() 함수 안에만 있을 테니까요. 모든 컴포넌트들이 이런 표준적인 메커니즘에 의해 인터페이스 레퍼런스를 제공하도록 만들고 싶은 경우도 있을텐데, 그렇게 할 경우 모든 인터페이스 클래스들이 또 다른 인터페이스 클래스를 상위 클래스로 가져야 한다는 문제가 있어 솔루션이 지나치게 복잡해 질 수 있습니다. 그러니 그건 그냥 패스하도록 하죠.


이 글은 스프링노트에서 작성되었습니다.

신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

Extremely Agile/UML2007.10.27 00:19

I. UML 컴포넌트

UML 컴포넌트 다이어그램을 구성하는 하나의 컴포넌트는 컴포넌트와 거기에 붙은 여러개의 인터페이스로 그릴 수 있습니다. 인터페이스는 provided interface와 required interface의 두 종류로 나뉘는데, 전자는 그 컴포넌트가 제공하는 인터페이스이고, 후자는 다른 컴포넌트가 제공하는 인터페이스를 사용한다는 의미입니다. 그러니까 어떤 컴포넌트 입장에서 봤을 때 제일 중요한 인터페이스는 provided 인터페이스인 셈입니다. 컴포넌트 다이어그램을 그리는 사람 입장에서도 그렇습니다. 그 다이어그램을 그리는 사람은 어떤 인터페이스가 어떤 컴포넌트에 속해야 하는지가 가장 뚜렷이 드러나도록 다이어그램을 그리려고 할 테니 말이죠.

사용자 삽입 이미지
 

이렇게 달랑 컴포넌트 하나만 놓고 설명하는 건 좀 심심하니까, 이번에는 컴포넌트가 여러개 등장하는 컴포넌트 다이어그램을 보도록 하겠습니다. 보시다시피 컴포넌트의 인터페이스 간에는 의존성 관계가 있습니다. 그 방향은 언제나 일정하죠. provided interface 쪽으로 화살표가 가게 되어 있습니다. (뭐 당연한 일이겠죠?)

컴포넌트 다이어그램

컴포넌트 다이어그램 - 누르면 커집니다



II. UML 컴포넌트의 인터페이스

그런에 위의 그림을 잘 보면, 인터페이스의 이름이 마치 자바 클래스나 자바 인터페이스의 이름과 비슷하게 만들어져 있다는 것을 보실 수 있을 겁니다. 그렇다면 저 동그라미 하나는 하나의 자바 인터페이스에 대응되어야 하나요?

흔히 컴포넌트 인터페이스를 정의할 때, 그 인터페이스가 가지는 역할을 중심으로 인터페이스 이름을 결정합니다. 해당 인터페이스를 호출하면 해당 컴포넌트가 어떤 종류의 역할을 수행하게 되는지를 중심으로 인터페이스 이름을 결정한다, 뭐 그렇게 생각해도 되겠죠.

그런데 문제는 그런 식으로 정해진 인터페이스가 꼭 자바 인터페이스 하나에 대응되는 것은 아닐 수도 있다는 것이죠. 자바의 인터페이스/클래스를 어떻게 나눌 것이냐 하는 문제는 단순히 '역할'이라는 하나의 관점만 사용해서는 풀기가 좀 힘듭니다. "UML, 실전에서는 이것만 쓴다"라는 책의 클래스 다이어그램 부분을 읽어보면 짐작할 수 있는 사항입니다만,  클래스들을 나눌 때에는 "의존도를 최소화해야"하고 "변경을 국지화해야 한다"는 등의 원칙들이 강하게 작용하거든요. 그러니 위의 그림에서 볼 수 있는 RequestAdmissionInterface 같은 것은 사실 그 인터페이스를 사용하는 외부 컴포넌트가 두 개 이상일 경우에는 역시 두 개 이상의 자바 인터페이스에 의해 모델링 될 수가 있습니다. 그렇다면 이렇게 정리하면 되겠군요.

하나의 컴포넌트 인터페이스는 하나 이상의 자바 인터페이스에 대응될 수 있다 



이 말이 어쩐지 좀 이상하게 들린다는 분들은 Enterprise Architect같은 UML 툴을 한 번 써 보시기 바랍니다. 실제로 저 동그라미 하나에 하나 이상의 자바 인터페이스 (혹은 C++ Abstract 클래스) 에 대한 '링크'를 만들어 넣을 수가 있습니다.

이런 관점은 애자일 적으로 봐도 유효합니다. 컴포넌트 다이어그램을 그리는 단계에서는 컴포넌트 안에 무슨 클래스들이 만들어질지 모르는 경우가 허다한데, 인터페이스 클래스의 이름까지 고정적으로 붙여버린다는 것은 솔직히 너무한 일 아니겠어요?

그렇게 본다면 위의 컴포넌트 다이어그램에서 RequestAdmissionInterface같은 이름은 어쩐지 이상하군요. 꼭 자바 인터페이스 같은 뉘앙스를 풍기니 말이죠. 그냥 Request Admission Interface같이 띄어쓰기를 해 주는 편이 더 낫겠어요.


참고문헌

"UML, 실전에서는 이것만 쓴다" (인사이트)

이 글은 스프링노트에서 작성되었습니다.


신고
Posted by 이병준

소중한 의견, 감사합니다. ^^