라이브러리
프로그래밍언어, 각종코드, 관련동향, 논문 등의 저장소
Technology/UML·모델링 (9)
UML의 기초: Unified Modeling Language 소개

UML의 기초: Unified Modeling Language 소개

 

20세기 말을 되돌아보며 --
정확히 1997년 Object Management Group (OMG)이 Unified Modeling Language (UML)을 발표했다. UML의 목표 중 하나는 개발 커뮤니티에 안정적이고, 일반적인 디자인 언어를 제공하는 것이었다. UML은 IT 전문가들이 수년 동안 바라던 통합된 표준 모델링 표기법을 탄생시켰다. UML을 사용하여 IT 전문가들은 시스템 구조와 디자인 계획을 읽고 분산시킬 수 있다. 건축가들이 빌딩의 청사진을 사용하는 것처럼 말이다.

이제 21세기가 되었고 UML은 전문성을 확립하게 되었다. 내가 보고 있는 이력서의 75 퍼센트 정도가 UML을 알고 있다고 쓰여있다. 하지만 면접을 통해 이야기를 해보면 이들이 진정으로 UML을 알지 못하고 있다는 것이 명확해진다. 일반적으로 당시 이슈가 되는 키워드 로서 알고 있거나 표면적인 면만 알고 있는 경우가 대부분이었다. 이것이 바로 내가 이 글을 쓴 이유이다. 이 글을 다 읽었다고 해서 이력서에 UML을 충분히 알고 있다고 쓸 수는 없겠지만, 이 언어를 보다 심도 깊게 연구할 출발선에는 설 정도는 된 것이다.

 

 

배경 지식

 

UML은 컴퓨터 애플리케이션을 모델링 할 수 있는 통합 언어이다. 주요 작성자들은 Jim Rumbaugh, Ivar Jacobson, Grady Booch이고 이들은 원래 그들만의 꽤 괜찮은 방식(OMT, OOSE, Booch)을 갖고 있었다. 결국 이들은 힘을 합쳤고 개방형 표준을 만들었다. (어디서 많이 들어본 소리인가?

 

J2EE, SOAP, Linux도 비슷한 현상이다.) UML이 표준 모델링 언어가 된 한 가지 이유는 이것이 프로그래밍 언어에 독립적이라는데 있다. (IBM Rational의 UML 모델링 툴은 .NET 뿐만 아니라 J2EE에서도 사용된다.) 또한 UML 표기법 세트는 언어이지 방법론이 아니다. 언어인 것이 중요한 이유는 방법론과는 반대로 언어는 기업이 비즈니스를 수행하는 방식에 잘 맞는다.

 

UML은 방법론이 아니기 때문에 (IBM Rational Unified Process lingo의 "객체(artifacts)" 같은) 어떤 형식적인 작업 생성물들이 필요 없다. 하지만 정해진 방법론 안에서 쓰이면, 애플리케이션을 개발할 때 애플리케이션을 쉽게 이해할 수 있도록 도와주는 여러 가지 유형의 다이어그램을 제공한다.

 

이 다이어그램은 현재 사용하고 있는 것의 언어와 원리를 잘 소개하고 있다. 사용중인 방법론에서 생긴 작업 생산품들에 표준 UML 다이어그램을 배치하여 UML에 능숙한 사람들이 프로젝트에 쉽게 참여하여 생산성을 높일 수 있도록 한다. 가장 유용한 표준 UML 다이어그램은 사용 케이스 다이어그램, 클래스 다이어그램, 시퀀스 다이어그램, 스테이트 차트 다이어그램, 액티비티 다이어그램, 컴포넌트 다이어그램, 전개 다이어그램 등이 있다.

 

각 유형의 다이어그램을 자세히 설명하지는 않겠다. 대신, 각 다이어그램에 대한 일반적인 개념을 소개하고 자세한 것은 나중에 다루도록 하겠다.

 

 

사용 케이스 다이어그램

 

사용 케이스는 시스템에서 제공한 기능 단위를 설명한다. 사용 케이스 다이어그램의 주요 목적은, 다른 사용 케이스들 간 관계 뿐만 아니라 주요 프로세스에 대한 "액터(actors)" (시스템과 인터랙팅하는 사람)들과의 관계를 포함하여, 개발 팀들이 시스템의 기능적 요구 사항들을 시각화 하는 데 있다. 사용 케이스 다이어그램은 사용 케이스 그룹들을 보여준다.

 

완전한 시스템에 대한 모든 사용 케이스이거나 관련된 기능을 가진 특정 사용 케이스 그룹(예를 들어, 보안 관리에 관련된 사용 케이스 그룹)의 사용 케이스일 수도 있다. 사용 케이스 다이어그램에 대한 사용 케이스를 보여주려면 다이어그램 중간에 타원을 그려서, 타원의 중앙 또는 아래에 사용 케이스 이름을 적어놓는다. 사용 케이스 다이어그램에 액터(시스템 사용자)를 그리려면 다이어그램의 왼쪽이나 오른쪽에 사람 모양을 그려 넣는다. (얼마나 예쁘게 그리는가는 여러분에게 달려있다.) 액터와 사용 케이스들간 관계는 그림 1에 나타나있다.

 

사용자 삽입 이미지

 

 

사용 케이스 다이어그램은 시스템의 고급 기능과 시스템의 범위를 설명하는데 사용된다. 그림 1의 사용 케이스 다이어그램을 통해, 시스템이 제공하는 기능을 쉽게 표현할 수 있다. 이러한 시스템에서는 밴드 매니저가 밴드가 발매한 CD에 대한 판매 통계 리포트와 Billboard 200 보고서를 볼 수 있다. 또한 레코드 매니저는 특정 CD에 대한 판매 통계 보고서와 Billboard 200 보고서를 볼 수 있다. 이 다이어그램에서는 Billboard Reporting Service라고 하는 외부 시스템에서 우리 시스템이 Billboard 리포트를 전달하고 있다는 것도 볼 수 있다.

 

또한, 이 다이어그램에 사용 케이스가 없다는 것은 시스템이 수행하지 않은 일을 보여주고 있는 것이다. 예를 들어, 이 다이어그램은 밴드 매니저가 Billboard 200의 다른 앨범들에 수록된 노래를 듣는 방식은 나와있지 않다. Billboard 200에서 Listen to Songs 라는 사용 케이스에 대한 어떤 레퍼런스도 볼 수 없다. 이것은 중요한 포인트이다. 그와 같은 다이어그램에 제공된 명확하고 간단한 사용 케이스 설명을 통해 프로젝트 스폰서는 시스템에 필요한 기능이 존재하는지 여부를 쉽게 볼 수 있는 것이다.

 

 

클래스 다이어그램

 

클래스 다이어그램은 다른 엔터티들(사람, 제품, 데이터)이 서로 어떻게 관계를 맺고 있는지를 보여준다. 다시 말해서, 이것은 시스템의 정적 구조라고 할 수 있다. 클래스 다이어그램은 록밴드, 씨디, 라디오 연주를 논리적 클래스로 나타내는데 사용될 수 있다. 또는 대출, 주택 저당 대출, 자동차 대출, 이자율을 나타내는데도 쓰일 수 있겠다. 클래스 다이어그램은 주로 프로그래머들이 다루는 구현 클래스들을 보여주는데 쓰인다. 구현 클래스 다이어그램은 논리적 클래스 다이어그램과 같은 클래스를 보여준다. 하지만 이 구현 클래스 다이어그램은 같은 애트리뷰트로는 그릴 수 없다. Vectors와 HashMaps 같은 것에 대한 레퍼런스를 갖고 있기 때문이다.

 

그림 2에서는 세 개의 섹션으로 클래스 다이어그램을 설명하고 있다. 위 섹션은 클래스의 이름을, 중간 섹션은 클래스의 애트리뷰트를, 가장 아래 섹션은 클래스의 연산(“그림 2에서는 세 개의 섹션으로 클래스 다이어그램을 설명하고 있다. 위 섹션은 클래스의 이름을, 중간 섹션은 클래스의 애트리뷰트를, 가장 아래 섹션은 클래스의 연산 ("메소드")을 보여주고 있다.

 

사용자 삽입 이미지

 

내 경험으로는 거의 모든 개발자들은 이 다이어그램이 무엇을 하고 있는지를 안다. 하지만 대부분의 프로그래머들은 관계도를 잘못 그리고 있다. 그림 3과 같은 클래스 다이어그램의 경우 상속 관계를 그릴 때에는 화살표 방향을 위로 향하게 하여 수퍼 클래스를 지시하게 하면서 화살표 모양은 완벽한 삼각형이 되도록 해야 한다. 상관 관계는 두 클래스들이 서로를 인식하고 있다면 일직선이 되어야 하고, 클래스의 한 편만 알고 있는 관계라면 화살표 표시가 되어있는 선을 그어야 한다.

 

사용자 삽입 이미지

 

그림 3에서, 상속 관계와 두 개의 상관 관계를 보았다. CDSalesReport 클래스는 Report 클래스에서 상속을 받고, CDSalesReport는 한 개의 CD와 관련이 되어 있지만, CD 클래스는 CDSalesReport에 대해 아무것도 모르고 있다. CD와 Band 클래스는 서로에 대해 알고 있고, 두 클래스는 서로 연관되어 있다.

 

클래스 다이어그램에는 이 보다 더 많은 개념들을 적용할 수 있다. 나중에 설명하도록 하겠다.

 

 

시퀀스 다이어그램

 

시퀀스 다이어그램은 특정 사용 케이스에 대한 상세한 흐름이나 심지어는 특정 사용 케이스의 일부분 까지도 보여준다. 대부분이 설명을 포함하고 있다. 시퀀스에서 다른 객체들 간의 호출관계를 보여주고 있고, 다른 객체들로의 다른 호출까지 상세하게 보여줄 수 있다.

 

시퀀스 다이어그램은 2차원으로 그려진다. 수직 차원은 발생 시간 순서로 메시지/호출 시퀀스를 보여주고 있다. 수평 차원은 메시지가 전송되는 객체 인스턴스를 나타내고 있다.

 

시퀀스 다이어그램은 그리기가 매우 간단하다. 다이어그램의 상단에 각 클래스 인스턴스를 박스 안에 놓아 클래스 인스턴스(객체)를 구분한다. (그림 4) 박스 안에 클래스 인스턴스 이름과 클래스 이름을 스페이스/콜론/스페이스 " : "로 분리시킨다. (예, myReportGenerator : ReportGenerator) 클래스 인스턴스가 메시지를 또 다른 클래스 인스턴스로 보내면 클래스 인스턴스를 받는 곳을 가리키는 화살표를 긋는다. 그 라인 위에 메시지/메소드 이름을 적는다. 중요한 메시지의 경우는 원래의 클래스 인스턴스를 다시 향하도록 점선 화살표를 그릴 수 있다. 점선 위에 리턴 값을 라벨링한다. 개인적으로는 리턴 값을 포함하곤 하는데 상세한 부분을 읽기 쉽기 때문이다.

 

시퀀스 다이어그램을 읽기는 매우 간단하다. 시퀀스를 시작하는 "드라이버(driver)" 클래스 인스턴스가 있는 왼쪽 상단 코너부터 시작한다. 그런 다음, 다이어그램 아래쪽을 각 메시지를 따라간다. 그림 4의 시퀀스 다이어그램 예제에서 전송 메시지에 대한 리턴 메시지는 선택적인 것임을 기억하라.

 

사용자 삽입 이미지

 

그림 4의 시퀀스 다이어그램을 읽다 보면 CD Sales Report가 어떻게 만들어지는지를 알 수 있다. aServlet 객체가 우리의 드라이버 예제이다. aServlet은 메시지를 gen이라고 하는 ReportGenerator 클래스 인스턴스로 보낸다. 이 메시지는 generateCDSalesReport 라는 라벨링이 붙는다.

 

ReportGenerator 객체가 이 메시지 핸들러를 구현한다는 의미이다. 자세히 보면, generateCDSalesReport 메시지 라벨은 괄호 안에 cdId가 있다. gen 인스턴스가 generateCDSalesReport 메시지를 받으면 CDSalesReport로 연속 호출을 하고 aCDReport 라고 하는 CDSalesReport의 실제 인스턴스가 리턴 된다. gen 인스턴스는 리턴된 aCDReport 인스턴스에 호출하면서 여기에 각 메시지 호출에 대한 매개변수를 전달한다. 시퀀스의 끝에서 gen 인스턴스는 콜러였던 aServlet에 aCDReport를 리턴한다.

 

그림 4의 시퀀스 다이어그램은 전형적인 시퀀스 다이어그램을 상세히 설명한 것이다. 하지만 충분히 이해할 수 있을 것이다. 또한 초보 개발자들에게는 각 레벨 마다 시퀀스를 끊어서 이해하는 것도 좋은 방법이다.

 

 

스테이트 차트 다이어그램

 

스테이트 차트 다이어그램은 클래스가 개입된 다양한 상태(state)를 모델링 하고 그 클래스가 상태간 어떻게 이동하는지를 모델링 한다. 모든 클래스는 상태를 갖고 있지만 각각의 클래스가 스테이트 차트 다이어그램을 가질 수 없다. "중요한" 상태, 말하자면 시스템 작동 중 세 개 이상의 잠재적 상태가 있는 클래스일 경우만 모델링 되어야 한다.

 

그림 5에서 보듯, 스테이트챠트 다이어그램에는 다섯 개의 기본 엘리먼트들이 사용된다. 시작점(짙은 원), 스테이트 간 이동(화살표), 스테이트(모서리가 둥근 직사각형), 결정 포인트(속이 비어있는 원), 한 개 이상의 종료점(원 내부에 짙은 원이 그려져 있음)이 바로 그것이다. 스테이트챠트 다이어그램을 그리려면 시작점과 클래스의 초기 상태를 향하는 화살표로 시작한다. 다이어그램 어디에나 이 스테이트를 그릴 수 있고 스테이트 이동 라인을 사용하여 연결한다.

 

사용자 삽입 이미지

 

그림 5의 스테이트 차트 다이어그램은 중요한 정보를 보여주고 있다. 예를 들어, 대출 프로세스가 Loan Application 상태에서 출발한다고 말할 수 있다. 결과에 따라 사전 승인 프로세스가 완료되면 Loan Pre-approved 상태나 Loan Rejected 상태로 옮겨간다. 이동하는 동안 내린 결정은 결정 포인트로 보여진다. 이동 라인 상의 비어있는 원이 바로 그것이다. 이 예제를 보면 Loan Closing 상태를 거치지 않고는 대출이 Loan Pre-Approved 상태에서 Loan in Maintenance 상태로 갈 수 없음을 알 수 있다. 또한, 모든 대출이 Loan Rejected 상태 또는 Loan in Maintenance 상태에서 끝난다는 것도 알 수 있다.

 

 

액티비티 다이어그램

 

액티비티 다이어그램은 액티비티를 처리하는 동안 두 개 이상의 클래스 객체들 간 제어 흐름을 보여준다. 액티비티 다이어그램은 비즈니스 단위 레벨에서 상위 레벨의 비즈니스 프로세스를 모델링 하거나 저수준 내부 클래스 액션을 모델링 하는데 사용된다. 내가 경험한 바로는 액티비티 다이어그램은 기업이 현재 어떻게 비즈니스를 수행하는지, 또는 어떤 것이 비즈니스에 어떤 작용을 하는지 등의 고차원 프로세스를 모델링 할 때 가장 적합하다. 액티비티 다이어그램은 언뜻 보기에 시퀀스 다이어그램 보다는 덜 기술적이기 때문에 비즈니스 마인드를 가진 사람들이 빠르게 이해할 수 있다.

 

액티비티 다이어그램의 표기법은 스테이트 차트 다이어그램과 비슷하다. 스테이트 차트 다이어그램과 마찬가지로 액티비티 다이어그램은 초기 액티비티에 연결된 실선으로 된 원에서 시작한다. 이 액티비티는 모서리가 둥근 직사각형을 그려 그 안에 액티비티 이름을 적어 넣으면서 모델링 된다. 액티비티들은 이동 라인을 통해 다른 액티비티들에 연결되거나 결정 포인트의 조건에 제약을 받는 다른 액티비티들에 연결하는 결정 포인트로 연결될 수 있다. 모델링 된 프로세스를 종료하는 액티비티는 (스테이트 차트 다이어그램에서처럼) 종료 포인트에 연결된다. 이 액티비티들은 수영 레인으로 그룹핑 될 수 있다. 이것은 실제로 액티비티를 수행하는 객체를 나타내는데 사용된다. (그림 6)

 

사용자 삽입 이미지

 

그림 5의 스테이트 차트 다이어그램은 중요한 정보를 보여주고 있다. 예를 들어, 대출 프로세스가 Loan Application 상태에서 출발한다고 말할 수 있다. 결과에 따라 사전 승인 프로세스가 완료되면 Loan Pre-approved 상태나 Loan Rejected 상태로 옮겨간다. 이동하는 동안 내린 결정은 결정 포인트로 보여진다. 이동 라인 상의 비어있는 원이 바로 그것이다. 이 예제를 보면 Loan Closing 상태를 거치지 않고는 대출이 Loan Pre-Approved 상태에서 Loan in Maintenance 상태로 갈 수 없음을 알 수 있다. 또한, 모든 대출이 Loan Rejected 상태 또는 Loan in Maintenance 상태에서 끝난다는 것도 알 수 있다.

 

액티비티 다이어그램 예제는 두 개의 객체(밴드 매니저와 리포팅 툴)에 의한 액티비티 제어를 나타내는 두 개의 수영 레인으로 되어있다. 프로세스는 한 밴드에 대한 판매 리포트를 보는 밴드 매니저로 시작한다. 리포팅 툴은 사람이 관리하는 모든 밴드들을 검색하여 디스플레이하고 이중 한 개를 고를 것을 요청한다. 밴드 매니저가 한 밴드를 선택하면 리포팅 툴은 판매 정보를 검색하여 판매 리포트를 디스플레이 한다.

 

 

컴포넌트 다이어그램

 

컴포넌트 다이어그램은 시스템을 물리적으로 볼 수 있도록 한다. 이것의 목적은 소프트웨어가 시스템의 다른 소프트웨어 컴포넌트들(예를 들어, 소프트웨어 라이브러리)에 대해 소프트웨어가 갖고 있는 종속 관계를 보여주는 것이다. 이 다이어그램은 매우 고급 레벨에서 볼 수 있거나 컴포넌트 패키지 레벨에서 볼 수 있다. 주 2

 

컴포넌트 다이어그램의 모델링은 이 예제에 잘 설명되어 있다. 그림 7은 네 개의 컴포넌트인 Reporting Tool, Billboard Service, Servlet 2.2 API, JDBC API를 보여주고 있다. Reporting Tool에서 출발하여 Billboard Service, Servlet 2.2 API, JDBC API로 가는 화살표는 Reporting Tool이 이들 세 개의 컴포넌트에 종속되어 있음을 나타낸다.

 

사용자 삽입 이미지

 

 

전개 다이어그램

 

전개 다이어그램은 하드웨어 환경에 시스템이 물리적으로 어떻게 전개되는지를 보여준다. 목적은 시스템의 다양한 컴포넌트들이 어디에서 실행되고 서로 어떻게 통신하는지를 보여주는 것이다. 다이어그램이 물리적 런타임을 모델링 하기 때문에 시스템 사용자는 이 다이어그램을 신중하게 사용해야 한다.

 

전개 다이어그램의 표기법에는 컴포넌트 다이어그램에서 사용되던 표기법 요소들이 포함된다. 이외에 노드 개념을 포함하여 두 가지 정도 추가되었다. 노드는 물리적 머신 또는 가상 머신 노드(메인프레임 노드)를 표현한다. 노드를 모델링 하려면 3차원 큐브를 그려 큐브 상단에 노드 이름을 적는다. 시퀀스 다이어그램에서 사용되던 네이밍 규칙([instance name] : [instance type]) (예, "w3reporting.myco.com : Application Server").

 

사용자 삽입 이미지

 

 

그림 8의 전개 다이어그램은 사용자가 로컬 머신에서 실행되고 기업의 인트라넷에서 HTTP를 통해 Reporting Tool에 연결되는 브라우저를 사용하여 Reporting Tool에 접근하는 것을 보여주고 있다. 이 툴은 물리적으로 w3reporting.myco.com 이라고 하는 Application Server에서 실행된다. 이 다이어그램은 IBM WebSphere 내부에서 그려진 Reporting Tool 컴포넌트를 보여준다. 이것은 결과적으로 node w3.reporting.myco.com에서 그려지게 되어있다. Reporting Tool은 자바를 사용하여 리포팅 데이터베이스를 IBM DB2의 JDBC 인터페이스에 연결하여 원시 DB2 통신을 사용하는 db1.myco.com 서버상에서 실행되는 실제 DB2 데이터베이스와 통신한다. 리포팅 데이터베이스와 통신하는 것 외에도 Report Tool 컴포넌트는 SOAP over HTTPS를 통해 Billboard Service와 통신한다.

 

 

결론

 

이 글은 Unified Modeling Language에 대한 간단한 입문서에 불과하지만 여러분이 이 정보를 실제 프로젝트에 적용하거나 더 깊게 UML을 연구하기를 바란다. UML 다이어그램을 소프트웨어 개발 프로세스에 통합시키는 여러 소프트웨어 툴이 있지만, 자동화된 툴이 없더라도 화이트보드에 마커와 펜을 사용하여 UML 다이어그램을 그려도 좋다.

 

참고자료

http://www.uml.org/
http://www.rational.com/uml/resources/documentation/index.jsp
http://www-140.ibm.com/developerworks/rational/products/rose
http://www-140.ibm.com/developerworks/rational/products/xde
http://argouml.tigris.org/
http://uml.sourceforge.net/index.php
PDF 로 보기

 

 

작성자 : Donald Bel(IBM)

작성일 : 06/04/06

출   처 :http://www.dbguide.net/know/know102001.jsp?mode=view&pg=1&idx=2959

 

사용자 삽입 이미지

 

원   문 : 한국IBM

신고
0  Comments,   0  Trackbacks
댓글 쓰기
[객체지향 SW 설계의 원칙] ③ 인터페이스 분리의 원칙

[객체지향 SW 설계의 원칙] ③ 인터페이스 분리의 원칙

 

연재순서
1회.
다시 보면 크게 보이는 개방-폐쇄 원칙
2히.헤어져서 행복해진 사례연구, 단일 책임 원칙
3회.인터페이스 분리의 원칙
4회. 리스코프 치환 원칙
5회. 의존 관계 역전의 원칙
6회. 정리

 

“사람은 다른 사람과 말을 할 때 듣는 사람의 경험에 맞추어 말해야만 한다. 예를 들어 목수와 이야기할 때는 목수가 사용하는 언어를 사용해야 한다.” - 플라톤의 파에톤(Phaethon)

“아무도 듣는 사람이 없는 숲 속에서 나무가 쓰러질 때 소리가 나는가?”라는 불가에서 유래한 질문이 있다. 그간 많은 현자들이 이 질문에 대해 ‘아니다’라는 일관된 대답을 해왔다. 소리는 지각되어야만 소리가 되기 때문에 나무가 쓰러질 때 음파는 발생하겠지만 듣는 사람이 없다면 소리는 없다는 것이다. 사람 사이의 커뮤니케이션도 마찬가지이다. 전달하려는 사람이 무언가를 외친다고 해도 듣는 사람이 없다면 커뮤니케이션은 없는 것이다.

만약 듣는 사람은 있지만 발신자가 수신자의 경험, 지식, 기대를 고려하지 않고 떠들어 대는 것은 어떨까? 이 역시 올바른 커뮤니케이션이라 할 수 없을 것이다. 수신자가 커뮤니케이션 메시지를 제대로 이해 또는 지각하지 못하거나, 기대와 어긋나 의식적으로 혹은 무의식적으로 메시지를 흘려버릴 가능성이 크기 때문이다. 그러므로 플라톤의 말대로 수신자의 경험, 역량 그리고 기대를 고려해 메시지를 전달해야만 제대로 된 커뮤니케이션이 될 수 있다.

맥킨지 일본 지사의 커뮤니케이션 스페셜리스트로 근무하고 있는 테루야 하나코는 좀 더 구체적으로 다음과 같이 이야기한다. “타인에게 무언가를 전하려고 할 때는 자신이 이야기하고 싶은 것을 어떻게 정리할까, 어떻게 말할까, 어떻게 쓸까를 생각하기 전에 반드시 과제(테마)와 상대방이 기대하는 반응을 확인하자.”

이 글을 읽고 있는 누구나 자신이 말하고 싶은 메시지를 더욱 잘 전달하기 위해 보고서를 몇 번씩 고치고 파워포인트의 디자인과 컬러에 공을 들여 본 경험이 있을 것이다. 그런데 혹시 이러한 노력이 과제 혹은 테마에 대해 자신이 말하고 싶은 것, 자신이 중요하다고 생각하는 것을 전달하기 위한 것은 아니었는지. ‘여러분’이 말하고 싶은 것, ‘여러분’이 중요하다 생각하는 것보다 더욱 중요한 것이 있다. 상대방이 전달받기를 기대하고 있는 ‘메시지’가 무엇이냐 하는 것이다.

여러분이 아무리 많은 준비를 했고, 많은 데이터를 축적했고, 하고 싶은 말이 많더라도 이러한 내용은 상대방의 기대라는 필터를 통해 여과되어 전달되어야 한다. 그렇지 않고 준비한 자료가 아까워서 이것저것 모두 전달하는 것은 수신자에게는 일종의 고역이다. 물론 준비한 노력과 자료 중 일부를 버려야 하겠지만 일부를 버리고 효과적으로 메시지를 전달하는 것이 모든 자료를 끌어 앉은 채 메시지를 허공 속으로 흘려보내는 것보다 훨씬 현명한 선택일 것이다.

객체지향 시스템은 메시지를 통해 커뮤니케이션하는 수많은 객체들로 구성된다. 그리고 이들 객체 간의 통신에도 앞에서 언급한 커뮤니케이션의 논리가 그대로 적용된다. 즉 상대방이 기대하고 있는 메시지를 ‘군더더기 없이’ 전달해야 하듯 서비스를 제공하는 객체는 자신을 이용하는 객체에게 해당 객체가 기대하는 서비스만을 제공해야 한다는 것이다. 이번 호에서 살펴볼 인터페이스 분리의 원칙(Interface Segregation Principle, 이하 ISP)이 바로 이러한 원칙을 설명해 준다.

인터페이스 분리의 원칙 개요
요즘 복제폰으로 인한 불법 결제가 사회적인 문제가 되고 있다. 특정 사용자의 폰 정보를 복제해 온라인상에서 불법 결제를 하는 것이다. 불법 결제자는 실물을 구매하거나 현금으로 환금 가능한 온라인 화폐 등을 결제하는데, 요금은 실제 폰 사용자에게 과금된다. 그래서 휴대폰 결제 서비스를 제공하는 모 업체에서는 이런 복제폰 사용자들의 패턴을 찾아 차단하고자 한다. 불법 결제 차단 시스템은 자사의 결제 시스템을 이용하는 각 컨텐츠 프로바이더(CP, Contents Provider) 별로 룰을 설정해 불법 결제 패턴에 해당하는 사용자의 결제를 차단하고, 이에 대해 회사 내부 담당자와 컨텐츠 프로바이더 담당자에게 특정 시간에 메일로 리포팅을 하게 된다. 이를 위해 이 회사의 개발자 A군은 다음과 같은 구조의 프로그램을 만들었다.

사용자 삽입 이미지
<그림 1> 초기의 불법 결제 차단 시스템


그런데 만약 이메일 리포팅 외에 SMS를 통한 리포팅 기능도 구현해 달라는 요청이 들어왔다면 어떻게 해야 할까? SMS와 관련된 메쏘드를 추가하거나, 현재의 이메일 관련 메쏘드를 SMS 관련 메쏘드와 통합해 getReportingRule과 같은 메쏘드를 만들어야 할 것이다.

그런데 이러한 메쏘드 추가는 이와는 전혀 상관 없는 BlockTransaction 클래스에게까지 영향을 미치게 되고, BlockTransaction 클래스의 재컴파일, 재배포 등과 똑같은 문제를 야기한다.

왜 이런 문제가 발생했을까? 원인은 BlockTransaction과 EmailReporting과 같은 클래스가 CPRule이 제공하는 서비스 중 일부만을 사용하는데 있다. CPRule 입장에서는 BlockRule과 EmailRule 모두를 갖는 것이 응집력 있는 구성이지만 BlockTransaction의 입장에서 보면 getEmailRule()은 필요없는 서비스이다. 역시 EmailReporting의 입장에서는 getBlockRule()이 필요없는 서비스라 할 수 있다. 즉 CPRule이 자신을 이용하는 클라이언트의 입장을 고려하지 않고 클라이언트에게 자기가 하고 싶은 말을 다 하고 있는 것이다. 현재는 CPRule을 이용하려면 모든 서비스를 이용하는 방법 밖에는 없다.

ISP를 통해 이런 문제를 해결할 수 있다. ISP를 간단히 정의하면 “클라이언트는 자신이 사용하지 않는 메쏘드에 의존 관계를 맺으면 안된다”는 것이다. 그런데 어떻게 자신이 사용하지 않는 메쏘드에 의존 관계를 맺지 않게 할 수 있을까? 답은 인터페이스를 사용하는 것이다. 이에 따라 앞의 프로그램 구조를 바꾸어 보면 다음과 같다.

사용자 삽입 이미지
<그림 2> ISP를 적용해 리팩토링한 불법 결제 차단 시스템


CPRule은 CPBlockRule과 CPEmailRule이라는 두 개의 인터페이스를 구현한다. 그리고 BlockTransaction과 EmailReporting은 CPRule을 직접 이용하지 않고 각각 자신의 기대에 맞는 인터페이스를 통해 CPRule이 제공하는 서비스를 이용할 수 있게 된다.

이제 SMS 관련 기능을 기존 이메일 기능과 통합해 제공하든, 별도로 제공하든 결제 차단 클래스는 전혀 변화의 영향을 받지 않게 된다. 결제 차단 규칙이라는 인터페이스가 이러한 변화의 방벽 역할을 해주기 때문이다. 그리고 SMS 기능을 이메일과 별도로 추가한다면 기존의 이메일 리포팅 역시 변화의 영향을 받지 않는다(이메일 기능과 SMS 기능을 통합할지 말지는 둘 사이에 얼마나 공통성과 유사성이 있느냐에 따라 달라지게 될 것이다).

ISP를 ‘하나의 일반적인 인터페이스보다는, 여러 개의 구체적인 인터페이스가 낫다’라고도 정의할 수 있다. 만약 어떤 클래스를 이용하는 클라이언트가 여러 개 있고, 이들이 해당 클래스의 특정 부분집합만을 이용한다면 이들을 따로 인터페이스로 빼내어 클라이언트가 기대하는 메시지만을 전달할 수 있도록 하는 것이다.

첫 연재에서 보았던 OCP에서는 ‘확장’이 핵심이었고 잘 정의된 공통의 인터페이스를 통해 수정에는 ‘닫고’ 확장에는 ‘열려 있는’ 구조를 만들었다. SRP에서는 ‘변화’가 핵심이었고 각 클래스가 하나의 책임만을 갖도록 하여 변화가 다른 클래스로 미치지 않도록 하는 구조를 가능케 하였다. 그러면 ISP의 핵심은 무엇일까? SRP와 마찬가지로 ‘변화’가 관전의 포인트가 된다. ISP는 뒤에서 설명하는 ‘ISP vs. SRP’에서 설명하듯이 어떤 클래스 혹은 인터페이스가 여러 책임 혹은 역할을 가질 수 있다는 것을 인정한다. 이러한 경우 ISP가 사용되는데 SRP가 클래스 분리를 통해 변화에의 적응성을 획득하는 반면, ISP에서는 인터페이스 분리를 통해 같은 목표에 도달하게 된다. 이제 전형적인 ISP 구조와 케이스 스터디로 넘어가기로 하자.

전형적인 ISP 구조
<그림 3>을 보면 Service 인터페이스는 3개 군의 메쏘드 집합을 제공하며 각 클라이언트는 이들 중 일부만 사용하고 있다. 그림과 같은 경우에는 Service 인터페이스의 어느 하나가 바뀌면 세 클라이언트 모두를 재컴파일, 재배포해줘야 한다.

사용자 삽입 이미지
<그림 3> ISP를 적용하기 전의 전형적인 구조


이제 <그림 3>에서 Service가 제공하는 메쏘드를 클라이언트가 사용하는 기준별로 그룹핑한다. 그리고 각 클라이언트는 자신의 기대에 부응하는 인터페이스만을 이용하게 된다. 이와 같이 인터페이스를 분리하면 한 클라이언트에서의 변화가 다른 쪽으로 확산되지 않는다.

사용자 삽입 이미지
<그림 4> ISP를 적용한 후의 전형적인 구조


자바 스윙이 제공하는 JTable 클래스는 이와 같은 ISP의 좋은 예제가 된다. JTable 클래스에는 굉장히 많은 메쏘드들이 있다. 컬럼을 추가하고 셀 에디터 리스너를 부착하는 등 여러 역할이 하나의 클래스 안에 혼재되어 있지만 JTable의 입장에서 본다면 모두 제공해야 하는 역할이다. JTable은 ISP가 제안하는 방식으로 모든 인터페이스 분리를 통해 특정 역할만을 이용할 수 있도록 해준다.

즉 Accessible, CellEditorListener, ListSelectionListener, Scrollable, TableColumnModelListener, TableMoldelListener 등 여러 인터페이스 구현을 통해 서비스를 제공하는 것이다. JTable은 자신을 이용하여 테이블을 만드는 객체, 즉 모든 서비스를 필요로 하는 객체에게는 기능의 전부를 노출시키지만, 이벤트 처리와 관련해서는 여러 리스너 인터페이스를 통해 해당 기능만을 노출시키고 있다.

수준에 따른 EAI 인터페이스
소프트웨어의 일반적인 목적은 업무를 자동화하고 인력을 시스템으로 대체화시키는 것이다. 이를 통해 새로운 비즈니스가 만들어지기도 하고 인간의 업무영역이 줄어들기도 한다. 지난 IT의 역사는 기업에서 사람이 행하던 업무를 전산화하여 업무의 효율을 극대화시키는 것이었다. 여러 가지 기술의 도움으로 점차 기업 시스템의 전산화가 차지하는 비율은 확대되고 있다. 하지만 실제 기업 업무가 그렇듯, 대부분의 비즈니스는 하나의 부서, 하나의 기업에서 완결되는 것이 아니라 서로 유기적인 소통을 통해서 이루어진다.

또한 기존에 구현된 시스템과 새로 구축되는 시스템간의 의사소통도 만만치 않은 작업이다. Aberdeen Group(
http://www.aberdeen.com/) 보고서에 의하면 이런 시스템간의 통합 요구는 시간이 지날수록 많아지고 있다. 이런 요구사항에서 등장된 개념이 EAI(Enterprise Application Integration) 개념이다. 즉 EAI는 기업 내, 기업 간의 서로 다른 애플리케이션 인터페이스를 통합하기 위해 제안된 기술이다.

사용자 삽입 이미지
<그림 5> 통합이 무시된 기업 시스템과 EAI로 구축된 기업 시스템


우리는 흔히 ‘인터페이스’라고 하면 객체나 컴포넌트의 인터페이스를 떠올리곤 한다. 하지만 인터페이스는 여러 타입과 여러 방식이 사용될 수 있으며 수준에 따른 EAI 인터페이스를 소개하면서 인터페이스의 개념을 확장하려고 한다. 다음은 EAI에서 분류하는 애플리케이션 통합을 위한 (인터페이스의) 종류이다. 더불어 결합도와 확장성의 관점을 더해서 생각해 보는 것도 좋을 듯하다.

데이터 수준의 통합을 위한 인터페이스
두 개 이상의 애플리케이션이 서로 통합하기 위해서 가장 간단한 방법은 한곳에 데이터베이스를 두고 모든 애플리케이션이 데이터베이스를 통하여 정보를 주고받는 것이다. 한 애플리케이션이 데이터베이스에 정보를 저장하면 그 정보에 관심있어 하는 다른 애플리케이션들이 그 정보를 발견하여 그 정보에 대한 처리를 한다. 즉, 이 때 데이터베이스는 하나의 애플리케이션들이 정보를 교환하는 일종의 인터페이스가 된다. 이런 아키텍처 스타일을 공유 리파지토리 패턴이라고 한다.

하지만 (잘 일어나지 않지만) 데이터베이스의 스키마가 변경되거나 새로 테이블이 추가되어 데이터베이스가 복잡해진다면? 즉 인터페이스가 바뀌거나 확장되게 된다면? 모든 애플리케이션이 이 구조에 따라서 애플리케이션이 변경되어야 한다. 즉, 잘 분리, 디자인되지 못하고 확장이 용이하지 못한 인터페이스는 거대한 변경에 대한 비용이 발생하게 된다.

또한 기존의 테이블 구조가 사용하려는 애플리케이션이 원하는 구조를 만족하지 못했을 때 데이터베이스에서 원하는 특정 정보를 다른 데이터베이스로 이동(migration)시키거나 여러 개의 데이터베이스에 있는 정보들을 취합하게 된다. 즉, 불필요한 인터페이스의 복제, 재정립하는 비용이 발생하게 된다. 이를테면 학사행정 시스템에서 ‘학생’ 데이터베이스와 ‘임직원’이란 데이터베이스가 있을 때 이 두 데이터베이스의 정보를 취합하여 ‘예비군’이란 데이터베이스가 만들어져야 하는 경우가 이에 해당한다.

사용자 삽입 이미지
<그림 6> 데이터 수준의 통합을 위한 인터페이스


이 방법은 매우 단순하고 빠르게 시스템 통합을 구축할 수 있다. 하지만 결과적으로 여러 다른 애플리케이션이 통합되기 위해서 중앙에 데이터 수준의 통합을 위한 인터페이스를 두고 모든 애플리케이션이 이 인터페이스에 맞춰야 한다. 이로써 확인되는 한계는 하나의 인터페이스가 여러 목적의 애플리케이션과 일대 다의 관계를 가질 때 여러 애플리케이션간의 관계가 하나의 인터페이스로 강결합되어 확장이나 변경의 자유도가 매우 떨어지게 된다. 이것은 ISP의 핵심인 “클라이언트가 자신이 사용하지 않는 메쏘드에 의존하도록 강제되어서는 안된다”는 원리에 위배된다. 이 구조는 인터넷 기반에 여러 서비스를 제공해야 하는, 따라서 인터페이스가 유연해야 하는 현대 시스템 상황에 적절하지 않은 방법이다.

또한 이 구조에서 중요한 축이 되는 데이터베이스가 변경이 될 경우 모든 애플리케이션이 같이 변경해야 하는 거대한 리스크를 안고 있다. 그리고 데이터베이스는 여러 애플리케이션이 원하는 인터페이스를 구축해야 하기 때문에 테이블 (인터페이스) 설계가 복잡하고 난해하게 이루어져 결국 이해를 위해 높은 진입장벽을 만나게 된다.

애플리케이션 수준의 통합을 위한 인터페이스
데이터 수준의 통합을 위한 인터페이스의 단점이 여러모로 확인된바 데이터가 아닌 API 수준의 통합이 제안된다. 기존에 우리가 사용하던 라이브러리나 패키지를 사용자(다른 애플리케이션)에게 제공하여 인터페이스를 통해 연동을 구축한다. 단순하고 독립적이지 않은 서비스의 경우 라이브러리나 패키지 형태로 배포되어 컴파일 타임에 바인딩하여 사용할 수 있다.

하지만 독립적인 애플리케이션간의 연동은 두 개 이상의 프로세스가 서로 통신(Inter-Process Communication)을 해야 하는데 IPC 방식에서는 연동을 위한 프로토콜이 정의되어야 한다. 즉, 프로토콜은 애플리케이션 간에 연동을 위한 인터페이스 역할을 한다. 나아가서 요즘 애용되고 있는 XML 전송에서 XML 스키마가 프로토콜과 같은 맥락을 갖는다. 좋은 IPC 구조를 위해서 잘 정의된 프로토콜이 전제되어야 한다. 프로토콜이 복잡하고 장황할수록 연동을 위한 비용이 많이 든다. 즉, 인터페이스가 지저분하지 않을수록 효과적이고 연동비용이 적게 든다. 실제로 잘 정의된 프로토콜(인터페이스)은 그 프로토콜 안에 여러 인터페이스를 식별하기 쉬운 구조를 제공한다(프로토콜 내의 ISP). 가령 HTTP의 경우 GET, POST, HEAD… 등의 메시지 식별이 단순하도록 구성되어 있다.

사용자 삽입 이미지
<그림 7> 애플리케이션 수준의 통합을 위한 인터페이스


세련된 인터페이스를 제공하는 기술이 RPC(Remote Procedure Call) 기술이다. RPC는 애플리케이션이 실제 함수 호출하듯 원격지에 있는 함수의 시그니처를 모방한 프록시를 두어, 그 프록시를 통해 원격 함수 호출을 제공한다. IPC 방식에서 RPC 방식으로 전환은 진화라 할 만큼 획기적이다. 프로토콜을 이용한 연동방식에서 원격 함수 호출을 이용한 호출방식으로 전환됐기 때문이다. 이것은 의미적으로 인터페이스를 더욱 단순하고 분리하기 쉽게 사용하도록 유도하고 있다.

비즈니스 로직 수준의 통합을 위한 인터페이스

애플리케이션 수준의 인터페이스와 비즈니스 로직 수준의 통합을 위한 인터페이스의 근본적인 차이점은 인터페이스의 형태가 일반 함수 수준에서 비즈니스 수준의 인터페이스를 제공한다는 것이다. 가령 전자의 경우 ‘복사’, ‘저장’, ‘~접근자’ 수준의 인터페이스를 제공하는데 반해 비즈니스의 경우 ‘입고’, ‘이체’, ‘결제’ 수준으로 인터페이스가 비즈니스화 되었다.

즉, 비즈니스 인터페이스는 분리된 객체 인터페이스의 묶음으로 해석할 수도 있다. 따라서 인터페이스가 큰 분류로 정의됨에 따라 복잡하던 인터페이스간의 관계가 단순하게 이루어진다. 객체 관계에 비교해 볼 때 컴포넌트 관계가 상대적으로 매우 단순하게 이뤄지는 이유가 여기에 있다. 정리하자면 비즈니스 인터페이스는 비즈니스 목적에 의해서 복잡한 객체 인터페이스를 구분하여 분류한 Facade (GoF의 Facade 패턴 참조) 역할을 한다.

사용자 삽입 이미지
<그림 8> 비즈니스 수준의 통합을 위한 인터페이스


이때부터 연동을 위해 본격적으로 CORBA, COM, EJB와 같은 기술들이 사용된다. 비즈니스 인터페이스를 통해 얻을 수 있는 이점은 비즈니스의 공유하여 재사용하기 위한 목적이다. 여기서 읽을 수 있는 현상은 잘 분리된 인터페이스는 재사용도가 높아진다는데 있다. 각 언어에서 제공하는 API는 근본적으로 재사용을 전제하기 때문에 인터페이스를 관찰해 보면 엄격하게 ISP 원칙을 지키고 있음을 볼 수 있다.

유저 인터페이스 수준의 통합을 위한 인터페이스
EAI에서의 유토피아는 모든 애플리케이션의 인터페이스를 접근하는데 있어서 마치 사람이 접근하듯이 접근하는 방법이다. 가령 엑셀에 연동하기 위해서 마치 사람이 엑셀을 다루는 것 같이 애플리케이션이 엑셀에 이벤트를 발생하여 연동하는 방식이다. 또 다른 예는 웹 서비스에 마치 사람이 웹 브라우저를 조작하여 문서를 요청하는 것 같이 애플리케이션이 HTTP 리퀘스트를 던져 결과를 얻어오는 것이다.

유저 인터페이스 수준의 통합을 위한 인터페이스는 이렇게 사람이 스크린을 통해 애플리케이션을 사용하듯 애플리케이션간의 연동이 이루어지는 방식을 말한다. 이런 요청을 스크린 카탈로그라 하며 이런 요청 방식을 스크린 스크래핑(screen scrapping)이라고 한다. <그림 9>는 애플리케이션이 여러 장의 스크린 카탈로그를 만들어 타겟 애플리케이션에 연동하는 장면이다.

사용자 삽입 이미지
<그림 9> 유저 인터페이스 수준의 통합을 위한 인터페이스


EAI 인터페이스 타입에서 본 바와 같이 컴포넌트의 확장성을 높이기 위해 결합도를 낮춰야 한다. 그렇기 위해 컴포넌트간의 관계에서 잘 분리된 인터페이스를 구성하여 관계를 단순화 하는 노력이 필요하다. 이 단순화된 관계는 컴포넌트간의 응집성을 향상시킨다.

인터페이스 분리 방법
SRP(지난 호 참조)에서 부분적으로 언급한 바와 같이 서로 목적이 다른 클라이언트가 하나의 인터페이스를 접근하고 있다면 그 인터페이스는 분리되어야 마땅하다. 왜냐하면 다른 클라이언트에 의해 나와 무관한 인터페이스가 변경됐을 때 그 변경으로 인해 내가 사용하는 인터페이스가 변경될 수 있기 때문이다. 따라서 서로 다른 종류의 클라이언트들이 하나의 인터페이스에 접근한다면 그 클라이언트의 종류만큼 인터페이스는 분리되어야 한다.

다시 처음에 예시한 <그림 1> 초기의 불법 결제 차단 시스템의 예제를 보자. CPRule 클래스의 getBlockRules(), getEmailRule()는 서로 성격이 다른 클라이언트에 의해 접근되고 있다. getBlockRules()는 Block Transactoin 클래스에 의해서 getEmailRule()은 Email Reporting 클래스에 의해서 사용된다. 인터페이스를 사용하는 클라이언트가 명백히 분리된다는 것은 인터페이스가 그 클라이언트의 개수만큼 다른 서비스를 제공한다는 의미이다. 하지만 애초에 이 여러 개의 인터페이스가 같이 있다는 것은 나름대로의 ‘공유, 연관되는 무엇인가’가 있다는 것이다.

그렇다면 공유, 연관되는 부분은 그대로 두되 효과적으로 인터페이스를 분리하는 방법이 필요하다. 여기서 몇 가지 규칙이 필요하다. ① 기 구현된 클라이언트의 변경을 주지 말아야 할 것 ② 두 개 이상의 인터페이스가 공유하는 부분의 재사용을 극대화할 것 ③ 서로 다른 성격의 인터페이스를 명백히 분리할 것 등이다. 분리 방법은 클래스 인터페이스를 통한 분리와 객체 인터페이스를 통한 분리를 이용할 수 있다.

클래스 인터페이스를 통한 분리
다중 인터페이스를 분리하는 방법으로 클래스의 다중 상속을 이용하여 인터페이스를 나눌 수 있다. <그림 10>에서와 같이 ‘결제 차단’에 관련한 인터페이스를 제공하는 getBlockRules()를 포함하는 BlockRule 인터페이스와 이메일 처리를 전담하며 getEmailRule()을 구현하는 EmailRule 인터페이스로 분리하여 인터페이스를 정의할 수 있다. 하지만 분리된 두 인터페이스는 상술하여 제시한 첫 번째 원칙인 ‘기 구현된 클라이언트의 변경을 주지 말아야’ 하는 조건을 만족해야 한다. 즉, 클라이언트 클래스는 기존의 인터페이스를 그대로 유지하여 변경없이 접근할 수 있어야 한다. 이런 조건을 만족하기 위해서 EmailRule과 BlockRule 클래스를 다중상속하는 CPRule이 정의될 수 있다.

사용자 삽입 이미지
<그림 10> 다중 상속을 이용한 클래스 인터페이스로의 통한 분리


이와 같은 구조는 Block Transaction, Email Reporting 클라이언트 모두에게 변화의 영향을 주지 않을 뿐 아니라 인터페이스를 분리하는 효과를 갖는다. 하지만 거의 모든 객체지향 언어에서는 상속을 이용한 확장은 상속받는 클래스의 성격을 디자인 시점에서 규정해 버리는 특징이 있다. 따라서 CPRule 클래스는 Block Transaction 인터페이스와 Email Reporting 인터페이스를 상속받는 순간 이 두 인터페이스에 예속되어 제공하는 서비스의 성격이 제한된다.

객체 인터페이스를 통한 분리
다른 방법으로는 위임(delegation)을 이용한 방법이 있다. 이 방법은 CPRule의 필드로 Rule이란 객체를 갖는다. Rule 객체는 인터페이스인데 BlockRule과 EmailRule이 각각의 서비스에 맞는 rule() 메쏘드를 구현한다. 이런 상황에서 Block Transaction 클라이언트는 getBlockRule() 메쏘드를 통해 BlockRule 클래스의 rule() 메쏘드를 호출한다. Email Reporting의 경우도 마찬가지로 동작한다. 즉 위임을 이용해서 getBlockRule(), getEmailRule() 메쏘드는 멤버변수 rule 객체의 rule() 메쏘드를 호출하게 된다.

위임을 이용한 객체의 인터페이스 분리는 Rule이란 객체를 확장한 어떤 구현도 대체될 수 있다. 만약 암호화된 EmailRule이 필요하다면 Rule 인터페이스를 구현하는 암호화된 SecuredEmailRule이라는 클래스를 정의하여 CPRule의 rule 필드에 꼽아주면 확장이 용이하다.

사용자 삽입 이미지
<그림 11> 위임을 이용한 객체 인터페이스로의 분리


위임을 이용한 확장과 상속을 이용한 확장은 똑같이 인터페이스를 분리하는 기능을 하지만 서비스 결정권의 차이가 있다. 대부분의 객체지향 언어에서 상속의 경우 컴파일 시점에서 부모의 구현을 차용하게 되고 부자간의 관계는 변경이 불가능하다(자식 클래스는 부모를 바꿀 수 없다). 반면, 위임을 이용한 관계는 런타임에 변경이 가능하다. 가령 일반 이메일 모드에서 암호화 이메일 모드로 역할이 변경될 경우 CPRule.rule 변수를 EmaileRule에서 SecuredEmailRule 객체로 바꿔주기만 하면 서비스의 변경이 동적으로 이뤄진다. 따라서 위임을 이용한 확장은 상속을 위한 확장보다 관계 설정의 변화가 상대적으로 유연하다.

다른 방식으로는 C++에서 템플릿을 이용한 확장 방법을 사용할 수 있다. 자바에서는 Generic 프로그래밍을 통해서 구현할 수 있는데 컴파일 시점(정확히 pre-processing 시점)에서 적용되는 클래스의 타입을 설정해줌으로써 확장성을 지원할 수 있다.

사실은 앞의 두 가지 분리 방법은 GoF의 Adapter 패턴에서 구현 방법 중 Class Adapter와 Object Adapter 구조를 그대로 차용한 방법이다. 하지만 정 반대의 목적을 갖는다. Adapter 패턴의 경우 기존의 구현된 인터페이스를 통해 클라이언트가 원하는 인터페이스로 개조하는 목적을 갖고 있지만 우리의 목적은 서로 다른 서비스를 하는 인터페이스를 분리하려는 목적이다. 하지만 목적과 해결 대상이 비꼈을 뿐이지 그 구조는 동일하다.

ISP vs. SRP
일반적으로 인터페이스와 역할은 1:1 관계를 갖는다. 하지만 인터페이스가 여러 역할을 갖는 경우도 있다. 이것은 컴포넌트의 크기에 따라 결정되게 되는데, 가령 ‘이체’라는 인터페이스는 "① 트랜잭션을 시작한다. ② 상대의 계좌 존재 여부를 확인한다 ③ 고객의 계좌에 원하는 금액을 출금한다 ④ 상대의 계좌에 입금한다 ⑤ 트랜잭션을 마친다"의 절차를 거친다. 여기에 참여하는 역할들은 서로 응집성이 결여된다.

하지만 특정 비즈니스 목적에 의해 하나의 처리 절차로 묶이면서 ‘이체’라는 인터페이스를 만족시킨다. 다시 말하자면, ‘이체’라는 인터페이스는 여러 역할의 묶음으로 구현된다(1:n 관계의 인터페이스와 역할). 이 때 ‘이체’ 인터페이스는 이런 역할의 묶음의 Facade가 된다. 앞에서 살펴본 JTable의 경우에도 테이블의 데이터 관리, 컬럼 관리, 렌더링 관리, 이벤트 관리라는 여러 역할이 JTable이라는 하나의 클래스 안에 혼재되어 있다.

반면 하나의 역할은 여러 인터페이스로 분해되기도 하는데 자바의 java.io.OutputStream 클래스는 데이터를 쓰는 write() 인터페이스를 갖고 있다. 똑같은 역할을 하지만 인터페이스가 다른 java.io.PrintWriter 클래스는 printXX() 류의 인터페이스로 그 역할을 세련되게 제공한다(1:n 관계의 역할과 인터페이스). 이처럼 인터페이스와 역할과의 관계는 상호의존성을 갖지만 꼭 같은 의미로 사용되지도 않는다. 따라서 ISP와 RSP를 구분할 때 역할과 인터페이스의 맥락은 명백히 다르게 규정하여 접근할 필요가 있다. 즉 SRP를 접근할 때와 ISP를 접근할 때의 접근법은 차이를 두어야 한다.

ISP를 지키지 않았을 때 발생할 수 있는 악취
앞에서 살펴본 바와 같이 규모가 큰 클래스에서만 ISP가 문제되는 것은 아니지만, ISP와 관련한 문제는 대부분 비대한 클래스로부터 발생하게 된다(JTable 클래스를 한번 보라). 비대한 클래스라는 악취는 Extract Class, Extract Subclass, Extract Interface와 같은 리팩토링 기법을 통해 해결하게 되는데 이중 Extract Class와 Extract Subclass는 SRP와 연관이 있고 Extract Interface가 ISP를 따라는 설계를 가능하게 해준다.

* Extract Interface :클라이언트가 클래스의 어느 특정 기능만을 이용한다면 이러한 기능의 부분 집합을 별도의 인터페이스를 통해 추출하라.

우리는 친구들에겐 친구가 되고, 부모님께는 자식이 되고, 사랑하는 사람에겐 연인이 된다. 같은 존재이건만 상대에 따라 우리의 역할은 다르다. 하지만 친구가 없다면 우린 친구가 될 수 없으며, 부모님이 계시지 않는다면 자식이 될 수 없고, 애인이 없다면 누군가의 연인이 될 수 없는 노릇이다. 우리의 상대에 대해 좀 더 관심과 애정을 기울이고 배려의 노력을 해야 하는 것은 아닐지.@

* 이 기사는 ZDNet Korea의 제휴매체인마이크로소프트웨어에 게재된 내용입니다.

 

최상훈 (핸디소프트), 송치형 (서울대)

2005/09/02

 

사용자 삽입 이미지
사용자 삽입 이미지

 

원문 : http://www.zdnet.co.kr/builder/dev/modeling/0,39031637,39139151,00.htm

 

신고
0  Comments,   0  Trackbacks
댓글 쓰기
[객체지향 SW 설계의 원칙] ② 사례연구, 단일 책임 원칙

[객체지향 SW 설계의 원칙] ② 사례연구, 단일 책임 원칙

- 헤어져서 행복해진 사례연구, 단일 책임 원칙

 

연재순서
1회.다시 보면 크게 보이는 개방-폐쇄 원칙
2히.헤어져서 행복해진 사례연구, 단일 책임 원칙
3회.인터페이스 분리의 원칙
4회. 리스코프 치환 원칙
5회. 의존 관계 역전의 원칙
6회. 정리

 

오래 전 질레트가 여러 분야로 사업을 다각화한 적이 있다. 자신의 경쟁력 있는 분야인 면도날, 면도기 사업을 벗어나 샴푸 등 일용품 사업에까지 뛰어든 것이다. 면도용품도 일용품이니 사업분야 간 시너지 효과가 있을 것이라는 판단이었던 듯하다.

하지만 실적은 나지 않았고 주가는 곤두박질쳤으며 결국은 많은 손실을 입은 채로 다각화한 사업분야를 정리해야만 했다. 현재는 면도용품 사업에 집중해서 세계 최고의 면도용품 회사라는 명성과 실적을 되찾게 되었다.

이처럼 많은 기업들이 위험을 분산시키고 실적을 향상시키기 위해서 다각화(diversification)를 한다. 하지만 많은 경우 다각화는 오히려 위험을 증가시키고 실적을 악화시킨다. 이를 들어 월 스트리트의 전설적인 투자가로 불리는 피터 린치(Peter Lynch)는 “다각화는 대부분 다악화(diworsfication)로 끝난다”고 충고한다. 실제 그는 자신의 포트폴리오에 다각화를 시도하는 기업은 가능한 배제하며, 경험상 이러한 결정을 후회한 적은 거의 없다고 자신 있게 말한다.

스탠포드의 짐 콜린스 교수는 피터 린치의 경험을 트럭 수십 대에 해당하는 자료를 분석한 결과로 지지해 준다. 그의 연구에 따르면 위대한 기업으로 도약한 기업들은 모두가 우직하게 한 우물을 팠다고 한다. 다음은 그가 "좋은 기업에서 위대한 기업으로"란 책에서 ‘예상치 못한 발견’이라 놀라며 서술한 내용이다.

“좋은 회사에서 위대한 회사로 도약한 기업들은 고슴도치 - ‘한 가지’만 알고 그것에 집중하는 단순하고 촌스러운 동물-에 가깝다. 비교 기업들은 여우 - 많은 것을 알지만 일관성이 결여된 꾀 많고 교활한 동물-에 가깝다.”

어떤 단일 조직이 여러 분야로 다각화하게 되면 조직 내에서 다른 목표를 추구하는 사람들 간의 이질감이 발생하고 또한 한 가지에 집중하지 못하고 힘이 흩어지기 때문에 다각화는 쉽사리 다악화로 변질된다. 소프트웨어 세계에서도 이와 비슷하게 다각화를 경계하라는 원리가 있다. 바로 하나의 클래스는 하나의 책임만을 가져야 한다는 ‘단일 책임 원칙(이하 SRP)’이다.

이번 글에서는 프로그램에서 객체가 가지는 책임이란 것이 무엇인지, 그리고 왜 객체가 단일 책임만 가지는 것이 좋은지를 살펴볼 것이다. 또한 현재 객체가 이미 여러 책임을 지니고 있는 여우 객체인 경우 나타날 수 있는 문제점(악취)과 이를 고슴도치 객체로 바꾸는 방법에 대해서도 논의해 본다.

단일 책임 원칙의 개요
다음은 국제 거래 은행에서 사용하는 ‘잔고’라는 클래스이다. 잔고 클래스는 다음과 같은 인터페이스를 갖는다. 이 클래스의 인터페이스는 직관적으로 단순하고 기능적으로 완결된 클래스일 수 있다. 하지만 만약 두 개의 서로 다른 애플리케이션이 잔고 클래스를 사용한다고 했을 때 이 두 사용자 클래스는 서로 다른 메쏘드를 이용하게 된다. 환율 조정 애플리케이션은 ‘환율 계산’ 메쏘드를 이용할 것이고 이율 관리 애플리케이션은 금액에 관한 인터페이스를 이용할 것이다.

하지만 이 각 애플리케이션이 각각 배포됐을 때 잔고 클래스는 정체성의 혼란이 생긴다. 왜냐하면 이율관리 애플리케이션에 배포될 때는 ‘환율 계산’ 메쏘드가 무용하게 되고 환율 조정 애플리케이션과 배포될 때는 금액에 관한 인터페이스가 소외되기 때문이다. 문제는 여기서 그치지 않는다. 만약 환율 계산 메쏘드의 시그니처가 변경될 경우 환율 계산을 요청하는 잔고 클래스의 다른 메쏘드들이 같이 변경되어야 한다. 간결하게 설계한 잔고 클래스는 확실히 문제를 내장하고 있었다.

사용자 삽입 이미지
<그림 1> 잔고 클래스


문제의 원흉은 무엇일까? 잔고 클래스는 사실은 두 가지 책임을 가지고 있다. 수리적 이율 연산을 담당하는 ‘환율 계산’의 책임과 금액에 관련한 처리를 담당하는 메쏘드들이 또 다른 책임이다. 또한 하나의 클래스 안에 필요에 의해 두 가지 책임이 공존할 때 서로의 의존관계는 심각하게 강결합되기 때문에 변경에 대한 충격이 전달될 수밖에 없다.

확실히 두 가지 책임을 담당해야 하는 한 클래스는 불편한 점이 많다. 지난 글에 소개한 OCP는 ‘확장’이 설계적 관전 포인트라면 단일 책임 원칙(Single Responsibility Principle : SRP)은 ‘변경’이 관전 포인트가 될 것이다. 이 ‘변경’의 거북함을 조장하는 요소는 서로 다른 ‘책임’이 혼재해 있다는데 있다.

SRP의 키워드는 책임으로 요약되는데, 그렇다면 책임이란 무엇일까? 책임이란 ‘변경을 위한 이유’이다. 만약 하나의 클래스에 변경을 위한 두 가지 이상의 이유가 있다면 그 클래스는 한 가지 이상의 책임을 갖고 있는 것이다. <그림 1>의 잔고 클래스는 변경의 내용이 두 가지로 요약된다. 금액과 환율이다. 즉, 잔고 클래스는 금액과 환율의 책임을 갖고 있다.

SRP는 하나의 클래스에 한 가지 책임을 가르치는 원칙이다. 우리는 설계 관점에서 우리가 인식하지 못하는 SRP 위반을 자주 하게 된다. 이 위반을 경계하기 위해 깊은 통찰력이 필요하지도 않다. 단지 머리에 ‘책임’이란 단어를 상기하는 습관이면 된다.

위반 사항에는 대가가 따른다. SRP를 위반할 경우 따르는 재앙은 첫 번째로 ‘왕따’가 발생한다는 것이다. 잔고 클래스가 이율 관리 애플리케이션과 배포됐을 때 확실히 ‘환율 계산’ 메쏘드는 소외된다. 즉 만약 A라는 책임과 B라는 책임을 갖고 있는 클래스가 있을 경우 A만 필요로 하는 애플리케이션은 항상 B를 들고 다녀야 한다.

문제는 여기서 그치지 않는다. 두 번째 재앙은 무관한 메쏘드에 변경이 발생할 경우 불필요한 변경 임팩트가 전달된다. 만약 ‘환율 계산’ 메쏘드가 변경됐을 경우 이율 관리 애플리케이션은 사용하지도 않는 ‘환율 계산’ 메쏘드 때문에 다시 컴파일해야 하고 리테스트해야 하며 재배포해야 한다. 이율 관리와 전혀 무관한데도 불구하고... 사실은 이 임팩트의 영향은 더 심각한데 다음의 케이스 스터디에서 살펴보겠다.

이미 구현된 소프트웨어에서 이 재앙들은 다시 (『리팩토링』에서 소개하는) 악취(bad smell)로 분류될 수 있다. 즉, 무관한 변경에 피해를 당한다든가 불필요한 요소가 따라다닐 경우 SRP를 적용해야 하는 빨간불(bad smell)로 생각해도 무방하다. 그렇다면 SRP는 어떤 구조를 제안하고 있을까?

마틴 파울러의 엔터프라이즈 패턴을 이용한 케이스 스터디
지금은 DB에 관한 여러 우수한 툴들이 제공되고 DB와 관련한 좋은 설계방식이 많이 제안되고 있다. 그래서 과거에 복잡하고 장황했던 DB 관련 코드들이 현재는 이런 툴과 기법을 통해 많이 단순화, 은닉되고 있지만 일반적으로 개발자가 간단하게 DB 관련 클래스를 설계할 때는 <그림 2>과 같은 방식을 사용한다.

사용자 삽입 이미지
<그림 2> 액티브 오브젝트 패턴


이 Person이란 클래스는 세 가지 필드를 가지고 있고 이 클래스의 행위를 처리하는 메쏘드(비즈니스 로직 메쏘드)와 DB를 접근하기 위한 CRUD(Create, Read, Update, Delete) 메쏘드를 가지고 있다. Person이란 객체가 비즈니스 로직 메쏘드에 의해 상태변화가 일어났을 경우 (필드가 CRUD 됐을 경우) 적절한 시점에서 DB에 그 변화된 값을 반영해야 하며 이때 DB 접근 메쏘드를 사용하게 된다.

이렇게 비즈니스 로직 메쏘드와 DB 처리 메쏘드를 분리하는 이유는 하나의 메쏘드에 비즈니스 로직 루틴과 DB 처리 루틴이 혼재하게 됐을 때 메쏘드의 처리 루틴의 복잡도가 2배 이상 증폭되기 때문이다. 만약 분리시키지 않았다면 자바의 경우 Connection, PreparedStatement, ResultSet 같은 JDBC 클래스들이 비즈니스 로직과 무관하게 전체 루틴 사이에 등장하게 된다. 또한 이런 루틴은 필연적이게도 루핑을 하며 ResultSet에서 레코드를 읽어 와서 어떤 처리를 한다든가 변수에 대입하는 루틴이 작성되게 된다.

하지만 이런 메쏘드는 DB 처리 루틴이 변할 때 비즈니스 코드를 변경해야 하며 그 역의 경우도 발생하게 된다. 즉 하나의 책임이 변할 때 역시 필연적이게도 다른 책임도 같이 변하게 된다. SRP 위반의 두 번째 재앙의 대표적인 사례가 이런 경우이다.

이런 경우를 이번 호의 언어로 풀이하자면 하나의 메쏘드에 두 가지의 책임(‘비즈니스 로직’과 ‘DB 로직’)이 같이 있었기 때문이며 이를 분리하여 관리하는 설계가 <그림 2>의 액티브 오브젝트 패턴이다. 액티브 오브젝트 패턴은 이렇게 DB관련 처리를 따로 메쏘드로 캡슐화하며 비즈니스 로직과 DB 메쏘드를 분리시킴으로써 깔끔한 설계와 효과적인 관리를 보장하는 장점을 갖는다.

액티브 오브젝트 패턴은 하나의 메쏘드에서 두 가지 책임을 분리시켰을 뿐이지 하나의 클래스에서 두 가지 책임을 분리시키지 못했다. 즉 <그림 2>의 Person 클래스에는 여전히 Person 객체에 대한 DB에 접근 책임과 Person의 비즈니스 로직 책임이 혼재되어 있다. 데이터 맵퍼 패턴은 이 두 책임을 분리시키는 구조를 제안하고 있다(<그림 3> 참조).

사용자 삽입 이미지
<그림 3> 데이터 멥퍼 패턴


사실 데이터 맵퍼 패턴은 우리가 흔히 DAO(Data Access Object)로 알고 있는 인터페이스로 실현화되어 익히 사용하고 있는 패턴이다. 흔히 『Core J2EE Patters』에서 소개된 ‘DAO 패턴’으로 DAO를 알게 된 자바 개발자는 DAO 개념이 J2EE에서 제안된 것으로 알고 있다. 하지만 DAO는 마이크로소프트에서 4GL 언어 아키텍처 작업 당시 객체단위 DB 접근 인터페이스로 제안한 DB 접근 객체 인터페이스다.

데이터 맵퍼는 클래스가 비즈니스 로직에 집중할 수 있도록 DB 접근 루틴을 데이터 맵퍼 클래스로 분리시킴으로써 액티브 오브젝트 패턴에서 필자가 제기했던 ‘한 지붕 두 책임’의 문제를 해결한다. 데이터 맵퍼 패턴을 따르면 객체와 데이터베이스, 맵퍼 간의 독립성이 유지되며, 객체와 DB 간에 데이터를 이동시키는 맵퍼 레이어를 제공받게 된다. 따라서 DB 테이블이 변하거나 DB 접근 루틴이 변한다 해도 Person 클래스는 변경의 충격에서 안전하다.

또한 데이터 맵퍼를 사용하면 Person 객체의 이용방식도 자연스럽게 DB 관련 부분과 Person 사용으로 분리된다. 즉 최초 DB에 저장된 Person 객체를 생성할 경우 PersonDAO에게 load를 요청해 DB에서 Person을 얻어오고, 사용자는 자연스럽게 Person 객체의 비즈니스 로직 부분만 집중하게 된다. 이 Person 객체를 변경하거나 삭제를 원할 경우 각각 PersonMapper를 통해 insert, update를 요청하여 DB 작업을 위임한다.

액티브 오브젝트 패턴의 경우 이 두 가지 책임에 관한 사용자의 작업이 명백히 분리되지 못했는데 데이터 맵퍼 패턴을 사용하므로 사용자의 Person 객체에 관한 책임을 사용하는 목적과 방법이 명확해진다(Person 객체의 인터페이스인지, DB 관련 작업인지).

이로써 액티브 오브젝트와 데이터 맵퍼 패턴으로 최초의 Person 클래스의 책임은 명확하게 분리될 수 있었다. 하지만 만약 Person 객체의 상태변화가 압도적으로 많아서 DB 접근이 빈번하게 이뤄지고 이 빈번한 DB 접근 비용으로 인해 성능장애가 올 경우를 상상해 보자. 우리는 이와 같은 경우 DB 접근 비용을 감소시키기 위해 일반적으로 맵퍼 레이어 뒤에 캐싱 레이어를 둔다. 즉 Person 클래스에게 또 하나의 ‘캐싱’이라는 책임이 더해진다.

가령 앞서 제기한 문제처럼 ‘boby’라는 Person 객체를 n번 load한다고 했을 때 기존 방식으로는 n번 DB에 SELECT해야 한다. 하지만 SELECT는 한번만으로도 족하다. 한번 load된 객체를 재사용한다면 DB 접근은 n-1번 생략할 수 있다.

문제는 이 캐시란 책임을 어디에 두느냐일 것이다. 액티브 오브젝트처럼 (같은 클래스의) 메쏘드 단위로 클래스 내에 분리시킬 것인가, 데이터 맵퍼처럼 클래스 단위로 서로 분리시킬 것인가, 아니면 더 큰 컴포넌트나 패키지로 분리할 것인가의 분리 단위 결정이 갈등요소가 된다.

여기서 설계자는 분리의 ‘크기(granularity)’를 고민한다. 작은 단위로 섬세하게 사용할 수 있는 미세단위(fine-grained)로 구분할 것인가, 아니면 단순하지만 입도가 큰(COARSE-GRAINED) 단위로 구분할 것인가에 대해서 말이다. 이 문제의 경우 애플리케이션에서 문제 영역이 각각 서로 다른 케이스 바이 케이스로 이루어지기 때문에 명백히 일관적으로 적용할 가이드라인을 제공하기 힘들다.

하지만 그 기준은 대상에 대한 복잡도, 크기, 용도가 된다. 복잡도가 높고 부피가 큰데 반해 그 용법이 단순하다면 COARSE-GRAINED가 적합하다. 역으로 복잡도가 낮고 부피가 작으며 용법이 다양하다면 fine-grained가 적합하다.

사용자 삽입 이미지
<그림 4> 식별자 맵 패턴


여하튼 이 경우 보통 식별자 맵 패턴이 사용되는데 식별자 맵은 DB를 통해 얻어온 객체를 캐시하는 맵이다(<그림 4>에서 식별자 맵은 클래스 크기로 분리하고 있다). 한번 load된 객체는 식별자 맵에 등록되고 두 번째 load 요청부터 DB에 SELECT할 필요 없이 식별자 맵에서 가져오면 된다.

사용자 삽입 이미지
높은 응집도, 낮은 결합도
사용자 삽입 이미지
 
사용자 삽입 이미지
‘높은 응집도, 낮은 결합도(High Cohesion, Loose Coupling)’의 원리는 1970년대 Larry Constantine과 Edward Yourdon이 정의했던 아주 고전적인 원리이다. 이것은 현재 모든 소프트웨어 시스템 고유의 유지보수성과 적응성을 측정하는 가장 좋은 방법으로 사용되고 있다. 소프트웨어 디자인뿐만 아니라 아키텍처 평가에도 이 원리가 기준이 되는데, 그 이유는 이 원리의 적용 효과가 아주 명백하기 때문이다.

이 원리의 예외는 거의 찾아보기 힘들만큼 보편성을 가지고 있어서 마치 물리학의 엔트로피 법칙처럼 절대적인 기반원리를 제시한다. 낮은 응집도를 갖는 구조는 변경이나, 확장 단계에서 많은 비용을 지불해야 하며 높은 결합도의 경우도 마찬가지이다.

응집도는 ‘하나의 클래스가 하나의 기능(책임)을 온전히 순도 높게 담당하고 있는 정도’를 의미하며 이들은 서로 조화될수록 그 구조는 단순해진다. 응집도가 높은 동네에서 내부 개체가 변했을 때 다른 개체에 충격을 주는 것은 오히려 당연한 징후이다. 이들은 하나의 책임아래 서로 유기적인 관계를 갖고 있기 때문에 내부 개체가 변했을 때 다른 개체의 변경 확률이 높아진다. 마치 예쁜 부츠를 사면 부츠에 어울리는 치마를 입어야 하듯이… 응집도의 종류는 다양한데 다음은 권장할 만한 순기능적 응집 관계들이다.

* 기능적 응집(Functional Cohesion)
일관된 기능들이 집합된 경우를 말하며 <그림 3>의 데이터 맵퍼는 DB 처리라는 기능 항목의 높은 응집성을 갖는다.
* 순차적 응집(Sequential Cohesion)
한 클래스 내에 등장하는 하나의 소작업(메쏘드)의 결과가 다음 소작업(메쏘드)의 입력으로 사용되는 관계(파이프라인 방식의 처리 체인 관계).
* 교환적 응집(Communicational Cohesion)
동일한 입력과 출력 자료를 제공하는 메쏘드들의 집합을 말하며, 팩토리 클래스는 전형적인 교환적 응집도가 높은 인터페이스를 갖는다.
* 절차적 응집(Procedural Cohesion)
순서적으로 처리되어야 하는 소작업(메쏘드)들이 그 순서에 의해 정렬되는 응집관계
* 시간적 응집(Temporal Cohesion)
시간의 흐름에 따라 작업 순서가 정렬되는 응집관계
* 논리적 응집(Logical Cohesion)
유사한 성격의 개체들이 모여 있을 경우를 말하며 java.io 클래스들의 경우가 대표적인 예이다.

이와 반해 결합도는 ‘클래스간의 서로 다른 책임들이 얽혀 있어서 상호의존도가 높은 정도’를 의미하며 이들이 조합될수록 코드를 보기가 괴로워진다. 이유는 서로 다른 책임이 산만하고 복잡하게 얽혀있기 때문에 가독성이 떨어지고 유지보수가 곤란해지기 때문이다. 이유는 필요 없는 의존성에 있다. 마치 키보드의 자판 하나가 고장나도 키보드 전체를 바꿔야 하는 것처럼. 하나의 변경이 엄청난 민폐를 야기하는 관계이다. 다음은 수용할 수 있는 수준의 결합 관계들이다.

* 자료 결합(Data Coupling)
두 개 이상의 클래스가 매개변수에 의해서 결합 관계를 가지므로 낮은 수준의 결합도로 연관되는 경우
* 스탬프 결합(Stamp Coupling)
자료 결합의 경우에서 매개변수 일부만을 사용하는 경우
* 제어 결합 (Control Coupling)
두 클래스간의 제어 이동이 매개변수를 이용하여 사용되는 경우로 커맨드 패턴이 대표적인 사례이다(지난 연재 기사 OCP 참조).
사용자 삽입 이미지
사용자 삽입 이미지

즉 순서는 ‘1. 우선 key에 해당하는 객체를 식별자 맵에서 찾는다( 1.1. 없다면 DB에서 얻어온다. 1.2. 식별자 맵에 등록한다). 2. 리턴한다’'의 절차를 밟는다. 마치 싱글톤 패턴처럼 한 번의 접근을 보장함으로써 DB 접근 비용을 감소시킨다.

이와 더불어 실제 엔터프라이즈 애플리케이션 설계 시 데이터 접근의 동기화, 동시성 처리, 풀링, O/R 맵핑 등의 ‘책임’들이 등장하게 되는데 이 각 책임들을 담당하는 클래스를 분리시키고 이들 간의 관계를 잘 정의할수록 복잡도는 감소하고 아키텍처는 깨끗해진다.

현재 제공되고 있는 DB 관련 프레임워크는 이 책임들을 맡는 기능을 구현한 녀석들이다. SRP의 효과가 바로 여기에 있다. SRP를 적용하면 무엇보다도 책임 영역이 확실해지기 때문에 한 책임의 변경에서 다른 책임의 변경으로의 연쇄작용에서 자유로울 수 있다.

하지만 무조건 책임을 분리한다고 SRP가 적용되는 건 아니다. 가령 데이터 맵퍼 클래스의 메쏘드들이 각각의 insert, delete, update, load 클래스로 분리됐을 경우를 생각해 보자. 마치 절차적 언어에서와 같은 함수 단위의 클래스가 될 것이다. 각 메쏘드 역할에 따른 책임들이 분리되었지만 설계는 장황해지고 관계는 복잡해진다. 하지만 이 문장은 틀린 문장이다. 동일한 책임을 갖는 여러 메쏘드들이 분리된 것이다. 즉 분리의 기준은 책임이며 분리의 목적은 복잡도 감소에 있다.

반면 각각 분리된 insert, delete, update, load 클래스들이 있다고 했을 때 이들은 한 책임아래 병합되어야 할 것이다. 왜냐하면 이들은 병합될수록 관계는 단순해지고 설계가 일목요연해지기 때문이다. 그렇다면 이 서로 상반된 관계, 즉 어떤 경우는 분리를 할수록 설계가 깨끗해지고, 반대로 어떤 경우는 병합을 할수록 설계가 깨끗해지는데 이 차이는 무엇일까?

각 개체 간의 응집력이 있다면 병합이 순작용의 수단이 되고 결합력이 있다면 분리가 순작용의 수단이 된다. 응집력이 있다는 것은 여러 개체가 같은 책임아래 있다는 것을 의미하며 결합력이 있다는 것은 한 개체가 여러 책임을 갖고 있다는 의미가 된다. 따라서 응집도는 높을수록, 결합도는 낮을수록 좋은 설계 품질을 보장받는다.

SRP 위반의 악취들
SRP는 하나의 객체가 하나의 책임, 즉 하나의 ‘변경의 이유’만 지니게 함으로써 설계를 단순하게 하고 변화에 기민하게 만들어 준다. 필자는 서두에 SRP 위반했을 때 재앙을 악취로도 소개했는데 이번에 소개할 악취들은 『리팩토링』에서 구체화된 악취들이다. SRP 위반의 악취는 ‘여러 원인에 의한 변경(divergent change)’와 ‘산탄총 수술(shotgun surgery)’을 들 수 있다.

여러 원인에 의한 변경
여러 원인에 의한 변경은 한 클래스를 여러 가지 다른 이유로 고칠 필요가 있을 때 발생한다. 즉, 하나의 클래스에 여러 책임이 혼재하고 있어서 하나의 책임의 변화가 다른 책임에게 영향을 준다. 그리고 이 책임이 두 개보다 훨씬 많은 여러 개로 혼재된다면 이 클래스는 심각한 고문관이 된다. 더욱이 이 구조는 더 괴로운 경우로 심화될 수 있다.

<그림 1>의 ‘잔고 클래스’에서 ‘환율 계산’이란 책임의 변화로 다른 금액 관련 책임들의 인터페이스까지 칼을 대야 할 상황에 이른다면 작은 ‘환율 계산’의 변경이 전혀 무관한 금액 관련 인터페이스를 이용하는 모든 사용자 클래스까지 변경해줘야 하는 것이다. 이런 위험 상황을 소개한 것이 ‘여러 원인에 의한 변경’이라는 나쁜 냄새이다.

‘여러 원인에 의한 변경’을 해결하는 방법은 경우에 따라 다르다. 다음은 여러 원인에 의한 변경을 해결하는 리팩토링 기법이다.


◆ Extract Class는 혼재된 각 책임을 각각의 개별 클래스로 분할하여 클래스 당 하나의 책임만을 맡도록 하는 것이다. 액티브 오브젝트 패턴에서 데이터 맵퍼 패턴으로의 진화가 대표적인 사례가 된다. 여기서 관건은 책임만 분리하는 것이 아니라 분리된 두 클래스간의 관계의 복잡도를 줄이도록 설계하는 것이다.

◆ 만약 Extract Class된 각각의 클래스들이 유사하고 비슷한 책임을 중복해서 갖고 있다면 Extract Superclass를 사용할 수 있다. Extract Class된 각각의 클래스들의 공유되는 요소를 부모 클래스로 정의하여 부모 클래스에 위임하는 기법이다. 따라서 각각의 Extract Class들의 유사한 책임들은 부모에게 명백히 위임하고 다른 책임들은 각자에게 정의할 수 있다.



사용자 삽입 이미지
여러 원인에 의한 변경
사용자 삽입 이미지
 
사용자 삽입 이미지
윤성준, 조재박 님이 번역하고 대청미디어에서 출간된 마틴 파울러의『리팩토링』 한국어판을 보면 여러 원인에 의한 변경(divergent change)이 ‘확산적 변경’이라 되어 있다. 하지만 확산적 변경이라 했을 때는 변경이 다른 클래스로 확산된다는 느낌이 강하고, 클래스가 여러 변경 원인에 의해 변경된다는 느낌이 언뜻 오지 않는다.

그래서 이번 글에서는 divergent를 수렴(convergent)에 대응하는 의미가 아닌 ‘다른’의 뜻으로 세기고 divergent change를 ‘여러 원인에 의한 변경’이라 하겠다. They hold divergent opinions on controversial issues like abortion(그들은 낙태와 같은 논란이 되는 이슈에 대해 서로 다른 의견을 주장했다)에서의 divergent 용례를 참고하면 될 듯하다. 흔히들 ‘확산적 변경’과 뒤에 소개할 ‘산탄총 수술’을 잘 구분하지 못하는데 ‘확산적 변경’을 ‘여러 원인에 의한 변경’으로 바꾸어 이해하면 이 둘의 구분이 조금 더 직관적으로 다가올 것이다.
사용자 삽입 이미지
사용자 삽입 이미지

산탄총 수술
산탄총을 발사하면 하나의 탄환이 부서지면서 여러 개의 탄환으로 확산되어 발사된다. 따라서 (상상하기도 싫지만) 산탄총을 맞은 대상의 총상은 온몸 전체에 퍼지게 된다. 만약 이런 환자를 수술하는 의사는 마치 수십 발의 총을 맞은 환자를 수술하는 것처럼 힘들 것이다.

‘산탄총 수술(shotgun surgery)’은 ‘여러 원인에 의한 변경’과 비슷한 듯 하면서도 정 반대의 내용을 갖는다. ‘여러 원인에 의한 변경’이 하나의 클래스가 여러 변경 원인(책임)을 지니는 반면, 산탄총 수술은 어떤 변경이 있을 때 여러 클래스를 수정해야 하는 증상이다. 즉 어떤 변경의 대상이 여러 곳에 분포되어 마치 산탄총 총상 환자를 수술해야 하는 것 같은 많은 노동비용이 따른다.

‘산탄총 수술’이 괴로운 이유는 단지 수술 부위가 많다는 것만이 아니다. 이 수술을 했음에도 불구하고 혹시 치료하지 못한 상처가 존재할 수 있다는 가능성이 ‘산탄총 수술’의 더 큰 위험성이다. 가령 하나의 테이블을 조작하는 DB 처리문이 애플리케이션 전역에 퍼져 있는 상황에서 DB 테이블의 구조가 바뀌게 됐을 경우에 발생하는 재앙과 같다. 수술도 고되지만 모든 환부를 찾아야 하는 집중력과 긴장감이 개발자를 더욱 힘들게 한다.

사용자 삽입 이미지
<그림 5> 산탄총 수술


산탄총 수술이란 악취는 하나의 책임이 여러 클래스에 분산되어 있기 때문에 발생한다. 한 클래스가 너무 많은 책임을 맡고 있어도 곤란하지만, 책임을 식별하지 못해 이를 담당할 클래스를 만들지 않고 여러 클래스에 흩뿌려 놓는 것 또한 문제가 있다. 이는 보통 프로그램의 전체 책임을 올바로 분담하지 못해서 발생하게 된다.

이 악취는 Move Field와 Move Method를 통해 책임을 기존의 어떤 클래스로 모으거나, 이럴만한 클래스가 없다면 새로운 클래스를 만들어 해결할 수 있다. 즉 산발적으로 여러 곳에 분포된 책임들을 한 곳에 모으면서 설계를 깨끗하게 한다. 즉 응집성을 높이는 작업이 필요하다.

산탄총 수술의 냄새는 특히 설정 정보(configuration information), 로깅(logging), DB 처리에서 발생하기 쉬운데 이들을 다룰 때는 항상 산탄총 수술의 악취를 경계해야 한다. 예를 들어 한 곳에서 관리할 필요가 있는 설정 정보를 여러 클래스에서 나누어 처리하고 있다면 이는 산탄총 수술을 할 수 있는 좋은 본보기가 된다.

이를테면 쓰레드, 커넥션, 오브젝트 풀의 크기 값이나 DB, 서버의 주소 정보들을 각각의 클래스에 자체적으로 관리하고 있다면 이들을 설정 파일이나 설정 관리자에게 Move Field하는 것이 바람직하다. 더 나아가 플러그인을 도입해 설정 정보를 통해 동적으로 행위 변화를 통제(Enable Configurable Behavior with Plugin)하는 것도 생각해 볼만하다. 또한 XML 처리나 프로토콜 해석을 담당하는 메쏘드가 여러 곳에 분포되었다면 각각의 유틸성 클래스로 Move Method하는 것이 바람직하다.

‘여러 원인에 의한 변경’과 ‘산탄총 수술’이란 악취를 SRP를 어긴 신호로 여기고 제거한다면 변경이 여러 곳으로 확산되지 않을 뿐 아니라 책임을 적절히 분배함으로 인해 코드의 가독성 향상, 유지보수 용이라는 이점까지 누릴 수 있다. 또한 적절한 책임 분배는 객체지향 원리들의 대전제 격인 OCP뿐 아니라 다른 원리들을 적용하는 기초가 되어준다.

사용자 삽입 이미지
핵심 리팩토링 기법과 책임 분배
사용자 삽입 이미지
 
사용자 삽입 이미지
리팩토링에서 소개하는 대부분의 냄새들(코멘트, 비대한 클래스에서 시작해 산탄총 수술까지)은 객체간의 책임 분배와 직간접적으로 관련이 있는데, 항상 코드를 최상으로 유지한다는 리팩토링의 근본 정신은 곧 항상 객체들의 책임을 최상의 상태로 분배한다는 것이기 때문이다. 그리고 다음의 리팩토링 기법들은 ‘객체들의 책임을 최상의 상태로 분배’하는 가장 기본이 된다.

Extract Class(6)

Move Method(6)

Extract Method(4)

Move Field(4)

이들은 가장 많은 냄새를 해결하는 리팩토링 기법들을 정리한 것으로 괄호 안의 숫자는 냄새를 해결하는 데 사용된 빈도수이다. 고급스럽고 우아한 고급 리팩토링 기법이나 빅 리팩토링 기법은 때때로 유용하지만, 이들은 항상 유용하다.

필자는 앞의 4개의 리스트에 ‘Rename *’를 추가하여 5개의 리팩토링 기법을 가장 단순하면서도 중요한 핵심 리팩토링 기법으로 여긴다. 파울러의 책에는 Rename Method만이 수록되어 있지만, Rename Class, Rename Field, Rename Parameter 역시 굉장히 자주 쓰이며 실제 이클립스의 리팩토링 기능을 보면 이 모두가 하나로 Rename이라 되어 있다. 그리고 경험에 비추어 보면 어느 리팩토링 기능보다도 Rename을 자주 사용하게 된다. 올바른 클래스 이름은 해당 클래스의 책임을 나타낼 수 있는 가장 좋은 방법이다.

코딩을 하면서 키보드 앞에 A4 용지를 놓고 수시로 CRC 카드, 클래스 다이어그램, 시퀀스 다이어그램을 간략히 그려보며 객체들 간의 책임을 점검해 보고, 리팩토링을 수행하는 것은 분명 좋은 SRP를 어기는 코드를 사전에 어느 정도 방지할 수 있는 좋은 대비책이 되어줄 것이다. 할 수만 있다면, ‘사후 대처’보다는 ‘사전 예방’이 더 좋은 해결책이지 않은가?
사용자 삽입 이미지
사용자 삽입 이미지


위대함보다 단순함은 없다
눈동자의 초점이 분산되면 난시가 되고 마음이나 정신의 초점이 정상을 상실하고 분산하는 상태가 지속되면 정신착란 혹은 정신 분열이 온다. 마찬가지로 클래스가 하나의 책임에 집중하지 못한 채 이것저것 두리번거리는 여우와 같고, 이러한 클래스들이 누적된다면 프로그램은 점점 유지보수, 변경에 대응하기 어려워진다. 어쩌면 ‘툭’하고 잘못 건드리면 정신착란이 올지도 모를 일이다.

소프트웨어는 항상 변경을 전제한다. 따라서 변경에 민감하게 반응하지 못하는 설계는 프로젝트를 힘들게 한다. “소프트웨어 설계에는 두 가지 방법이 있다. 한 가지는 분명히 결함이 없도록 단순하게 설계하는 것이고 다른 한 가지는 분명한 결함이 없도록 가능하면 복잡하게 설계하는 것이다"라는 명언이 있다.

SRP를 적용하면 클래스의 숫자가 늘 수는 있다. 하지만 클래스 숫자의 증가가 프로그램의 복잡도 증가와 비례하는 것은 아니다. 오히려 SRP를 잘 따르는 프로그램은 적절한 책임 분배로 인해 클래스 숫자와 프로그램의 복잡도가 반비례하는 경향이 있다고도 할 수 있게 된다.

위대함보다 단순함은 없다. 실제로 단순한 것이 위대한 것이다. 그리고 이 단순함의 중심에는 단일 책임의 원칙이 있다.@

* 이 기사는 ZDNet Korea의 제휴매체인마이크로소프트웨어에 게재된 내용입니다.

 

저자 :최상훈 (핸디소프트), 송치형 (서울대)

2005/04/25

 

사용자 삽입 이미지

 

원문 :http://www.zdnet.co.kr/techupdate/lecture/etc/0,39024989,39135552,00.htm

신고
0  Comments,   0  Trackbacks
댓글 쓰기
[UML 제대로 알기] ⑤ 표준 넘나드는 UML의「적절한 사용」

[UML 제대로 알기] ⑤ 표준 넘나드는 UML의「적절한 사용」

 

연재순서
1회.
가능성·확장성 품고 등장한 UML 2.0
2회.초보자를 위해 다각도로 살펴본 UML
3회.바로 알고 제대로 쓰는 UML 실전 모델링
4회.닷넷 환경에서 UML 툴 활용 가이드
5회.표준을 넘나드는 UML의 적절한 사용

 

UML은 표준 표기법으로써 그 자리를 확고히 했다. 이제는 한 걸음 더 나아가 UML을 보다 효과적으로 사용할 수 있는 방법을 생각해 볼 때이다.

음계를 이용하여 아름다운 음악을 작곡하듯이 UML을 이용하여 좋은 소프트웨어를 개발하는, 이른바 UML 사용의 베스트 프렉티스를 생각해야 한다. 간혹 베스트 프렉티스가 UML 표준을 준수하지 않는 경우도 있는데 중요한 것은 표준 준수 여부가 아니라 어느 것이 더 효과적이냐는 것이다. 성공적인 소프트웨어 개발을 위해서라면 표준을 넘나들 수도 있어야 한다.

이에 이번 글에는 유즈 케이스를 중심으로 UML을 잘 표현하기 위한 시맨틱을 제대로 정리하고 사용하는 방법에 대한 고찰해 보겠다.

* UML에서 유스케이스는 액터, 유스케이스, 유스케이스 다이어그램 등을 모두 포함하는 전체를 지칭하는 [유스케이스]와 특정 기능을 설명하는 유스케이스의 두 가지로 쓰인다. 이 글에서는 구분을 위해 전체를 지칭하는 것은 대괄호를 붙여 [유스케이스]로 사용하고 특정 기능을 설명하는 유스케이스는 그냥 유스케이스로 쓰겠다.


[유스케이스]는 시스템이 사용자에 의해서 어떠한 형태로 사용되는지를 기술하는 UML의 표준 표기법이다. 다르게 말하면 시스템이 갖추어야 하는 여러 기능적, 비기능적 요구사항(주로 기능적 요구사항)을 표현하는 방법이 [유스케이스]이다. 이전에도 요구사항을 기술하는 방법은 여러 가지가 있었지만 모델링의 표기법이 UML로 통합되면서 유스케이스가 요구사항을 기술하는 일반적인 방법으로 사용되어 오고 있다.

그런데 [유스케이스]는 표준 표기법임에도 불구하고 UML의 다른 표기법에 비해 그 구성 요소가 적고 그것들을 활용해서 표현하는 방식에 있어서 자유도가 매우 높다. UML의 구성 요소 중 UML 사용의 시맨틱적 요소가 가장 큰 것이 [유스케이스]라 할 수 있다. 유스케이스 사용의 다양한 방식들 중 많은 사람들의 지지를 받고 있는 이른바 베스트 프랙티스를 살펴봄으로써 유스케이스의 효과적인 사용법을 알아보기로 하자.

[유스케이스]의 큰 그림
[유스케이스]는 크게 [유스케이스] 모델과 [유스케이스] 기술서로 구성되어 있다. [유스케이스] 모델에 관한 것은 표준에 의해 정의되어 있지만 유감스럽게도 [유스케이스] 기술서는 특별히 표준이라 할 수 있는 것이 없다. 다만 방법론을 다루는 쪽이나 [유스케이스]를 많이 사용해 본 사람들이 [유스케이스] 기술서 작성을 언급할 뿐이다. [유스케이스] 모델은 [유스케이스]의 구성 요소인 액터와 유스케이스, 그리고 그들의 전체적인 관계를 다이어그램의 형태로 가진다. [유스케이스] 모델을 통해 시스템의 전체적인 개요와 구성을 쉽게 알 수 있다. [유스케이스] 모델에 나타난 구성 요소의 세부적인 내용은 [유스케이스] 기술서에 작성한다.

[유스케이스] 모델
[유스케이스]는 소프트웨어 시스템이 무엇을 만들어야 하는지, 어떠한 기능을 제공해야 하는지를 기술하는 표기법을 통칭해서 부르는 말이다. [유스케이스]는 시스템을 사용하는 사용자와 내가 만들어야 하는 시스템 자체를 설명하는 방법이다. [유스케이스]에서는 시스템을 사용하는 사용자를 액터(actor)라 하고 시스템의 행동을 유스케이스(use case)라고 한다. 그리고 내가 만들려고 하는 소프트웨어 시스템을 주제영역(subject)이라고 한다. 내가 만들 시스템에 대한 유스케이스들은 주제영역 안에 존재하고 주제영역 밖의 액터와 연결된다. <그림 1>은 [유스케이스] 다이어그램의 전형적인 예이다.

사용자 삽입 이미지
<그림 1> [유스케이스] 다이어그램의 전형적인 예


액터라고 해서 모두 사용자를 지칭하는 것만은 아니다. 주제영역으로 정의되는 시스템과 연결되어 상호작용하는 외부 시스템도 액터로 정의한다. 하나의 시스템을 여러 팀이 나누어 개발할 때 다른 팀에서 만든 모듈도 나의 팀의 관점에서 본다면 액터로 정의할 수 있다. 쉽게 말해서 내가 만들어야 하면 유스케이스이고 남이 만들면 액터가 된다. <그림 1>과 같은 [유스케이스] 다이어그램을 통해 시스템이 어떠한 액터들과 상호작용하며 어떤 기능을 액터에게 제공하는 지를 일목요연하게 알 수 있다.

[유스케이스] 모델 구성 요소에 대한 세부적인 내용은 [유스케이스] 기술서에 정의하고 [유스케이스] 다이어그램에서는 어떤 [유스케이스] 기술서와 연결되는지 정도를 첨가해 주면 된다. 이는 현존하는 대부분의 UML 모델링 툴이 지원해 주는 기능이다.

‘역할’을 뜻하는 액터
액터는 시스템의 사용자 측면을 정의할 때 사용한다. 액터는 보통 특정 작업을 완수할 목적으로 시스템과 상호 작용하는 사람이나 시스템이 수행하는 역할이라고 정의하고 <그림 2>와 같이 표기한다.

사용자 삽입 이미지
<그림 2> 액터를 형상화한 모습
여기서 주목해야 할 것은 역할이라는 말이다. 액터의 표기법이 사람 모양을 하고 있어서 사람만이 액터라는 선입견을 가질 수 있는데 사람과는 관계가 없고 그 사람이 수행하는 역할과 더 밀접한 관계가 있다.

액터는 역할에 더 가깝기 때문에 사람 이름보다 직책 이름이 많이 사용된다. 만약 웹사이트 애플리케이션이라면 사이트 회원, 비회원, 관리자 등이 액터로 사용될만한 것들이다.

관심을 갖고 있는 주제영역 시스템과 상호작용하는 외부 시스템도 전형적인 액터이다. 외부 시스템은 주제영역 내의 시스템의 요청에 따라 정보를 제공하는 것이 일반적이다. 전자상거래가 필요한 시스템이라면 외부 시스템으로 신용 정보나 금융 정보 등을 제공하는 시스템을 생각할 수 있고, 여행 상품을 제공하는 시스템이라면 외부 시스템으로 호텔 예약 시스템이나 교통편 예약 시스템 등을 생각할 수 있겠다. 다음은 액터의 전형적인 사례이다.


◆ 사람 : 텔레마케터, 관리자 등
◆ 외부 시스템 : 신용 정보 시스템, 예약 시스템 등
◆ 장치 : 온도 감응 장치, 출입 통제 장치 등
◆ 외부 조직 : 금융감독원, 보안 조직 등
◆ 이벤트 : 매일 밤 12시, 월급날 등


이벤트도 액터?
액터는 시스템의 기능적 요구사항을 정의할 때 매우 유용하게 사용된다. 특히 이벤트 발생 시점과 같은 액터는 시스템의 기능적 요구사항을 정의하는 데 매우 유용하다. 주기적으로 수행되는 배치 작업이 일반화되어 있는 현대의 시스템에서 이벤트 발생 시점은 매우 훌륭한 액터가 된다.

사실 시간과 같은 이벤트를 액터로 해도 되느냐 하는 부분에 대해서는 논란의 여지가 있는 것도 사실이다. 액터는 시스템을 사용함으로써 원하는 목적을 달성하려는 사람 혹은 외부 시스템으로 정의하기도 하는데, 시간 자체는 특별한 목적을 가지지 않기 때문에 액터로 해서는 안 된다고 주장하는 경우도 있다.

[유스케이스]는 그 사용에 있어 자유도가 높기 때문에 이러한 논쟁이 유달리 많기도 하다. 중요한 것은 시스템의 요구사항을 [유스케이스]로 정의하고 보다 많은 사람이 그것을 통해 서로의 생각을 얼마나 잘 공유할 수 있느냐는 것이다. 이벤트를 액터로 하는 것은 시스템의 기능 정의에 많은 도움이 된다고 생각한다.

액터의 분류
[유스케이스]의 창시자인 이바 야콥슨은 액터를 주요(primary) 액터와 보조(secondary) 액터의 두 가지로 분류했다. 주요 액터는 시스템에 어떠한 작업의 실행을 요구하는 능동적인 입장의 액터로 유스케이스를 기동하는 역할을 수행한다. 보조 액터는 시스템의 요청에 따라 수동적으로 어떤 작업을 해 주는 액터로써 유스케이스로부터 어떠한 요청이나 메시지를 전달 받는 액터를 말한다. 최근에는 액터를 더 세분화해서 분류하기도 하는데, 액터의 성격에 따라 크게 네 가지로 나눌 수 있다.


◆ 유스케이스를 기동시키는 액터
◆ 시스템의 요청에 따라 정보를 제공하는 외부 액터
◆ 시스템이 제공하는 정보를 단순히 수신하는 액터
◆ 다른 액터와 시스템간의 상호 작용을 돕는 프록시 역할의 액터


네 가지 액터 유형 중 특이한 것이 프록시 역할을 하는 액터이다. 액터는 유스케이스와 연결될 뿐 액터와 액터는 서로 연결되지 않게 하는 것이 일반적인 액터의 설계 방식으로 여겨져 왔다. 그러나 액터끼리 서로 연결되게 모델링을 하는 것이 시스템을 좀 더 이해하기 쉽게 만드는 경우도 있다.

사용자 삽입 이미지
<그림 3> 전화로 예약을 받는 시스템


<그림 3>은 전화로 예약을 받는 시스템의 예이다. 시스템을 직접 사용하는 사용자는 전화를 받는 창구 직원이 되겠지만 예약이라는 목적을 가지는 것은 고객이기 때문에 고객이 창구 직원에게 전화를 걸어 시스템을 사용하는 것은 <그림 3>처럼 모델링하는 것이 보다 효과적이게 된다. <그림 3>과 같은 시스템은 보통 클라이언트/서버 유형이 애플리케이션인 경우가 많은데 이후 시스템을 웹으로 확장시켜 고객이 직접 웹 사이트를 통해 예약이 가능하도록 하게 되면 창구 직원 액터가 웹을 통한 예약 유스케이스로 변환될 수도 있다.

유스케이스
시스템이 액터에게 주목한 만한 결과를 내놓기 위해 수행하는 여러 작업들의 집합을 유스케이스라고 한다. 즉, 앞서 나온 예약 접수나 구매 주문, 주문 현황 점검과 같은 것들이 유스케이스이다. 유스케이스는 시스템이 수행하는 특정 기능에 대해서 그 기능의 수행을 원하는 액터와 시스템간의 상호 작용과 시스템 내부에서 발생하는 모든 가능한 사항을 기술한다. 유스케이스는 <그림 4>와 같이 표기한다.

사용자 삽입 이미지
<그림 4> 유스케이스


유스케이스의 구성 요소는 여러 가지가 있지만 이름과 작업 흐름이 제일 중요하다. 유스케이스 이름은 [유스케이스] 모델에서 중요하고 작업 흐름은 [유스케이스] 기술서에서 중요하다. 유스케이스의 이름을 지을 때는 동사나 동사구의 형태로 능동형을 사용하는 것이 좋다. 유스케이스의 작업 흐름을 기술할 때 유의해야 할 점은 ‘무엇’에 대한 것을 작성해야 한다는 것이다.

간혹 유스케이스가 무엇이 아닌 ‘어떻게’를 기술하게 작성하는 경우가 있는데, 이는 그리 바람직하지 않은 모습이다. 유스케이스는 시스템이 무엇을 제공하고 액터는 무엇을 얻는가를 기술하는 방편이지 시스템을 어떻게 구축할 것인가에 대한 것은 아니다.

유스케이스 간의 관계
유스케이스와 유스케이스 사이에는 서로 밀접하게 연관되어 있어 상호간에 관계를 가지는 경우가 있다. 유스케이스는 포함(include), 확장(extend), 일반화(generalization)의 세 가지 관계 유형이 있다.

포함 관계
하나의 유스케이스가 유스케이스 내의 작업 흐름의 과정 안에 다른 유스케이스의 작업 흐름을 포함하게 하는 관계이다. 포함 관계는 <그림 5>와 같이 표기한다.

사용자 삽입 이미지
<그림 5> 포함 관계


유스케이스는 액터와 시스템간의 상호 작용이나 시스템 내부의 작업 등을 기술한다. 이때 여러 유스케이스에서 비슷한 작업이 공통으로 발생하는 경우가 있을 수 있다. 이때 이렇게 공통으로 발생하는 유스케이스의 특정 부분을 하나의 유스케이스로 따로 분리하고 포함 관계를 통해 정의하는 것이 가능하다. 이는 프로그램에서 서브 루틴을 호출하는 개념과 유사하다.

포함 관계에서 유스케이스는 ‘포함하는(including) 유스케이스’와 ‘포함되는(included) 유스케이스’로 나눌 수 있다. 유스케이스는 액터가 그 작업 흐름을 기동시키는데, 포함 관계에서 ‘포함되는 유스케이스’는 액터가 아닌 ‘포함하는 유스케이스’가 작업 흐름을 기동시킨다. 그래서 ‘포함되는 유스케이스’는 ‘포함하는 유스케이스’가 없으면 제 구실을 하지 못하고 ‘포함하는 유스케이스’에 합쳐져야 제 기능을 하게 된다.

포함 관계에서 ‘포함되는 유스케이스’를 ‘포함하는 유스케이스’에 포함시킬지 여부는 ‘포함하는 유스케이스’에서 결정한다. 보통 조건절과 같은 내용이 ‘포함하는 유스케이스’에 들어가게 되고 조건절의 만족 여부에 따라 ‘포함되는 유스케이스’를 수행할 지가 결정된다. <그림 6>과 같은 유스케이스가 포함 관계의 가장 전형적인 예이다.

사용자 삽입 이미지
<그림 6> 포함 관계의 전형적인 예


주문 결제 유스케이스는 액터가 결정한 결제 형태에 따라 현금 결제, 카드 결제, 포인트 결제 유스케이스 중에 하나를 포함하게 된다. 포함 관계는 유스케이스 간의 관계를 설정할 때 가장 쉽게 사용할 수 있는 관계 설정 방법이다.

확장 관계
하나의 유스케이스의 흐름이 다름 유스케이스 내의 작업 흐름의 과정에 추가되어 작업 흐름을 확장하는 관계이다. 확장 관계는 <그림 7>과 같이 표기한다.

사용자 삽입 이미지
<그림 7> 확장 관계


확장 관계에서 유스케이스는 ‘확장되는 유스케이스’와 ‘확장하는 유스케이스’로 나눌 수 있다. ‘확장되는 유스케이스’가 액터와 상호작용하면서 작업 흐름을 수행하던 중 확장하는 조건이 만족하게 되면 그 만족되는 시점에서 ‘확장하는 유스케이스’가 ‘확장되는 유스케이스’에 합쳐져서 작업 흐름을 수행한다. 예를 들면 특정 작업을 수행하던 중 사용자가 도움말 버튼을 눌러서 도움말 내용을 확인하는 것 같은 작업이 전형적인 확장 관계이다.

확장 관계에서는 ‘확장하는 유스케이스’가 ‘확장되는 유스케이스’의 특정 지점으로 합쳐지게 되는데, 이 지점을 확장 지점(Extension point)이라고 한다. 확장 지점은 ‘확장되는 유스케이스’에 위치하게 되고 ‘확장되는 유스케이스’는 여러 개의 확장 지점을 가질 수 있다. ‘확장하는 유스케이스’가 ‘확장되는 유스케이스’의 어떤 확장 지점으로 확장될 것인가는 확장 관계에 표시한다. 확장 관계는 확장하는 조건과 어떤 확장 지점으로 확장될 것인가에 대한 정보를 보유한다.

유스케이스가 합쳐져서 보다 큰 작업을 한다는 점에서는 포함 관계와 확장 관계가 크게 다를 바는 없지만 그 적용되는 방법과 내용상에 있어서는 몇 가지 차이점이 존재한다.

첫째, 포함 관계는 ‘포함하는 유스케이스’가 주 흐름 유스케이스이고 ‘포함되는 유스케이스’가 주 흐름 유스케이스에 내용을 추가하는 것인 데 반해 확장 관계에서는 ‘확장되는 유스케이스’가 주 흐름 유스케이스이고 ‘확장하는 유스케이스’가 주 흐름 유스케이스에 내용을 추가하는 것이 된다.

둘째, 포함 관계에서 ‘포함되는 유스케이스’는 ‘포함하는 유스케이스’가 정상적으로 동작하기 위해서 반드시 필요한 필수 요소인 데 반해 확장 관계에서 ‘확장하는 유스케이스’는 선택 사항으로써 ‘확장되는 유스케이스’는 ‘확장하는 유스케이스’와 상관없이 독립된 기능을 수행할 수 있다.

보통 유스케이스에 내용을 추가할 때는 포함 관계나 확장 관계 중 어느 방법을 사용하더라도 큰 무리가 없다. 약간의 차이가 있다면 포함 관계로 내용을 추가하려고 할 때에는 내용 추가의 기반이 되는 ‘포함하는 유스케이스’의 내용 변경이 반드시 동반되어야 하는 데 반해 확장 관계로 내용을 추가할 때는 내용 추가의 기반이 되는 ‘확장되는 유스케이스’의 내용 변경이 불필요하다는 것이다. 따라서 이미 존재하는 유스케이스 도큐먼트 내용의 수정이 가능한지 불가능한지 여부가 포함 관계로 내용을 추가할 것인지 확장 관계로 내용을 추가할 것인지를 선택하는 기준이 될 수 있다.

일반화 관계
유스케이스 간의 일반화 관계는 객체 지향 개념에서의 상속 관계와 유사해서 자식 유스케이스가 부모 유스케이스가 가지는 속성, 작업 흐름, 확장 지점, 다른 유스케이스와의 관계 등을 모두 가진다는 의미이다. 일반화 관계는 <그림 8>과 같이 표기한다.

사용자 삽입 이미지
<그림 8> 일반화 관계


자식 유스케이스는 새로운 작업 흐름이나 별도의 속성, 확장 지점, 다른 유스케이스와의 관계 등을 정의할 수 있다. 하나의 유스케이스는 여러 개의 부모 유스케이스를 가질 수 있고, 자신이 여러 유스케이스의 상위 유스케이스가 될 수도 있다.

유스케이스의 레벨
UML에 정의되어 있는 [유스케이스]의 표준에는 유스케이스에 대한 레벨이나 범위에 대한 개념이 없다. 레벨이나 범위는 유스케이스를 작성하는 과정에서 그 필요성이 자연스럽게 도출된 개념들이다. 레벨이 높은 유스케이스가 넓은 범위의 내용을 광범위하게 다루고 레벨이 낮은 유스케이스가 보다 적은 범위의 내용을 상세히 다룬다. <그림 9>는 유스케이스의 레벨에 대한 개념을 보여준다.

사용자 삽입 이미지
<그림 9> 유스케이스의 레벨 개념


보통 유스케이스의 레벨은 그 유스케이스를 필요로 하는 사람에 따라 다르게 구성된다. 전체 시스템을 개괄적으로 보기를 원하는 매니저나 관리자들은 보다 높은 레벨로 구성된 유스케이스를 필요로 한다. 이들에게는 어떻게 유스케이스가 수행되는가는 주 관심 분야가 아니고 보다 높은 레벨의 관점으로 시스템을 바라보고 싶어 한다. 반면 요구사항 분석을 통해 시스템 전체의 모습을 구성해야 하는 시스템 분석가들은 보다 세부적으로 어떠한 기능을 수행하는지를 볼 수 있는 수준이 필요하다.

반면 개발자들은 요구되는 기능을 어떻게 실제로 구현할 것인지를 정의할 수 있는 수준의 유스케이스를 필요로 한다. 유스케이스를 통해 요구사항에 대한 의사소통을 하는 사람의 역할이 무엇이냐에 따라 유스케이스는 다른 레벨의 형태를 띠게 된다.

유스케이스의 레벨에 관련해서는 ‘왜’라는 물음과 ‘어떻게’란 물음이 중요한 역할을 한다. <그림 10>에서와 같이 유스케이스의 작업 흐름 내용에 대해서 ‘왜’라는 물음에 대한 답이 상위 레벨 유스케이스가 되고 ‘어떻게’라는 물음에 대한 답이 하위 레벨 유스케이스가 된다.

사용자 삽입 이미지
<그림 10> 상위와 하위 레벌 유스케이스


적절한 레벨은?
유스케이스가 많이 사용됨에 따라 유스케이스가 어느 정도의 범위를 커버하도록 구성하는 것이 가장 적절한지에 대한 많은 고민이 있어왔다. 유스케이스를 작성하는 데 있어서 전형적으로 등장하는 좋지 않은 예 중에 하나가 같은 레벨의 유스케이스 간에 상세화 정도의 차이가 생기는 것이다. 같은 레벨의 유스케이스는 비슷한 정도의 범위를 비슷한 상세화 정도로 기술해야 한다.

레벨은 크게 요약(summary), 사용자 목적(user goal), 하위 기능(sub function)으로 나눌 수 있다. 사용자 목적 레벨이 요구사항을 분석하는 데 가장 적절한 수준이다. 사용자 목적 레벨에서 ‘왜’라는 질문을 통해서 내용을 정리하면 요약레벨의 유스케이스가 되고 ‘어떻게’라는 질문을 통해서 내용을 상세화하면 하위 기능 유스케이스가 된다. 사용자 목적 레벨의 유스케이스를 판단할 때 다음과 같은 정도의 기준을 사용할 수 있다.


◆ 액터가 한자리에 앉아서 한번(2분~20분)에 끝낼 수 있는 정도의 작업
◆ 작업이 완료되었을 때 액터가 자리를 뜨는데 어려움이 없는 정도


하나의 유스케이스는 사건 흐름에 보통 3~9 스텝 정도를 밟는 것이 좋다. 단 2스텝으로 끝나버린다거나 10스텝 이상으로 길어지는 것은 유스케이스를 이해하는 데 별로 좋지 않다. 만약 스텝이 길다면 다음의 예와 같은 스텝들을 하나의 스텝으로 합쳐서 스텝의 수를 조절할 수 있다.


◆ 같은 액터가 여러 스텝을 점유한 경우
◆ 액터가 사용자 인터페이스를 사용하는 부분을 여러 스텝을 통해 기술한 경우


그래도 스텝이 길다면 그 유스케이스는 너무 큰 유스케이스이거나 너무 상세화된 유스케이스인 경우가 대부분이다. 유스케이스가 크다면 여러 개의 유스케이스로 나누는 것을 고려해야 하고 너무 상세화된 유스케이스라면 ‘왜’라는 질문을 통해 레벨을 높이도록 해야 한다.

[유스케이스] 기술서
앞에서 [유스케이스]라고 하는 요구사항 분석 설계 표기법에 사용하는 여러 요소들에 대해 살펴보았다. UML이 [유스케이스]에 대해 표준으로 정의하고 있는 것은 액터나 유스케이스, 유스케이스 간의 관계와 같은 구성 요소와 그들이 서로 어떻게 연계되어 전체적인 모습을 보여주는 지와 같은 것들이다. 이것은 요구사항 분석 설계 메커니즘으로써의 [유스케이스]의 반쪽밖에 되지 않는다.


[유스케이스]의 또 다른 반쪽은 [유스케이스] 기술서라고 하는 문서의 형태로 존재하는데, 이는 표준으로 정의되어 있지 않다. 오히려 방법론 등에서 [유스케이스] 기술서를 어떠한 형태로 어떻게 작성해야 하는지를 제시하고 있다. 그래서 다양한 형태의 [유스케이스] 기술서가 정의되어 사용되고 있다. 그러면서 베스트 프랙티스가 정립되면서 표준이라 할 수 있을 정도의 [유스케이스] 기술서가 만들어 졌다.

구성 요소
[유스케이스] 기술서에는 대체로 다음과 같은 내용들이 들어가게 된다.


◆ 이름 : 유스케이스의 이름
◆ 반복 : 반복이 이루어진 횟수. 버전과 유사한 개념
◆ 액터 : 유스케이스와 관련된 액터들의 목록
◆ 범위 : 유스케이스가 어떤 수준의 범위를 다루는지에 대한 설명
◆ 레벨 : 유스케이스가 어느 레벨의 것인지에 대한 설명
◆ 요약 : 유스케이스가 어떠한 일을 하는 지를 개략적으로 설명하는 내용
◆ 주 작업 흐름 : 유스케이스가 수행하는 작업의 흐름을 여러 스텝으로 기술한 내용 중 가장 전형적으로 발생하는 것. 유스케이스가 설명하는 업무의 80% 정도가 주 작업 흐름에서 커버한다.
◆ 대안 흐름 : 주 작업 흐름을 따르는 과정에 조건에 따라 다르게 작업하는 것을 기술한 내용
◆ 예외 흐름 : 작업 흐름이 진행되는 과정에서 예외사항이 발생하였을 경우 어떻게 처리해야 하는 지를 기술한 내용
◆ 사전 조건 : 유스케이스가 제대로 작동하기 위해 사전에 만족되어야 하는 조건을 기술
◆ 사후 조건 : 유스케이스가 끝나면 어떠한 결과가 제공되는지를 기술
◆ 비즈니스 룰 : 유스케이스의 작업 흐름과 관련해서 업무 규칙에 관한 내용을 기술
◆ 사용자 화면 : 사용자 인터페이스 화면에 대한 내용
◆ 작성자 : 유스케이스의 작성자
◆ 작성일 : 유스케이스 작성일


몇 가지의 기술서 작성 양식
앞에서 여러 가지 [유스케이스] 기술서의 구성 요소에 대해서 설명했지만 일반적으로는 [유스케이스] 기술서의 구성 요소들 중 필요한 것을 선별하여 [유스케이스] 기술서 양식을 만들어서 [유스케이스]의 내용을 만드는 데 사용하게 된다. [유스케이스] 기술서의 양식은 프로젝트의 규모나 문서화를 얼마나 세세하게 할 것인지 등을 살펴보고 적합한 수준에서 결정한다.

프로젝트의 규모가 크거나 프로젝트에 대한 위험 부담이 높은 프로젝트에서는 대개 엄격한(rigorous) 방법론을 사용하는 것이 일반적이다. 엄격한 방법론에서는 산출물의 형식이나 내용의 유무를 중요하게 생각한다. [유스케이스] 기술서에도 예외가 아니어서 항목이나 내용이 많고 그 내용을 규칙에 따라 작성하도록 요구한다. 유스케이스의 엄격한 양식에는 앞서 기술한 [유스케이스] 기술서의 구성 요소가 거의 대부분 들어간다.

프로젝트의 규모가 작아서 산출물 작성의 형식에 그리 큰 비중을 두지 않는 경우나 혹은 기민한 방법론을 채택해서 산출물의 신속한 작성과 변경이 요구되는 경우는 [유스케이스] 기술서의 형식을 간략하게 사용하는 경우도 있다. <표 1>은 간략화한 양식의 예이다.

 <표 1> [유스케이스] 기술서의 간략화한 양식
사용자 삽입 이미지

유스케이스 25 로그인
주요액터: 사용자
범위: 애플리케이션
레벨: 하위기능
사용자는 시스템에 자신을 알리기 위해 로그인을 한다. 사용자는 사용자이름과 패스워드를 입력한다. 시스템은 사용자를 확인하기 위해 사용자가 제시한 사용자이름과 패스워드를 검증한다. 사용자 이름과 패스워드가 일치하면 시스템은 사용자에게 시스템을 사용할 수 있는 권한을 준다.
만약 사용자가 제시한 사용자이름과 패스워드가 관리자 레벨의 것일 경우 사용자는 시스템을 조작할 수 있는 권한을 함께 부여 받는다.
만약 사용자이름이 존재하지 않거나 패스워드가 틀릴 경우 권한의 부여는 거부되고 사용자는 시스템을 이용할 수 없게 된다.
사용자 삽입 이미지

 <표 2> RUP에서 제시하고 있는 유스케이스 기술서 양식
사용자 삽입 이미지

1. Use Case Name
1.1. Brief Description
…text…
1.2. Actors
…text…
1.3. triggers
…text…
2. Flow of events
2.1. Basic flow
…text…
2.2. Alternative flows
2.2.1. Condition 1
…text…
2.2.2. Condition 2
…text…
2.2.3. …
3. Special Requirements
3.1. platform
…text…
3.2. …
4. Preconditions
…text…
5. Postconditions
…text…
6. Extension Points
…text…

사용자 삽입 이미지

점증적이며 반복적인 작성 프로세스
소프트웨어 개발 방법론에서는 점증적·반복적 접근이 많이 사용되는데 [유스케이스]의 작성에도 예외는 아니다. 대부분의 [유스케이스] 작성 프로세스가 반복을 통해 점증적으로 [유스케이스]의 내용을 추가하는 방식을 취하고 있다. <그림 11>은 세 번의 반복을 통해 점진적으로 유스케이스의 항목을 추가해 나가는 유스케이스 작성 프로세스의 모습을 간략히 한 모습이다.

사용자 삽입 이미지
<그림 11> 점진적으로 유스케이스 항목을 추가해 나가는 모습


초기(Initial) 단계에서는 시스템의 범위를 정하고 액터와 유스케이스를 찾는다. 여기서 액터와 유스케이스는 이름과 간략한 요약 정도만을 기술해 주면 된다. 기반(Base) 단계에서는 초기 단계에서 찾아낸 액터와 유스케이스의 내용을 보강한다. 각 유스케이스에 대해서 사건 흐름을 기술하고 선행 조건과 사후 조건을 기술한다. 상세(Elaboration) 단계에서는 유스케이스의 모든 세부 항목을 완성 시키는 단계이다. 각 유스케이스에 사건 흐름에 대해 대안 흐름과 예외 흐름을 추가한다.

코번의 12 단계 정의
writing effective use case의 저자인 코번은 유스케이스를 작성하는 12단계를 정의했다.

[1] 시스템의 범위와 경계 설정
[2] 시스템에 관계된 모든 액터 찾기
[3] 액터가 시스템을 통해 얻으려고 하는 목적들 찾기
[4] 각 액터에 대한 최상위 유스케이스(summary use case) 설정
[5] 최상위 유스케이스들에 대한 정제 작업(시스템 범위의 재확인)
[6] 상세 작업을 할 유스케이스 선택
[7] 이해 관계자와 그들의 목적, 선행 조건, 후행 조건 등을 뽑아냄
[8] 주 성공 작업 흐름 작성
[9] 대안 흐름과 예외 흐름 찾기
[10] 대안 흐름과 예외 흐름 작성
[11] 복잡한 스텝을 하위 유스케이스로, 자잘한 스텝들은 모아서 하나로 합치는 작업 수행
[12] 유스케이스 조절 작업(읽기는 쉬운지, 구색은 갖췄는지, 이해 관계자는 만족하는지) 수행

코번의 12단계도 앞서 설명한 작업 절차와 그리 큰 차이는 보이지 않는다. 중요한 것은 반복적으로 점증적으로 [유스케이스]를 작성해 나간다는 것이다.

UML을 제대로 사용하려면 이것은 기억하자
[유스케이스] 모델과 [유스케이스] 기술서 등 [유스케이스]와 관련한 여러 가지를 살펴보았다. 이제는 [유스케이스]와 관련해서 유의해야 할 점을 짚어 보기로 하자.

액터와 유스케이스의 연결
UML 표준에는 액터와 유스케이스의 연결에 단순한 직선 연결만을 사용하고 있는데 화살표를 사용해서 나름의 의미를 부여하는 경우도 있다. 다음은 화살표 사용의 몇 가지 사례이다.


◆ 주요 액터가 유스케이스를 기동하는 경우에만 액터에서 유스케이스 쪽으로 화살표 머리 사용
◆ 주요 액터가 유스케이스를 기동하거나 유스케이스가 보조 액터를 기동하는 경우 기동하는 쪽으로 화살표 머리 사용.
◆ 단 방향 커뮤니케이션에만 화살표 머리 사용. 기대되는 응답이 없는 경우에 사용한다(예 : 프린터로 명령을 보내는 경우, 정부 기관에 내용을 통보하는 경우)


[유스케이스] 다이어그램에서 화살표를 사용할 때에는 데이터의 흐름이 아니라 커뮤니케이션의 기동 방향을 보여주는 데 사용하는 것이 좋다. 데이터는 보통 액터와 유스케이스 사이에 양방향으로 흐르는 것이 일반적이기 때문에 데이터의 흐름으로 화살표를 사용하게 되면 양방향 화살표가 되게 되고 이것은 다이어그램을 어지럽히는 원인이 된다.

전통적인 실수들
[유스케이스]를 작성하는 데 있어서 다음과 같은 실수가 자주 발생한다.


액터가 없는 유스케이스, 시스템이 없는 유스케이스
액터와 유스케이스는 반드시 서로 연결되어 있어야 한다. ‘포함되는 유스케이스’나 ‘확장하는 유스케이스’의 경우도 포함 또는 확장되어 액터와 연결된다. 간혹 혼자 동떨어져 있는 유스케이스가 있는 시스템이 보이기도 하는데 이는 잘못 작성된 것이다.

사용자 인터페이스의 내용을 너무 상세히 담고 있는 [유스케이스]
[유스케이스]는 기능적 요구사항을 담는 것이기 때문에 사용자 인터페이스의 상세한 내용은 담지 않는다. 다만 사용자 인터페이스를 상세하게 설명한 문서에 대한 참조 정도를 추가하면 된다.

너무 낮은 레벨의 [유스케이스]
구현에 대한 상세한 내용이 담겨 있는 [유스케이스]는 적절하지 않다. [유스케이스]에 소스코드 레벨의 설명이 들어 있는 경우가 간혹 있는데 ‘왜’라는 물음을 통해 상위레벨의 [유스케이스]로 만드는 것이 좋다.

전산인의 언어를 사용한 유스케이스
[유스케이스]는 요구사항을 기술하고 그것을 통해 여러 관여자 들과 의사소통을 하기 위해 만드는 것이다. [유스케이스]에 사용하는 용어는 많은 사람이 이해할 수 있도록 보편적인 용어를 사용해야 한다.

애플리케이션 관점의 유스케이스
유스케이스는 액터의 관점에서 기술해야 한다. 시스템의 관점에서 기술한 유스케이스는 적절하지 않다.

‘~해야 한다’ 식의 표현
요구사항을 기술하는 전통적인 방법에서는 ‘시스템은 ~해야 한다’는 식의 표현이 자주 등장한다. 이러한 표현을 [유스케이스]에서는 사용하지 않는 것이 좋다. 만약 고객의 요구로 ‘~해야 한다’는 식의 표현을 넣어야 한다면 [유스케이스]의 요약 부분에 넣는 것이 좋다. 작업 흐름 부분에는 ‘~해야 한다’가 아닌 ‘~한다’라는 표현을 사용해야 한다.


유스케이스 작성에 대한 10가지 잘못
[1]다른 형태의 요구사항 문서는 만들 필요가 없다. [유스케이스]면 요구사항을 충분히 반영할 수 있다.
아니다. 요구사항 문서는 요구사항을 가장 잘 반영할 수 있는 형태의 문서로 만들어야 한다. 데이터베이스 설계에 대한 요구사항은 ER모델이 적합하고, 화면 구조에 대한 요구사항은 그래픽이 가미된 문서가 더 적합하다.

[2]읽는 사람이 [유스케이스]의 목적에 대해 이해하기 힘들게 한다. [유스케이스]의 이름을 지을 때 ‘작업하다’, ‘처리하다’와 같은 말을 사용하여 혼란스럽게 한다. 만약 읽는 사람을 혼란스럽게 하는 데 성공했다면 [유스케이스]를 실제로 구현할 때 어떻게 해도 상관없을 것이다.
[유스케이스]를 이용해서 효과적으로 소프트웨어 시스템을 구현하기 위해서는 명확하게 [유스케이스]를 작성할 필요가 있다. 간혹 어떻게 [유스케이스]를 작성해야 하는지 모르는 경우에 이렇게 처리하는 경우가 있는데 좋지 않은 모습이다.

[3][유스케이스]의 범위에 대해 혼란스럽게 한다. 범위는 어차피 점점 퍼져나갈 것이고 나중에 리펙토링을 하면 된다. 사용자는 어차피 생각을 계속 바꿀 것인데 왜 성가시게 범위를 미리 확정하겠는가?
[유스케이스]는 만들려고 하는 시스템이 어떠한 범위를 다루는지를 표현하는 것에도 사용된다. 시스템의 범위를 명확히 하고 그것을 여러 관여자가 충분히 이해할 수 있도록 [유스케이스]를 작성해야 한다.

[4][유스케이스] 기술서에 비기능적 요구사항과 사용자 인터페이스 디테일을 포함시킨다.
유스케이스의 작업 흐름에 사용자 인터페이스에 대한 세부 내용을 포함시키면 작업 흐름이 늘어나게 된다. 사용자 인터페이스를 요약한 내용을 추가하면 되지 상세한 내용까지는 포함시킬 필요가 없다.

[5]초기 [유스케이스] 다이어그램에 포함 관계와 확장 관계를 많이 사용한다. 그러면 유스케이스를 작은 단위의 것으로 나눌 수가 있다.
초기 버전의 유스케이스는 상위레벨의 유스케이스를 작성하고 반복을 거치면서 보다 상세화한 유스케이스를 작성하는 것이 좋다. CRUD를 처리하는 유스케이스가 대표적인데, 초기에는 ‘관리하다’라는 유스케이스로 하나로 만들고 이후에 반복을 통해 ‘생성’, ‘조회’, ‘수정’, ‘삭제’ 유스케이스로 세분화한다.

[6]비즈니스 룰을 정의하는 것에는 관여하지 말라.
비즈니스 룰을 만들고 사용하는 것은 사용자이지만 그것을 산출물로 표현하도록 하는 것은 매우 중요하다. 룰 자체를 만드는 것에는 관여할 필요가 없지만 그것을 [유스케이스]를 통해 표현하도록 독려해야 한다.

[7][유스케이스]의 작성에 도메인 전문가를 관여시키지 말라. 그들은 질문이나 해댈 뿐이다.
[유스케이스]는 요구사항에 대한 표준 표기법인데, 소프트웨어 시스템에 대한 요구사항을 가장 잘 알고 있는 것은 도메인 전문가이다. 물론 이들이 작업을 성가시게 할 수도 있지만 좋은 결과를 내기 위한 고통이라 생각해야 한다.

[8]만약 사용자를 [유스케이스] 정의에 관여시킨다면 그냥 그래라. 왜 사용자와의 미팅을 준비하는 데 골머리를 썩힐 것인가? 많은 양의 문서나 만들게 되고, 어쨌든 그들은 계속 마음을 바꾸게 될 것이다.
될대로 되라는 식의 태도는 좋지 않다. 사용자에게 [유스케이스]를 충분히 이해시키고 [유스케이스]를 통해 효과를 볼 수 있도록 노력해야 한다.

[9][유스케이스]를 한 번에 아주 상세하게 만들어라.
반복적으로 점증적으로 [유스케이스]를 작성하는 것이 좋다.

[10][유스케이스]를 검증하거나 평가하지 말라. 재작업이나 만들어 낼 뿐이다.
반복적으로 점증적으로 작성하고 중간중간 계속 사용자나 도메인 전문가의 피드백을 받아야 한다.

아름다운 표현 양식이 되길 바라며
요구사항을 수집하는 일은 오래 걸리거나, 잘못된 것을 기록하거나, 발생하지 않을 일을 추측하거나, 시간에 맞춰 허겁지겁 끝내는 등과 같은 결과를 초래하는 경우가 많다. 이는 요구사항 수집이 비생산적인 경로를 거치거나, 요구사항 수집을 무시하거나, 요구사항 수집 자체만을 위해 매달리거나, 요구사항을 한 사람이 결정하기 때문에 발생한다.

[유스케이스]는 이러한 요구사항 수집에 사용하기 좋은 방법 중 하나이다. [유스케이스]의 표준을 따라 보편화된 방법으로 요구사항을 기술하면 보다 많은 사람들이 사용할 수 있을 것이다. 물론 표준에 대한 준수 여부보다는 [유스케이스]의 내용을 어떠한 생각을 가지고 채워 넣었느냐가 더욱 중요하다.

UML은 단순한 표기법에 지나지 않지만 아주 좋은 표기법임에는 틀림없다. 마치 한글처럼. 아름다운 우리말을 한글이 잘 표현하듯이 소프트웨어 개발에 대한 여러분의 멋진 생각들을 UML을 통해 잘 표현해 보기를 바란다.@

* 이 기사는 ZDNet Korea의 제휴매체인마이크로소프트웨어에 게재된 내용입니다.

 

이경원 (한국오라클)

2005/04/11

 

[UML 제대로 알기] ④ 닷넷 환경 UML 툴 활용 가이드

 

연재순서
1회.가능성·확장성 품고 등장한 UML 2.0
2회.초보자를 위해 다각도로 살펴본 UML
3회.바로 알고 제대로 쓰는 UML 실전 모델링
4회.닷넷 환경에서 UML 툴 활용 가이드
5회.표준을 넘나드는 UML의 적절한 사용

 

케이스 도구는 양날의 검이다. 활용도에 따라서 소프트웨어를 죽일 수 도 있다. 래쇼날 로즈(이하 로즈) 같은 케이스 도구는 능숙하게 다룰 수 있어야 되기까지 많은 학습 곡선을 필요로 한다. 능숙해진 다음에도 여전히 불편하다.

하지만 IDE와 통합된 케이스 도구는 코드의 자동 생성 등의 많은 편리한 도구를 제공한다. IDE와 통합된 케이스 도구는 UML이라는 것에 너무 얽매이지만 않고 자유롭게만 사용한다면 아주 훌륭한 프로젝트 도우미가 될 수 있다.

전통적으로 MS의 개발 플랫폼에서 사용하는 개발 도구는 MS가 100% 독점하다시피 해 왔다. STL이나 MFC를 개발하거나 사용하는 도구는 거의 비주얼 C++가 독점적이었고, COM 기반의 개발을 위해 사용되는 도구는 거의가 비주얼 베이직이었다(COM 개발을 위해 비주얼 C++를 사용하는 경우도 많이 봤지만 그 당시 이슈가 되던 RAD와는 거리가 먼 환경이었다). 물론 볼랜드의 델파이 등을 많이 사용하기도 했지만 MS의 막강한 개발 도구 비주얼 스튜디오를 넘기에는 벅차 보였다.

닷넷 환경이 발표되고, 닷넷이 산업계에서 서서히 자리를 잡아가자 닷넷 개발 도구의 필요성이 절실해 졌고, 당연히 MS의 비주얼 스튜디오 닷넷이 닷넷 개발 도구의 최강자 자리를 당연히(!) 차지했다. 사실, 비주얼 스튜디오 닷넷이 없으면 닷넷 개발이 불가능하다고 생각하는 사람들도 많다.

볼랜드가 C# 빌더 등의 닷넷 환경을 지원하는 도구를 내 놓았고, 기타 여러 벤더들이 제품을 출시했지만 MS의 아성을 무너트리기에는 역부족이다. 비주얼 스튜디오 닷넷은 닷넷 환경이 존재하는 한 닷넷 기반 IDE의 최강자로서 그 자리를 내놓지는 않을 듯 하다.

그렇다면 비주얼 스튜디오 닷넷에는 약점이 없을까? 아니다, 분명히 약점은 존재한다. 그것도 아주 커다란, 치명적인 약점이 있다. MS는 닷넷 환경을 분명한 객체지향 개발 환경(닷넷 환경에서의 CBD는 객체지향이 없이는 존재할 수 없다)이라고 했다. 객체지향 개발 환경이라면 객체지향 설계 도구가 없다면 그 활용 범위가 반감될 수밖에 없는데, 비주얼 스튜디오 닷넷 엔터프라이즈 아키텍트 버전에 포함된 비지오가 어느 정도 그런 기능을 해 주긴 하지만, 다른 객체지향 개발 도구인 로즈나 볼랜드 투게더(이하 투게더) 등의 편리함과 기능성에는 결코 미치지 못한다.

설계 도구와 개발 도구의 진정한 결합. 이상적인 환경이지만 사실 구현하기 어려운 개발 환경임에 틀림없다. 비주얼 스튜디오 닷넷은 분명 막강한 개발 환경이고, 비주얼 스튜디오 닷넷을 사용하면서 투게더 또는 로즈 같은 개발 도구를 같이 사용할 수는 없을까 하는 생각을 누구나 한번쯤은 해 보았을 것이다. 정말 그럴 수 있을까? 대답은 "물론 있다"이다. 로즈와 투게더는 비주얼 스튜디오 닷넷 XDE를 제공한다(물론 구입해야 한다).

래쇼날 로즈 2000 XDE
객체지향 모델링 도구 중 가장 유명하며, 많이 사용되는 도구인 로즈는 2002년 MS의 비주얼 스튜디오 닷넷에 애드인되어 사용될 수 있는 ‘래쇼날 로즈 2000 XDE for 비주얼 스튜디오 닷넷’을 발표했다(어찌된 일인지 아는 사람도 별로 없고 사용하는 사람은 더더욱 없다). 로즈 XDE를 가지고 있다면 그 자리에서 설치해 보기를 바란다. 물론 설치하는 시스템에 비주얼 스튜디오 닷넷이 설치되어 있어야 한다.

사용자 삽입 이미지
<화면 1> 로즈가 설치된 비주얼 스튜디오 닷넷 2003


로즈를 처음 설치하고 나면 처음엔 아무것도 없다. 도구상자에 뭔가 추가된 것도 아니고, 특별히 뭔가가 설치되었다는 느낌을 받을 수가 없는데(굳이 뭔가 설치되었다는 느낌이라면 아마 비주얼 스튜디오 닷넷의 실행 속도가 눈에 띄게 느려졌다는 느낌이 될 것이다) 솔루션 탐색기를 눈여겨 보면 평소에 볼 수 없던 아이콘이 하나 생겨있음을 알 수 있다. 그 아이콘을 주저 없이 클릭해 보자.

사용자 삽입 이미지
<화면 2> 추가된 동기화 아이콘


동기화 아이콘을 클릭하면 로즈와 비주얼 스튜디오 닷넷이 동기화되어 mdx 파일을 생성한다. 그리고 Model Explorer 창이 새로 생기고 프로젝트에 포함되어 있는 개체들을 탐색할 수 있게 해준다.

사용자 삽입 이미지
<화면 3> 로즈 XDE를 이용하여 Iterator 패턴을 디자인한 모습


로즈를 사용하여 모델링을 어느 정도 마쳤으면, 다시 동기화 버튼을 눌러 순 공학할 수 있다.

사용자 삽입 이미지
<화면 4> 로즈가 생성한 C# 코드


감동의 기능


[1] 너무 깔끔한 코드를 생성하고 닷넷 환경에서 권장하는 주석 내용들을 그대로 생성해준다. 다른 도구들은 생성한 코드의 indentation이 잘 되지 않거나 참조한 라이브러리의 네임 스페이스를 제대로 표시하지 않는 경우가 많은데, 그런 단점이 사라졌다.

[2] 참조한 라이브러리의 개체들을 모두 설계에 사용할 수 있게 해준다. 다른 모델링 도구들은 기본으로 포함되거나 직접 작성한 개체들만이 사용가능 한 경우가 대부분인데, 최상의 도구다운 기능을 보여준다.

[3] 깔끔하고 예쁜 출력을 지원한다. 다른 설계 도구의 경우 한 페이지 또는 두 페이지에 깔끔하게 출력할 수 있는 기능에 대한 지원이 부족한데, 깔끔하고 예쁘장한 산출물을 만들 수 있도록 도와준다.

[4] ASP.NET/ASP/Service Page 들에 대한 설계를 지원한다. Web Presentation Pattern을 응용한 설계가 필요할 때 아주 유용하다.


단점이라면, C#으로 작성한 메쏘드의 수정이 아주 불편하다. 또한, RUP를 너무 강조하는 경향이 있어 닷넷의 빠른 개발과는 어울리지 않는 부분이 엿보이고, 일일이 동기화를 해 주어야 코드와 설계가 연동이 되는데, 에러를 자주 발생하여 동기화가 되지 않는 경우가 빈번히 발생한다.

볼랜드 투게더
비주얼 스튜디오 닷넷에서 다른 유명한 설계 도구인 투게더를 사용할 수 있다. 투게더 역시 로즈와 마찬가지로 비주얼 스튜디오 닷넷에 애드인되어 설치된다. ‘볼랜드 투게더 for 비주얼 스튜디오 닷넷 2.0’을 설치하면 비주얼 스튜디오 닷넷에 투게더 VS.NET Model View라는 창이 생성된다.

사용자 삽입 이미지
<화면 5> 투게더 for 비주얼 스튜디오 닷넷 Model View


또한 솔루션 탐색기에 ModelSupport라는 폴더가 생성되고 폴더 내부에는 .txvpak이라는 확장자를 가지는 모델 파일이 생성된다. 이 파일을 더블클릭하여 모델링 도구를 사용하여 설계할 수 있는 설계 창을 열 수 있다.

사용자 삽입 이미지
<화면 6> 투게더를 사용해서 Iterator 패턴을 디자인 한 모습


투게더는 로즈와 달리, 코드의 실시간 생성을 지원한다. <화면 6>에서 보이는 클래스 아이콘을 더블클릭하면 코드를 곧 바로 생성하게 된다. 코드를 수정하건, 설계를 수정하건 간에 설계 또는 코드의 수정 사항이 즉시 상호간에 적용되게 되어있다.

감동의 기능


[1] 필자가 투게더를 사용해 보고 가장 감동적이었던 기능은 시퀀스 다이어그램을 실시간으로 생성해 주는 기능이었다. 메쏘드가 특정 객체들을 사용하도록 구성되었으면, 투게더는 그 메쏘드의 시퀀스 다이어그램을 아주 믿을만한 수준으로 자동 생성해 준다. <화면 7>은 Petshop 3.0의 AccountController 클래스의 CreateAccount 메쏘드의 시퀀스를 자동 생성한 것이다.


 

사용자 삽입 이미지
<화면 7> 자동 생성한 시퀀스 다이어그램


 


[2] 여러 디자인 패턴에 기반한 설계를 지원한다(로즈 역시 이 기능을 지원한다). GOF 디자인 패턴에 기반하여 설계를 하고자 하면 투게더는 디자인 패턴에서 각 객체들의 역할을 보여주며 각 역할을 하는 객체를 추가하고 삭제하는 Node by Pattern 도구를 지원한다. 투게더는 디자인패턴에 기반한 설계를 쉽고 오류 없이 할 수 있도록 도와주며 특히 디자인 패턴을 공부하는 사람에게 아주 유용한 도구가 될 수 있다.


단점이라면 생성된 코드가 그다지 깔끔하지 않아 재 정렬을 해줘야 한다는 점 등이다. 앞에서 설명한 두 가지 도구의 치명적인 단점이 하나 있다. 닷넷 환경에서는 실행할 때 참조되는 라이브러리를 복사하고 실행시 참조하므로 개발 중 라이브러리를 수정하고 다시 컴파일하여도 누군가 파일을 사용 중이기 때문에 덮어쓸 수 없다는 메시지를 절대로 보여주지 않는다. 하지만 앞의 두 도구는 모델링에 사용하고 있는 참조되는 라이브러리를 ‘물고’있기 때문에 참조하는 프로젝트를 종료하고 컴파일한 후 다시 비주얼 스튜디오 닷넷을 실행하여 계속 진행해야 한다.

그리고 전통적으로 닷넷 개발에서는 RUP 같은 개발 방법론이 사용되지 않아, 만약 UML을 그렇게 많이 사용하지 않는 개발자라거나 다른 개발 방법론을 준수하는(MSF 등의) 프로젝트라면 사용할 수 있는 다이어그램은 클래스 다이어그램뿐이고, 너무 많은 도구를 제공함으로서 개발에 혼란이 오며, 비주얼 스튜디오 닷넷 자체가 너무 느려져서 개발자의 '성질'에 나쁜 영향을 끼칠 수 있다는 것이다.

비주얼 스튜디오 닷넷 2005에 포함된 모델링 도구
MS도 닷넷 환경이 객체지향 환경이고, 객체를 모델링 할 수 있는 통합된 개발 도구가 필요하다는 것을 모를 리가 없다. 그래서 MS는 비주얼 스튜디오 닷넷의 차기 버전인 비주얼 스튜디오 닷넷 2005에 그런 모델링 도구를 추가했다(전체적으로는 투게더와 비슷한 모습이고, 필자가 현재 기사를 작성하고 있는 시점에서는 클래스 다이어그램 기능 이외의 기능은 들어있지 않다).

비주얼 스튜디오 닷넷 2005의 클래스 다이어그램 기능을 알아보자. 비주얼 스튜디오 닷넷 2005는 특별히 이전 버전과 비교해서 달라진 기능이 없다. 웹 프로젝트를 다른 프로젝트와 구분해서 생성하는 정도가 외관상으로 볼 때 달라진 기능이라 할 것이다. 비주얼 스튜디오 닷넷에서 클래스 다이어그램을 그리고 실시간으로 변경될 수 있는 기능을 사용하려 한다면 이전 버전에서 새 항목 추가 메뉴를 선택하는 것과 같이 한다. 새 항목 추가 다이얼로그 박스를 유심히 살펴보면 클래스 다이어그램이라는 항목 아이콘이 보이고 그 항목을 사용하여 클래스 다이어그램을 작성할 수 있다.

사용자 삽입 이미지
<화면 8> 비주얼 스튜디오 닷넷 2005의 새 항목 추가 다이얼로그 박스


 

사용자 삽입 이미지
<화면 9> 비주얼 스튜디오 닷넷 2005를 사용해서 Iterator 패턴을 디자인 한 모습


장점


[1] 아무래도 비주얼 스튜디오 닷넷에 애드인된 것이 아닌 빌트인된 모델링 도구이다 보니 애드인된 도구보다는 강한 결합성을 가진다. 빌트인되었을 때의 가장 큰 기대점은 아무래도 성능적인 측면인데 아직 베타 버전이기에 평가 내리기가 이른 듯 하다. 하지만 꽤 만족할만한 성능을 보여주고 있으며, C# 또는 비주얼 베이직 닷넷에 종속적인 멤버들만을 포함하므로 닷넷 개발에 어울리는 도구가 될 듯 하다.

[2] 비주얼 스튜디오 닷넷에 포함된 도구이다 보니 닷넷 개발에 가장 어울리는 코드를 생성하고 다른 도구들과 통합하여 사용할 수 있다. 닷넷에 추가된 수많은 새로운 개념들과 도구들을 사용할 수 있다.

[3] 비주얼 스튜디오 닷넷에는 지면 관계상 다 소개할 수는 없지만 모델링에 관계된 많은 새로운 도구들이 추가되었다. XML 디자인이나 데이터베이스 디자인, 배포 디자인까지 비주얼 스튜디오 닷넷에서 할 수 있다. 이런 기능들은 평소 비주얼 스튜디오를 사용하던 개발자들에게 아주 친숙한 환경을 제공해 줄 수 있다.


단점이라면, 그 외에 아무것도 없다는 것이다. 또한, 현재 베타 버전에서는 다른 라이브러리에 포함된 개체들을 클래스 다이어그램에 포함하는 인터페이스가 상당히 불편하다. 이는 개선되어야 할 점이다. 사실 투게더나 로즈같은 훌륭한 도구들을 사용하던 입장에서 비주얼 스튜디오 닷넷 2005의 설계 도구를 테스트 하는 입장에서는 전혀 새로울 것도 없고 감동적일 것도 없다.

또한 MS가 자사의 객체지향 개발 방법론을 연구하고 있다는 소문이 풍문에 들려오는 것을 보면, 정식 제품에는 다른 도구가 추가될 지도 모르고, 로즈나 투게더 같은 도구 정도의 많은 기능은 아니더라도 다른 많은 도구들이 추가될 것으로 보인다.

독이 될 수도 갈라드리엘의 별이 될수도
UML은 좋은 도구다. 하지만 대부분의 개발 팀에는 도움이 되기보다는 방해가 되기 일쑤다. UML에는 너무나 많은 것이 있고, 다 활용하기는 벅차고, 그렇다고 사용하지 않기에는 또 뭔가 빠진 듯한 느낌이 드는 것이 그것이다. 늘 절제하는 마음으로 UML을 사용한다면, UML은 아주 좋은 도구가 된다.

필자는 항상 이런 얘기를 한다. "로즈가 설치되어 있는 책상 위에는 항상 연필과 지우개, 그리고 종이가 있어야 한다" 특히 개발자의 입장에서는 UML이라는 도구는 독이 될 때는 한 모금에 사람을 죽일 수도 있는 치명적이 독이 될 수도, 또는 길을 안내해주는 갈라드리엘의 별이 될 수도 있다.@

* 이 기사는 ZDNet Korea의 제휴매체인마이크로소프트웨어에 게재된 내용입니다.

 

김상훈 (동명정보대학 정보기술 연구원)

2005/03/31

 

사용자 삽입 이미지

 

원문 :http://www.zdnet.co.kr/techupdate/lecture/etc/0,39024989,39134587,00.htm

신고
0  Comments,   0  Trackbacks
댓글 쓰기
[객체지향 SW 설계의 원칙] ① 개방-폐쇄 원칙

[객체지향 SW 설계의 원칙]① 개방-폐쇄 원칙

-다시 보면 크게 보이는 개방-폐쇄 원칙

 

연재순서
1회.다시 보면 크게 보이는 개방-폐쇄 원칙
2히.헤어져서 행복해진 사례연구, 단일 책임 원칙
3회.인터페이스 분리의 원칙
4회. 리스코프 치환 원칙
5회. 의존 관계 역전의 원칙
6회. 정리

 

소프트웨어 설계의 묘미는 개발자가 작업하는 시스템의 창조자 역할을 할 수 있다는 것이다. 실세계의 경우 좋은 세상을 만들기 위해 적절한 질서, 정책, 의식 등이 전제돼야 하듯, 소프트웨어 설계의 경우는 객체와 객체간의 유기적 관계를 가장 효과적으로 구성하는 방법이 관건이 된다.

설계자는 자신의 문제영역에서 몇 가지 원리, 원칙, 패턴, 모델에 따라 문제들을 해결하면서 좋은 설계를 만들어간다. 이런 원리, 원칙들은 과거의 선배 설계자들이 시행착오를 거치면서 발견했던 것들이며 ‘설계자’란 종의 유전자에 묵시적으로 주입한 원칙들이다. 필자는 이번 연재를 통해 이 원칙들을 여러 측면에서 심도 있게 다룰 계획이다.

정상 세포와 암 세포는 거의 동일한 구조로 되어 있다. 단지 암 세포는 변이를 일으켜 정상 세포와 조금 달리 행동할 뿐이다. 세포 하나만 놓고 봤을 때는 크게 위험할 것 같지 않다. 하지만 이러한 세포들이 모였을 때 어떤 규칙은 생명을 유지하는 항상성을, 어떤 규칙은 생명을 앗아가는 암을 일으킨다. 개별 세포의 몇 가지 행동 방식이 다를 뿐이지만, 수천수만의 세포가 상호 작용하게 되면 이 조그만 규칙의 차이는 걷잡을 수 없이 커지게 된다.

세상은 생각보다 단순하다
유명한 NP 문제 중에 TSP(Traveling Salesman Problem)라는 것이 있다. 여러 도시가 있을 때, 가장 빠른 시간에 모든 도시를 순방하는 경로를 찾는 문제다. 언뜻 보면 쉬울 것 같지만, 도시의 수가 증가함에 따라 경로가 기하급수적으로 늘어나기 때문에 최단 경로 찾기는 지극히 어려워진다. 이는 네트워크에서 패킷이 목적지까지 도달하는 최단 경로를 구하는 문제와 똑같다.

1999년 간단한 규칙을 이용해 TSP를 가장 효율적으로 해결한 알고리즘이 발견됐다. 정말 단순하다. A에서 B를 향해 가상의 세일즈맨들을 보내면, 이들이 임의로 경로를 택해 B까지 도달한다. 그리고 B에 도달한 세일즈맨은 자신이 왔던 길을 따라 A로 돌아가면서, 각 도시에 시간이 지날수록 냄새가 옅어지는 무엇을 떨어뜨린다. 이제 다시 A에서 세일즈맨을 보낸다. 이 세일즈맨은 냄새가 가장 짙은 도시를 따라 B까지 가게 된다. 이 경로가 이 알고리즘의 최단 경로가 된다. 이 방법은 매우 효율적인 것으로 알려져 있으며, 유럽의 전화 회사에서 라우팅을 위해 사용하고 있다.

사용자 삽입 이미지
<그림 1> 독일 도시들로 구성한 TSP, 그리고 최단 경로


현대 의학으로 고치기 어려운 암도 결국은 구성 요소들의 간단한 규칙으로 인해 발생한다. 그리고 TSP와 같은 난공불락일 것 같은 문제도 구성 요소 간의 간단한 규칙으로 해결할 수 있다(이 때는 규칙으로 인해 암 대신 최단 경로라는 특성이 창발한다). 구성 요소들이 일정한 규칙을 따르고, 이러한 방식으로 상호 작용하는 요소가 많아질 때 부분보다 큰 전체가 나타나는 것이다.

단순하고 유연한 프로그램과 복잡하면서도 경직된 프로그램이라는 차이도 결국은 프로그램을 구성하는 가장 기본 단위인 객체들이 어떤 규칙을 가지고 상호 작용하는지에 의해 결정된다. 객체들이 정상 세포와 같이 좋은 규칙으로 관계를 맺는다면 좋은 프로그램이 나오고, 암 세포와 같이 (인간이 보기에) 나쁜 규칙으로 관계를 맺는다면 나쁜 프로그램이 나오는 것이다. 간단한 규칙이지만 이를 따라 관계 맺는 객체들이 모여 차이를 낳는다. 이러한 규칙을 알 수 있다면 얼마나 좋을까? 많은 인기를 끌고 있는 디자인 패턴이 이에 대한 답이 될 수 있을까?

디자인 패턴
디자인 패턴은 많은 프로그래머들이 성공적인 프로젝트에서 무수히 반복해 사용했던 문제 해결 기술을 발견해 정형화한 것이다. 각 패턴은 특정 맥락의 문제를 효과적으로 해결할 수 있게 해주며, 패턴들은 해결하는 문제의 맥락(GoF의 용어로는 Intent)이 다르다.

분명 패턴을 잘 이해하고 사용하면, 수많은 개발자, 연구자들의 “아하(Aha)!” 경험을 (그들이 들였던 노력에 비해서는) 손쉽게 사용할 수 있게 된다. 하지만 패턴은 빈번히 발생하는 ‘특정’ 문제에 대해 적용할 수 있는 해결책이기 때문에 객체들 간의 게임에 법칙에 관한 일반 룰까지 알려주지는 않는다.

패턴이 좋은 게임의 규칙을 이용해 객체들의 관계를 맺고 있음은 분명하다(좋은 게임의 규칙을 사용하고 있지 않다면, 특정 문제에 대해서도 좋은 해결책이 나올 수 없다). 그런데 이 때 패턴이 암묵적으로 사용하는 게임의 법칙을 모르면, 패턴이란 고도의 게임 전술을 유용하게 구사할 수 없게 된다. 패턴은 성공한 프로젝트 코드들에서 발견, 일반화되는 과정에서 코드에서 디자인으로 추상화됐기 때문에 이들 다시 코드로 구체화하려면 패턴이 사용하는 게임의 법칙을 알아야 한다. 이를 모른다면 장님이 코끼리 다리 만지듯 패턴을 사용하게 될 위험이 있다. 패턴을 사용해 프로그램을 만들었는데, 괜히 복잡해지기만 하던 걸? 글쎄….

게임의 법칙은 있다
수십 년간, 많은 개발자, 연구자들은 베일에 가려진 좋은 게임의 법칙을 찾기 위해 노력해 왔다. 노련한 개발자의 경험이 깃든 패턴으로 승화된 디자인은 이러한 게임의 규칙을 철저히 지키고 있으며, 이러한 규칙들을 지킨다면 단순하면서도 유연한 프로그램이 창발하게 된다. 이번 글에서는 많은 사람들이 노력해 발견한 이러한 게임의 법칙을 설명하려 하며, 구체적인 내용은 다음과 같다.


◆ OCP(Open-Closed Principle) : 개방-폐쇄 원칙
◆ LSP(Liskov Substitution Principle) : 리스코프 교체 원칙
◆ SRP(Single Responsibility Principle) : 단일 책임의 원칙
◆ DIP(Dependency Inversion Principle) : 의존 관계 역전 원칙
◆ ISP(Interface Segregation Principle) : 인터페이스 격리 원칙


이제 본격적으로 OCP에 대해 살펴보자.

개방-폐쇄 원칙
휴대전화를 살 때마다 느끼는 것이지만 똑같은 기능을 하는 충전기가 (같은 회사의 제품임에도 불구하고) 저마다 다른 모양으로 제작되는지 불만이었다. 의도는 뻔하게도 하나라도 더 팔아서 이윤을 높이기 위함이다. 기업에는 이익이겠지만 소비자에게는 똑같은 기능의 부품을 또 사야 하는 스트레스를 유발시키고, 국가적으로도 엄청난 자원 낭비가 될 만도 하다.

얼마 후 정통부에서 표준 규격으로 24핀 잭을 발표했다. 그 정책 덕분에 이제 휴대전화만 사고 충전기는 재사용할 수 있게 됐다. 따라서 휴대전화의 여러 종류에는 ‘개방하지만’ 충전기의 쓸데없는 생산은 ‘닫아두는’ 효과를 얻은 것이다. 바로 이번 호에서 소개할 개방-폐쇄의 원칙을 잘 반영한 결과라고 생각한다.

사용자 삽입 이미지
<그림 2> 1×1 호출 관계


다시 우리의 필드로 돌아와서 <그림 2>는 클라이언트가 서버의 서비스를 실행하는 모습이다. 일반적인 경우지만 서버의 서비스 타입이 여러 개 있을 경우 1×n의 클라이언트 대 서비스의 관계가 성립된다. 따라서 각각의 다른 서비스를 호출하는 클라이언트들은 호출 코드를 각 서비스 타입에 따라 다르게 작성해야 한다. 이 때 클라이언트가 파일만을 읽는 것이 아니라 스트링 버퍼로 바이트 배열로 읽는다면 실제로 그 관계는 n×m의 관계가 된다. 이렇게 읽는 대상의 타입이 확장, 변경될수록 복잡도는 <그림 3>과 같이 두 배 이상 증가한다.

사용자 삽입 이미지
<그림 3> n×m 호출 관계


물론 약간의 경력자들은 이런 객체 관계를 무의식적으로 피한다. 실제 자바 설계에도 반영됐지만 보통 <그림 4>와 같은 상속을 통한 다형성을 이용한다. 목적은 InputStream의 확장은 열어두고 클라이언트의 변경은 닫아두기 위함이다. 따라서 클라이언트는 InputStream 자식 클래스의 실제 타입에 상관없이 InputStream을 통해 충분히 읽고 싶은 것을 읽을 수 있다. 즉, 이상적인 1×n의 관계가 됐다. 확장에 대한 비용은 단지 생성 시점에 실제로 사용할 자식 클래스의 타입을 선택해주면 되는 정도다.

사용자 삽입 이미지
<그림 4> 상속을 통한 다형성을 이용한 호출 관계(1×n)


이 개방-폐쇄 원칙을 잘 정의한 버틀란트 메이어(Bertrand Meyer)는 소프트웨어 구성 요소(컴포넌트, 클래스, 모듈, 함수)는 확장에 대해서는 개방돼야 하지만 변경에 대해서는 폐쇄되어야 한다고 말한다. 변경을 위한 비용은 가능한 줄이고 확장을 위한 비용은 가능한 극대화해야 한다는 의미다.

방법은 우선 변하는(확장되는) 것과 변하지 않는 것을 엄격히 구분해야 한다. 변하는 것은 가능한 변하기 쉽게, 변하지 않는 것은(폐쇄돼야 하는 것은) 변하는 것에 영향을 받지 않게 설계하는 것이다. 다음으로 이 두 모듈이 만나는 지점에 인터페이스를 정의해야 한다. 인터페이스는 변하는 것과 변하지 않는 모듈의 교차점으로 서로를 보호하는 방죽 역할을 한다.

서버에 있어서 인터페이스는 확장의 내용이 정의되고 이 규약에 따라 확장이 구체화하는 역할을 한다. 따라서 인터페이스는 서비스 내용을 추상화하는 형태로 제공되므로 인터페이스 설계에 주의가 필요하다. 또한 인터페이스는 클라이언트에 있어서 서버의 확장·변경에 따른 클라이언트 변경을 무색하게 하는 방패가 된다. 서버에서는 인터페이스 규약에 의해서만 확장·변경하기 때문이다. 따라서 안정된 계약에 의한 설계(Design by Contract)를 보장한다.

이를 통해 얻을 수 있는 효과, 즉 목적은 앞의 예처럼 객체간의 관계를 단순화해 복잡도를 줄이고, 확장·변경에 따른 충격을 줄이는 데 있다. 또한 클라이언트는 InputStream의 타입을 알아야 할 시점(InputStream의 자식 클래스 생성 시점)과 각 타입의 무관한 사용 시점(호출 시점)을 명확히 분리해 사용할 수 있다. 따라서 다른 InputStream이 확장될 때 클라이언트에 있어서 InputStream의 자식 클래스를 생성하는 코드만 변경해 주면 된다. 물론 클라이언트의 확장에 따른 코드 충격은 다른 방법으로 단순화, 자동화할 수 있다(환경 변수로 타입을 정의하거나 문자열로 동적 객체 바인딩 메커니즘을 이용하는 등).

사례들
사실 이 원칙은 실세계에서도 흔히 찾아볼 수 있을 정도로 너무도 당연한 원칙이어서 소프트웨어에서 사례를 찾는데 오히려 안 보이는 곳이 없을 정도로 많이 적용된 원칙이다.

사용자 삽입 이미지
사례 1 : 컴파일러의 계층
사용자 삽입 이미지
 
사용자 삽입 이미지
컴파일러 개발자들은, 특히 GCC 같이 여러 종류의 시스템에 포팅되는 소프트웨어를 만드는 사람은 고생이 많을 것이다. 시스템마다 바이너리 포맷이 다르고 프로세서에 따라 명령어가 차이가 있다. 게다가 병렬 처리나 실시간, 임베디드 시스템의 경우는 제공해야 하는 라이브러리도 가중된다. 여기서 가변적인 요소는 운영체제와 프로세스의 종류이다. 따라서 컴파일러 개발자는 지금 주제의 관점에서 (앞의 두 요소에 의해) 변하는 모듈과 변하지 않는 모듈을 구분하고 이 두 모듈간의 인터페이스를 정의하는 미션이 중요할 것이다.

컴파일러 처리 과정을 보면 이 두 가지의 Open 모듈과 Closed 모듈이 명백히 분리되어 있다. 스캐닝, 파싱이나 구문, 문법, 의미 분석은 OS나 CPU에 영향을 받지 않는 프로그램 언어의 영역이다. 따라서 변경되지 않는 모듈로 보호해야 한다. 하지만 각 플랫폼에 따른 기계어로 바이너리 코드를 만드는 모듈은 포팅되는 시스템마다 확장되어야 하는 모듈이다. 즉 앞에 열거한 작업은 시스템에 의존성이 없기 때문에 시스템이 변경된다 하더라도 변경해줄 필요가 없다.

하지만 기계어 코드를 만드는 과정에서 최적화 제네레이팅하는 작업은 시스템에 의존적이기 때문에 시스템별로 확장을 요하는 모듈이다. AIX, 윈도우, 솔라리스 등의 버전이 필요하게 된다. 따라서 이 모듈은 확장에 적합한 구조로 개방해야 할 것이다. 여기서 중간 표현(intermediate representation) 데이터는 이 두 모듈간의 인터페이스 역할을 한다. 함수 형태의 인터페이스도 있지만 프로토콜과 같이 메시지(데이터 포맷) 형태의 인터페이스도 가능하다.
사용자 삽입 이미지
사용자 삽입 이미지

사용자 삽입 이미지
<그림 5> 컴파일러의 OCP 계층


GCC 처럼 여러 시스템을 지원하는 컴파일러의 경우와 같이 POSIX(Portable Operating System Interface)는 유닉스 기반 운영체제의 시스템 인터페이스 표준이다. 자바의 경우 한번 작성된 코드로 JVM이 제공되는 모든 플랫폼에서 실행을 보장한다(고수준의 플랫폼 추상화). 비슷하게 POSIX 표준 또한 여러 종류의 유닉스 시스템에서 공통으로 제공하는 시스템 인터페이스를 정의하고 있다(저수준의 플랫폼 추상화). 따라서 POSIX를 준수한 시스템 인터페이스를 사용하는 코드는 다른 운영체제의 시스템 함수를 사용하는 데 문제가 되지 않는다.

앞에서 예를 든 정통부의 휴대전화 충전기 24핀 표준 규격이나 자바 표준, POSIX 표준, IEEE에 이르기까지 어디에나 '표준'이 일종의 해결사, 중재자 역할을 한다. 이 '표준'의 역할은 지금의 맥락에서 의미심장하게도 OCP의 '인터페이스'의 기능을 한다. 표준에 의해 사용자는 서비스의 기능(규약)을 신뢰할 수 있으며(closed), 서비스 제공자는 자신의 목적에 맞게 확장·특화하여 서비스의 차별화, 상품성을 높인다(open).

OCP 주의점 1
다시 <그림 5>로 돌아가서, 공통 모듈(shared module)의 존재는 (그림에서와 같이) 시스템을 지저분하게 하는 경향이 있다. <그림 4>와 같이 상속 구조를 갖는 자식 클래스들이 있을 때 공통된 루틴이나 변수를 리팩토링의 ‘Pull Up Method/Pull Up Field’하고 싶은 유혹에 빠진다. 리팩토링은 설계를 깔끔하게 하는 좋은 방법이지만 문제는 대상의 크기에 있다. 위의 공통 모듈이 작을 경우 공통 모듈 재사용성을 얻기 위해 너무 잦은 (다른 영역의) 모듈을 접근해야 하고 모듈 구성도 보는 바와 같이 지저분해진다.

OCP에서 주의할 점은 확장되는 것과 변경되지 않는 모듈을 분리하는 과정에서 크기 조절에 실패하면 오히려 관계가 더 복잡해져서 설계를 망치는 경우가 있다는 것이다. 설계자의 좋은 자질 중 하나는 이런 크기 조절과 같은 갈등 상황을 잘 포착하여 (아깝지만) 비장한 결단을 내릴 줄 아는 능력에 있다.

사용자 삽입 이미지
사례 2 : 미들웨어의 출현
사용자 삽입 이미지
 
사용자 삽입 이미지
C/S에서 미들웨어로의 전환은 역시 변하지 않는 서비스를 독립시키려는 이유에서이다(물론 다른 의미도 많겠지만). 트랜잭션이나 분산 시스템, 메시징 서비스 같은 미들웨어적인 기능은 비대해지는 서버와 클라이언트 모두에게 부담이 됐다. 또한 이 모듈의 목적도 어느 정도 정리되어 있어 변하지 않는 모듈로도 손색이 없다. 따라서 자연스럽게 closed의 영역으로 분리됐다.

하지만 미들웨어도 완결된 시스템이 아니기 때문에 분리되는 과정에서 미들웨어 인터페이스를 만들게 된다. 즉 미들웨어 자체의 버전 업그레이드나 내부 모듈의 확장 여지를 남기기 위해 (변하지 않아서 분리됐음에도 불구하고) 자신의 인터페이스를 클라이언트와 서버에 제공한다.

여기서 레이어 시스템의 양방향 OCP 전략을 볼 수 있는데, 한 레이어의 인터페이스는 관계하는 양쪽을 위해 두 개의 인터페이스로 정의하게 된다. 가령 OSI 레이어에서 각 레이어는 위, 아래를 위한 두 개의 인터페이스를 갖는다. 이로써 그 레이어 내부의 확장·변경으로부터 외부에 전달되는 충격을 무력화한다. 마치 이더넷 카드를 다른 제품으로 바꾼다 하더라도 그 이더넷 카드는 하위 망 계층과 상위 드라이버 계층에 동일한 인터페이스를 준수하기 때문에 동작하는 데 아무 문제가 생기지 않는다.
사용자 삽입 이미지
사용자 삽입 이미지


OCP 주의점 2
하지만 재미있는 현상은 JTA와 같은 어댑터(adapter)의 역할이다. 가령 트랜잭션 모니터의 경우 MS의 MTS나 JTS, 턱시도(Tuxedo)들은 인터페이스의 차이가 있어 비슷한 기능을 함에도 불구하고 상호 운용을 위해 서로의 인터페이스를 변환시켜 주는 어댑터를 필요로 한다. 적절한 비유가 될지 모르지만, InputStream의 예에서도 공유 메모리 스트림을 확장해야 한다고 했을 때 문제가 발생한다. 공유 메모리 접근은 비동기적이기 때문에 기존의 동기적인 read() 메쏘드를 그대로 적용하는 데 문제가 생긴다. 이전까지 동기적인 스트림만 상대했던 설계자에게 있어서 공유 메모리는 경악할만한 요구 사항이다. 이 경우에도 비동기적 접근을 동기적으로 표현하기 위한 어댑터가 필요할 것이다.

확장을 보장하는 open 모듈 영역에서 예측하지 못한 확장 타입을 만났을 때 인터페이스 변경하려는 안과 어댑터를 사용하려는 안 사이에서 갈등하게 된다. 위의 두 예에서처럼 변경의 충격이 적은 후자를 택하는 경우가 대부분이다. 한 번 정해진 인터페이스는 시간이 갈수록 사용하는 모듈이 많아지기 때문에 바꾸는 데 엄청난 출혈을 각오해야 한다. 자바의 deprecated API가 대표적인 경우다.

즉, 인터페이스는 가능하면 변경해서는 안 된다. 따라서 인터페이스를 정의할 때 여러 경우의 수에 대한 고려와 예측이 필요하다. 물론 과도한 예측은 불필요한 작업을 만들고 보통, 이 불필요한 작업의 양은 크기 마련이다. 따라서 설계자는 적절한 수준의 예측 능력이 필요한데, 설계자에게 필요한 또 하나의 자질은 예지력이다.

사용자 삽입 이미지
사례 3 : 커맨드 패턴
사용자 삽입 이미지
 
사용자 삽입 이미지
텍스트 에디터에서 Copy란 명령은 여러 방법으로 실행할 수 있다. 아이콘, 메뉴에서 선택, 오른쪽 마우스, 단축키 등을 통해 사용할 수 있다. 하지만 명령을 요청하는 방법이 다를 뿐이지 처리하는 핸들러는 하나다. 이렇게 요청자와 처리자의 관계가 복잡해지는 객체 관계에서 그 처리를 단순화하기 위해 커맨드 패턴을 사용한다. 즉, 명령을 실행하는 방식이 어떤 방법이든지 Copy 기능을 구현한(execute() 메쏘드로) CopyCommand라는 객체를 생성하여 처리자에 전달하면 처리자는 CopyCommand가 어떤 작업을 하는지 알 필요 없이 execute()를 실행하여 객체 관계를 단순화할 수 있다.

Command 객체는 실제 작업과 정보를 캡슐화하여 처리자에 전달된다. 따라서 복잡도는 낮아진다. 이렇게 처리하는 방식은 스트럿츠에서도 적용되는데, 스트럿츠 Action 클래스는 커맨드 패턴의 좋은 사례가 된다. 커맨드 패턴은 이렇게 호출을 요청하는 요청자와 그 요청을 처리하는 처리자 간에 Command라는 실제 처리 로직을 캡슐한 객체를 통해 의존성을 분리하는 패턴이다.

이제 우리는 이 구조에서도 OCP의 형태를 직관할 수 있다. 이 패턴이 유용한 점은 이 처리 캡슐 단위의 조합으로 또 하나의 처리 단위를 만들 수 있다는 것이다. 가령 '파일 비교'란 명령을 수행하기 위해 '파일 열기' → diff → '파일 닫기' 명령을 두 파일을 통해 수행함으로써 하나의 처리가 완성된다.
사용자 삽입 이미지
사용자 삽입 이미지

사용자 삽입 이미지
<그림 6> 커맨드 패턴


OCP 주의점 3
이 패턴이 성공하기 위한 포인트는 요청자와 처리자 사이의 계약인 커맨드의 역할이다. 처리자는 execute()란 인터페이스만 알면 어떤 처리도 수행할 수 있다. 따라서 서로 의미적 관계가 없는 Command들도 execute()란 메쏘드로 무엇이든 확장할 수 있다. OCP 구조에서 서버가 확장할 수 있는 운신의 폭이 넓어진 반면 클라이언트는 서버가 어떤 처리를 하는지 무지해진다. 물론 커맨드 패턴에서의 execute() 메쏘드는 적절하지만 InputStream 예제에서의 read()를 doWork() 같은 메쏘드로 대치한다면 좋은 구조가 되지 못 할 것이다. 왜냐하면 클라이언트는 자신이 어떤 작업을 하는지 모르기 때문이다.

즉, 인터페이스 설계에서 적당한 추상화 레벨을 선택하는 것이 중요하다. 우리는 추상화라는 개념에 '구체적이지 않은' 정도의 의미로 약간 느슨한 개념을 갖고 있다. 그래디 부치(Grady Booch)에 의하면 ‘추상화란 다른 모든 종류의 객체로부터 식별될 수 있는 객체의 본질적인 특징’이라고 정의하고 있다. 즉, 이 '행위'에 대한 본질적인 정의를 통해 인터페이스를 식별해야 한다. 이것이 OCP의 세 번째 주의점이다.

설계 원칙의 역설
디자인 패턴은 소프트웨어 설계의 좋은 템플릿이다. 우리는 디자인 패턴을 이용하여 설계 모델을 좋은 구조로 유도한다. 이 구조는 소프트웨어 품질을 높이게 하고 기능을 강화시키기도 한다. 소프트웨어 설계 모델의 메타적인 원리가 디자인 패턴의 단위라고 한다면 디자인 패턴에 등장하는 좋은 구조들에 대한 메타적인 원리가 이번 연재를 통해 소개할 원칙들 정도 된다.

이 원리들은 물론 표준화 작업에서부터 아키텍처 설계에 이르기까지 다양하게 적용할 수 있지만 그 크기의 대비를 보면 패턴보다 훨씬 작고 여러 곳에 적용되는 원칙이다. 그리고 우리는 이 원칙들에 자연스럽게 익숙한지도 모른다. 하지만 이 원칙의 정체에 대해서는 (필자가 앞에서 추상화를 언급한 것처럼) 모호하게 생각한다. 이 연재를 통해 좀더 이 원칙들의 의미와 내용을 심도 있게 다룰 계획이다.

초로의 나이이임도 불구하고 태극권의 일인자였던 어느 노인이 이런 말을 했다고 한다. “나는 한평생을 걸쳐 무술을 연습했지만 이제 서기(자세)를 제대로 할 수 있을 것 같다.” 입문자 때 배우는 서기 자세는 아주 쉬운 것 같지만 역설적이게도 아주 어렵다고 한다. 우리에게 있어서 이 설계 원칙이 이 정도의 의미가 아닐까 생각된다. 따라서 한 번 더 고민할 만한 화두일 것이다.@

* 이 기사는 ZDNet Korea의 제휴매체인마이크로소프트웨어에 게재된 내용입니다.

 

최상훈 (핸디소프트), 송치형 (서울대)

2005/04/07

 

사용자 삽입 이미지

 

원문 :http://www.zdnet.co.kr/techupdate/lecture/etc/0,39024989,39134727,00.htm

신고
1  Comments,   0  Trackbacks
댓글 쓰기
[UML 제대로 알기] ④ 닷넷 환경 UML 툴 활용 가이드

[UML 제대로 알기] ④ 닷넷 환경 UML 툴 활용 가이드

 

연재순서
1회.가능성·확장성 품고 등장한 UML 2.0
2회.초보자를 위해 다각도로 살펴본 UML
3회.바로 알고 제대로 쓰는 UML 실전 모델링
4회.닷넷 환경에서 UML 툴 활용 가이드
5회.표준을 넘나드는 UML의 적절한 사용

 

케이스 도구는 양날의 검이다. 활용도에 따라서 소프트웨어를 죽일 수 도 있다. 래쇼날 로즈(이하 로즈) 같은 케이스 도구는 능숙하게 다룰 수 있어야 되기까지 많은 학습 곡선을 필요로 한다. 능숙해진 다음에도 여전히 불편하다.

하지만 IDE와 통합된 케이스 도구는 코드의 자동 생성 등의 많은 편리한 도구를 제공한다. IDE와 통합된 케이스 도구는 UML이라는 것에 너무 얽매이지만 않고 자유롭게만 사용한다면 아주 훌륭한 프로젝트 도우미가 될 수 있다.

전통적으로 MS의 개발 플랫폼에서 사용하는 개발 도구는 MS가 100% 독점하다시피 해 왔다. STL이나 MFC를 개발하거나 사용하는 도구는 거의 비주얼 C++가 독점적이었고, COM 기반의 개발을 위해 사용되는 도구는 거의가 비주얼 베이직이었다(COM 개발을 위해 비주얼 C++를 사용하는 경우도 많이 봤지만 그 당시 이슈가 되던 RAD와는 거리가 먼 환경이었다). 물론 볼랜드의 델파이 등을 많이 사용하기도 했지만 MS의 막강한 개발 도구 비주얼 스튜디오를 넘기에는 벅차 보였다.

닷넷 환경이 발표되고, 닷넷이 산업계에서 서서히 자리를 잡아가자 닷넷 개발 도구의 필요성이 절실해 졌고, 당연히 MS의 비주얼 스튜디오 닷넷이 닷넷 개발 도구의 최강자 자리를 당연히(!) 차지했다. 사실, 비주얼 스튜디오 닷넷이 없으면 닷넷 개발이 불가능하다고 생각하는 사람들도 많다.

볼랜드가 C# 빌더 등의 닷넷 환경을 지원하는 도구를 내 놓았고, 기타 여러 벤더들이 제품을 출시했지만 MS의 아성을 무너트리기에는 역부족이다. 비주얼 스튜디오 닷넷은 닷넷 환경이 존재하는 한 닷넷 기반 IDE의 최강자로서 그 자리를 내놓지는 않을 듯 하다.

그렇다면 비주얼 스튜디오 닷넷에는 약점이 없을까? 아니다, 분명히 약점은 존재한다. 그것도 아주 커다란, 치명적인 약점이 있다. MS는 닷넷 환경을 분명한 객체지향 개발 환경(닷넷 환경에서의 CBD는 객체지향이 없이는 존재할 수 없다)이라고 했다. 객체지향 개발 환경이라면 객체지향 설계 도구가 없다면 그 활용 범위가 반감될 수밖에 없는데, 비주얼 스튜디오 닷넷 엔터프라이즈 아키텍트 버전에 포함된 비지오가 어느 정도 그런 기능을 해 주긴 하지만, 다른 객체지향 개발 도구인 로즈나 볼랜드 투게더(이하 투게더) 등의 편리함과 기능성에는 결코 미치지 못한다.

설계 도구와 개발 도구의 진정한 결합. 이상적인 환경이지만 사실 구현하기 어려운 개발 환경임에 틀림없다. 비주얼 스튜디오 닷넷은 분명 막강한 개발 환경이고, 비주얼 스튜디오 닷넷을 사용하면서 투게더 또는 로즈 같은 개발 도구를 같이 사용할 수는 없을까 하는 생각을 누구나 한번쯤은 해 보았을 것이다. 정말 그럴 수 있을까? 대답은 "물론 있다"이다. 로즈와 투게더는 비주얼 스튜디오 닷넷 XDE를 제공한다(물론 구입해야 한다).

래쇼날 로즈 2000 XDE
객체지향 모델링 도구 중 가장 유명하며, 많이 사용되는 도구인 로즈는 2002년 MS의 비주얼 스튜디오 닷넷에 애드인되어 사용될 수 있는 ‘래쇼날 로즈 2000 XDE for 비주얼 스튜디오 닷넷’을 발표했다(어찌된 일인지 아는 사람도 별로 없고 사용하는 사람은 더더욱 없다). 로즈 XDE를 가지고 있다면 그 자리에서 설치해 보기를 바란다. 물론 설치하는 시스템에 비주얼 스튜디오 닷넷이 설치되어 있어야 한다.

사용자 삽입 이미지
<화면 1> 로즈가 설치된 비주얼 스튜디오 닷넷 2003


로즈를 처음 설치하고 나면 처음엔 아무것도 없다. 도구상자에 뭔가 추가된 것도 아니고, 특별히 뭔가가 설치되었다는 느낌을 받을 수가 없는데(굳이 뭔가 설치되었다는 느낌이라면 아마 비주얼 스튜디오 닷넷의 실행 속도가 눈에 띄게 느려졌다는 느낌이 될 것이다) 솔루션 탐색기를 눈여겨 보면 평소에 볼 수 없던 아이콘이 하나 생겨있음을 알 수 있다. 그 아이콘을 주저 없이 클릭해 보자.

사용자 삽입 이미지
<화면 2> 추가된 동기화 아이콘


동기화 아이콘을 클릭하면 로즈와 비주얼 스튜디오 닷넷이 동기화되어 mdx 파일을 생성한다. 그리고 Model Explorer 창이 새로 생기고 프로젝트에 포함되어 있는 개체들을 탐색할 수 있게 해준다.

사용자 삽입 이미지
<화면 3> 로즈 XDE를 이용하여 Iterator 패턴을 디자인한 모습


로즈를 사용하여 모델링을 어느 정도 마쳤으면, 다시 동기화 버튼을 눌러 순 공학할 수 있다.

사용자 삽입 이미지
<화면 4> 로즈가 생성한 C# 코드


감동의 기능


[1] 너무 깔끔한 코드를 생성하고 닷넷 환경에서 권장하는 주석 내용들을 그대로 생성해준다. 다른 도구들은 생성한 코드의 indentation이 잘 되지 않거나 참조한 라이브러리의 네임 스페이스를 제대로 표시하지 않는 경우가 많은데, 그런 단점이 사라졌다.

[2] 참조한 라이브러리의 개체들을 모두 설계에 사용할 수 있게 해준다. 다른 모델링 도구들은 기본으로 포함되거나 직접 작성한 개체들만이 사용가능 한 경우가 대부분인데, 최상의 도구다운 기능을 보여준다.

[3] 깔끔하고 예쁜 출력을 지원한다. 다른 설계 도구의 경우 한 페이지 또는 두 페이지에 깔끔하게 출력할 수 있는 기능에 대한 지원이 부족한데, 깔끔하고 예쁘장한 산출물을 만들 수 있도록 도와준다.

[4] ASP.NET/ASP/Service Page 들에 대한 설계를 지원한다. Web Presentation Pattern을 응용한 설계가 필요할 때 아주 유용하다.


단점이라면, C#으로 작성한 메쏘드의 수정이 아주 불편하다. 또한, RUP를 너무 강조하는 경향이 있어 닷넷의 빠른 개발과는 어울리지 않는 부분이 엿보이고, 일일이 동기화를 해 주어야 코드와 설계가 연동이 되는데, 에러를 자주 발생하여 동기화가 되지 않는 경우가 빈번히 발생한다.

볼랜드 투게더
비주얼 스튜디오 닷넷에서 다른 유명한 설계 도구인 투게더를 사용할 수 있다. 투게더 역시 로즈와 마찬가지로 비주얼 스튜디오 닷넷에 애드인되어 설치된다. ‘볼랜드 투게더 for 비주얼 스튜디오 닷넷 2.0’을 설치하면 비주얼 스튜디오 닷넷에 투게더 VS.NET Model View라는 창이 생성된다.

사용자 삽입 이미지
<화면 5> 투게더 for 비주얼 스튜디오 닷넷 Model View


또한 솔루션 탐색기에 ModelSupport라는 폴더가 생성되고 폴더 내부에는 .txvpak이라는 확장자를 가지는 모델 파일이 생성된다. 이 파일을 더블클릭하여 모델링 도구를 사용하여 설계할 수 있는 설계 창을 열 수 있다.

사용자 삽입 이미지
<화면 6> 투게더를 사용해서 Iterator 패턴을 디자인 한 모습


투게더는 로즈와 달리, 코드의 실시간 생성을 지원한다. <화면 6>에서 보이는 클래스 아이콘을 더블클릭하면 코드를 곧 바로 생성하게 된다. 코드를 수정하건, 설계를 수정하건 간에 설계 또는 코드의 수정 사항이 즉시 상호간에 적용되게 되어있다.

감동의 기능


[1] 필자가 투게더를 사용해 보고 가장 감동적이었던 기능은 시퀀스 다이어그램을 실시간으로 생성해 주는 기능이었다. 메쏘드가 특정 객체들을 사용하도록 구성되었으면, 투게더는 그 메쏘드의 시퀀스 다이어그램을 아주 믿을만한 수준으로 자동 생성해 준다. <화면 7>은 Petshop 3.0의 AccountController 클래스의 CreateAccount 메쏘드의 시퀀스를 자동 생성한 것이다.


 

사용자 삽입 이미지
<화면 7> 자동 생성한 시퀀스 다이어그램


 


[2] 여러 디자인 패턴에 기반한 설계를 지원한다(로즈 역시 이 기능을 지원한다). GOF 디자인 패턴에 기반하여 설계를 하고자 하면 투게더는 디자인 패턴에서 각 객체들의 역할을 보여주며 각 역할을 하는 객체를 추가하고 삭제하는 Node by Pattern 도구를 지원한다. 투게더는 디자인패턴에 기반한 설계를 쉽고 오류 없이 할 수 있도록 도와주며 특히 디자인 패턴을 공부하는 사람에게 아주 유용한 도구가 될 수 있다.


단점이라면 생성된 코드가 그다지 깔끔하지 않아 재 정렬을 해줘야 한다는 점 등이다. 앞에서 설명한 두 가지 도구의 치명적인 단점이 하나 있다. 닷넷 환경에서는 실행할 때 참조되는 라이브러리를 복사하고 실행시 참조하므로 개발 중 라이브러리를 수정하고 다시 컴파일하여도 누군가 파일을 사용 중이기 때문에 덮어쓸 수 없다는 메시지를 절대로 보여주지 않는다. 하지만 앞의 두 도구는 모델링에 사용하고 있는 참조되는 라이브러리를 ‘물고’있기 때문에 참조하는 프로젝트를 종료하고 컴파일한 후 다시 비주얼 스튜디오 닷넷을 실행하여 계속 진행해야 한다.

그리고 전통적으로 닷넷 개발에서는 RUP 같은 개발 방법론이 사용되지 않아, 만약 UML을 그렇게 많이 사용하지 않는 개발자라거나 다른 개발 방법론을 준수하는(MSF 등의) 프로젝트라면 사용할 수 있는 다이어그램은 클래스 다이어그램뿐이고, 너무 많은 도구를 제공함으로서 개발에 혼란이 오며, 비주얼 스튜디오 닷넷 자체가 너무 느려져서 개발자의 '성질'에 나쁜 영향을 끼칠 수 있다는 것이다.

비주얼 스튜디오 닷넷 2005에 포함된 모델링 도구
MS도 닷넷 환경이 객체지향 환경이고, 객체를 모델링 할 수 있는 통합된 개발 도구가 필요하다는 것을 모를 리가 없다. 그래서 MS는 비주얼 스튜디오 닷넷의 차기 버전인 비주얼 스튜디오 닷넷 2005에 그런 모델링 도구를 추가했다(전체적으로는 투게더와 비슷한 모습이고, 필자가 현재 기사를 작성하고 있는 시점에서는 클래스 다이어그램 기능 이외의 기능은 들어있지 않다).

비주얼 스튜디오 닷넷 2005의 클래스 다이어그램 기능을 알아보자. 비주얼 스튜디오 닷넷 2005는 특별히 이전 버전과 비교해서 달라진 기능이 없다. 웹 프로젝트를 다른 프로젝트와 구분해서 생성하는 정도가 외관상으로 볼 때 달라진 기능이라 할 것이다. 비주얼 스튜디오 닷넷에서 클래스 다이어그램을 그리고 실시간으로 변경될 수 있는 기능을 사용하려 한다면 이전 버전에서 새 항목 추가 메뉴를 선택하는 것과 같이 한다. 새 항목 추가 다이얼로그 박스를 유심히 살펴보면 클래스 다이어그램이라는 항목 아이콘이 보이고 그 항목을 사용하여 클래스 다이어그램을 작성할 수 있다.

사용자 삽입 이미지
<화면 8> 비주얼 스튜디오 닷넷 2005의 새 항목 추가 다이얼로그 박스


 

사용자 삽입 이미지
<화면 9> 비주얼 스튜디오 닷넷 2005를 사용해서 Iterator 패턴을 디자인 한 모습


장점


[1] 아무래도 비주얼 스튜디오 닷넷에 애드인된 것이 아닌 빌트인된 모델링 도구이다 보니 애드인된 도구보다는 강한 결합성을 가진다. 빌트인되었을 때의 가장 큰 기대점은 아무래도 성능적인 측면인데 아직 베타 버전이기에 평가 내리기가 이른 듯 하다. 하지만 꽤 만족할만한 성능을 보여주고 있으며, C# 또는 비주얼 베이직 닷넷에 종속적인 멤버들만을 포함하므로 닷넷 개발에 어울리는 도구가 될 듯 하다.

[2] 비주얼 스튜디오 닷넷에 포함된 도구이다 보니 닷넷 개발에 가장 어울리는 코드를 생성하고 다른 도구들과 통합하여 사용할 수 있다. 닷넷에 추가된 수많은 새로운 개념들과 도구들을 사용할 수 있다.

[3] 비주얼 스튜디오 닷넷에는 지면 관계상 다 소개할 수는 없지만 모델링에 관계된 많은 새로운 도구들이 추가되었다. XML 디자인이나 데이터베이스 디자인, 배포 디자인까지 비주얼 스튜디오 닷넷에서 할 수 있다. 이런 기능들은 평소 비주얼 스튜디오를 사용하던 개발자들에게 아주 친숙한 환경을 제공해 줄 수 있다.


단점이라면, 그 외에 아무것도 없다는 것이다. 또한, 현재 베타 버전에서는 다른 라이브러리에 포함된 개체들을 클래스 다이어그램에 포함하는 인터페이스가 상당히 불편하다. 이는 개선되어야 할 점이다. 사실 투게더나 로즈같은 훌륭한 도구들을 사용하던 입장에서 비주얼 스튜디오 닷넷 2005의 설계 도구를 테스트 하는 입장에서는 전혀 새로울 것도 없고 감동적일 것도 없다.

또한 MS가 자사의 객체지향 개발 방법론을 연구하고 있다는 소문이 풍문에 들려오는 것을 보면, 정식 제품에는 다른 도구가 추가될 지도 모르고, 로즈나 투게더 같은 도구 정도의 많은 기능은 아니더라도 다른 많은 도구들이 추가될 것으로 보인다.

독이 될 수도 갈라드리엘의 별이 될수도
UML은 좋은 도구다. 하지만 대부분의 개발 팀에는 도움이 되기보다는 방해가 되기 일쑤다. UML에는 너무나 많은 것이 있고, 다 활용하기는 벅차고, 그렇다고 사용하지 않기에는 또 뭔가 빠진 듯한 느낌이 드는 것이 그것이다. 늘 절제하는 마음으로 UML을 사용한다면, UML은 아주 좋은 도구가 된다.

필자는 항상 이런 얘기를 한다. "로즈가 설치되어 있는 책상 위에는 항상 연필과 지우개, 그리고 종이가 있어야 한다" 특히 개발자의 입장에서는 UML이라는 도구는 독이 될 때는 한 모금에 사람을 죽일 수도 있는 치명적이 독이 될 수도, 또는 길을 안내해주는 갈라드리엘의 별이 될 수도 있다.@

* 이 기사는 ZDNet Korea의 제휴매체인마이크로소프트웨어에 게재된 내용입니다.

 

김상훈 (동명정보대학 정보기술 연구원)

2005/03/31

 

사용자 삽입 이미지

원문 :http://www.zdnet.co.kr/techupdate/lecture/etc/0,39024989,39134439,00.htm

신고
0  Comments,   0  Trackbacks
댓글 쓰기
[UML 제대로 알기] ③ 개발 프로세스에 따른 UML 실전 모델링

[UML 제대로 알기] ③ 개발 프로세스에 따른 UML 실전 모델링

개발 프로세스에 따른 UML 실전 모델링

 

연재순서
1회.가능성·확장성 품고 등장한 UML 2.0
2회.초보자를 위해 다각도로 살펴본 UML
3회.바로 알고 제대로 쓰는 UML 실전 모델링
4회.닷넷 환경에서 UML 툴 활용 가이드
5회.표준을 넘나드는 UML의 적절한 사용

 

UML과 개발 프로세스라는 것이 만나게 되면 각 프로세스 별로 UML을 활용하여 모델링을 하는 방법이 약간씩 달라지기 때문에 사용상 주의가 필요하게 된다. 이와 더불어 웹 애플리케이션 개발을 위한 UML 모델링은 어떻게 하면 좋은지에 대해서도 생각해볼 필요가 있다.

이번 글에서는 지금까지 UML을 이용하여 소프트웨어 개발을 수행하면서 느꼈던 개념상의 모호함과 모델링 시 주의할 점에 대해 살펴보고자 한다.

약 7년 전 필자는 UML에 관하여 세미나를 하려고 어느 업체를 방문한 적이 있었다. 세미나를 막 시작하려고 하는 순간 어느 분께서 'UML이 이번에 새로 나온 XML의 한 종류인가 보죠?'라고 질문을 했다. 과연 이 난관을 어떻게 헤쳐 나가야 할지 막막한 순간이 UML에 관한 이야기를 하려고 하면 지금도 떠오른다.

UML이 우리나라에 처음 소개되던 시기에는 많은 분들이 객체지향이나 모델링 언어에 대한 개념이 일반적이지 않았다. 하지만 약 7년이 지난 지금은 소프트웨어 개발을 하는 대부분의 종사자들은 UML이라는 것이 무엇이고 어디에 쓰는 것인지 알고 있다. 또한 소프트웨어를 개발하기 위해서는 적어도 UML 다이어그램 몇 개 정도는 그려줘야 할 것 같은 생각을 갖고 있다. 많은 인식의 변화가 있었지만 지금 이 순간에도 여전히 UML이라는 것을 제대로 활용하여 소프트웨어를 개발하고 있는지 제대로 알고 있는지는 의문을 갖지 않을 수 없다.

UML과 모델 그리고 산출물
UML과 모델, 산출물은 비슷한 것 같지만 실은 아주 다른 개념이다. 우리가 소프트웨어라는 것을 개발하기 위해 '무엇을 만들 것인가?'라는 질문에 답하기 위해서는 대상이 되는 문제영역을 정확히 알 필요가 있다. 소프트웨어 개발팀 혹은 개발자는 문제영역에 대하여 정확하게 이해하기 위한 가장 좋은 방법은 모델을 통하는 것이다. 모델은 문제영역의 현실을 단순화시킴으로써 우리가 만들고자 하는 시스템을 더 잘 이해할 수 있게 한다.

『The UML User Guide』에 의하면 모델링을 통해 우리는 다음과 같은 4가지 목적을 얻을 수 있다고 한다.


◆ 모델은 시스템을 현재 또는 원하는 모습으로 가시화하도록 도와준다.

◆ 모델은 시스템의 구조와 행동을 명세화할 수 있게 한다.

◆ 모델은 시스템을 구축하는 틀을 제공한다.

◆ 모델은 우리가 결정한 것을 문서화 한다.


즉, 복합한 시스템에 대해 모델을 만드는 이유는 그러한 시스템을 전체적으로 이해할 수 없기 때문이다. UML은 앞에서 언급한 4가지 목적에 충실히 부합하기 때문에 소프트웨어를 개발함에 있어 모델링 언어로 UML을 이용한다.

UML 다이어그램이 산출물인가?
필자는 어느 프로젝트의 개발 프로세스 멘터링를 하기 위해 한 업체를 방문한 적이 있었다. 그 곳에서 도착하여 간단한 미팅을 한 후 가장 먼저 요구했던 정보는 고객과 합의한 활동과 산출물의 목록이었다. 그 문서에는 역시 예상대로 요구사항 산출물에 '유스케이스 다이어그램'이라는 것이 있었고 분석 산출물에 '클래스 다이어그램'이라는 것이 들어 있었다. 이외 여러 부분에 'XXX 다이어그램'이 눈에 띄었다.

UML 다이어그램이 산출물이 될 수 있는가? 결론적으로 말하자면 UML 다이어그램은 산출물이 아니다. 나중에 자세히 설명하겠지만 산출물의 한 종류가 모델이고 모델을 표현하기 위한 수단 중에 하나가 UML 다이어그램이다.

예를 들어 UML의 클래스 다이어그램을 생각해 보자. 다양한 종류의 산출물은 그 산출물이 표현하고자 하는 정보를 보여주기 위해 UML 다이어그램을 이용한다. 유스케이스 실현(Realization)의 VOPC(View of Participating Classes)에서도 사용하고 비즈니스 조직을 표현하고자 할 때도 클래스 다이어그램을 사용할 수 있다. 또한 아키텍처 메커니즘을 표현하고자 할 때도 클래스 다이어그램을 이용한다. 유스케이스 다이어그램의 경우도 비즈니스 유스케이스 모델을 표현할 때도 쓰이고 시스템 유스케이스 모델을 표현할 때도 쓰인다. 다양한 산출물에 UML 다이어그램을 쓴다.

요구사항에서 혹은 분석/설계에서 산출물로 클래스 다이어그램이라고 명시해 놓으면 과연 어떤 클래스 다이어그램인지 알 수 있을까? 또한 시퀀스 다이어그램이 산출물 목록에 버젓이 들어있다면 그 다이어그램은 과연 어떤 정보를 표현하려고 하는 다이어그램인지 알 수 없다. 다이어그램은 산출물의 의도를 표현하기 위해 사용하는 하나의 표현도구이다. 산출물은 절대로 아니다.

우리의 목적은 산출물이다
앞에서 UML은 산출물이 아니며 모델은 산출물의 한 종류라는 것의 이야기했다. 그렇다면 산출물을 무엇을 의미하는가? 일반적으로 산출물이라는 것은 종이 형태의 문서로 알고 있다. 하지만 산출물은 프로세스를 통해 프로젝트 기간 동안 만들어지는 의미를 갖는 모든 것을 일컫는다. 그 중 하나가 모델이며 실행 가능한 바이너리 형태의 컴포넌트, 문서, 소스코드, 스크립트 등이 해당한다. 산출물(Artifact)의 정의를 보면 다음과 같다.


산출물은 어떤 정보의 일부로서 1) 프로세스를 통해 만들어지고 변경되고, 사용되며 2) 책임영역을 정의하며 3) 버전컨트롤의 대상이 된다. 산출물은 모델, 모델요소, 또는 문서 등이 될 수 있으며 문서는 다른 문서의 일부분으로 포함 될 수 있다(A piece of information that: 1) is produced, modified, or used by a process, 2) defines an area of responsibility, and 3) is subject to version control. An artifact can be a model, a model element, or a document. A document can enclose other documents).

모델(model) :유스케이스 모델, 분석 모델, 설계 모델과 같이 다른 산출물을 포함하는 형태를 갖는 산출물

모델 요소(model element) :다른 산출물 내부에 포함되어 있는 산출물로 예를 들면 유스케이스 모델 안의 유스케이스, 액터와 설계 모델 내부의 설계 클래스, 설계 서브시스템 등과 같은 산출물

문서(document) :문서로 존재하는 산출물로 비즈니스 케이스, 소프트웨어 아키텍처 문서 등과 같은 산출물

◆ 소스코드나 실행 가능한 것(컴포넌트) 등


<그림 1>은 산출물과 모델 그리고 UML과의 관계를 클래스 다이어그램으로 표현한 것이다.

사용자 삽입 이미지
<그림 1> 산출물의 종류와 UML간의 관계


모델링은 개발기간을 늘이는 원흉?
필자는 지금까지 여러 프로젝트에서 직접 개발에 참여하기도 했고 컨설팅 또는 멘터링 형태로 참여하면서 사람들로부터 많은 질문을 받아왔지만 그 중에 가장 많이 하는 질문은 “우리 프로젝트에 UML이 꼭 필요하겠습니까? 프로젝트 규모가 좀 작으면 UML을 적용하지 않아도 괜찮지 않을까요?”라는 것과 “UML을 적용하면 개발이 좀 늦어지지 않겠습니까?”라는 두 가지 질문이 대표적이다.

우선 첫 번째 질문의 의미를 생각해 보자. 프로젝트 규모가 작으면 UML을 굳이 적용하지 않고 두어 명 개발자들이 그냥 뚝딱뚝딱 시스템을 만들면 되지 않을까 하는 것이다. 필자도 비슷한 생각으로 모델링을 하지 않고 프로젝트를 진행해 본적이 있었다. 개발자 3명이 기능 수 약 100개 정도의 시스템을 개발한 적이 있었는데, 작고 간단한 시스템이었으므로 순진한 생각에 그냥 테이블 정도만 정리해 놓고 코딩부터 시작하면 쉽고 금방 될 줄 알았다.

하지만 상황은 그렇게 호락호락하지 않았다. 용어와 기능부터 명확히 정의되지 않았고, 시작부터 개발자간의 서로 다른 이해수준은 프로젝트를 암울하게 만들었다. 어렴풋한 이해를 바탕으로 만들어지는 코드는 만들고 나서 뜯어고치는 코드가 더 많아 졌고 비즈니스 컴포넌트간의 인터페이스로 수시로 어긋났다. 결국 간단하게나마 모델을 만들면서 진행하기로 했고 모델링 시간 약간 줄이려고 하다가 우왕좌왕한 만큼 시간을 허비한 결과로 나타났다. 꼭 UML이 아니더라도 어떤 형태로든지 모델링은 해놓았어야 했고 그것이 업계 표준인 UML로 했더라면 더 좋지 않았을까 하는 후회가 든다.

혼자 만들더라도 역시 UML로 모델링을 하는 것이 개발하는 중에도 좋고 개발하고 난 뒤를 생각해봐도 반드시 필요하다는 생각이다. 개발을 마치고 난 뒤에 누군가 그 시스템을 유지보수 해야 한다면 전 개발자가 UML을 이용하여 만들어 놓은 모델을 보고 아마 감사하게 생각 할 것이다. 또 개발하고 있는 순간에도 몇 명밖에 없지만 그 사람들끼리 의견 교환이나 문제 영역에 대한 공통적인 이해를 돕기 위해서도 필요하다. 혼자 개발하더라도 생각이 정리가 잘 안되면 UML로 아이디어를 정리하는 판에 다른 사람과 생각을 맞추는데 필요가 없겠는가?

“UML을 적용하면 개발 기간이 늦어진다”. 어떻게 보면 약간 황당할 정도의 이야기임에 틀림없다. UML 때문에 개발기간이 늘어나는 것이 아니라 익숙지 않은 UML을 모델링 언어로 선택함으로써 배우는 기간이 더 늘어나는 것이 정확한 의미가 아닐까 싶다. 심지어 어떤 프로젝트 매니저는 개발은 그냥 개발대로 나가고 산출물은 산출물대로 만들어 나가서 나중에 소스코드가 나오게 되면 역공학(Reverse Engineering)을 통해 UML 모델을 만들어내자는 제안을 하기도 했다. 모델과 코드간의 동기화를 위해 역공학을 이용하지만 과연 이것이 시간을 줄이는 방법일까?

개발 프로세스와 과도한 모델링
무엇을 모델링 할 것인가? 어느 정도의 정밀도 수준으로 모델링 할 것인가? 모델링의 범위는 어떻게 설정해야 하는가? 이러한 질문에 답하기 위해 이것저것 고민해보기도 하고 업계에 종사하는 분들과 메신저로 혹은 술자리에서 때로는 프로젝트 회의 시간에 토의를 많이 해 보았다. 그 중 필자가 알고 지내는 대부분의 개발자들의 한결같은 주장은 '과도한 모델링'의 압박에 시달린다는 것이었다. 이야기를 해 본 결과 실제로 개발자들이 느끼는 '과도한 모델링'의 기준은 주관적이었지만 몇몇 주장은 일견 수긍이 가기도 했다.

그 중에 하나가 프로세스의 적용 문제였는데 지구상에 존재하는 모든 프로젝트는 서로 다른 시스템을 만들고 있기 때문에 모든 프로젝트 천편일률적으로 적용되는 모델링 범위나 정밀도 수준은 없다. 하지만 그것을 프로젝트의 규모나 도메인의 종류 등의 일반화된 기준으로 묶고 그 기준에 해당하는 개발 프로세스를 제공해야 한다. 예를 들어 현재 우리나라에서는 RUP(Rational Unified Process)나 마르미와 같은 프로세스 프레임워크를 많이 사용한다. 또 SI 업체에서는 자체적으로 발전시켜온 방법론이나 앞에서 언급한 RUP 또는 마르미를 기반으로 하여 자체 프로세스를 개발하여 사용한다.

문제는 각 프로젝트마다 프로세스를 조정(Tailoring)해서 적용해야 하는데 현실은 그렇지 않다는 것이다. 심지어 이런 이야기를 들은 적도 있다. "CBD를 적용하기엔 우리 프로젝트 규모에 좀 안 어울리지 않나요? 아는 사람한테 물어봤더니 규모가 작으면 CBD가 안 어울린다고 하더라고요. 대신 굳이 CBD를 하려면 UML 모델링 툴을 반드시 도입해서 진행해야 한다고 하던데…" 누가 이 분에게 그런 이야기를 했는지 모르지만 이 정도 되면 거의 사기에 가깝다. 그 분이 생각한 CBD라는 것이 무엇이었는지 어림짐작되는 대목인데 마치 신발에 발을 맞추는 꼴이 되어 버렸다.

발을 보호하는 것이 1차적인 목표이고 멋도 부리는 것이 신발을 신는 2차 목표라고 보면, 우선 성공적인 프로젝트를 수행하기 위해 프로세스를 도입하고 이왕 개발할 것 좀 체계적으로 가이드를 받아보자는 목적도 있을 것이다. 객체지향이나 CBD와 같은 단어의 의미는 일단 논외로 하고 앞에서 언급한 프로세스 조정에 관하여 이야기 해보자.

프로세스 조정
앞에서 언급했듯이 RUP나 마르미는 일반적이고 범용적인 개발 프로세스이다. 세 달간 3명이 개발하는 프로젝트와 2년간 50명이 개발하는 프로젝트 모두 개발 프로세스가 같을 수 있겠는가? MS 워드와 같은 워드프로세서를 개발하는 것과 은행을 위한 전산 시스템을 개발하는 개발 프로세스가 같을 수 있겠는가?

서로 다른 특성을 갖는 프로젝트를 위해 프로세스 조정(Tailoring)이란 작업을 하게 되는데 여기서 유의해야 할 것은 조정할 수 있는 영역을 제한해야 한다는 것이다. 프로젝트 현장에서 편의대로 프로세스를 고치거나 누락시켜서는 안되고 프로세스 조정의 결과는 승인되어야 한다. 더 나아가 프로젝트 세부 유형에 따른 개발 프로세스를 제공한다면 더할 나위 없이 좋을 것이다. 프로세스의 대표적인 구성 요소로는 작업 영역, 작업 흐름, 활동, 산출물, 역할 등이 있다. 필자는 이 모든 것이 프로세스 조정 대상이 될 수 있다고 생각한다.

RUP의 경우 '프로세스 엔지니어'가 프로세스 조정 작업을 진행하고 마르미 경우 ‘도구 및 방법론 관리자’가 그 역할을 수행한다(XP의 경우는 코치라고 한다. 편의상 이 글에서는 모두를 프로세스 엔지니어라고 칭하겠다). 이런 역할의 특성상 다른 사람과의 의견 교환이나 대립이 있기 때문에 프로세스 엔지니어는 소프트웨어 개발에 관한 폭넓은 지식을 갖고 있어야 하며 의사소통 능력이 있어야 한다. 프로젝트 관리자나 프로젝트 리더 또는 시스템 분석가나 아키텍트를 설득해야 할 일이 있을 수도 있다.

프로젝트 관리자나 프로젝트 리더는 프로젝트 관리 관점으로 개발 프로세스를 바라볼 것이고 시스템 분석가나 아키텍트는 소프트웨어 시스템을 개발하는데 중요한 결정을 내리기 위한 관점으로 프로세스를 바라보며 자신의 의견을 제시 할 것이다. 이들의 의견을 통합하고 조정하며 고객의 요구를 반영하여 해당 프로젝트의 상황에 맞는 프로세스로 조정하게 된다.

사용자 삽입 이미지
<그림 2> 프로세스 엔지니어의 활동과 산출물


<그림 2>에서 프로세스 엔지니어는 현 개발 조직 평가, 개발 케이스(Development Case) 작성, 프로젝트 전용 템플릿 작성의 세 가지 활동을 하게 된다. 이에 따른 개발 조직 평가, 개발 케이스 프로젝트 전용 템플릿의 세 가지 산출물을 작성하는데 여기서 가장 핵심적인 산출물은 개발 케이스이다. 특정 프로젝트를 위한 프로세스를 조정하고 개발 케이스를 작성하기 위해서는 프로젝트의 상황을 이해 할 필요가 있는데 이를 위하여 현 개발 조직에 대한 평가가 이루어져야 한다. 또한 개발 조직 이외에도 고객에 대한 평가도 동시에 이루어져야 한다.

예를 들어, 기업을 위한 애플리케이션을 개발한다고 가정한다면 개발 완료 후에 고객은 유지보수를 위한 산출물을 요구할 것이다. 프로세스 엔지니어는 개발 조직 및 고객을 대상으로(좀 더 의미를 확장하자면 이해관계자를 의미 할 수 있다) 현 개발 조직에 대한 평가를 할 때 프로세스, 툴, 사람들의 능력, 사람들의 태도, 고객들, 사용 기술, 문제점, 개선 분야의 관점에서 개발 조직의 현재 상태를 평가한다.

프로세스 조정을 위한 요구사항을 파악하고 이를 근거로 프로세스 조정을 실시한다. 프로세스 조정의 결과는 개발 케이스이다. 프로세스 조정에 관한 자세한 사항을 알고 싶으면 RUP나 마르미 또는 Barry Boehm과 Richard Turner가 쓴 『Rebalancing Your Organization's Agility and Discipline』를 참조하면 도움이 될 것이다.

케이스 툴을 쓰면 생산성이 높아지는가?
Steve McConnell은 그의 저서인 『Professional Software Development(2003)』에서 코끼리에 관한 재미있는 이야기를 소개했다. 이야기를 요약하면 이렇다.

고대 이집트 어느 왕의 피라미드를 만드는 공사가 한 참 진행 중이었다. 엄청나게 큰 암석을 사람들이 일일이 날라야 했으므로 공사의 진척은 매우 더디었다. 그래서 공사 프로젝트 관리자는 고민 끝에 어디선가 코끼리라는 엄청난 동물이 있는데 이 동물은 사람이 운반하는 것 보다는 몇 배 혹은 몇십 배 높은 생산성은 낸다는 이야기가 얼핏 기억이 기억났다. 이 동물만 들여오면 지금까지 지연되었던 일정을 단번에 만회할 수 있을 것 같은 생각이 들었다.

공사 프로젝트 관리자는 그 동물을 도입하기로 결심하고 일을 추진했다. 코끼리라는 동물을 들여놓고 보니 과연 듣던 대로 몸집도 엄청나고 그에 걸맞게 힘도 대단했다. 공사 프로젝트 담당자는 입가에 미소를 머금으며 공사현장에 코끼리를 투입하라는 지시를 내렸다. 그러나 그 동물을 투입하는 순간 순조롭게 진행될 것 같은 공사가 점점 이상하게 진행되고 일정도 생각했던 것만큼 줄여지지 않았다. 줄여지기는커녕 오히려 사람이 진행했던 것보다 더 늦어지는 조짐이 보였다.

공사 프로젝트 관리자는 상황파악에 나섰는데 공사 현장에 가서 자세히 관찰을 해보니 문제를 바로 파악할 수 있었다. 바로 코끼리를 다룰 수 있는 사람이 없었던 것이었다. 그의 공사팀은 그런 동물을 부리면서 일을 한 적이 단 한번도 없었기 때문에 기존의 공사프로세스와 엄청난 혼선을 빗었다. 또 코끼리에 대해 아는 것이 전혀 없었기 때문에 코끼리를 돌보지 못해 걸핏하면 앓아눕기 일 수였고 몇몇 코끼리는 도망가 버려 엄청난 비용을 들여 도입한 코끼리가 무용지물이 되어 버렸다. 공사 진행은 그 만큼 지연되었고 코끼리를 포기할 수밖에 없었다"


필자가 보기엔 그 코끼리가 바로 케이스 툴이 아닌가 싶다. 프로젝트 생산성을 높이기 위해 케이스 툴을 도입하는 것은 바람직하지만 그 생산성을 높이기 위해서는 일정 기간의 훈련이 필요하다. 요즘 나오는 케이스 툴은 기능도 막강하고 더불어 복잡하다. 또 종류도 많아 수많은 케이스 툴과 연동도 필요하다. 일례로 IBM 래쇼날의 스위트 제품은 내장하고 있는 서브 제품만 해도 10여 가지가 넘는다. 다른 케이스 도구도 사정은 다를 바 없다.

프로젝트 현장의 요구는 이러한 제품을 좀 편하게 사용하고 싶어 한다. 소프트웨어 개발 라이프 사이클 전반에 걸쳐 케이스 툴을 적용하려고 서로 다른 회사 목적이 다른 툴을 서로 연계시켜야 한다. 이 일은 대단히 복잡하고 가변적이어서 앞의 요구를 충족시키려면 프로세스적으로나 케이스 툴에 대한 상당한 지식과 수준의 기술이 요구된다.

요구사항관리 도구와 분석/설계를 위한 모델링 도구와의 연계 부분, 모델링 도구와 개발 및 테스팅 도구와의 연계 부분이 대표적인 연계 부분이다. 또한 각 케이스 툴에서 쏟아져 나오는 다양한 모델과 문서들을 통합적으로 관리할 수 있는 형상 및 변경 관리와 각 작업영역(요구사항, 분석/설계, 구현, 테스트 등)을 기반으로 하여 반복 개념으로 프로젝트를 관리해야 하므로 실제 케이스 툴이 소프트웨어 개발을 도와주려면 아주 많은 것들을 고민해야 한다.

특히 프로젝트 현장에서 따르고 있는 프로세스를 정확히 지원해줘야 하므로 케이스 툴 자체의 유연성도 갖춰야 한다. 케이스 툴은 단어의 의미에서와 같이 소프트웨어 개발을 정말로 도와주는 케이스 툴이 되어야 하지 않을까 싶다.

머릿속 아이디어를 모델로 구체화하기
필자는 항상 프로젝트를 진행하다 보면 항상 딜레마에 빠지는 문제가 있다. 프로젝트에 참여하는 사람들이 UML을 잘 모르는 경우이다. UML을 모델링 언어로 채택한 프로젝트는 그 프로젝트에 참여하는 모든 사람들이 UML을 알고 있어야 한다는 전제조건이 따른다.

하지만 현실은 어떠한가? 프로젝트를 수주해야만 먹고 사는 개발 업체의 경우 UML을 알던 모르던 일단 수주를 해야만 하는 상황이다. 그 회사의 개발팀 구성원이 UML을 잘 알고 있다면 문제가 없겠지만 잘 모르는 경우 심하면 그 구성원 중 단 한 명도 제대로 알지 못하는 경우 문제가 아닐 수 없다.

이 때 가장 많이 활용하는 방법은 UML을 알고 있는 사람이나 업체를 고용하여 먼저 샘플을 만들게 한 후 그것을 템플릿으로 하여 모델링을 진행하는 것이다. 물론 이런 프로젝트가 많아야 필자 같은 사람들이 먹고 살긴 하겠지만 프로젝트 입장에서는 참 못마땅한 일이 아닐 수 없다.

예를 들어 UML을 알고 있는 사람이 시스템의 한 부분에 대하여 클래스 다이어그램을 그렸다고 하자. 그 클래스 다이어그램이 샘플로 나오면 다른 모든 사람들은 그 샘플을 기반으로 모델링을 시작하게 된다. 맞는지 틀리는지 자신의 판단 기준이 없는 채로 샘플을 '다른 이름으로 저장하기'로 해서 따로 하나는 만들어 놓은 다음 다이어그램을 그리고 저장을 한다. 예전에 학교에서 다른 친구 소스코드 구해다가 변수명 좀 바꾸고 약간 짜깁기해서 리포트를 제출하는 것과 비슷한 상황이 된다.

다이어그램이야 만들어 졌지만 모델링을 하는 사람이 그 모델이 적합한지 아닌지 판단할 수 없으므로 그려진 다이어그램을 들고 샘플을 만든 사람에게 달려와 이것저것 물어본다. 물론 어쩔 수 없는 상황이고 그런 과정을 거치면서 사람들의 모델링 실력이 향상되겠지만 모르면서 그림을 그리는 사람도 답답하고 프로젝트 진행에도 문제가 많다.
잘 모르는 사람이 프로젝트를 하는, 어떻게 보면 시작부터 이상하긴 하지만 어쩔 수 없다고 보고 조금이나 도움이 되도록 머릿속의 아이디어를 모델로 구체화 하는 과정을 소개하면 조금 낫지 않을까 싶다.

시작은 글쓰기부터
만들고자하는 모델이나 그리고자 하는 다이어그램에 따라 접근 방식이 다르겠지만 결국 시작은 머릿속의 생각을 글로 정리하는 것부터 시작한다. 글로 쓰기 귀찮다면 메모장이나 화이트보드에 본인의 생각을 간단하게나마 자유로운 형식으로 정리하면서 시작하게 된다.

예를 들어, 고과장이 애플리케이션 프레임워크를 모델링 한다고 가정해 보자. 프레임워크를 모델링하는 사람이 UML을 설마 모르진 않겠지만 이 사람이 어떤 과정을 거치면서 머릿속 아이디어에서부터 구체적인 모델을 만들어 가는지 살펴보자. 고과장은 프레임워크의 한 부분을 모델링하기 위해 고심하다가 머릿속에서만 맴도는 아이디어를 글로 써보기로 했다.

클라이언트에서 어떠한 메시지를 보내면 프레임워크에서는 그 메시지를 해석하여 어떤 비즈니스 로직을 수행할 지 결정하여 수행한다. 메시지에 따라 수행하는 비즈니스 로직은 메시지가 변해도 동일한 비즈니스 로직이 수행되어야 하거나 동일한 메시지에도 상황에 따라 비즈니스로 로직이 바뀔 수 있어야 한다.

써 놓고 읽어보니 대충 어떤 방향으로 만들어야 할지 느낌이 좀 오기 시작했다. 왠지 잘 될 것 같은 느낌으로 입가엔 미소를 머금으며 모델링 도구를 실행시켰다.

모델링을 시작하다
우선 고과장은 클라이언트와 클라이언트가 보내는 메시지를 받는 무엇인가가 있어야 하지 않을까 하는 생각이 들었다. 또 어떤 비즈니스 로직을 수행할지 판단하는 객체도 있어야 할 것 같고, 클라이언트가 보낸 메시지에 대응하는 비즈니스 로직을 갖고 있는 정보를 갖고 있는 객체도 있어야 할 것 같다.

고과장은 우선 '클라이언트', '메시지 판단자', '메시지와 비즈니스 로직 맵핑 정보' 등이 객체가 되지 않을까 생각했다. 모델링 툴을 띄워놓고 세 가지 객체를 그리고 나니 이들 간의 관계와 각 객체가 어떤 일을 해야 하는지(Responsibility)가 알쏭달쏭 했다. 그래서 이 세 가지 객체를 놓고 이들 객체가 서로 어떻게 인터랙션(Interaction)하는지 알아보기 위해 시퀀스 다이어그램을 그려보기로 했다.

사용자 삽입 이미지
<그림 3> 개념 정리를 위한 시퀀스 다이어그램


이렇게 그려놓고 보니 객체 간에 어떻게 교류하는지 눈에 들어와 더 구체적으로 생각할 수 있게 되었다. 고과장은 시퀀스 다이어그램을 보면서 차근차근 짚어보기로 했다. 클라이언트가 메시지를 '메시지 판단자'에게 보내면 해당 메시지에 대응하는 비즈니스 로직을 알려주고 메시지 판단자가 비즈니스 로직을 수행하여 클라이언트에게 보내주는 깔끔한 형태로 정리된 것 같았다.

뭔가 빠진 것 같은데?
하지만 객체 간에 어떻게 교류하는지 눈에는 보였지만 왠지 무엇인가 빠진 듯한 느낌이 들었다. 시퀀스 다이어그램을 쳐다보고 있으니 메시지 판단자가 '비즈니스 로직 수행'을 하는 것이 메시지 판단자의 역할에 비해 좀 오버하는 듯한 느낌이 들었다. 또 비즈니스 로직 수행이 잘 되었는지 아닌지 판단하는 부분도 있어야 할 듯 했다. 그래서 '비즈니스 로직 수행자'라는 이름은 좀 이상하지만 이런 객체를 따로 빼 두어 시퀀스 다이어그램을 보완하기로 했다.

사용자 삽입 이미지
<그림 1> 산출물의 종류와 UML간의 관계


비즈니스 로직 수행자를 넣어 시퀀스 다이어그램을 다시 그려보니 이제 뭔가 맞아 돌아가는 느낌이 들었다.

사용자 삽입 이미지
<그림 5>"그림 3"의 클래스 다이어그램


UML의 시퀀스 다이어그램과 클래스 다이어그램을 통해 객체간에 교류와 각 객체의 책임(Responsibility)를 찾아냈다.

설계를 위한 모델로 발전
이제 개념적으로 정리한 모델을 바탕으로 좀 더 구현하기 좋은 형태로 발전시켜 보자. 구현을 위해서는 좀 구체적인 형태로 정의하고 실제적인 비즈니스 로직 처리와 에러 처리를 표현하기 위한 무엇인가가 필요했다. 고과장은 고민 끝에 웹 서버로부터 아이디어를 얻었다. 웹 서버는 웹 브라우저와 커뮤니케이션을 위해 Request와 Response를 사용한다. 브라우저의 요청은 Request에 담아 웹 서버로 보내고 웹 서버의 응답은 Response에 담아 브라우저로 보내게 된다. 이런 비슷한 개념을 프레임워크에 적용해보면 어떨까 생각했다.

즉, 클라이언트의 요청은 BusinessRequest에 담아 보내고 서버의 응답은 BusinessResponse에 담아 보내되, 비즈니스 로직 수행시 Exception이 발생하면 BusinessResponse에 담아 메시지 판단자가 처리하게 하면 어떨까 하는 생각을 했다. 고과장은 이렇게까지 생각이 정리되자 시퀀스 다이어그램을 통해 아이디어를 구체화 해보기로 했다. 시퀀스 다이어그램은 <그림 6>과 같다.

사용자 삽입 이미지
<그림 6> 보다 더 구체화된 시퀀스 다이어그램


클라이언트 쪽의 예상 소스코드도 넣어 보고 메시지를 비즈니스ID라는 용어로 바꿔봤다. 또한 비즈니스ID의 해당 비즈니스 로직을 실행시키기 위해서는 리플렉션(Reflection)이라는 기술도 써야 할 것 같고 Exception 처리를 위한 부분도 따로 둬야겠다는 생각이 들어 BusinessResponse에 BusinessExcuteHelper가 Exception을 담아주는 형태로 모델링을 했다.

<그림 6>의 시퀀스 다이어그램을 보면 중간 중간 노트가 많이 달려있는 것을 볼 수 있다. 시퀀스 다이어그램의 중간 중간을 보면 샘플 코드나 리플랙션, Exception과 같은 구현을 염두 한 노트를 볼 수 있다. UML로 모델링을 할 때 노트의 역할은 필수 불가결한데 해당 다이어그램의 이해를 돕기 위해서나 모델러의 의도를 명확히 하기 위해서 또는 아직 불분명한 부분이 있을 경우 판단에 도움이 될 만한 주석을 달기 위한 수단으로 이용하면 좋다.

구체화된 모델
자 이제 구현을 위한 시퀀스 다이어그램도 그렸고 구체적으로 어떻게 접근하면 될지 방안이 섰기 때문에 최종 클래스 다이어그램을 그려보기로 했다. 클래스 다이어그램을 그리면서 고과장은 클라이언트가 보내는 메시지와 해당 비즈니스 로직 정보를 어떤 형태로 할 까 고민하다 XML 형태로 하는 것이 가장 좋을 것 같다는 판단이 들었다.

애플리케이션이 실행되면서 XML에 있는 정보를 읽어 캐싱하고 있는 형태로 만들고 그 역할은 BusinessMapper라는 객체에 해당 정보를 Map에 담아 두기로 했다. BusinessMapper는 단 하나만 존재해야 하므로 싱글턴(Singleton) 패턴을 적용하기로 했다(실제 구현을 하기 위해서는 보다 더 구체적으로 모델링을 해야겠지만). <그림 7>는 고과장의 아이디어를 반영한 최종 클래스 다이어그램이다.

사용자 삽입 이미지
<그림 7> 고과장 생각을 정리한 최종 클래스 다이어그램


이 클래스 다이어그램에서 XXX_ServerPage나 XXX_Action, XXX_ActionForm, XXX_Mgr과 같이 XXX라는 접두어가 붙은 클래스는 비즈니스 로직 개발자들이 직접 만들어야 하는 부분이다. 개발자들은 XXX라는 접두어가 붙은 클래스만 개발하면 되고 고과장이 만든 프레임워크에 끼워 넣어 어떤 메시지가 어떤 비즈니스 로직과 맵핑되는지 XML 파일만 편집하면 되는 구조로 모델링이 되었고 고과장의 생각대로 메시지와 비즈니스 로직과의 느슨한 관계를 유지할 수 있는 모델이 만들어 졌다.

일단 이런 구조의 프레임워크가 좋은 것인지 아닌지는 일단 논외로 하고 머릿속의 아이디어를 모델로 구체화하는 과정을 다시 한번 정리하자면 우선 1) 머릿속의 아이디어를 글로 정리하고 2) 정리한 글을 바탕으로 UML로 바꿔 본다. 이때 동적인 측면과 정적인 측면을 고려하고 전에 정리한 글에서 UML로 변환하는 과정에서 빠진 것은 없는지 미처 생각하지 못한 것들이 있는지 확인한다. 그냥 글로 확인하는 것보다는 UML의 시퀀스 다이어그램이나 엑티비티 다이어그램 등을 이용하여 확인하면 보다 더 정확하게 모델링할 수 있다. 3) 이렇게까지 진행이 되었으면 실제 구현을 위한 모델로 발전시켜 본다. 특정 플랫폼이나 개발언어, 미들웨어 등을 고려하면서 그려나간다.

결국 1)~3)까지가 실제 모델링을 통해 아이디어를 구체화 시켜나가는 모든 것이다. 1)번을 잘 하기 위해 각종 기법(예를 들어, 유스케이스나 유저스토리 등)이 동원되고 2)번을 잘 하기 위해 CRC 카드와 같은 기법이 사용된다. 3)번 역시 마찬가지로 각종 설계 패턴이나 J2EE 패턴과 같은 것을 참조한다. 개발 프로세스에 따라 어떤 모델을 만드는가, 어떤 산출물을 만드는가에 따라 그려야 할 다이어그램이나 모델의 정밀도가 다르겠지만 결국 1)~3)까지의 행위를 반복함으로써 우리가 얻고자 하는 모델을 얻어낼 수 있다.

쉽고도 어려운 유스케이스 모델링
1960년대 후반쯤 이바 야콥슨에 의해 만들어진 유스케이스는 1990년대에 들어서면서 아주 폭넓게 사용하는 요구사항 파악 및 분석 기법으로 자리 잡았다. 우리나라의 경우 아마도 대부분의 프로젝트에서는 유스케이스라는 이름의 산출물을 만들고 있고 만들었을 것이다. 필자도 여러 프로젝트를 하면서 유스케이스를 써서 요구사항 분석을 했었다.

초기 접근하기에 개념적으로 어려운 부분이 별로 없기 때문에 누구나 의욕적으로 참여하여 유스케이스를 작성해 해 나간다. 하지만 이 유스케이스라는 것이 단순해 보이지만 결코 만만치 않은 특성을 갖고 있다. 처음에는 쉬운 듯하지만 진행해 나갈수록 어려워지는 경향이 있다. 또한 프로젝트의 진행 상태나 규모에 따라 유스케이스 작성 방식이 달라진다. 이러한 특성 때문에 바쁜 프로젝트에서 뭔가 별 고민을 하지 않고 쉬운 작성 형식이나 방법을 목말라하는 개발자들에게는 혼돈의 연속일 수밖에 없다.

필자 개인적으로 유스케이스에 관해 잘 설명한 도서는 Alistair Cockburn의 『Writing Effective Use Cases (2001)』이다. 영어에 어려움을 겪는 분들은 번역본도 나와 있으니 구해서 한번 꼭 읽어보길 바란다. 이 책의 내용 중에 유스케이스 작성시 주의할 점이 있는데 그 중 현장에서 실제로 많이 나타나는 몇 가지를 소개하고자 한다. 일부 주의사항은 책에서 발췌하고 필자가 느낀 점을 중심으로 설명해본다.

유스케이스는 산문체 수필이다
유스케이스 다이어그램을 갖고 지지고 볶던 독자들에게는 약간 의아한 말일 수 있다. 사실 유스케이스는 텍스트 기반의 서술이다. UML의 유스케이스 정의를 보아도 '유스케이스는 시스템 전체나 유스케이스 일부 행동을 명세화 하고 순차적으로 발생하는 활동들을 서술하는 것이다. 시스템은 이러한 활동을 수행하여 액터에게 원하는 결과를 준다'라고 되어 있다. 그래픽으로는 타원으로 표현하고 중심에는 몇 단어로 이루어진 이름이 있다.

프로젝트를 진행하면서 다이어그램에 얽매여 오로지 다이어그램만으로 유스케이스를 작성하려고 하면 관련 팀은 점점 어려움으로 빠져 들게 된다. 유스케이스 다이어그램 그 자체가 담고 있는 정보는 매우 한정적이다. 유스케이스명과 어떤 액터와 관계가 있는지를 나타내는 선 몇 개, 복잡하게 뒤 얽힌 '포함(include)와 확장(extends)을 표현하는 점선들이 뒤덮여 있을 뿐이다. 사람들이 그 다이어그램을 보고 요구사항이 뭔지 정확하게 알 수 있을까?

단어 몇 개로 이루어진 유스케이스 명을 보고 무엇을 하는 유스케이스인지 추측을 할 뿐이다. 다이어그램의 정보가 충분치 않으므로 답답한 마음에 다이어그램에 갖가지 정보를 넣으려고 하고 유스케이스의 목표 수준은 점점 내려가고 복잡해지는 현상이 나타난다. 결국 아무도 이해할 수 없는 다이어그램이 만들어지면서 오히려 팀간의 명확한 이해의 공유는커녕 혼란만 가중시키는 결과를 낸다. 유스케이스 다이어그램만을 놓고 이틀 동안 논쟁만 하는 개발팀을 실제로 보았다. 다시 한번 강조하지만 유스케이스는 텍스트 형식의 서술이다. 액터와 유스케이스 간에 어떤 일이 일어나는지 글로 적음으로써 이해를 명확히 할 수 있다.

유스케이스와 사용자 매뉴얼
유스케이스 교육을 들어 봤거나 프로젝트를 해 본 분들이면 아마도 귀가 따갑게 유스케이스는 GUI에 관한 부분은 적지 않는 것이라고 들어왔을 것이다. 유스케이스를 작성하면서 유저 인터페이스에 관한 내용을 언급하기 시작하면 유스케이스가 점점 사용자 매뉴얼이나 화면 설계서처럼 변해간다.

유스케이스는 향후 작성할 분석/설계 모델이나 화면 설계 등의 모델의 기본 정보를 제공한다. 또한 유스케이스로 추적(Trace)할 수 있다. 아니 추적되어야 한다. 사용자 매뉴얼이나 화면 설계서가 분석/설계 모델의 상위 요건이 될 수 있는가? 결코 그렇지 않다. 유스케이스는 적당한 목표수준으로 작성함으로써 상위 요건으로써의 역할을 다 할 수 있어야 한다.

포함과 확장의 오남용
어떤 유스케이스 다이어그램을 보면 다이어그램 가득히 실선과 점선이 어지럽게 꼬여 있는 그림을 가끔 본다. 왜 이런 다이어그램이 나오는지는 앞에서 언급하였다. 필자의 경우 이런 다이어그램은 십중팔구 뭔가 잘못되었을 것이라는 예감이 뇌리를 스친다. 우선 복잡하면 제대로 파악할 수 없고 서로 이해를 명확하게 하지 못했을 가능성이 높으며 이해도가 떨어지는 상황에서 유스케이스가 제대로 작성되었을 리가 없다.

사용자 삽입 이미지



유스케이스 다이어그램이 복잡하면 각 유스케이스의 이벤트 흐름을 작성하면서 아주 여러 부분에 포함(include)과 확장(Extends)이 나타나게 되고 결국 전체적으로 유스케이스의 유지보수를 어렵게 만든다. 유지보수가 어렵게 되면 요구사항을 정확히 담는데 점점 힘들어지고 현실과 동떨어진 그저 서로 다른 이해수준으로 각자의 머릿속에만 존재하는 요구사항이 나오게 된다.

최초 확장이라는 개념이 등장하게 된 이유는 이전 시스템의 요구사항 파일을 건드릴 수 없다는 실행 지침 때문이었다(Alistair Cockburn, 2001). 그 당시 개발팀의 임무는 새로운 서비스를 추가하는 것이었고 기존의 요구사항 문서를 건드릴 수 없는 상황에서 원래의 요구사항은 한 줄도 건드리지 않은 채 새로운 요구사항을 추가했다. Alistair Cockburn은 확장이 필요할 경우 다이어그램 상에서 보여주지 말고 기존 유스케이스 안에서 확장 유스케이스의 참조를 그저 텍스트로 서술할 것을 권유한다. 다이어그램에 복잡하게 확장을 표현함으로써 정작 중요한 유스케이스를 볼 수 없게 만들기 때문이다. 필자도 그의 주장에 동의 한다.

케이스 툴로 유스케이스 작성하기
케이스 툴로 유스케이스를 작성한다는 것이 잘못되었다는 것은 아니다. 오히려 케이스 툴이 활용상의 문제로 인해 정확한 유스케이스를 작성하는데 걸림돌로 작용하는 현상을 이야기하고 싶은 것이다. 필자는 지금까지 프로젝트를 진행하면서 유스케이스의 고단함에 대해 무척 많은 고민을 했었다. 일반적으로 개발자들은 작문을 싫어하는 습성이 있지만 요구사항을 파악하고 분석하는 사람들은 일반 고객과의 의사소통이 많기 때문에 산문 형식의 문서 작성(Technical Writing)에 능숙해야 함에도 불구하고 대부분의 프로젝트에서는 이러한 사실을 애써 외면한다.

작성하기 귀찮은 유스케이스를 케이스 툴로 그리고 끝내 버리려는 생각을 한다. 사실 필자도 예외는 아니어서 웬만하면 케이스 툴에서 모든 걸 해결하고 싶은 유혹에 항상 시달렸다. 하지만 대부분의 케이스 툴은 유스케이스를 서술하기 위한 조그만 다이얼로그 창만을 제공한다. 유스케이스를 기술한 문서를 따로 하이퍼링크 방식으로 케이스 툴과 연결하는 방법을 주로 취했는데 사실 힘들고 불편하다. 만약 어떤 케이스 툴의 기능 중에 일정한 유스케이스 작성 형식의 레이아웃을 디자인할 수 있고 그 템플릿 안에서 유스케이스를 작성하면 다이어그램이 역으로 만들어지는 케이스 툴이 있다면 얼마나 좋을까 하는 생각을 해본다. 언제쯤이면 편하게 유스케이스 모델링을 할 수 있는 케이스 툴이 나올까?

분석/설계 모델과 MDA
분석(分析)은 그 단어의 의미에서도 알 수 있듯이 무엇인가를 어떠한 목적 때문에 나누어(分) 쪼개는(析)것이다. 소프트웨어 개발에서 나누어 쪼개야 할 필요가 있는 부분은 문제 영역으로 시스템을 개발하는 사람들이 문제 영역을 올바로 이해하기 위한 목적으로 분석을 한다. 이해한 것을 즉시 시스템으로 만들 수 없으므로 중간에 문제 영역의 이해와 실 시스템간의 가교역할을 하는 것이 있는데 그것이 바로 설계이다.

사실 웬만하면 설계를 하지 않고 시스템을 만들고 싶은데 구현 언어나 플랫폼 등의 영향을 많이 받기 때문에 분석한 결과를 바로 시스템화하기 힘든 것이다. 현재 분석에서 설계를 거치지 않고 바로 실 시스템으로 건너가기 위한 노력이 진행되고 있는데 독자 여러분들도 잘 알다시피 MDA(Model Driven Architecture)가 그것이다.

현재 소프트웨어를 만드는 사람들의 작업 행태는 당연하게 생각되지만 지루하게도 4단계를 거친다. 문제 영역을 파악하고 분석하여 그 결과를 바탕으로 설계한 후 소프트웨어를 구현한다. 만약 정말 MDA가 활성화 된다면 중간에 1가지 단계가 빠지는 3단계 개발 공정이 나올 것이며 그저 요구사항 파악해서 분석 모델을 만들어 놓으면 실행 시스템이 튀어나오는 정말 환상적인 세상이 오지 않을까 싶다. 그런데 정말 이런 세상이 가능할까?

현 컴퓨팅 시스템은 다 계층 분산 시스템인 관계로 많은 설계 요소와 다양한 관련 기술이 필요하다. 이 모든 기술을 모두 알 수 없으므로 특정 기술 기반을 가진 사람들이 한 프로젝트에 모여 개발을 하고 그 중 충분한 경험과 깊은 지식을 갖고 있는 누군가가 아키텍트라는 역할로 소프트웨어 개발을 이끌고 나간다.

아키텍트라는 일반 비즈니스 로직 개발자들의 개발 자유도를 통제하기 위해 '메커니즘'이 라는 것도 만들어 놓고, 마음이 안 놓이는지 '프레임워크'라는 것도 만들어 놓아 오직 비즈니스 로직 구현에 몰두할 수 있게 만들어 놓는다. 비즈니스 로직 개발하는 것도 '패턴'이라는 이름으로 개발하는 방식을 제한하는 경우가 많다. MDA에서는 이러한 부분을 프로파일로 작성한다. 이 프로파일을 바탕으로 비즈니스 분석 모델을 빌드하면 실행 컴포넌트가 나오게 된다.

현재도 제품으로 출시되어 있는 MDA 솔루션들이 있다. 필자가 보기엔 어떤 솔루션은 무늬만 MDA인 것도 있고 실제 MDA의 비전에 상당히 근접한 솔루션도 있었는데 모델링 도구에서 모델을 만들고 OCL을 작성해 놓으면 놀랍게도 실제로 시스템이 작동했었다. 다만 일부 표준을 지원하지 않아 문제가 되긴 했지만 말이다.

하지만 언젠가는 MDA가 우리 피부에 와 닿을 정도로 현실화 되리라 믿는다. 초창기 컴퓨팅 환경에서 고급 언어로 일컫는 3세대 언어들은 그 당시 개발자들에겐 환상적인 꿈의 개념이었다고 한다. 기계어와 어셈블리 수준에서 프로그래밍을 하던 그들에게는 자연어와 비슷한 모양의 개발 언어는 얼마나 환상적으로 보였을까? 지금 우리는 이와 같은 과도기를 겪고 있다고 필자는 생각한다. 독자 여러분들도 그런 시대를 대비하여 하루빨리 모델링 능력을 한껏 끌어올리기 바란다.

자바 웹 애플리케이션 모델링
만약 개발 프로세스가 비슷하다면 그 프로세스를 적용하여 개발하는 모든 애플리케이션 모델링의 방법은 거의 유사하다. 웹 애플리케이션이라고 해서 별다르게 특이한 것은 없겠지만 웹 애플리케이션의 특성상 몇 가지 짚고 넘어갈 부분이 있다. 사실 엄밀하게 말 하면 웹이라는 특성도 있지만 자바의 특성으로 인해 모델링 방법이 약간 달라지는 수준으로 볼 수 있다. 특히 현 엔터프라이즈 컴퓨팅 환경은 다 계층 분산 시스템이므로 계층과 분산에 관한 부분의 모델링이 강조된다.

또한 사용자 웹 인터페이스 모델링도 중요한 부분으로 생각할 수 있다. 웹 페이지의 특성상 HTML이라는 제약으로 인해 약간 특이한 점이 있다. 웹 페이지 모델링에서 폼(form)과 같은 구성요소는 스테레오 타입(stereo type)으로 정의하여 모델링을 한다. 또 웹 페이지는 화면의 흐름에서 해당 정보를 갖고 다니거나 세션을 참조하기 때문에 어디까지 해당 정보를 갖고 다닐지 세션을 어떻게 참조할 지가 모델링의 주요 포커스가 된다. 일단 개요 수준은 여기까지 하고 실제 예제를 보면서 모델링이 어떻게 진행되는지 살펴보자.

분석 모델
좀 전에도 언급했듯이 웹 애플리케이션도 역시 다른 시스템과 마찬가지로 요구사항 파악 및 분석으로부터 시작한다. 요구사항을 위한 모델링으로 유스케이스를 이용하는 것은 이미 앞에서 이야기했고 특집 4부에서 자세히 다룰 예정이므로 유스케이스 자체에 관한 설명은 하지 않겠다. 또한 웹 애플리케이션이나 다른 기술을 이용한 애플리케이션이나 요구사항과 분석 모델링의 기법은 사실 별반 다르지 않다. 분석 모델은 구현과 관계가 없는데 분산(distribution), 영속성(persistency), 커뮤니케이션(communication), 인증(authentication)과 같은 메커니즘과 상관없는 개념적인 모델이기 때문이다. 즉, 유스케이스 모델을 기반으로 분석관점으로 유스케이스 실현(realization)을 표현한 객체모델이 바로 분석 모델이다.

사용자 삽입 이미지
<그림 8> 분석 클래스 다이어그램의 예


<그림 8>은 분석 모델의 유스케이스 실현(realization)에 참여하는 분석클래스 다이어그램이다. RUP에 의하면 분석클래스는 <<boundary>>, <<control>>, <<entity>> 등 세 가지 종류의 스테레오 타입을 갖는다. 원래 스테레오 타입은 태기드 벨류(tagged value)와 함께 UML의 확장 메커니즘의 한 종류이기 때문에 필요하다면 추가적인 스테레오타입을 정하여 사용하여도 무방하다.

사용자 웹 인터페이스 모델링
사용자 웹 인터페이스 모델링 부분은 웹 애플리케이션을 개발하면서 모델링 하기에 가장 껄끄러운 부분이 아닌가 생각된다. Jim Conallen은 그의 저서 『Modeling Web Application Architectures with UML(2002)』에서 웹 인터페이스 모델링을 자세히 설명하고 있다. 한마디로 요약하자면 웹 애플리케이션 모델링을 위한 다양한 '스테레오 타입'을 만들어 냈다.

필자가 보기에는 실무 프로젝트에서 과연 이런 노가다 작업을 할 필요가 있을까 생각이 되지만 순수 모델링 관점에서 볼 때 웹 페이지를 모델링 하기 위한 작업으로서 의미는 있다고 본다. <그림 9>는 그가 제안한 웹 페이지를 모델링 예제이다. 참고하기 바란다.

사용자 삽입 이미지
<그림 9> Jim Conallen이 제안한 웹 인터페이스 모델링 예


실무 프로젝트에서 Jim Conallen이 제안한 방법으로 모델링 하는 경우를 본적은 없고 필요한 부분만을 발췌해 많이 단순화시킨 형태로 모델링을 진행한다. 사용자 인터페이스 모델은 화면 흐름, 참여 화면의 설명, 화면 이동 맵, 화면 클래스 다이어그램, UI 프로토타입 등으로 구성된다. 이중 UML로 모델링 하는 몇 가지를 소개하겠다.

화면 흐름
화면 흐름의 경우 비즈니스 로직 처리와는 전혀 관계없이 오직 해당 작업을 수행하기 위한 화면 관점에서 모델링을 한다.

사용자 삽입 이미지
<그림 10> 시퀀스 다이어그램으로 표현한 화면 흐름도


화면 이동 맵
화면 이동 맵은 각 화면의 구성 요소를 클래스 다이어그램으로 표현한 것이다.

사용자 삽입 이미지
<그림 11> 클래스 다이어그램으로 표현한 화면 이동 맵


웹 애플리케이션을 위한 프레임워크 모델링
자바를 이용하여 웹 애플리케이션을 개발하게 되면 우선 여러 제약 사항들이 나타나게 된다. 앞서 이야기한 페이지 제어 문제, 세션 처리 문제, 데이터 처리 문제, 다양한 프로토콜의 처리 문제, 까다로운 보안 문제, 웹과 분산 컴포넌트간의 동적 호출 문제, 예외처리 문제, 웹 애플리케이션과 레거시(legacy)와 인터페이스 문제 등 각 메커니즘에 관해 다루어야 할 부분이 많다. <그림 12>는 각 메커니즘을 고려한 일반적인 웹 애플리케이션의 시스템 구성도이다.

사용자 삽입 이미지
<그림 12> 일반적인 웹 애플리케이션의 시스템 구성도


이 그림에서 메커니즘으로 정리해야 할 주요 부분은 여러 가지가 있지만 그 중에서 Web Server와 Web App Server와의 연동 부분으로 JSP에서 어떠한 Action을 통해 EJB 비즈니스 컴포넌트를 수행시키고자 하는 부분과 데이터 처리하는 부분, 타 시스템과 인터페이스 기술을 만약 웹 서비스로 할 경우 웹 서비스 클라이언트와 웹 서비스 서버간의 메커니즘 등을 들 수 있다. 몇 부분에 대한 메커니즘에 대하여 모델을 보면서 살펴보자.

JSP에서 Action을 통해 비즈니스 컴포넌트를 수행하는 부분
이 부분의 경우 프리젠테이션 레이어와 비즈니스 레이어간의 느슨한 결합을 지원하기 위해 J2EE 패턴 중에 '비즈니스 델리게이트 패턴(business delegate pattern)'을 사용할 수 있다. 원래 비즈니스 델리게이트 패턴은 비즈니스 서비스 컴포넌트와 일어나는 복잡한 원격 통신에 관련된 사항을 클라이언트로부터 숨기기 위해 사용한다. 비즈니스 델리게이트에 관해 자세한 것을 알고 싶으면 자바 웹 사이트나 코어 J2EE 패턴을 참고하면 된다.

다음에 소개할 프로젝트의 상황 때문에 약간 변경이 되었는데 비즈니스 델리게이트는 원격 통신에 관한 처리와 함께 해당 프로젝트의 사정으로 EJB 비즈니스 컴포넌트와 일반 자바 클래스 형태의 비즈니스 컴포넌트, 그리고 웹 서비스를 통해 타 시스템의 비즈니스 컴포넌트도 함께 수행해야 했다.

따라서 비즈니스 컴포넌트가 EJB건 일반 자바 클래스건 SOAP 기반의 통신이던 간에 클라이언트는 그저 비즈니스 컴포넌트 아이디와 비즈니스 컴포넌트 쪽에 넘겨줘야 할 파라미터만 알고 있으면 되도록 설계하였다. 해당 비즈니스 컴포넌트는 비즈니스 델리게이트에서 리플렉션을 이용해 동적으로 수행되도록 했다.

사용자 삽입 이미지
<그림 13> 비즈니스 델리게이트 부분의 클래스 다이어그램


<그림 13>에서 BusinessMapper의 역할은 XML 형태의 컨피규레이션(Configuration)로 빠져있는 파일을 읽어 웹 애플리케이션이 기동할 때 캐싱하게 된다. 이 컨피규레이션 파일에 담겨있는 정보를 바탕으로 BusinessMap 클래스가 모델의 역할을 하게 되는데 BusinessMapper는 BusinessMap을 자신이 갖고 있는 Map에 담아 갖고 있는다. 또한 BusinessMapper는 JVM상에 오직 하나만 존재해야 했으므로 '싱글턴 패턴(singleton pattern)'을 적용하였다. 이것을 실제로 구현하기 위해서 필자는 자카르타의 커먼스(commons)의 다이제스터(digester)를 이용하여 구현했다.

사용자 삽입 이미지
<그림 14> 비즈니스 델리게이트 부분의 시퀀스 다이어그램


외부 시스템과 연동 부분
웹 서비스의 SOAP을 이용한 통신을 하기 위해서는 웹 서비스 RMI 리모트 인터페이스를 상속한 인터페이스를 상속한 스텁(stub)을 통해 비즈니스 컴포넌트를 수행하게 된다. 이 부분은 위에서 설명한 비즈니스 델리게이트 부분과 아주 관련이 깊은데 일반 자바 비즈니스 컴포넌트의 경우 같은 머신의 동일 컨텍스트에 존재하므로 스트럿츠 액션(Struts Action)에서 비즈니스 델리게이트를 통해 바로 부르면 비즈니스 델리게이트는 그저 리플렉션을 통해 해당 비즈니스 컴포넌트를 실행하면 된다.

하지만 웹 서비스 비즈니스 컴포넌트인 경우는 다른 머신에 존재하는 컴포넌트이므로 원격 호출에 대한 부분 동일한 방법으로 서비스의 위치를 찾아낼 수 있도록 J2EE 패턴 중에 '서비스 로케이터 패턴(service locator pattern)'을 이용하였다. 이 부분 역시 약간의 변형이 가해졌는데 다이내믹 바인딩 시간이 비교적 길기 때문에 서버에서 받아온 스텁을 웹 애플리케이션 서버 쪽에 풀(pool)을 하나 만들어 스텁을 한번 가져온 이후 풀에 넣어놓고 다음 호출부터는 풀에서 꺼내어 쓰도록 설계하였다. 필자는 이런 설계를 구현하기 위해 자카르타 커먼스에 있는 풀(pool)을 이용하였다. EJB의 경우도 이와 거의 유사하다. <그림 15, 16>은 웹 서비스 부분의 클래스 다이어그램과 시퀀스 다이어그램이다.

사용자 삽입 이미지
<그림 15> 웹 서비스 부분의 클래스 다이어그램


사용자 삽입 이미지
<그림 16> 웹 서비스 부분의 시퀀스 다이어그램


데이터 처리 부분
필자가 이 부분을 설계하고 구현해 놓고 보니 사실 메커니즘이라기보다는 일종의 유틸리티성의 헬퍼 클래스 성격이 짙었다. 주요 특징 중에 하나는 SQL 쿼리를 소스코드에 직접 넣지 않고 XML 형식의 파일로 뽑아내었다는 것이다. 데이터베이스를 통해 데이터를 주고받아야 하는 비즈니스 컴포넌트 입장에서는 쿼리 아이디와 Object 배열에 담긴 파라미터를 QueryHelper에 넘겨주면 쿼리를 실행하고 결과를 넘겨준다.

결과는 여러 형태로 받을 수 있는데 종류로는 Map 형태, Map의 리스트 형태, 특정 Bean 형태, Bean의 List 형태로 Object 객체에 담아 받아 올 수 있다. 필자는 이런 설계를 구현하기 위해 자카르타 커먼스에 있는 디비유틸(DBUtil)을 이용하였다. <그림 17, 18>은 데이터 처리 부분의 클래스 다이어그램과 시퀀스 다이어그램이다.

사용자 삽입 이미지
<그림 17> 데이터 처리 부분의 클래스 다이어그램


사용자 삽입 이미지
<그림 18> 데이터 처리 부분의 시퀀스 다이어그램


컴포넌트 모델링
컴포넌트 모델링의 과정은 컴포넌트를 식별하고 그것의 인터페이스를 정의하고 컴포넌트의 내부는 어떻게 작동하며 구현을 어떻게 할 건지에 대한 종합적인 과정이 필요하다. CBD(Component Based Development)에는 많은 이견들이 있지만 이 글에서는 현존하는 기법을 통해 컴포넌트 식별 방법을 아주 간략하게 설명하고 컴포넌트 모델링과정이 어떻게 진행되는지 궁금해 하는 독자들을 위해 각종 다이어그램을 보면서 살펴보기로 한다.


Catalysis :타입과 조인트 액션을 중심으로 상호작용을 분석하여 네트워크 다이어그램을 만들고, 결합력과 응집력을 고려한 메트릭을 만들어 컴포넌트 식별한다.

마르미III :유스케이스/클래스 연관 메트릭을 사용하여 각 유스케이스와 관련 있는 클래스를 클러스터링 하여 컴포넌트 후보로 등록한 다음 다른 유스케이스도 분석하여 이전에 후보로 등록되었던 컴포넌트가 쓰이면 나머지 유스케이스도 활용할 수 있도록 인터페이스를 공개한다. 유스케이스/클래스 연관 메트릭을 분석하기가 좀 어려운 것 같다. 실무에서 활용 가능할지 의문시 된다.

UML Components :비즈니스 타입 모델에서 타입을 식별하고 이 타입을 관리할 책임이 있는 인터페이스를 정의한다. 식별된 인터페이스의 상호작용을 분석함으로써 서로간의 의존관계를 파악/정제하여 컴포넌트를 제안한다. 분석가의 경험에 많이 의존하는 경향이 있다.

RUP :분석/설계가 상당히 진행된 후 각 클래스를 종횡으로 묶는 방식을 취한다. 초기 컴포넌트 식별은 불가능 하다.


컴포넌트 인터페이스 정의
어찌됐던 간에 컴포넌트를 식별했으면 인터페이스를 정의한다. 이 단계에서 정의되는 컴포넌트 인터페이스는 Business Facade의 성격으로 각 인터페이스를 명세화 한다.

사용자 삽입 이미지
<그림 19> 컴포넌트 인터페이스


컴포넌트 내부 설계
컴포넌트 내부 설계는 앞에서 정의한 인터페이스를 구현하기 위한 설계를 일컫는다.

사용자 삽입 이미지
<그림 20> 컴포넌트 내부 설계 클래스 다이어그램


EJB 컴포넌트 설계
EJB 컴포넌트 자체에 관한 설계로 <그림 21>은 Customer 비즈니스 컴포넌트의 워크플로우를 관리하고 클라이언트 요청에 대해 Facade 역할을 수행하는 Stateless Session Bean 에 대한 클래스 다이어그램이다.

사용자 삽입 이미지
<그림 21> EJB 컴포넌트 설계 클래스 다이어그램


유능한 모델러로 거듭나기
지금까지 개발 프로세스 측면에서 바라본 모델링과 자바 웹 애플리케이션을 위한 모델을 보았다. 사실 아주 많은 내용을 한정된 페이지에 집어넣으려고 하다 보니 주마간산 격이 되어버렸는지도 모르겠다. 모델링이라는 것이 개인적인 주관과 경험에 많은 영향을 받는 것은 사실이다.

필자는 지금까지 모델링과 관련된 프로젝트와 교육을 여러 번 해보았지만 아직까지 잘된 모델링은 바로 이런 것이라고 꼭 집어 이야기하기 힘들다. 다만 어떤 모델은 보면 왠지 푸근하고 어떤 모델은 왠지 어색하다는 느낌이 든다. 그 느낌이 뭐라는 것도 아직 정확히 모르겠지만 말이다. 모델링을 잘 하기 위해 어떻게 트레이닝을 해야 할까라고 고민하던 중에 필자가 겪었던 짧은 경험이 떠올랐다.

올해 여름에 비슷한 일을 하는 사람들과 함께 어느 업체에 방문했던 적이 있었다. 날씨는 아주 더웠지만 차 안은 에어컨을 켜서 시원했다. 문제는 주차장에 차를 세워놓고 몇 시간 동안 뜨거운 여름 뙤약볕 아래 차를 세워놔야 하므로 일을 마치고 돌아올 시점에는 차 안이 불가마 찜질방 수준으로 될 거라는 것은 충분히 예상할 수 있는 상황이었다. 그때 누군가 “그늘 아래 세워놔야 할 텐데”라고 하자 어떤 사람이 “그늘 오리엔티드(Oriented)구먼”이라고 응수했다. 그러자 또 누군가 “오리엔티드는 아니지, 오리엔티드는 왠지 그늘 자체가 되어야 하는 듯한 느낌을 준다고, 그늘 드리븐(Driven)이 맞지 않을까? 드리븐은 목표를 향해 돌진하는 느낌을 주자나? 결국 우리는 지금 그늘을 찾아가고 있는 거고”라고 했다. 이때 필자는 “음~ 정확히 말하자면 그늘 베이스드(Based)가 어울릴 것 같은데? 우리는 그늘을 베이스로 깔고 앉아야 하잖아?”라고 주장하여 모두들 웃으며 짧은 말장난을 했던 기억이 있다.

예로 든 이야기에서 그 상황에 오리엔티드(Oriented)나 드리븐(Driven), 베이스드(Based)라는 용어의 의미에 정확하게 맞았는지는 일단 논외로 하겠지만 실제 모델링을 하는 상황에서는 이와 같은 일들이 자주 일어난다. 모델링을 하는 사람들은 그 상황에 맞는 의미를 정확히 파악하여 모델을 만들기 위한 노력을 끊임없이 해야 하고 특히 용어, 단어의 의미, 그리고 단어간의 관계에 대하여 고민해보고 정확하게 짚고 넘어가는 버릇을 들여야 하지 않을까 싶다.

우리가 지금 주제로 이야기하는 UML을 이용한 모델링이라는 것이 결국 모호성이 아주 높은 자연 언어를 몇 개의 모델링 요소로 표현하는 작업이기 때문에 소프트웨어 모델링을 할 때만 모델에 대하여 생각하는 것이 아니라 실생활 속에서 패러다임에 맞게 사고하는 지속적인 훈련을 해야만 한다.

앞에서 MDA에 관하여 짧게 언급 했지만 아마 앞으로 소프트웨어 개발에 있어서 모델은 점점 더 중요한 요소로 부각될 것이다. 필자도 그렇고 이 글을 읽는 독자 여러분도 지속적인 수련을 통해 더욱 유능한 모델러로 거듭나리라 믿는다.@

* 이 기사는 ZDNet Korea의 제휴매체인마이크로소프트웨어에 게재된 내용입니다.

 

고재현

2005/03/26

 

[UML 제대로 알기] ① 가능성·확장성 품고 등장한 UML 2.0

 

연재순서
1회.가능성·확장성 품고 등장한 UML 2.0
2회.초보자를 위해 다각도로 살펴본 UML
3회.바로 알고 제대로 쓰는 UML 실전 모델링
4회.닷넷 환경에서 UML 툴 활용 가이드
5회.표준을 넘나드는 UML의 적절한 사용

 

UML을 중심으로 소프트웨어 업계에서 벌어지는 경제적, 사회적 현상들을 알아보고 UML 2.0 발표 이후 소프트웨어 업계에 불어 닥칠파장에 대해 알아본다. 또한 UML 2.0에서 개발자들이 주목해야 하는 세부 내용도 간단히 검토해 보자.

UML 2.0의 실로 엄청난 중요성을 미리 알고 대비할 것인지, 뒷짐 지고 좀 더 지켜볼지는 이번 글을 보고 판단해 주기를 바란다.

필자는 지난 2004년 마이크로소프트웨어 8월호에 MDA 관련 글을 기고하던 당시부터 지금까지 필자의 소속 회사가 지난 10여 년간 전문적으로 개발해 오던 인적 자원 관리(HRM) 시스템에 대한 획기적인(?) 개선 방안으로 MDA 기반의 시스템 개발을 추진하고 있다. 필자가 본격적으로 UML 2.0을 검토하기 시작한 것도 8월을 전후해서였다.

그러나 회사에서 표준으로 사용하는 모델링 도구 제작 업체에서는 4개월 전만 해도 UML 2.0을 지원하지 않았고, MDA 패러다임을 표방하면서도 아쉽게도 그 요체인 UML 2.0은 그저 각종 문서나 자료들을 통해서만 접할 수 있었다. 인사 비즈니스 프로세스 개선 작업(BPI)과 같은 초기 설계 작업은 UML 1.4 기반으로 추진해야 했고, 올 연말로 예정됐던 도구 공급사의 차기 버전을 기대해야 하는 상황이었다.

그러던 얼마 전, 필자는 해당 업체로부터 UML 2.0을 충실히 지원하게 된 새 버전의 케이스 도구를 입수했다. 비록 필자가 이미 여러 책이나 자료들을 통해 UML 2.0을 검토했었음에도, 막상 본격적으로 UML 2.0 지원 모델링 도구를 설치하고 작업을 착수하려던 그 순간의 첫 느낌을 말로 하자면 막막함 그 자체였다.

그 모델링 도구의 새로운 버전이 완전히 개편된 새로운 사용자 인터페이스로 구성됐으며 내부적으로도 상당한 기술적인 패러다임 전환이 있었던 것도 한 원인이었겠지만, 무엇보다도 근본적으로 UML 2.0이 내포한 그 가능성과 확장성에 대한 놀라움과 설렘이 교차하면서 만들어낸 미묘한 흥분과 두려움이었다는 것이 적절한 것 같다. 1620년 메이플라워호를 타고 미지의 땅 아메리카에 첫 발을 내디뎠던 이주민들의 마음이 이렇지 않았을까?

UML의 사회적 파장
UML 2.0 발표와 더불어 개발자들이 주목해야 하는 세부 내용을 살펴보기 전에 우선, UML을 중심으로 소프트웨어 업계에서 벌어지는 경제적, 사회적 현상들을 통해 향후 UML 2.0 발표 이후 소프트웨어 업계에 불어 닥칠 파장에 대해 미리 가늠해 보는 시간을 가져 보기로 하겠다.

IT 시장 변화에 주목하자
이 시대 소프트웨어 산업에 종사하는 사람이, 딴 세상에 사는 사람(beings in heaven)이 아닌 이상, 자본주의 시대를 살아가는 현대인으로서 공급과 수요를 결정하는 시장 논리로부터 자유로울 수는 없다.

우리는 종종 뛰어난 기술력을 갖추고 있음에도 망하는 반면, 특별한 기술력을 가지고 있지 않음에도 번창하는 사람이나 기업을 종종 목격하곤 한다. 즉, 기술력이 곧 성공을 의미하지는 않는다. 마찬가지 논리로, UML 2.0이 아니라 그 어떤 뛰어난 기술이 존재한다 하더라도 IT 시장에서 그 기술력을 필요로 하지 않거나 수용할 수 없다면, 그 기술력의 시장 가치는 무의미할 수밖에 없다.

2000년을 전후해서 전세계적으로 Y2K 문제가 사회적 문제로 부각되고 시스템의 대공황 사태가 예고되던 시절, 아이러니컬하게도 당시 소프트웨어 산업에서는 사양길로 접어들었던 프로그래밍 언어의 전문가들이 국내의 IMF 사태와 맞물려 고액 연봉으로 대접 받으면서 해외로 진출했던 일이 기억난다. 역시 기술의 가치(technology value)는 시장 원리(market behavior)에 의해 결정될 수밖에 없음을 인정하지 않을 수 없다.

그런 관점에서 UML 2.0이 공식적으로 공표되는 전후의 소프트웨어 산업계 판도를 살펴보는 것은 의의가 있다. 세계적으로 이미 프로그램 개발 도구 시장은 그 성장세가 둔화됐고, 모델링 도구는 빠른 속도로 보편화되어 가고 있다. 지난 몇 년간 일어났던 IT 업계의 큰 사건들을 살펴보면 그러한 사실을 쉽게 확인할 수 있다.

이를테면 예전에는 비싸게 판매하던 개발 도구를 점차 저렴하게 행사 가격으로 판매한다거나, 개발자 저변 확산이라는 명목 하에 학교나 학원을 중심으로 무료로 배포하고 있다. 심지어는 이클립스 등과 같은 막강한 개발 도구를 오픈소스로서 인터넷을 통해 무료로 배포하고 있다.

몇 년 전 세계적인 소프트웨어 업체인 MS에서는 비지오(Visio)라는 2D 전용 도구 개발 업체를 인수했고, IBM은 세계적인 모델링 도구 전문 개발 업체인 래쇼날을 인수합병했으며, 연이어 볼랜드에서는 투게더를 사들였다. 한편, 국내외 UML 관련 포럼이나 협회들에서는 앞다퉈 UML 관련 인증 제도를 만들어 발표하면서 그 인지도를 넓혀 가기 위한 대대적인 작업을 벌이고 있다.

UML 인증 제도의 필요성이라든지, 인증 제도 자체의 신빙성이나 효용성에 대해 논하기 이전에, 어떠한 사상이나 개념이 제도화 되는 과정을 거치고 있다는 사실은 그 사상이나 개념이 해당 분야에서 도입기(intro)와 성장기(growth)를 거쳐 성숙기(mature)에 진입하고 있음을 암시하는 것이다.

표준화의 숨은 뜻
UML을 논하면서 표준화(standardization)라는 키워드를 빼놓을 수 없다. UML이 발표되기 전에 국방이나
MIS분야 엔지니어들에게 친숙한 IDEF라든지 DFD, ER 혹은 Petri nets 등과 같은 정형 기법(formal method)으로 통칭되는 수많은 표기법(notation)과 지원 케이스 도구들이 존재했음에도 불구하고(참고자료:[1]번혹은[2]번등), UML은 가장 단기간 동안 소프트웨어 공학 분야에서만큼은 빠른 속도로 사실상의 표준(de-facto)의 위치를 확보했다. 언뜻 생각해 보면 UML이 여타 표기법들을 교통정리해 준 안도감(?)이 들 수도 있겠지만, 겉으로 잘 드러나지 않는 그 내막에는 무서운 음모(?)가 도사리고 있다.

표준화 작업에 주도적인 역할을 수행하는 업체들이 왜 그토록 천문학적인 자본을 투자하면서 공개적인 표준화 작업에 동참하는 것일까? 여러 가지 복합적인 이유들이 있을 수 있겠지만, 결론적으로 표준화 경쟁이다.

유명한 예로, 1970년대부터 시작됐던 빅터(Victor)의 VHS 방식과 소니의 베타 방식으로 대표되는 비디오 표준 전쟁을 들 수 있고, 최근에는 유럽과 미국을 중심으로 벌어지고 있는 위성방송 표준화 전쟁을 들 수 있다. 표준화 전쟁에서의 승패는 곧 기업의 운명을 좌우하는 것이다.

표준화의 이면에는 높은 진입 장벽을 통해 허가 받지 않은 침입자(intruder)를 봉쇄하려는 무서운 저의가 자리 잡고 있다. 시야를 좀 더 넓혀 보면, 의사나 판사, 회계사 등. 통속적인 표현으로 소위 ‘사’자로 끝나는 직업들에 대한 사회적 가치관을 살펴보면 쉽게 이해할 수 있다.

사람 몸을 열어서 칼질하고, 같은 인간으로서 다른 인간을 판단하고, 숫자 가지고 씨름하는 직업이 산업혁명 이전에는 별볼일 없는 직업이었다. 인류의 보편적인 가치관으로 판단하더라도 결코 즐거운 일이 될 수 없음에도 불구하고 전세계적으로 공히 가장 선호하는 직업이자 사회적으로도 가장 대접받는 직업이 된 현실에 미루어 짐작해 보면, 왜 그토록 세계적인 소프트웨어 업체들이 표준화를 통해 높은 진입 장벽을 구축하고 제도화에 전념하는지 그 이유를 충분히 이해할 수 있다.

어려운 시험을 통과하지 않고 누구라도 일정한 요건만 갖추면 수행할 수 있는 일반적인 직종 중의 하나라면 그렇게들 동경하는 직종이 됐겠는가? UML 2.0이 경제적으로나 사회적으로 주목 받는 이유 중의 하나는 바로 그러한 맥락에서 비전문인과 전문가를 구별하는 높은 장벽(?)을 쌓을 수 있는 재료(material)를 확보하고 토대를 마련했다는 점에서 의의가 있는 것이다.

주목해야 할 UML 2.0의 핵심 메커니즘
1997년 11월 UML 1.1로 시작된
OMG의 표준화 노력은 2001년 5월 UML 1.4 발표와 더불어 부분적인 개정 작업(minor version upgrade)의 막을 내리고, 대대적인 수술 작업을 거쳐 2004년 연말을 전후로 드디어 그 실체를 드러내었다.

그 동안 쟁쟁한 세계적인 소프트웨어 벤더들간의 보이지 않는 이해 관계(?)에 얽혀 2002년 말로 예정됐던 최종 발표 시한을 2년여를 연장하면서 이제서야 그 대단원의 막이 마무리되고 있다. 향후 UML 2.0의 일정은 명실상부한 국제 표준(de jure)으로 자리매김하기 위해 ISO 설계 표준으로 추진 중인 것으로 알려져 있다.

UML 2.0이 주목 받는 가장 중요한 이유는 무엇일까? 처음 세상에 나오고 나서는 여기저기서 수많은 비판을 받았지만, 그것은 UML이 어떠한 플랫폼이나 도메인에도 의존하지 않고 소프트웨어 개발의 전 공정(SDLC)을 지원하는 방향으로 지향해왔다는 데에 그 원인을 찾을 수 있다. 즉, 요구사항 획득으로부터 마지막 테스트까지 모두 지원하는 표기법으로서 진화해 왔다는 것이다.

그리고 점진적으로 UML 2.0부터는 실행 모델(executable UML)이라는 기법을 수용함으로써, 소프트웨어 공학에서 궁극적으로 염원하던 분석 설계(analysis & design)와 실제 구현(implementation) 간의 차이(chasm)를 극복하는 성과를 보였기 때문이다.

OMG의 UML 2.0에 대한 제안요청서(RFP)의 주제이자 현재 채택된 명세서 초안은 크게 4가지의 영역으로 분류된다. CASE 도구 벤더들간의 모델 호환성 문제를 다루고 있는 다이어그램 호환(Diagram Interchange) 영역과 모델 수준에서의 요소(elements) 제어 및 제약 문제를 다루고 있는 OCL(Object Constraint Language) 영역, UML뿐만 아니라 OMG가 주관하는 각종 표준의 통합과 정의에 활용되는 메타 모델 수준의 기본 구조체(constructs)를 명시하고 있는 하부구조(Infrastructure), 그리고 메타 모델을 기반으로 사용자 수준에서 모델을 활용하여 시스템의 구조(structure)와 행위(behavior)를 정의하고 있는 14개의 다이어그램을 정의하고 있는 상부구조(Superstructure)로 분류할 수 있다.

UML 2.0의 본질을 제대로 이해하려면 핵심인 하부구조로부터 차근차근 살펴보는 것이 순서이겠지만, 지면과 주제를 고려할 때, 일반인들이나 설계자들이 UML 2.0을 처음 대면하는 경우 가장 먼저 관심을 가지게 되는 UML 구조체(user-level constructs)인 상부구조로부터 이야기를 풀어가는 방식을 택하기로 하겠다.

사용자 삽입 이미지
<그림 1> UML 2.0 표준 다이어그램

*빨간 밑줄: 새롭게 추가된 다이어그램, 녹색 밑줄: 명칭이 변경된 다이어그램

상부 구조는 크게 6개의 다이어그램으로 구성된 구조형 다이어그램(Structural Diagram)군과 7~8개의 다이어그램으로 구성된 행위형 다이어그램(Behavioral Diagram) 군으로 분류할 수 있는데, 각 군의 대표적인 복합 구조 다이어그램(Composite Structure Diagram)과 순차도(Sequence Diagram)를 중심으로 그 특징과 의의를 살펴보도록 하겠다.

이어서 UML 2.0의 기반을 설명하고 있는 하부구조의 의미는 무엇인지, 그리고 실제 설계 작업에서 하부구조의 접근법은 어떠한 방식으로 활용하게 될 것인지 논의하기로 하겠다.

상부구조 - 구조형 다이어그램
일명 아키텍처 다이어그램(architectural diagram)이라고도 불리는 복합 구조 다이어그램(composite structure diagram)은 UML의 핵심 다이어그램인 클래스 다이어그램의 변형된 형태이다. 이는 시스템 구조 설계에 있어 또 다른 핵심 축으로 평가 받고 있으며 가장 주목 받는 다이어그램 중의 하나이다.

복합 구조 다이어그램은 기본적으로 시스템 혹은 컴포넌트의 내부 구조(internal structure)를 명시적으로 중첩시켜 표현하고 있으며, 시스템 아키텍처의 보다 섬세한 분석과 설계 사상을 담을 수 있게 된 점이 가장 큰 매력으로 꼽을 수 있다.

그렇다면 왜 복합 구조 다이어그램이 주목받는지, 그리고 복합 구조 다이어그램은 왜 탄생하게 되었으며, 향후 어떠한 용도로 활용하게 될까? 보는 시각에 따라 의견을 달리 할 수 있겠지만, UML 1.x은 근본적으로 OOAD 수준의 설계 사상을 표현하기에 최적화된 표기법으로 평가되어 왔다.

UML 1.x에도 비록 컴포넌트 다이어그램이라는 것이 있기는 했지만, 실제 너무 빈약한 문맥(semantics)으로 인해 별로 활용되지 못했으며, 강경한 컴포넌트 신봉자들이나 대용량 시스템 혹은 전체 시스템을 통합적으로 표현하기 원했던 아키텍처 전문가 진영 개발자들에게는, 그저 객체 옹호론자들이 제시하는 옹색한 명분(?)에 지나지 않았다. 사실 UML 1.x 자체에도 명시하고 있듯이, 컴포넌트 다이어그램은 몇몇 다이어그램들과 더불어 클래스 다이어그램에 일종의 간단한 확장 메커니즘을 통한 단순한 관점(view) 변경 수준에 지나지 않았다.

비즈니스 컴포넌트에 관심이 많았던 컴포넌트 신봉자들의 경우, UML 1.x의 스테레오타입(stereotype)등의 확장 메커니즘을 통해 그럭저럭 UML 1.x과의 관계를 유지하면서도 BPM이라는 포괄적이고 확장된 별도의 비즈니스 컴포넌트 표기법을 병행하며 UML 1.x의 미비한 부분을 채워 나갔다.

아키텍처 전문가 진영에서는 상황이 조금 달랐는데, 대다수의 아키텍처 전문가 진영에서 관심을 가지고 있던 임베디드 혹은 리얼타임 도메인에서는 단순히 UML 1.x 정도의 확장 메커니즘으로는 그들이 필요로 하는 아키텍처를 통한 시뮬레이션 등과 같은 시스템의 섬세한 분석 및 설계라는 목적 달성이 거의 불가능했고, 그러한 목적 달성을 위해 UML의 확장 메커니즘을 활용한다는 것은 차라리 자신들만의 특정 영역에 필요한 표기법을 자체 정의하여 사용하는 것이 훨씬 경제적이었다는 것이다.

왜냐하면 이미 아키텍처 전문가 진영에서는 UML 1.x가 발표되기 이전에 광범위하게 수많은 ADL(Architectural Description Language)과 관련 시뮬레이션 도구들이 개발되어 활용되고 있었으며, 굳이 UML에 순응하는(compliant) 방안을 모색하기 위해 UML을 연구하고 고민할 시간적 여유나 명분이 없었던 것이다.

그러나 그러한 두 진영에서 근본적으로 해결하지 못한 결정적인 문제는 자신들이 독자적으로 발전시켰던 표기법 중에 어떠한 것도 명실상부한 사실 표준(de-facto)으로 합의하지 못했다는 것이다. 가령, 아키텍처 전문가 진영에서 필요로 하는 시스템 시뮬레이션 기능을 구현하는 데 사용하는 정형 기법의 경우 동일한 도메인에서조차 연구소나 익숙한 기법에 따라 서로 달리 정의하고 필요한 시뮬레이션 도구를 개발해야 했다.

국제적인 공동 작업은 말할 것도 없이 국내에서 서로 다른 연구기관이 공동 작업을 수행하기 위해서도 사전에 일정한 표준 정형 기법을 합의하고 정립한 후 과제를 수행해야 했으며, 최종적으로 통합하는 과정에서는 결국에 모델 수준에서의 통합을 포기하고 구현 수준에서 테스트를 통해 통합하는 방식을 따라야 하는 문제점을 내포하고 있었다.

덧붙여 두 진영에서 해결하지 못한 결정적인 문제 중의 하나는 실제 구현(code)에 필요한 낮은 추상화 수준의 설계에 대해서만큼은 어설픈 UML 1.x의 메커니즘만한 수준의 방안을 제시하지 못했다는 것이다.

UML 2.0에서 새롭게 등장한 복합 구조 다이어그램은 바로 지금까지 앞서 살펴 본 아키텍처 전문가 진영으로 대표되는 임베디드 혹은 리얼타임 도메인의 핵심 개념이자 도구였던 SDL(Specification Description Language)을 수용하여 탄생한 다이어그램이다.

사용자 삽입 이미지
<그림 2> UML 2.0 복합 구조 다이어그램 예


UML을 잠시라도 살펴 본 경험이 있는 개발자들이라면, 복합 구조 다이어그램의 개략적인 형태만을 보고서도 쉽게 그 특징을 이해할 수 있을 것이다. 즉, 복합 구조 다이어그램은 매우 직관적인 형태를 취하고 있으며, 기존의 UML 1.x에서 단순한 패키지 개념의 서브시스템 내부를 구성하고 있는 클래스 다이어그램으로만 표현이 가능하던 시스템 내부 구조를 보다 섬세하게 설계할 수 있게 됐다.

그렇다고 <그림 2>와 같이 대부분의 UML 2.0을 기반으로 한 샘플들처럼 임베디드나 리얼타임 도메인과 같이 상대적으로 소프트웨어의 비중이 작은 단위 시스템이나, 특정 MIS 분야의 단위 서브시스템의 내부 설계에만 국한되어 복합 구조 다이어그램을 활용하겠다고 생각한다면, UML 2.0의 본질을 제대로 이해하지 못하고 있는 것이다.

복합 구조 다이어그램의 형태는 앞서 언급한 아키텍처 전문가 진영에서 아키텍처를 표기하는데 가장 많이 활용하는 아키텍처 스타일인 C&C(Component & Connector) 뷰 타입(view type)과도 일맥상통하는데, 복합 구조 다이어그램을 활용하고자 하는 모델의 추상 수준을 높이면 대규모 시스템의 아키텍처도 매우 유용하게 설계할 수 있게 된다.

<그림 2>에서 벤딩머신(VendingMachine)으로 되어 있는 부분을 인사시스템이라 정의하고 내부 부분(parts)들을 그것을 구성하고 있는 단위 시스템으로 정의하게 되면, 외부 인터페이스를 통해 회계시스템(AS)이나 고객관리시스템(CRM) 등과 주고받아야 할 데이터나 정보를 명시적으로 설계에 반영할 수 있을 것이다.

바로 설계자가 의도하는 어떠한 추상화 수준의 모델이라도 UML 2.0의 복합 구조 다이어그램은 보다 섬세하게 설계할 수 있도록 일관된 문맥(context)과 의미(semantics)를 제공하고 있는 것이다.

상부구조 - 행위형 다이어그램
UML 2.0 상부구조 중 구조형 다이어그램은 말 그대로 구조적인 혁명을 꾀했다면, 행위형 다이어그램 군에서는 시스템의 동적 설계를 제대로 반영하기 위해 기존의 행위형 다이어그램 군 소속 다이어그램의 의미(semantics)를 보강하고 정제함으로써, 진화 방식을 선택했다는 표현이 적절할 것 같다.

그 근거로서 앞서 복합 구조 다이어그램으로 대표되는 구조형 다이어그램에서 수용한 SDL의 경우와는 다르게 UML 1.x에서 이미 수용하던 MSC(Message Sequence Chart) 개념을 UML 2.0에 와서는 전폭적으로 수용하여 순차도(Sequence Diagram)를 중심으로 행위형 다이어그램들의 유기적 결합 통로를 확보함으로써 시스템의 모델 수준에서의 논리적인 실행을 그대로 설계에 반영할 수 있는 발판을 마련했다.

사용자 삽입 이미지
<그림 3> UML 2.0 순차도의 예


<그림 3>에서 보는 바와 같이 UML 2.0 순차도의 가장 두드러진 특징은, 기존의 UML 1.x에서 지원하지 못했던 시스템의 분기, 참조, 병렬 실행 등과 같은 세세한 부분들까지도 지원이 가능하도록 중첩된(nested) 표기법 체계를 설계 기법으로 도입했다는 사실이다.

MSC와 같은 기법에 익숙한 개발자들에게는 언뜻 보기에 별로 특이할 것이 없어 보일지 모르지만, 중요한 사실은 UML 2.0을 표준 표기법으로 수용함으로써 어떠한 비즈니스 도메인이나 기술 영역에서도 <그림 3>의 순차도 뿐만 아니라 UML 2.0의 다른 다이어그램들과 유기적인 연결고리를 가지고 활용함으로써 거의 무한대에 가까운 표현 수단을 확보할 수 있다는 사실이다.

UML 2.0 상부구조 중 행위형 다이어그램의 갱신에 대해 많은 관심을 가지는 사람은 임베디드 혹은 리얼타임 진영에 종사하고 있는 개발자들이겠지만, 기존의 비즈니스 프로세스 모델링 분야에서 종사하던 개발자 진영도 깊은 관심과 기대를 가지고 있다.

필자 또한 비즈니스 프로세스 모델링과 관련하여 행위 형 다이어그램의 특성과 최적 방안을 모색하고 있는데, 동일 비즈니스 도메인에서조차 개별 기업마다 그 특성과 비즈니스 프로세스 처리 방식이 천차만별인 문제를 해결하고자 등장했던 워크플로우 엔진 혹은 설계 시스템(workflow engine or system)과 같은 전문적인 도구의 기능을 충분히 대치할 방안이 마련된 것으로 평가되고 있다.

하부구조 - 메타 모델
소프트웨어 공학 분야에서는 이런 속설이 있다. 자신의 분야에서 메타 모델 기반의 접근을 하게 되면 하나의 논문이 된다. 매일 고객들과 씨름하면서 현장에서 일하는 개발자들에게는 먼 나라 이야기처럼 들리고, 현실적으로는 일정 규모의 연구소 혹은 학교에서나 다루어질 만한 주제로 치부됐던 것이 사실이다.

UML 2.0 하부구조(Infrastructure)는 일반적으로 UML 2.0을 지칭할 때 생각하는 UML 2.0 상부구조뿐만 아니라 OMG의 또 다른 메타 모델 집합인 MOF, CWM 뿐만 아니라 미래의 새로운 표준을 정의하기 위해 심혈을 기울여 정의한 메타 모델이다.

OMG에서 처음 메타 모델 4계층 개념을 발표했을 때에는 그저 개념적인 내용으로만 인식하지 못했지만, UML 2.0의 실체가 드러나고 그것을 지원하는 케이스 도구들의 기능들이 메타 모델 기반 설계 방식을 지원함으로써, 이제는 메타 모델이라는 주제가 현장에서조차 피해갈 수 없는 현실 문제로 다가올 것이다. 그러므로 이제는 메타 모델 4계층 개념을 충분히 이해하고 응용하는 노력을 기울일 필요가 있다.

사용자 삽입 이미지
<그림 4> OMG 4계층 메타 모델 예


글의 주제와 지면 관계상 메타 모델에 대한 깊이 있는 논의를 하지는 못하지만, <그림 4>의 예로 간단히 살펴보자. 시스템 분석가나 설계자들이 일반적인 모델링 케이스 도구를 통해 특정 도메인 시스템을 설계한다고 했을 때의 메타 모델 수준(level)이 바로 사용자 모델을 도식하게 되는 M1 수준이다.

M2 수준은 그러한 UML 기반의 설계를 가능케 하는 어트리뷰트, 클래스, 인스턴스 등과 같은 모델 요소를 정의하는 메타 모델이며, UML 2.0의 하부구조는 바로 위 4계층 메타 모델 관점에서 M2 수준의 UML 메타 모델이 된다. M3 수준에 위치한 MOF(Meta Object Facility)는 M2 수준에 속한 메타 모델을 정의하는 메타메타 모델이 된다.

참고로 CWM(Common Warehouse Metamodel)은 M2 레벨이며, MOF의 내부 구조는 추상화된 UML 하부구조와 동일한 방식으로 정의하고 있다. 자세한 사항은 OMG UML 2.0 Infrastructure, 7. Language Architecture를 참조한다.

앞에서 살펴 본 바와 같이 OMG에서 UML 2.0 관련 제안요청서(RFP)를 제기한 목적은 단순히 UML 2.0을 체계적으로 정리하고자 한 것이 아니라, OMG의 또 다른 표준인 MOF와 CWM 및 미래의 새로운 표준을 체계적으로 정의하기 위한 용도로 제기됐던 것이다. 여기서 우리가 주목해야 할 사항은 UML 2.0 하부구조에 대한 제안요청서를 통해 제기한 또 다른 목적이다.

그것은 바로 지금까지 M1 수준에서 UML을 활용하던 사용자들이 보다 수월하게 M2 수준에서 UML을 커스터마이징하여 활용할 수 있는 메커니즘을 제공하는, 즉 이원화된 메커니즘을 제공하여 사용자들이 유연하게 특정 기술 도메인이나 비즈니스 도메인에 최적화된 방식으로 설계를 수행할 수 있도록 하자는 데 그 취지가 있었다.

그 핵심이 바로 UML 프로파일(UML Profiles)이다. 지금 UML 2.0 작업과 동시에 진행되고 있는 대표적인 기술 도메인 프로파일로는 우리들에게 친숙한 EJB 프로파일(Profile for EJB), 닷넷 프로파일(Profile for .Net)을 들 수 있다. 프로파일을 간단히 설명하면, 일종의 특정 기술이나 비즈니스에 적절한 커스터마이징된 확장 메커니즘을 사전 정의해 놓고, 추상화 수준이 서로 다른 모델들간의 전환(transformation)을 자동화시키는 핵심 메커니즘이다.

플랫폼 독립 모델(PIM: Platform Independent Model)로부터 특정 플랫폼 종속 모델(PSM: Platform Specific Model)로의 자동화된 전환이라는 MDA의 사상이 바로 대표적인 일례라고 볼 수 있다. UML 프로파일은 향후 MDA를 통해서 달성하려고 하는, 아니 궁극적으로 UML 2.0을 통해 달성하게 될 소프트웨어 공학의 핵심 화두인 소프트웨어 개발 생산성 향상의 핵심 메커니즘으로 평가 받고 있다.

만약 이 글을 읽는 개발자가 속한 관련 분야에 MIS 분산 시스템 개발의 사실 표준으로 통용되는 J2EE나 닷넷 등과 같은 개발 기술 표준 프레임워크가 존재한다면 다행스러운 일이다. 모델링 도구 벤더에서 제공하는 EJB 프로파일이나 닷넷 프로파일과 같은 기술 메타 모델은 그대로 활용하고, 관심 비즈니스 영역에 해당하는 표준 도메인 프로파일을 활용하거나, 독자적으로 정의해 설계 작업을 추진해 나갈 수 있기 때문이다.

하지만 최악의 경우 관련 분야에 기술이나 도메인 프로파일이 존재하지 않고, 더욱이 활용할 만한 케이스 도구조차 존재하지 않는다면 난감하다. 하지만 UML 2.0을 충분히 지원하는 범용 혹은 상용 케이스 도구를 통해 구현된 방식이나 기능을 살펴보면 놀랄 만큼 간결하다. 문제는 UML 2.0의 프로파일 방식과 같은 메커니즘을 이해하는 것이 아니라, 그 동안 개발자들이 간과해 왔던 문제, 가령 “해당 비즈니스 도메인을 제대로 이해하고 있었는가?” 등과 같은 근본적인 문제를 되돌아보는 계기가 될 것으로 생각된다.

어떻게 대처할 것인가
지금까지 UML 2.0 출시를 전후해서 전개되어 왔던 소프트웨어 산업계의 전반적인 흐름과 사회적 파장, 그리고 UML 2.0의 상부 및 하부구조의 핵심 메커니즘을 중심으로 간단히 살펴보았다. 그렇다면 과연 어디서부터 어떻게 UML 2.0을 시작할 것인가?

기본 원칙에 충실하자
우선 스스로에게 UML 1.4는 제대로 이해하고 활용해 왔는가라는 질문을 던져 보아야 한다. 필자의 경우 하는 일이 하는 일인만큼 UML 2.0이 발표되기 이전에도 자바나 비주얼 베이직 등과 같은 프로그래밍 용어나 주제에 비해 상대적으로 UML(1.x), OOAD, CBD, 방법론 등이라는 용어가 훨씬 낯설지 않았다.

당연히 주변에는 상대적으로 코딩보다는 현장에서 분석(analysis)이나 설계(design)를 전문으로 하거나, 학교나 학원 등에서 학생들을 가르치는 사람들이 많았지만 그 중에 UML 1.x 관련된 OMG 무료 명세를 제대로 살펴보았거나, 가까이 두면서 참조하는 사람은 찾아보기 어려웠다.

필자 가까이에 ‘UML 1.4 사용자 지침서’를 한글로 번역했던 분을 통해 확인해 보아도, 국내 출판사에서 출간한 책 부수로 미루어 UML 원문은 차치하고서라도 핵심 내용만을 추려서 발간한 그 UML 사용자 지침서마저 꼼꼼히 살펴 본 사람은 별로 보지 못한 것 같다. 필자도 예외는 아닌데, 돈이 없어서 혹은 원서이기 때문에라는 것은 이유가 되지 않았던 것이다.

그런데 UML 2.0이 공식 발표되는 이 시점에도 상황은 예전이나 별반 다르지 않은 것 같다. UML 2.0으로 공식 공표되기 전에 이미 오래 전부터 OMG에는 UML 관련 명세를 1.5의 형태로 인터넷에 배포하고 있었지만, 살펴본 사람은 찾기 어려웠다. UML 1.1이 처음 발표되던 시점에는 표기법으로서의 표준화 경쟁에서 판정승이 나지 않았던 때여서 그랬다고 하더라도, UML 2.0이 공표되는 이 시점에는 이미 국내외 많은 대학의 컴퓨터 관련학과에서 필수 과목으로 개설되었을 만큼 그 중요도와 필요성이 검증된 마당에 애써 그 사실을 외면하는 것은 더 이상 이유가 될 수 없다.

물론 지금까지의 현실은 그렇지 못했던 것이 사실이다. UML 전문가들마저도 UML 1.x의 설계 도구로서의 완성도가 받쳐주지 못했고, 무엇보다도 고객들도 유기적으로 논리적인 설계 모델을 기대하지 않았기 때문에 UML이라는 포장지를 가지고 피상적이고 개념적으로 대충 구색 맞추기식 설계 산출물을 만들어 주면 그만이었다.

그러나 앞으로의 상황은 그렇지 못할 것이다. 당장은 아니겠지만 UML 2.0 표기법이 소프트웨어 산업 시장에서 보편적으로 활용되고 국내외에서 하나 둘 그 무한한 잠재력과 가능성이 증명되어 그 시장 가치가 확연히 드러나기 시작하는 시점에는 우리 주변의 고객들 또한 단순히 보기 좋은 산출물 정도의 설계를 요구하지는 않을 것이다.

그렇다면 어디서부터 어떻게 준비해야 할 것인가? 그 실마리는 처음 접하면 이해하기 어렵고 복잡한 UML 2.0 관련 명세나 두꺼운 책에서 찾을 것이 아니고, 누구나 알고 있으면서도 충실하지 못했던 가장 기본적이고 원칙적인 원리를 고민하는 것부터 시작해야 한다.

원칙 하나, 도메인을 철저하게 분석하자
시스템을 설계한다고 했을 때, UML과 같은 설계 기법을 동원하여 작업하는 시스템 분석 및 설계자 그룹 외에 매우 중요한 역할을 수행하는 집단이나 개인을 가리켜 도메인 전문가 혹은 비즈니스 분석가라고 한다. 가장 이상적인 시스템 설계자는 두 가지 능력 즉, 해당 도메인에 대한 공인된 전문적인 지식을 가지고 있으면서 동시에 설계 능력을 고루 갖춘 인재일 것이다.

그러나 현장에서 그런 핵심 인재를 찾기는 어려운 것이 사실이다. IT 업계로만 보더라도 시스템 설계자와 개발자 간에 차이가 좀처럼 좁혀지지 않는데, 전혀 그 분야와 전공이 다른 비즈니스 전문가와 시스템 전문가 간에 느끼는 갈등은 말할 필요도 없다. 시스템을 설계해 본 사람은 누구라도 공감하겠지만, 시스템을 제대로 설계하려면 해당 도메인을 충분히 이해하고 철저하게 분석해야 한다. 그렇지 않으면 제대로 된 시스템을 설계할 수 없다.

시스템 설계자 입장에서 문제는 해당 도메인을 제대로 이해하기 위한 충분한 시간도 주어지지 않고, 나름대로 시스템 설계자가 충분히 이해한 것을 객관적으로 검증해 줄 만한 기준도 마련되어 있지 않다는 것이다. 설사 객관적 기준이 있더라도 그것은 현실적으로 거의 불가능하다는 것이다.

가령 회계 시스템을 설계하려면 회계사 자격증을 갖춰야 하는가? 물론 아니다. 그런데 우리는 주변에서 타의든 자의든 특정 도메인 시스템을 반복해서 설계하는 설계자의 경우 점점 해당 도메인에 대한 이해력이 높아지고, 회계사와 같은 공인된 자격증은 취득하지 못하더라도 나름대로 그 전문성을 인정받아 시장에서 높이 평가되는 경우를 보곤 한다.

비단 시스템 설계자에게만 해당되는 문제는 아니다. 조각조각 할당된 부분만 열심히 해야 하는 개발자에게도 비슷한 현상은 쉽게 찾아 볼 수 있다.

설계하고자 하는 해당 도메인에 대한 철저한 분석 없이는 일정한 추상화 수준을 유지한 유기적인 모델을 만들어 낼 수가 없다. 몇몇 책이나 발표 자료에서 설계 팁으로 이야기 하듯이 해당 도메인에서 반복적으로 등장하는 명사(nouns)를 클래스명으로 명명한다는 식으로 설계를 진행하다 보면 점점 헤어나지 못하는 미궁으로 빠져들게 된다. 결국에는 UML 2.0이라는 강력한 설계 도구를 가지고도 설계 따로, 코딩 따로라는 늪에서 벗어날 수 없다.

UML 표준화를 주도하는 OMG에 대해서 많은 사람들은 단순히 CORBA, ORB 등과 관련한 국제적인 기술 표준화 단체 정도로만 인식하고 있다. 하지만 앞서 주장한 도메인 지식 혹은 도메인 표준에 대한 중요성에 대해서는, 그러한 기술 표준화 단체로 출범한 OMG에서 2002부터 발족하여 추진하고 있는 DTF(Domain Task Forces) 위원회의 활동을 살펴보면 쉽게 이해할 수 있다.

이미 전략전술 통제(C4I), 재무(finance), 의료(healthcare), 제조(manufacturing), 우주항공(space), 통신(telecommunications), 운송(transportation) 등의 도메인을 필두로 그 표준화 작업을 진행 중에 있으며, 여러 표준화 단체들과 연합하여 다른 도메인으로까지 표준화 작업을 확장 중에 있다.

물론 아직까지 그 시도는 기술적인 관점에서의 접근이라는 한계를 크게 뛰어 넘고 있지는 못하지만 인터넷, 즉 IT 기술을 배제한 고전적 의미의 비즈니스는 점차 그 경쟁력을 잃어 가고 있는 현실을 생각할 때 OMG의 영향력은 쉽게 무시할 수 없는 것이 될 것이다.

원칙 둘, 모델의 추상 수준
사전적 의미로도 알 수 있듯이 모델은 본질적으로 어떤 특정 사물이나 현상에 비해 상대적으로 추상화되어 있는 무엇이기 때문에 똑같은 실체에 대한 서로 다른 모델은 서로 다른 추상화 수준(level of abstraction)을 가질 수밖에 없다.

사용자 삽입 이미지
<그림 5> 모델의 서로 다른 추상화 수준


<그림 5>를 보면 똑같은 자동차를 모델로 만든 것이지만, 상단의 자동차 그림(혹은 모델)은 추상화 수준이 높고 하단의 자동차는 추상화 수준이 낮다. 여기서 중요한 것은 추상화 수준의 높고 낮음은 상대적이라는 것이다. 우리가 UML에서 제시하는 여러 다이어그램을 가지고 모델을 제작한다는 것은 결국 목표하는 자동차나 건물 등과 마찬가지의 실체 즉, 특정 시스템 하나를 완성하기 위한 노력인 것이다.

즉, 설계 작업을 수행한다는 UML 1.4의 표기법을 동원하든 UML 2.0의 표기법을 동원하든 아니면 제3의 표기법을 활용하든 목표하는 시스템을 완성하기 위한 과정이지 다이어그램 혹은 표기법 자체가 목적이 되지는 않는다는 것이다. 이러한 똑같은 모델의 원리를 UML의 다이어그램을 가지고 설명할 수 있다. <그림 5>는 UML 1.4에서 제시하는 9개의 표준 다이어그램의 추상화 수준을 계량화하는 방안으로 방사형의 표로 도식해 본 것이다.

사용자 삽입 이미지
<그림 6> UML 1.4 다이어그램 추상화 분포


<그림 6>의 중앙에 위치한 지점을 설계자가 목적하는 목표 시스템의 코드 혹은 운영(run-time) 시스템이라고 한다면, 유스케이스 축에서 0.8으로 표시된 지점 정도의 추상화 수준으로 유스케이스를 작성한 것을 비즈니스 유스케이스라 할 수 있겠고, 0.4 정도의 지점 추상화 수준으로 작성한 것을 시스템 유스케이스라고 할 수 있을 것이다. 그렇게 가정해 본다면, 중앙에 가까운 지점의 추상화 수준으로 낮게 모델을 작성한다면 설계자가 목적하는 시스템은 보다 세세하게(detailed) 보이게 될 것이다.

유럽의 모든 길이 로마로 향하듯이, 어떠한 길(다이어그램)을 선택하더라도 종국에는 목적지(목표 시스템)에 도달할 수 있다. 하지만 각 다이어그램은 각자 목표하는 시스템으로 접근할 수 있는 추상화 수준의 한계를 가지고 있다.

가령, 유스케이스 다이어그램만을 가지고 시스템 설계를 완성할 수는 없는 것이다. 반면에, 클래스 다이어그램만 가지고 시스템 설계에 접근하다 보면 나무는 보고 숲을 보지 못하는 우를 범할 수 있다. 그러한 이유로 소프트웨어 설계에서 UML을 활용하여 목표 시스템을 설계할 때는 하나 이상의 다이어그램을 활용하게 된다.

대표적으로 많이 활용되는 다이어그램으로는 유스케이스, 클래스, 시퀀스 등을 들 수 있을 것이다. 문제는 여기서부터 시작 된다. 시스템 설계에 대표적인 3개의 다이어그램을 활용하든 아니면 9개의 다이어그램을 모두 활용하든 활용하는 다이어그램들이 각자 따로 존재하게 되는 것이다.

유스케이스 다이어그램 따로 클래스 다이어그램 따로 심지어는 동일한 시스템에 대한 유스케이스 다이어그램을 그리더라도 그리는 사람에 따라 서로 다른 추상화 수준(level of abstraction) 혹은 입도(granularity)의 유스케이스가 작성된다는 것이다. 이건 비즈니스 유스케이스니 이건 시스템 유스케이스니 하면서 무의미한 논쟁으로 치닫게 된다.

이러한 문제를 본질적으로 해결책하기 위해서는 그것이 UML 1.4이든 UML 2.0이든 각 다이어그램의 주된 용도(usage)와 목적(objectives), 그리고 그 한계를 충분히 이해하고, 각 다이어그램이 그러한 용도와 목적을 충족시키기 위해 제시하는 특성 표기법의 명확한 의미와 용도를 숙지해야 한다. 그 후에 활용하려는 다이어그램의 핵심 표기들 간의 추상화 수준에 대해 일관된 원칙(principle)을 우선 정립하고 설계 작업을 수행해야 한다.

가령 이러한 원칙 수립이 가능하다. 유스케이스 다이어그램을 통해 작성한 하나의 유스케이스를 하나의 활동도(Activity Diagram)로 도식하기로 했다면, 활동도의 활동(Activity)은 유스케이스 시나리오로 작성하는 사건 흐름(flow of event) 상의 단일 스텝(step)이라는 원칙을 설정하게 되면 일관된 설계 작업을 수행할 수 있다. 그러한 설계 전략을 위 <그림 6> 위에 상징적으로 표현해 보면, <그림 7>과 같이 도식할 수 있을 것이다.

사용자 삽입 이미지
<그림 7> 다이어그램 간의 추상화 수준 조정


지금까지 UML 1.4를 중심으로 모델의 추상 수준이라는 원리에 대해 살펴보았다. 그러한 모델의 추상 수준이라는 핵심 메커니즘은 본질적으로 UML 2.0이라고 해서 다르지 않다. 앞선 <그림 1>과 <그림 7>을 언뜻 비교해 보아도 UML 2.0에서는 표준 다이어그램의 개수로도 UML 1.4에 비해 수적으로 많이 늘어났으며(<그림 4>에서 빨간색으로 표시된 다이어그램), 이전부터 있었던 몇몇 다이어그램들은 명칭이 변경됐고(<그림 4>에서 초록색으로 표시된 다이어그램), 무엇보다도 전반적으로 모든 다이어그램들이 보다 섬세한 설계자의 의도를 반영할 수 있도록 세부적인 표기들이 많이 추가되고 세분화됐다. 즉, 사용할 수 있는 다이어그램 선택의 폭(width)이 넓어졌고, 설계자의 의도를 보다 정밀하게 반영할 수 있는 깊이(depth)도 깊어졌다.

원칙 셋, 모델 자체의 완성도를 높이자
앞서 소프트웨어 업계에서 최근 발생하고 있는 현상들을 통해 잠시 언급했지만, UML 관련 국내외 포럼이나 협회들을 중심으로 UML 자체 혹은 설계 능력 인증 제도가 점차 많아지고 있다. 필자가 인증 제도의 본질적인 목적이나 그 가치 자체를 부정하는 것은 아니지만, 올해 사회적으로 충격을 던져 주었던 대입 수능 시험에서의 대량 부정 사태라든지, 얼마 전부터 공공연하게 제기됐던 영어 관련 인증 제도 등에서 발생하고 있는 문제점 등에 비추어 UML 인증 제도에서도 충분히 발생할 수 있는 그 변별력 문제에 대해 우려를 감출 수 없다.

그러나 다행히도 UML 2.0이 가지고 있는 그 강력한 표현력(semantic expressiveness)과 섬세함(elements precision) 그리고 다이어그램들간의 유기적 연결성 지원(support for diagram interchange) 능력으로 인해 인증서를 가지고 있다고 들먹이지 않아도 모델 결과물 자체로 그 완성도를 검증(self verification)할 수 있다. 즉, 모델 결과물만으로도 충분히 설계자의모델링 역량을 충분히 증명할 수 있는기반을 제공하고 있는 것이다.

UML 2.0이 공식으로 발표되기 이전 특정 케이스 도구들을 중심으로 시도됐지만 UML 1.4의 제약으로 그 실효성(efficiency)을 의심받았던 코드 자동 생성(automatic code generation) 기능은 케이스 도구들이UML 2.0 엔진으로 교체함으로써 그 완성도를 높일 수 있게 됐다. 더 나아가 UML 2.0이 내포한 그 풍부한 표현력과 정교함은, 특정 플랫폼에 종속적인 코드를 생성해 내기 이전에 케이스 도구의 도움을 통해 모델들만을 가지고 사전에 시뮬레이션마저도 어려운 문제가 되지 않는다.

앞으로의 전망
지금까지 개발자들은 새로운 기술이나 제품이 출시되면, 여기저기서 화려한 수식어와 찬사로 밝은 미래를 전망하는 이야기에 너무나도 익숙해져 있다. 1997년 UML 1.1이 처음 세상에 나왔을 때도 마찬가지였다. 그런 맥락에서 단순히 UML 2.0이라는 새로운 패러다임에 무조건 주목하자고 주장하고 싶지는 않다. 실리에 밝은 국내외 소프트웨어 업체들과 협회들의 행보와 여러 가지 상황을 종합해 보아도 UML 2.0이 소프트웨어 산업계에 미칠 파장의 크기는 실로 엄청날 것으로 예상된다.

그것이 더 이상 거스를 수 없는 현실이라면 그러한 도전에 수동적으로 대처할 것인가, 아니면 능동적으로 대처할 것인가의 문제는 독자 스스로 선택할 문제이다. 혹시 이솝 우화에 나오는 거짓말하는 늑대 이야기에서처럼 중요하다는 말을 너무 자주 들어 개발자들이 UML의 중요성을 공허한 메아리 정도로만 치부하고 지나칠까 걱정될 뿐이다.@

* 이 기사는 ZDNet Korea의 제휴매체인마이크로소프트웨어에 게재된 내용입니다.

 

사용자 삽입 이미지

 

원문 :http://www.zdnet.co.kr/techupdate/lecture/etc/0,39024989,39134178,00.htm

 

원문 :http://www.zdnet.co.kr/techupdate/lecture/etc/0,39024989,39134557,00.htm

신고
0  Comments,   0  Trackbacks
댓글 쓰기
[UML 제대로 알기] ② 초보자를 위해 다각도로 살펴본 UML

[UML 제대로 알기] ② 초보자를 위해 다각도로 살펴본 UML

 

연재순서
1회.가능성·확장성 품고 등장한 UML 2.0
2회.초보자를 위해 다각도로 살펴본 UML
3회.바로 알고 제대로 쓰는 UML 실전 모델링
4회.닷넷 환경에서 UML 툴 활용 가이드
5회.표준을 넘나드는 UML의 적절한 사용

 

7년 전 필자는 UML이라는 단어조차 들어본 적 없었다. 국내에서는 그래도 꽤 잘하는 비주얼 베이직 프로그래머라고 자부했는데 당시 봇물같이 쏟아지던 약어들에 질려 UML이라는 알파벳 세 글자로 이루어진 '신규어'에 별 신경을 쓰지 않았다.

몇 년이 지난 후, 필자도 객체지향이라는 무림 강호에 몸을 던지지 않을 수 없는 시점에 이르러서, 그 몇 년 전에 들었던 UML이라는 것이 무림에 출사표를 던지기 위한 필수 무공이었다는 사실을 깨달았다. 그리고 그 이름도 원망스러운 디자인 패턴!

비주얼 베이직이라는 한물간 초식에서는 ‘꽤’ 강자라고 생각했던 필자는 객체지향이라는 드넓은 무림에 발을 들여서는 초고수가 되어야 되겠다는 결심을 했고, 높은 내공을 쌓기 위한 필수 비급이라는 UML과 디자인 패턴을 익히기 시작했다. 그러면서 필자가 느낀 것은? ‘초고수는 아무나 하는 것이 아니구나’하는 것이었다.

필자는 디자인 패턴에 한이 맺힌 사람이다. 디자인 패턴을 며칠 밤씩 새워 가면서 공부할 때 느낀 고통은 이루 말할 수 없다. 가끔씩 감동을 느낄 때도 있었지만 대부분의 경우가 이해하기 힘들고 패턴에 따라 프로그램을 작성하기는 더 힘든 경우가 많았다.

결국은 객체지향에 대한 기초 지식이 부족하기 때문이라는 사부님의 조언을 듣고는 HTDP와 SICP 등의 패러다임 입문서, 리스코프나 메이어 등의 객체지향 이론서 등을 짧은 영어 실력에 열심히 번역하며 읽었다. 객체지향 디자인을 제대로 이해하기 위해서는 UML은 필수사항이었고, UML에 관련된 책도 열심히 사서 읽었다. 그때부터 필자의 머릿속에는 이상한 고정 관념이 생기기 시작했다.


"디자인 패턴도 모르는 개발자가 무슨 개발을..."
"UML은 자유롭게 쓸 수 있어야 개발을 한다고 할 수 있지..."


결국은 내공이 좀 쌓이고, 디자인 패턴과 UML을 어렵지 않게 응용해서 프로그램을 짤 수 있는 수준이 되었을 무렵에, 필자는 병적으로 디자인 패턴과 UML에 집착하기 시작했다. 래쇼날 로즈 등의 케이스 툴을 사용해 설계를 하고 있으면, 화면에 보여 지는 여러 예쁜 아이콘들을 보면서 ‘아, 나는 살아 있구나’하는 존재의 가치를 느끼곤 했다.

그렇게 열심히 익힌 기술들을 이용해서 프로그램을 열심히 개발하던 어느 날 밤, 필자는 어떤 의문을 가지게 되었다. 왜 내가 동작하는 코드를 개발하지 않고 그림을 그리고 있을까? 프로그램을 작성하는 목적이 잘 동작하는 프로그램을 작성하는 것이지 출력해서 벽에 걸어놓을 미술 작품을 만들고자 하는 것이 아니지 않은가?

필자는 플라톤의 동굴의 비유에 비견될 만한 엄청난 진리를 깨달았다. UML이든, 디자인 패턴이든 꼭 필요한 부분에만 사용하면 되는 것이고, 프로그램을 작성하기 전 개념을 잡거나 최종적으로 정리하는데 유용한 도구, 특히 UML은 개발자들 간의 상호 커뮤니케이션에 아주 유용한 도구가 될 수 있다는 것을 알게 되었다.

필자는 UML 케이스 툴을 만드는 업체에 근무하는 개발자 몇 명을 잘 알고 있다. 대학원에서 꽤 실력을 쌓아 어렵게 취업한 후배들인데, 업체에 근무한지 3개월쯤 되면 이런 말을 한다.


"UML에 이렇게 많은 것들이 있는 줄 몰랐어요. 무척 힘드네요"


1년쯤 근무하면 이런 말들을 한다.


"개발자라면 UML은 반드시 알아야죠. UML의 구석구석을 모르고 어떻게 제대로 된 프로그램을 작성할 수 있습니까?"


3년쯤 근무한 후배는 이런 말을 한다.


"UML요? 꼭 쓸데만 쓰면 되지 오버해서 쓰면 나중에 감당 못하죠"


악순환의 반복이랄지, 디자인 패턴과 UML이 남긴 폐해랄지, 이런 현상은 매년 계속된다.

아키텍트 입장에서 UML
필자가 조선 업계에서 근무할 때, 새로운 시리즈를 시작할 경우(배는 하나의 설계로 여러 척을 찍어낸다) 먼저 모형을 만들어서 테스트를 하는 것을 본 적이 있다. 모형을 만들어 수영장 같은 곳에서 테스트를 해 보고 실제로 배가 목표한 만큼의 성능을 낼 수 있는지 테스트 한다. 또한, 배를 설계할 때 거대한 캐드 시스템으로 설계한 후 파도와 바람 등에 견딜 수 있는지를 테스트한다.

배를 만들 때는 엄청난 비용과 시간이 소모되기 때문에 모형을 만들거나 컴퓨터상에서 수치로 테스트한다. 컴퓨터로 만들건, 정말 모형을 만들건, 그렇게 만들어진 것을 모델이라고 하고, 대부분의 경우 모형을 만드는 비용이 실제 배를 만드는 것보다 비용이 훨씬 적게 소모되므로 모델 테스트를 한다. 이런 모델을 만들어 테스트 해보는 과정을 ‘모델링’이라고 부른다.

배를 지을 때도 선실의 세부 구조나 엔진의 동작들은 모델링하지 않는다. 모델링이라는 것은 어떤 것이 실제로 잘 동작하는지를 알아보려고 만드는 것이다. 실제 크기대로 배를 지어 바다에서 항해해 가며 파도와 바람의 영향을 최소화하거나 풍랑에 버틸 수 있을지를 테스트 해 본다는 것은 비용이 너무 많이 드는 일이다. 모델을 만드는 이유는 모델을 만드는 비용이 실제 물건을 만드는 것보다 훨씬 적은 비용으로 설계가 제대로 되었는지 알고 싶어서이다.

소프트웨어를 만들 때도 이와 같은 이치가 적용된다. 하지만 소프트웨어를 설계할 때 사용하는 이 UML이라는 것은 조선 엔지니어나 토목 엔지니어들이 모델링을 하기 위해 사용하는 미니어처나 캐드 모델과 비교해 볼 때 훨씬 비효율적이고 테스트하기 곤란하다. UML 다이어그램에는 다른 공학 모델과 비교해 보았을 때 확고한 시험 기준을 세우기도 곤란하고 평가를 내릴 때도 주관적인 관점이 상당부분 차지할 수 밖에 없다.

조선이나 건축에서 모델을 만드는 것은 실제 배나 건물을 짓는 것과 비교할 때 비교도 할 수 없을 만큼의 적은 비용이 들지만, 소프트웨어를 설계하는 입장에서 실제 프로그램을 작성하는 것과 UML을 사용한 설계를 비교했을 때 비용적인 측면에서나 생산성적인 측면에서나 그렇게 차이 나지 않는다.

사실, UML을 사용해서 테스트하는 것보다 소스코드를 직접 수정하는 것이 비용이 훨씬 적게 들고 손쉬운 경우도 있다. 개발자의 입장에서는 더욱 그러하다. 하지만 UML을 사용해야 하는 이유는 무엇일까? 잘 사용하면 비용 절감의 효과를 가져 올 수 있고, 포괄적인 설계가 가능하다는 것이다.

UML 다이어그램이라는 것은 앞서 이야기 했듯이 다른 공학에 비해 모델을 사용했을 때 실제 건축물(소프트웨어에서는 실제 동작하는 코드)을 작성하는 것보다 비용이 명확하게 절약되는지가 명확하지 않다. 필자는 실제 프로그램을 작성하는 것보다 UML 다이어그램을 작성하는 것이 훨씬 시간이 많이 드는 경우를 허다하게 봤다(사실 그렇게 하지 않으면 제대로 된 프로그램이 나오지 않는 경우가 대부분이다).

UML 다이어그램은 세부적인 설계를 하기 보다는 포괄적인 설계를 구성하였을 때 그 전체적인 비용의 절감 효과를 가져 올 수 있다. 세부적인 그림을 UML 다이어그램으로 표시하기 보다는 전체적인 그림을 UML 다이어그램으로 표시하고 세부적인 표현은 코드로 작성하는 등의 탄력성 있는 설계 운영이 전체를 UML로 설계하는 것보다 훨씬 나은 효율을 가져올 수 있다는 것이다.

실제로 아키텍트들의 설계는 이러해야 한다. 아키텍트들은 UML 다이어그램을 세부적으로 표현하기 보다는 전체적인 그림을 그리고, 그린 그림이 실제 소프트웨어로 동작했을 때 바르게 동작할 수 있을 것인지를 개발자들과 토론하고 설계를 수정한다.

필자는 프로젝트를 시작할 때 전체 소프트웨어의 요구사항을 격자 형태로 나누고 각 부분을 개개의 개발자들에게 할당하는 경우를 본 적이 있다. 큰 부분으로 나뉜(이 큰 부분으로 나누는 것조차 PM급의 아키텍트가 하지 않는다. 그러한 큰 부분은 대 부분의 기업형 응용 프로그램이라면 부서별 또는 업무별로 자연스럽게 할당되어 있기 마련이다) 업무 분할대로 각 개발자가 ER-Diagram부터 클래스 다이어그램, 컴포넌트 다이어그램까지 작성하는 경우를 실제로 본 적이 있다.

큰 수정 없이 프로젝트가 진행되어 다행이었지만, 한 부분이라도 어긋난 부분이 있었다면 엄청난 비용이 소모되었을 것이다(사실 그렇게 작성된 프로그램은 전체적인 소프트웨어의 부품이 유기적으로 동작하는 소프트웨어가 아니고 각 부품이 각기 따로 동작하는 작은 프로그램들의 집합일 수밖에 없고, 실제로도 그러했다).

개발자 입장에서 UML
자, 이제 개발자 입장에서 UML을 생각해 보자. 실제로 개발자가 UML 다이어그램의 모든 부분을 다 알아야 하는가? 개발자가 프로그램을 작성하기 위해서 UML의 메타 모델을 모조리 이해하고 각 프로젝트와 다른 케이스 도구들에서 쓰이는 스테레오 타입들을 다 알아야 한다는 것이다.

필자는 여기에 반대한다. 필자는 주로 닷넷 기술들을 가지고 소프트웨어를 작성하고 강의하고 컨설팅을 수행하는데, 사실 닷넷 기술은 너무 빠른 속도로 변화하고 있다. 곧 출시될 비주얼 스튜디오 2005와 MS-SQL 서버 2005는 닷넷 프레임워크 2.0을 기반으로 하는데, 닷넷 프레임워크 2.0은 1.1 버전과는 상당히 다른 모습을 보여준다.

C#이나 비주얼 베이직 닷넷 같은 언어적인 측면에서만 봐도, 겉으로 보기에도 제네릭(Generic)이 포함되는 등 상당히 많은 부분이 변하였다(필자는 이 부분에서 상당히 불만이 많다. MS는 이런 부분을 발표만 하고는 다른 이야기가 없다.

여러 잡지에 소개되는 글들을 봐도 이런 기능들이 추가되었다. 이런 내용만 있지 실제적으로 테스트 해 볼 수 있는 코드를 제시하거나 근본적인 변화를 이야기하는 경우는 드물다). ASP.NET 2.0만 해도 ASP.NET 프레임워크가 전체적으로 변화한 부분도 몇 군데 있을 뿐더러 사용자 정의 컨트롤이 상당히 많이 추가되고 변화함으로 인해서 새로 익혀야 할 부분이 늘어났다.

사용자 삽입 이미지



ADO.NET도 마찬가지다. 개발자의 부담은 가중되고 실제적으로 필드에서 사용되어야 할 코드와 컨트롤들의 사용법을 익히는 것과 UML의 전체적인 내용을 학습하는 것 사이에서 갈등하게 된다.

디자인 패턴도 이럴 때 부담이 된다. 개발자 누구나가 디자인 패턴과 UML을 사용할 수 있어야 하고 열심히 학습해야 한다는 것은 알고 있지만, 현실적으로 당장 사용하여야 할 요소 기술과 끝이 보이지 않는 기반 기술을 사이에 두고 갈등하다 보면 당연히 당장 사용하게 되는 요소 기술 쪽으로 치우칠 수밖에 없다.

이럴 때 누군가에게 "UML을 조금 알아야 되겠는데 어떤 책을 봐야 되겠습니까?"라고 물어보면 그 누군가는 책을 산더미처럼 던져주고(보통 이런 경우에 이유 없이 원서를 권하는 경우가 많다. 안 그래도 바빠 죽겠는데 원서가 포함된 책 뭉텅이를 받은 개발자의 입에서는 욕 빼고는 나올 것이 없다) 이 책의 내용들을 거의 다 숙지해야 제대로 쓸 수 있다는 교과서의 화신 같은 이야기를 하게 된다. 사실, 이 말은 격무에 시달리는 개발자들에게 UML을 공부하지 말라는 이야기와 동일하게 밖에는 안 들린다.

개발자들은 프로젝트에 투입될 때 UML의 어떤 부분을 알아야 하는가? 사실 UP의 모든 부분을 다 안다는 것은 업무 형태와 업무량으로 볼 때 거의 불가능 하다고 볼 수 있다. 그렇다고 UML을 전혀 모르는 상태에서 개발에 투입되었다면 그 개발자의 앞길은 십자가를 지고 골고다 언덕을 오르는 예수님의 모습처럼 보일 것이 뻔하다. UML을 효과적으로 사용하기 위한 효과적인 길을 알아보자.

의사소통 수단으로서 UML
초보 개발자라면, 우선 UML의 표기법에 익숙해져야 한다. 이렇게 생긴 아이콘은 클래스고, 이렇게 생긴 화살표는 실제화고(물론 실제화를 이해하기 위해서는 객체지향을 이해하여야 한다는 원론적인 이야기를 피하기는 힘들다. 산 너머 산이다) 이렇게 생긴 화살표는 집단화이고 등의 표기법(Notation)을 익히는 것이 중요하다. 개발은 혼자 하는 것이 아니기 때문이다. UML은 개발자들끼리 설계 개념에 대한 의견을 주고받을 때 굉장히 편리한 도구로 사용될 수 있다. UML의 표기는 매우 명확한 의미를 전달해 줄 수 있다.

개발 경로로서의 UML
UML은 기업 형 소프트웨어를 작성할 때 구조의 개발 경로를 작성할 때 유용하다. PM이 이렇게 개발해라 하는 지시를 내리면 사실 그 지시라는 것은 추상화 된 개념이라서 바로 프로그램으로 옮기기가 곤란한 경우가 대부분이다. 이런 경우, 어떤 객체를 먼저 작성하여야 하고 어떤 객체는 어떤 객체에 의존하고 하는 식의 로드맵이 필요한데, UML은 이런 도구로서도 훌륭하다.

개발 경로로서 UML 다이어그램을 활용하려 한다면, 클래스 다이어그램, 객체 다이어그램, 시퀀스 다이어그램, 협력 다이어그램을 읽을 수 있고 작도할 수 있어야 한다. UML 표기법을 완벽하게 익힐 필요까지는 없을 테고, 적당히 다른 사람과 상호 통신할 수 있을 정도의 수준이면 충분하다.

스테레오 타입 등은 잘 알아야 하지 않느냐고? 처음엔 잘 몰라도 된다. "<<", ">>"가 붙은 기호는 스테레오 타입이라고만 아는 것으로 충분하다. UML이라는 것은 쓰다보면 이해가게 되어있는 아주 신기한 물건이다.

언제 다이어그램을 그려야 하는가?
UML은 도구일 뿐 그 자체가 목적이 되어서는 안된다. UML이 목적이 되는 경우도 물론 있긴 하다(대부분의 경우 UML이 목적이 되는 경우는 작성된 소프트웨어가 클라이언트 또는 감리에 의해 검수 받을 때뿐이다). UML을 남용하는 것은 소프트웨어 개발에 큰 걸림돌이 될 수 있다. 하지만 남용하지 말고 아껴서 사용한다면 큰 도움을 줄 수 있다. 예전의 ‘약 좋다고 남용 말고..."라는 표어는 UML에서 그대로 통한다.

다이어그램을 그려야 하는 경우 어떤 지침을 따르는 것이 좋을까? 모든 개발자들이 설계에서 특정한 부분의 구조를 이해해야 할 경우 다이어그램을 그리는 것이 좋다. 그림이 완벽할 필요는 없다. 모든 개발자들이 이해했다고 생각되면 그만 그리면 된다.

개발자들 간에 구조에 대한 분쟁이 일어날 경우 그림을 그리고 그림을 판독할 수 있는 중재자를 구할 때. UML 다이어그램은 아주 명확한 의미를 전달 할 수 있기 때문에 같은 생각이지만 다른 말을 통일시켜주는 역할을 할 수 있다. 새로운 아이디어를 떠올리고 그 아이디어를 주위 개발자 또는 상급자에게 칭찬받고 싶을 때 UML 다이어그램을 작성한다. 말로 떠드는 것보다 한번 보여주는 것이 200%의 효과를 발휘한다.

“백문이 불여일견”일 필요가 있을 때 UML 다이어그램을 작성한다. 그리고 마지막으로 클라이언트에게 ‘있어 보이는’ 문서를 보여줘야 할 필요가 있을 때 작성한다. 부차적인 설명이 없이도 다들 이해하리라 믿는다.@

* 이 기사는 ZDNet Korea의 제휴매체인마이크로소프트웨어에 게재된 내용입니다.

 

김상훈 (동명정보대학 정보기술원 연구원)

2005/03/22

 

사용자 삽입 이미지

 

원문 :http://www.zdnet.co.kr/techupdate/lecture/etc/0,39024989,39134386,00.htm

신고
0  Comments,   0  Trackbacks
댓글 쓰기
[UML 제대로 알기] ① 가능성·확장성 품고 등장한 UML 2.0

[UML 제대로 알기] ① 가능성·확장성 품고 등장한 UML 2.0

 

연재순서
1회.가능성·확장성 품고 등장한 UML 2.0
2회.초보자를 위해 다각도로 살펴본 UML
3회.바로 알고 제대로 쓰는 UML 실전 모델링
4회.닷넷 환경에서 UML 툴 활용 가이드
5회.표준을 넘나드는 UML의 적절한 사용

 

UML을 중심으로 소프트웨어 업계에서 벌어지는 경제적, 사회적 현상들을 알아보고 UML 2.0 발표 이후 소프트웨어 업계에 불어 닥칠파장에 대해 알아본다. 또한 UML 2.0에서 개발자들이 주목해야 하는 세부 내용도 간단히 검토해 보자.

UML 2.0의 실로 엄청난 중요성을 미리 알고 대비할 것인지, 뒷짐 지고 좀 더 지켜볼지는 이번 글을 보고 판단해 주기를 바란다.

필자는 지난 2004년 마이크로소프트웨어 8월호에 MDA 관련 글을 기고하던 당시부터 지금까지 필자의 소속 회사가 지난 10여 년간 전문적으로 개발해 오던 인적 자원 관리(HRM) 시스템에 대한 획기적인(?) 개선 방안으로 MDA 기반의 시스템 개발을 추진하고 있다. 필자가 본격적으로 UML 2.0을 검토하기 시작한 것도 8월을 전후해서였다.

그러나 회사에서 표준으로 사용하는 모델링 도구 제작 업체에서는 4개월 전만 해도 UML 2.0을 지원하지 않았고, MDA 패러다임을 표방하면서도 아쉽게도 그 요체인 UML 2.0은 그저 각종 문서나 자료들을 통해서만 접할 수 있었다. 인사 비즈니스 프로세스 개선 작업(BPI)과 같은 초기 설계 작업은 UML 1.4 기반으로 추진해야 했고, 올 연말로 예정됐던 도구 공급사의 차기 버전을 기대해야 하는 상황이었다.

그러던 얼마 전, 필자는 해당 업체로부터 UML 2.0을 충실히 지원하게 된 새 버전의 케이스 도구를 입수했다. 비록 필자가 이미 여러 책이나 자료들을 통해 UML 2.0을 검토했었음에도, 막상 본격적으로 UML 2.0 지원 모델링 도구를 설치하고 작업을 착수하려던 그 순간의 첫 느낌을 말로 하자면 막막함 그 자체였다.

그 모델링 도구의 새로운 버전이 완전히 개편된 새로운 사용자 인터페이스로 구성됐으며 내부적으로도 상당한 기술적인 패러다임 전환이 있었던 것도 한 원인이었겠지만, 무엇보다도 근본적으로 UML 2.0이 내포한 그 가능성과 확장성에 대한 놀라움과 설렘이 교차하면서 만들어낸 미묘한 흥분과 두려움이었다는 것이 적절한 것 같다. 1620년 메이플라워호를 타고 미지의 땅 아메리카에 첫 발을 내디뎠던 이주민들의 마음이 이렇지 않았을까?

UML의 사회적 파장
UML 2.0 발표와 더불어 개발자들이 주목해야 하는 세부 내용을 살펴보기 전에 우선, UML을 중심으로 소프트웨어 업계에서 벌어지는 경제적, 사회적 현상들을 통해 향후 UML 2.0 발표 이후 소프트웨어 업계에 불어 닥칠 파장에 대해 미리 가늠해 보는 시간을 가져 보기로 하겠다.

IT 시장 변화에 주목하자
이 시대 소프트웨어 산업에 종사하는 사람이, 딴 세상에 사는 사람(beings in heaven)이 아닌 이상, 자본주의 시대를 살아가는 현대인으로서 공급과 수요를 결정하는 시장 논리로부터 자유로울 수는 없다.

우리는 종종 뛰어난 기술력을 갖추고 있음에도 망하는 반면, 특별한 기술력을 가지고 있지 않음에도 번창하는 사람이나 기업을 종종 목격하곤 한다. 즉, 기술력이 곧 성공을 의미하지는 않는다. 마찬가지 논리로, UML 2.0이 아니라 그 어떤 뛰어난 기술이 존재한다 하더라도 IT 시장에서 그 기술력을 필요로 하지 않거나 수용할 수 없다면, 그 기술력의 시장 가치는 무의미할 수밖에 없다.

2000년을 전후해서 전세계적으로 Y2K 문제가 사회적 문제로 부각되고 시스템의 대공황 사태가 예고되던 시절, 아이러니컬하게도 당시 소프트웨어 산업에서는 사양길로 접어들었던 프로그래밍 언어의 전문가들이 국내의 IMF 사태와 맞물려 고액 연봉으로 대접 받으면서 해외로 진출했던 일이 기억난다. 역시 기술의 가치(technology value)는 시장 원리(market behavior)에 의해 결정될 수밖에 없음을 인정하지 않을 수 없다.

그런 관점에서 UML 2.0이 공식적으로 공표되는 전후의 소프트웨어 산업계 판도를 살펴보는 것은 의의가 있다. 세계적으로 이미 프로그램 개발 도구 시장은 그 성장세가 둔화됐고, 모델링 도구는 빠른 속도로 보편화되어 가고 있다. 지난 몇 년간 일어났던 IT 업계의 큰 사건들을 살펴보면 그러한 사실을 쉽게 확인할 수 있다.

이를테면 예전에는 비싸게 판매하던 개발 도구를 점차 저렴하게 행사 가격으로 판매한다거나, 개발자 저변 확산이라는 명목 하에 학교나 학원을 중심으로 무료로 배포하고 있다. 심지어는 이클립스 등과 같은 막강한 개발 도구를 오픈소스로서 인터넷을 통해 무료로 배포하고 있다.

몇 년 전 세계적인 소프트웨어 업체인 MS에서는 비지오(Visio)라는 2D 전용 도구 개발 업체를 인수했고, IBM은 세계적인 모델링 도구 전문 개발 업체인 래쇼날을 인수합병했으며, 연이어 볼랜드에서는 투게더를 사들였다. 한편, 국내외 UML 관련 포럼이나 협회들에서는 앞다퉈 UML 관련 인증 제도를 만들어 발표하면서 그 인지도를 넓혀 가기 위한 대대적인 작업을 벌이고 있다.

UML 인증 제도의 필요성이라든지, 인증 제도 자체의 신빙성이나 효용성에 대해 논하기 이전에, 어떠한 사상이나 개념이 제도화 되는 과정을 거치고 있다는 사실은 그 사상이나 개념이 해당 분야에서 도입기(intro)와 성장기(growth)를 거쳐 성숙기(mature)에 진입하고 있음을 암시하는 것이다.

표준화의 숨은 뜻
UML을 논하면서 표준화(standardization)라는 키워드를 빼놓을 수 없다. UML이 발표되기 전에 국방이나
MIS분야 엔지니어들에게 친숙한 IDEF라든지 DFD, ER 혹은 Petri nets 등과 같은 정형 기법(formal method)으로 통칭되는 수많은 표기법(notation)과 지원 케이스 도구들이 존재했음에도 불구하고(참고자료:[1]번혹은[2]번등), UML은 가장 단기간 동안 소프트웨어 공학 분야에서만큼은 빠른 속도로 사실상의 표준(de-facto)의 위치를 확보했다. 언뜻 생각해 보면 UML이 여타 표기법들을 교통정리해 준 안도감(?)이 들 수도 있겠지만, 겉으로 잘 드러나지 않는 그 내막에는 무서운 음모(?)가 도사리고 있다.

표준화 작업에 주도적인 역할을 수행하는 업체들이 왜 그토록 천문학적인 자본을 투자하면서 공개적인 표준화 작업에 동참하는 것일까? 여러 가지 복합적인 이유들이 있을 수 있겠지만, 결론적으로 표준화 경쟁이다.

유명한 예로, 1970년대부터 시작됐던 빅터(Victor)의 VHS 방식과 소니의 베타 방식으로 대표되는 비디오 표준 전쟁을 들 수 있고, 최근에는 유럽과 미국을 중심으로 벌어지고 있는 위성방송 표준화 전쟁을 들 수 있다. 표준화 전쟁에서의 승패는 곧 기업의 운명을 좌우하는 것이다.

표준화의 이면에는 높은 진입 장벽을 통해 허가 받지 않은 침입자(intruder)를 봉쇄하려는 무서운 저의가 자리 잡고 있다. 시야를 좀 더 넓혀 보면, 의사나 판사, 회계사 등. 통속적인 표현으로 소위 ‘사’자로 끝나는 직업들에 대한 사회적 가치관을 살펴보면 쉽게 이해할 수 있다.

사람 몸을 열어서 칼질하고, 같은 인간으로서 다른 인간을 판단하고, 숫자 가지고 씨름하는 직업이 산업혁명 이전에는 별볼일 없는 직업이었다. 인류의 보편적인 가치관으로 판단하더라도 결코 즐거운 일이 될 수 없음에도 불구하고 전세계적으로 공히 가장 선호하는 직업이자 사회적으로도 가장 대접받는 직업이 된 현실에 미루어 짐작해 보면, 왜 그토록 세계적인 소프트웨어 업체들이 표준화를 통해 높은 진입 장벽을 구축하고 제도화에 전념하는지 그 이유를 충분히 이해할 수 있다.

어려운 시험을 통과하지 않고 누구라도 일정한 요건만 갖추면 수행할 수 있는 일반적인 직종 중의 하나라면 그렇게들 동경하는 직종이 됐겠는가? UML 2.0이 경제적으로나 사회적으로 주목 받는 이유 중의 하나는 바로 그러한 맥락에서 비전문인과 전문가를 구별하는 높은 장벽(?)을 쌓을 수 있는 재료(material)를 확보하고 토대를 마련했다는 점에서 의의가 있는 것이다.

주목해야 할 UML 2.0의 핵심 메커니즘
1997년 11월 UML 1.1로 시작된
OMG의 표준화 노력은 2001년 5월 UML 1.4 발표와 더불어 부분적인 개정 작업(minor version upgrade)의 막을 내리고, 대대적인 수술 작업을 거쳐 2004년 연말을 전후로 드디어 그 실체를 드러내었다.

그 동안 쟁쟁한 세계적인 소프트웨어 벤더들간의 보이지 않는 이해 관계(?)에 얽혀 2002년 말로 예정됐던 최종 발표 시한을 2년여를 연장하면서 이제서야 그 대단원의 막이 마무리되고 있다. 향후 UML 2.0의 일정은 명실상부한 국제 표준(de jure)으로 자리매김하기 위해 ISO 설계 표준으로 추진 중인 것으로 알려져 있다.

UML 2.0이 주목 받는 가장 중요한 이유는 무엇일까? 처음 세상에 나오고 나서는 여기저기서 수많은 비판을 받았지만, 그것은 UML이 어떠한 플랫폼이나 도메인에도 의존하지 않고 소프트웨어 개발의 전 공정(SDLC)을 지원하는 방향으로 지향해왔다는 데에 그 원인을 찾을 수 있다. 즉, 요구사항 획득으로부터 마지막 테스트까지 모두 지원하는 표기법으로서 진화해 왔다는 것이다.

그리고 점진적으로 UML 2.0부터는 실행 모델(executable UML)이라는 기법을 수용함으로써, 소프트웨어 공학에서 궁극적으로 염원하던 분석 설계(analysis & design)와 실제 구현(implementation) 간의 차이(chasm)를 극복하는 성과를 보였기 때문이다.

OMG의 UML 2.0에 대한 제안요청서(RFP)의 주제이자 현재 채택된 명세서 초안은 크게 4가지의 영역으로 분류된다. CASE 도구 벤더들간의 모델 호환성 문제를 다루고 있는 다이어그램 호환(Diagram Interchange) 영역과 모델 수준에서의 요소(elements) 제어 및 제약 문제를 다루고 있는 OCL(Object Constraint Language) 영역, UML뿐만 아니라 OMG가 주관하는 각종 표준의 통합과 정의에 활용되는 메타 모델 수준의 기본 구조체(constructs)를 명시하고 있는 하부구조(Infrastructure), 그리고 메타 모델을 기반으로 사용자 수준에서 모델을 활용하여 시스템의 구조(structure)와 행위(behavior)를 정의하고 있는 14개의 다이어그램을 정의하고 있는 상부구조(Superstructure)로 분류할 수 있다.

UML 2.0의 본질을 제대로 이해하려면 핵심인 하부구조로부터 차근차근 살펴보는 것이 순서이겠지만, 지면과 주제를 고려할 때, 일반인들이나 설계자들이 UML 2.0을 처음 대면하는 경우 가장 먼저 관심을 가지게 되는 UML 구조체(user-level constructs)인 상부구조로부터 이야기를 풀어가는 방식을 택하기로 하겠다.

사용자 삽입 이미지
<그림 1> UML 2.0 표준 다이어그램

*빨간 밑줄: 새롭게 추가된 다이어그램, 녹색 밑줄: 명칭이 변경된 다이어그램

상부 구조는 크게 6개의 다이어그램으로 구성된 구조형 다이어그램(Structural Diagram)군과 7~8개의 다이어그램으로 구성된 행위형 다이어그램(Behavioral Diagram) 군으로 분류할 수 있는데, 각 군의 대표적인 복합 구조 다이어그램(Composite Structure Diagram)과 순차도(Sequence Diagram)를 중심으로 그 특징과 의의를 살펴보도록 하겠다.

이어서 UML 2.0의 기반을 설명하고 있는 하부구조의 의미는 무엇인지, 그리고 실제 설계 작업에서 하부구조의 접근법은 어떠한 방식으로 활용하게 될 것인지 논의하기로 하겠다.

상부구조 - 구조형 다이어그램
일명 아키텍처 다이어그램(architectural diagram)이라고도 불리는 복합 구조 다이어그램(composite structure diagram)은 UML의 핵심 다이어그램인 클래스 다이어그램의 변형된 형태이다. 이는 시스템 구조 설계에 있어 또 다른 핵심 축으로 평가 받고 있으며 가장 주목 받는 다이어그램 중의 하나이다.

복합 구조 다이어그램은 기본적으로 시스템 혹은 컴포넌트의 내부 구조(internal structure)를 명시적으로 중첩시켜 표현하고 있으며, 시스템 아키텍처의 보다 섬세한 분석과 설계 사상을 담을 수 있게 된 점이 가장 큰 매력으로 꼽을 수 있다.

그렇다면 왜 복합 구조 다이어그램이 주목받는지, 그리고 복합 구조 다이어그램은 왜 탄생하게 되었으며, 향후 어떠한 용도로 활용하게 될까? 보는 시각에 따라 의견을 달리 할 수 있겠지만, UML 1.x은 근본적으로 OOAD 수준의 설계 사상을 표현하기에 최적화된 표기법으로 평가되어 왔다.

UML 1.x에도 비록 컴포넌트 다이어그램이라는 것이 있기는 했지만, 실제 너무 빈약한 문맥(semantics)으로 인해 별로 활용되지 못했으며, 강경한 컴포넌트 신봉자들이나 대용량 시스템 혹은 전체 시스템을 통합적으로 표현하기 원했던 아키텍처 전문가 진영 개발자들에게는, 그저 객체 옹호론자들이 제시하는 옹색한 명분(?)에 지나지 않았다. 사실 UML 1.x 자체에도 명시하고 있듯이, 컴포넌트 다이어그램은 몇몇 다이어그램들과 더불어 클래스 다이어그램에 일종의 간단한 확장 메커니즘을 통한 단순한 관점(view) 변경 수준에 지나지 않았다.

비즈니스 컴포넌트에 관심이 많았던 컴포넌트 신봉자들의 경우, UML 1.x의 스테레오타입(stereotype)등의 확장 메커니즘을 통해 그럭저럭 UML 1.x과의 관계를 유지하면서도 BPM이라는 포괄적이고 확장된 별도의 비즈니스 컴포넌트 표기법을 병행하며 UML 1.x의 미비한 부분을 채워 나갔다.

아키텍처 전문가 진영에서는 상황이 조금 달랐는데, 대다수의 아키텍처 전문가 진영에서 관심을 가지고 있던 임베디드 혹은 리얼타임 도메인에서는 단순히 UML 1.x 정도의 확장 메커니즘으로는 그들이 필요로 하는 아키텍처를 통한 시뮬레이션 등과 같은 시스템의 섬세한 분석 및 설계라는 목적 달성이 거의 불가능했고, 그러한 목적 달성을 위해 UML의 확장 메커니즘을 활용한다는 것은 차라리 자신들만의 특정 영역에 필요한 표기법을 자체 정의하여 사용하는 것이 훨씬 경제적이었다는 것이다.

왜냐하면 이미 아키텍처 전문가 진영에서는 UML 1.x가 발표되기 이전에 광범위하게 수많은 ADL(Architectural Description Language)과 관련 시뮬레이션 도구들이 개발되어 활용되고 있었으며, 굳이 UML에 순응하는(compliant) 방안을 모색하기 위해 UML을 연구하고 고민할 시간적 여유나 명분이 없었던 것이다.

그러나 그러한 두 진영에서 근본적으로 해결하지 못한 결정적인 문제는 자신들이 독자적으로 발전시켰던 표기법 중에 어떠한 것도 명실상부한 사실 표준(de-facto)으로 합의하지 못했다는 것이다. 가령, 아키텍처 전문가 진영에서 필요로 하는 시스템 시뮬레이션 기능을 구현하는 데 사용하는 정형 기법의 경우 동일한 도메인에서조차 연구소나 익숙한 기법에 따라 서로 달리 정의하고 필요한 시뮬레이션 도구를 개발해야 했다.

국제적인 공동 작업은 말할 것도 없이 국내에서 서로 다른 연구기관이 공동 작업을 수행하기 위해서도 사전에 일정한 표준 정형 기법을 합의하고 정립한 후 과제를 수행해야 했으며, 최종적으로 통합하는 과정에서는 결국에 모델 수준에서의 통합을 포기하고 구현 수준에서 테스트를 통해 통합하는 방식을 따라야 하는 문제점을 내포하고 있었다.

덧붙여 두 진영에서 해결하지 못한 결정적인 문제 중의 하나는 실제 구현(code)에 필요한 낮은 추상화 수준의 설계에 대해서만큼은 어설픈 UML 1.x의 메커니즘만한 수준의 방안을 제시하지 못했다는 것이다.

UML 2.0에서 새롭게 등장한 복합 구조 다이어그램은 바로 지금까지 앞서 살펴 본 아키텍처 전문가 진영으로 대표되는 임베디드 혹은 리얼타임 도메인의 핵심 개념이자 도구였던 SDL(Specification Description Language)을 수용하여 탄생한 다이어그램이다.

사용자 삽입 이미지
<그림 2> UML 2.0 복합 구조 다이어그램 예


UML을 잠시라도 살펴 본 경험이 있는 개발자들이라면, 복합 구조 다이어그램의 개략적인 형태만을 보고서도 쉽게 그 특징을 이해할 수 있을 것이다. 즉, 복합 구조 다이어그램은 매우 직관적인 형태를 취하고 있으며, 기존의 UML 1.x에서 단순한 패키지 개념의 서브시스템 내부를 구성하고 있는 클래스 다이어그램으로만 표현이 가능하던 시스템 내부 구조를 보다 섬세하게 설계할 수 있게 됐다.

그렇다고 <그림 2>와 같이 대부분의 UML 2.0을 기반으로 한 샘플들처럼 임베디드나 리얼타임 도메인과 같이 상대적으로 소프트웨어의 비중이 작은 단위 시스템이나, 특정 MIS 분야의 단위 서브시스템의 내부 설계에만 국한되어 복합 구조 다이어그램을 활용하겠다고 생각한다면, UML 2.0의 본질을 제대로 이해하지 못하고 있는 것이다.

복합 구조 다이어그램의 형태는 앞서 언급한 아키텍처 전문가 진영에서 아키텍처를 표기하는데 가장 많이 활용하는 아키텍처 스타일인 C&C(Component & Connector) 뷰 타입(view type)과도 일맥상통하는데, 복합 구조 다이어그램을 활용하고자 하는 모델의 추상 수준을 높이면 대규모 시스템의 아키텍처도 매우 유용하게 설계할 수 있게 된다.

<그림 2>에서 벤딩머신(VendingMachine)으로 되어 있는 부분을 인사시스템이라 정의하고 내부 부분(parts)들을 그것을 구성하고 있는 단위 시스템으로 정의하게 되면, 외부 인터페이스를 통해 회계시스템(AS)이나 고객관리시스템(CRM) 등과 주고받아야 할 데이터나 정보를 명시적으로 설계에 반영할 수 있을 것이다.

바로 설계자가 의도하는 어떠한 추상화 수준의 모델이라도 UML 2.0의 복합 구조 다이어그램은 보다 섬세하게 설계할 수 있도록 일관된 문맥(context)과 의미(semantics)를 제공하고 있는 것이다.

상부구조 - 행위형 다이어그램
UML 2.0 상부구조 중 구조형 다이어그램은 말 그대로 구조적인 혁명을 꾀했다면, 행위형 다이어그램 군에서는 시스템의 동적 설계를 제대로 반영하기 위해 기존의 행위형 다이어그램 군 소속 다이어그램의 의미(semantics)를 보강하고 정제함으로써, 진화 방식을 선택했다는 표현이 적절할 것 같다.

그 근거로서 앞서 복합 구조 다이어그램으로 대표되는 구조형 다이어그램에서 수용한 SDL의 경우와는 다르게 UML 1.x에서 이미 수용하던 MSC(Message Sequence Chart) 개념을 UML 2.0에 와서는 전폭적으로 수용하여 순차도(Sequence Diagram)를 중심으로 행위형 다이어그램들의 유기적 결합 통로를 확보함으로써 시스템의 모델 수준에서의 논리적인 실행을 그대로 설계에 반영할 수 있는 발판을 마련했다.

사용자 삽입 이미지
<그림 3> UML 2.0 순차도의 예


<그림 3>에서 보는 바와 같이 UML 2.0 순차도의 가장 두드러진 특징은, 기존의 UML 1.x에서 지원하지 못했던 시스템의 분기, 참조, 병렬 실행 등과 같은 세세한 부분들까지도 지원이 가능하도록 중첩된(nested) 표기법 체계를 설계 기법으로 도입했다는 사실이다.

MSC와 같은 기법에 익숙한 개발자들에게는 언뜻 보기에 별로 특이할 것이 없어 보일지 모르지만, 중요한 사실은 UML 2.0을 표준 표기법으로 수용함으로써 어떠한 비즈니스 도메인이나 기술 영역에서도 <그림 3>의 순차도 뿐만 아니라 UML 2.0의 다른 다이어그램들과 유기적인 연결고리를 가지고 활용함으로써 거의 무한대에 가까운 표현 수단을 확보할 수 있다는 사실이다.

UML 2.0 상부구조 중 행위형 다이어그램의 갱신에 대해 많은 관심을 가지는 사람은 임베디드 혹은 리얼타임 진영에 종사하고 있는 개발자들이겠지만, 기존의 비즈니스 프로세스 모델링 분야에서 종사하던 개발자 진영도 깊은 관심과 기대를 가지고 있다.

필자 또한 비즈니스 프로세스 모델링과 관련하여 행위 형 다이어그램의 특성과 최적 방안을 모색하고 있는데, 동일 비즈니스 도메인에서조차 개별 기업마다 그 특성과 비즈니스 프로세스 처리 방식이 천차만별인 문제를 해결하고자 등장했던 워크플로우 엔진 혹은 설계 시스템(workflow engine or system)과 같은 전문적인 도구의 기능을 충분히 대치할 방안이 마련된 것으로 평가되고 있다.

하부구조 - 메타 모델
소프트웨어 공학 분야에서는 이런 속설이 있다. 자신의 분야에서 메타 모델 기반의 접근을 하게 되면 하나의 논문이 된다. 매일 고객들과 씨름하면서 현장에서 일하는 개발자들에게는 먼 나라 이야기처럼 들리고, 현실적으로는 일정 규모의 연구소 혹은 학교에서나 다루어질 만한 주제로 치부됐던 것이 사실이다.

UML 2.0 하부구조(Infrastructure)는 일반적으로 UML 2.0을 지칭할 때 생각하는 UML 2.0 상부구조뿐만 아니라 OMG의 또 다른 메타 모델 집합인 MOF, CWM 뿐만 아니라 미래의 새로운 표준을 정의하기 위해 심혈을 기울여 정의한 메타 모델이다.

OMG에서 처음 메타 모델 4계층 개념을 발표했을 때에는 그저 개념적인 내용으로만 인식하지 못했지만, UML 2.0의 실체가 드러나고 그것을 지원하는 케이스 도구들의 기능들이 메타 모델 기반 설계 방식을 지원함으로써, 이제는 메타 모델이라는 주제가 현장에서조차 피해갈 수 없는 현실 문제로 다가올 것이다. 그러므로 이제는 메타 모델 4계층 개념을 충분히 이해하고 응용하는 노력을 기울일 필요가 있다.

사용자 삽입 이미지
<그림 4> OMG 4계층 메타 모델 예


글의 주제와 지면 관계상 메타 모델에 대한 깊이 있는 논의를 하지는 못하지만, <그림 4>의 예로 간단히 살펴보자. 시스템 분석가나 설계자들이 일반적인 모델링 케이스 도구를 통해 특정 도메인 시스템을 설계한다고 했을 때의 메타 모델 수준(level)이 바로 사용자 모델을 도식하게 되는 M1 수준이다.

M2 수준은 그러한 UML 기반의 설계를 가능케 하는 어트리뷰트, 클래스, 인스턴스 등과 같은 모델 요소를 정의하는 메타 모델이며, UML 2.0의 하부구조는 바로 위 4계층 메타 모델 관점에서 M2 수준의 UML 메타 모델이 된다. M3 수준에 위치한 MOF(Meta Object Facility)는 M2 수준에 속한 메타 모델을 정의하는 메타메타 모델이 된다.

참고로 CWM(Common Warehouse Metamodel)은 M2 레벨이며, MOF의 내부 구조는 추상화된 UML 하부구조와 동일한 방식으로 정의하고 있다. 자세한 사항은 OMG UML 2.0 Infrastructure, 7. Language Architecture를 참조한다.

앞에서 살펴 본 바와 같이 OMG에서 UML 2.0 관련 제안요청서(RFP)를 제기한 목적은 단순히 UML 2.0을 체계적으로 정리하고자 한 것이 아니라, OMG의 또 다른 표준인 MOF와 CWM 및 미래의 새로운 표준을 체계적으로 정의하기 위한 용도로 제기됐던 것이다. 여기서 우리가 주목해야 할 사항은 UML 2.0 하부구조에 대한 제안요청서를 통해 제기한 또 다른 목적이다.

그것은 바로 지금까지 M1 수준에서 UML을 활용하던 사용자들이 보다 수월하게 M2 수준에서 UML을 커스터마이징하여 활용할 수 있는 메커니즘을 제공하는, 즉 이원화된 메커니즘을 제공하여 사용자들이 유연하게 특정 기술 도메인이나 비즈니스 도메인에 최적화된 방식으로 설계를 수행할 수 있도록 하자는 데 그 취지가 있었다.

그 핵심이 바로 UML 프로파일(UML Profiles)이다. 지금 UML 2.0 작업과 동시에 진행되고 있는 대표적인 기술 도메인 프로파일로는 우리들에게 친숙한 EJB 프로파일(Profile for EJB), 닷넷 프로파일(Profile for .Net)을 들 수 있다. 프로파일을 간단히 설명하면, 일종의 특정 기술이나 비즈니스에 적절한 커스터마이징된 확장 메커니즘을 사전 정의해 놓고, 추상화 수준이 서로 다른 모델들간의 전환(transformation)을 자동화시키는 핵심 메커니즘이다.

플랫폼 독립 모델(PIM: Platform Independent Model)로부터 특정 플랫폼 종속 모델(PSM: Platform Specific Model)로의 자동화된 전환이라는 MDA의 사상이 바로 대표적인 일례라고 볼 수 있다. UML 프로파일은 향후 MDA를 통해서 달성하려고 하는, 아니 궁극적으로 UML 2.0을 통해 달성하게 될 소프트웨어 공학의 핵심 화두인 소프트웨어 개발 생산성 향상의 핵심 메커니즘으로 평가 받고 있다.

만약 이 글을 읽는 개발자가 속한 관련 분야에 MIS 분산 시스템 개발의 사실 표준으로 통용되는 J2EE나 닷넷 등과 같은 개발 기술 표준 프레임워크가 존재한다면 다행스러운 일이다. 모델링 도구 벤더에서 제공하는 EJB 프로파일이나 닷넷 프로파일과 같은 기술 메타 모델은 그대로 활용하고, 관심 비즈니스 영역에 해당하는 표준 도메인 프로파일을 활용하거나, 독자적으로 정의해 설계 작업을 추진해 나갈 수 있기 때문이다.

하지만 최악의 경우 관련 분야에 기술이나 도메인 프로파일이 존재하지 않고, 더욱이 활용할 만한 케이스 도구조차 존재하지 않는다면 난감하다. 하지만 UML 2.0을 충분히 지원하는 범용 혹은 상용 케이스 도구를 통해 구현된 방식이나 기능을 살펴보면 놀랄 만큼 간결하다. 문제는 UML 2.0의 프로파일 방식과 같은 메커니즘을 이해하는 것이 아니라, 그 동안 개발자들이 간과해 왔던 문제, 가령 “해당 비즈니스 도메인을 제대로 이해하고 있었는가?” 등과 같은 근본적인 문제를 되돌아보는 계기가 될 것으로 생각된다.

어떻게 대처할 것인가
지금까지 UML 2.0 출시를 전후해서 전개되어 왔던 소프트웨어 산업계의 전반적인 흐름과 사회적 파장, 그리고 UML 2.0의 상부 및 하부구조의 핵심 메커니즘을 중심으로 간단히 살펴보았다. 그렇다면 과연 어디서부터 어떻게 UML 2.0을 시작할 것인가?

기본 원칙에 충실하자
우선 스스로에게 UML 1.4는 제대로 이해하고 활용해 왔는가라는 질문을 던져 보아야 한다. 필자의 경우 하는 일이 하는 일인만큼 UML 2.0이 발표되기 이전에도 자바나 비주얼 베이직 등과 같은 프로그래밍 용어나 주제에 비해 상대적으로 UML(1.x), OOAD, CBD, 방법론 등이라는 용어가 훨씬 낯설지 않았다.

당연히 주변에는 상대적으로 코딩보다는 현장에서 분석(analysis)이나 설계(design)를 전문으로 하거나, 학교나 학원 등에서 학생들을 가르치는 사람들이 많았지만 그 중에 UML 1.x 관련된 OMG 무료 명세를 제대로 살펴보았거나, 가까이 두면서 참조하는 사람은 찾아보기 어려웠다.

필자 가까이에 ‘UML 1.4 사용자 지침서’를 한글로 번역했던 분을 통해 확인해 보아도, 국내 출판사에서 출간한 책 부수로 미루어 UML 원문은 차치하고서라도 핵심 내용만을 추려서 발간한 그 UML 사용자 지침서마저 꼼꼼히 살펴 본 사람은 별로 보지 못한 것 같다. 필자도 예외는 아닌데, 돈이 없어서 혹은 원서이기 때문에라는 것은 이유가 되지 않았던 것이다.

그런데 UML 2.0이 공식 발표되는 이 시점에도 상황은 예전이나 별반 다르지 않은 것 같다. UML 2.0으로 공식 공표되기 전에 이미 오래 전부터 OMG에는 UML 관련 명세를 1.5의 형태로 인터넷에 배포하고 있었지만, 살펴본 사람은 찾기 어려웠다. UML 1.1이 처음 발표되던 시점에는 표기법으로서의 표준화 경쟁에서 판정승이 나지 않았던 때여서 그랬다고 하더라도, UML 2.0이 공표되는 이 시점에는 이미 국내외 많은 대학의 컴퓨터 관련학과에서 필수 과목으로 개설되었을 만큼 그 중요도와 필요성이 검증된 마당에 애써 그 사실을 외면하는 것은 더 이상 이유가 될 수 없다.

물론 지금까지의 현실은 그렇지 못했던 것이 사실이다. UML 전문가들마저도 UML 1.x의 설계 도구로서의 완성도가 받쳐주지 못했고, 무엇보다도 고객들도 유기적으로 논리적인 설계 모델을 기대하지 않았기 때문에 UML이라는 포장지를 가지고 피상적이고 개념적으로 대충 구색 맞추기식 설계 산출물을 만들어 주면 그만이었다.

그러나 앞으로의 상황은 그렇지 못할 것이다. 당장은 아니겠지만 UML 2.0 표기법이 소프트웨어 산업 시장에서 보편적으로 활용되고 국내외에서 하나 둘 그 무한한 잠재력과 가능성이 증명되어 그 시장 가치가 확연히 드러나기 시작하는 시점에는 우리 주변의 고객들 또한 단순히 보기 좋은 산출물 정도의 설계를 요구하지는 않을 것이다.

그렇다면 어디서부터 어떻게 준비해야 할 것인가? 그 실마리는 처음 접하면 이해하기 어렵고 복잡한 UML 2.0 관련 명세나 두꺼운 책에서 찾을 것이 아니고, 누구나 알고 있으면서도 충실하지 못했던 가장 기본적이고 원칙적인 원리를 고민하는 것부터 시작해야 한다.

원칙 하나, 도메인을 철저하게 분석하자
시스템을 설계한다고 했을 때, UML과 같은 설계 기법을 동원하여 작업하는 시스템 분석 및 설계자 그룹 외에 매우 중요한 역할을 수행하는 집단이나 개인을 가리켜 도메인 전문가 혹은 비즈니스 분석가라고 한다. 가장 이상적인 시스템 설계자는 두 가지 능력 즉, 해당 도메인에 대한 공인된 전문적인 지식을 가지고 있으면서 동시에 설계 능력을 고루 갖춘 인재일 것이다.

그러나 현장에서 그런 핵심 인재를 찾기는 어려운 것이 사실이다. IT 업계로만 보더라도 시스템 설계자와 개발자 간에 차이가 좀처럼 좁혀지지 않는데, 전혀 그 분야와 전공이 다른 비즈니스 전문가와 시스템 전문가 간에 느끼는 갈등은 말할 필요도 없다. 시스템을 설계해 본 사람은 누구라도 공감하겠지만, 시스템을 제대로 설계하려면 해당 도메인을 충분히 이해하고 철저하게 분석해야 한다. 그렇지 않으면 제대로 된 시스템을 설계할 수 없다.

시스템 설계자 입장에서 문제는 해당 도메인을 제대로 이해하기 위한 충분한 시간도 주어지지 않고, 나름대로 시스템 설계자가 충분히 이해한 것을 객관적으로 검증해 줄 만한 기준도 마련되어 있지 않다는 것이다. 설사 객관적 기준이 있더라도 그것은 현실적으로 거의 불가능하다는 것이다.

가령 회계 시스템을 설계하려면 회계사 자격증을 갖춰야 하는가? 물론 아니다. 그런데 우리는 주변에서 타의든 자의든 특정 도메인 시스템을 반복해서 설계하는 설계자의 경우 점점 해당 도메인에 대한 이해력이 높아지고, 회계사와 같은 공인된 자격증은 취득하지 못하더라도 나름대로 그 전문성을 인정받아 시장에서 높이 평가되는 경우를 보곤 한다.

비단 시스템 설계자에게만 해당되는 문제는 아니다. 조각조각 할당된 부분만 열심히 해야 하는 개발자에게도 비슷한 현상은 쉽게 찾아 볼 수 있다.

설계하고자 하는 해당 도메인에 대한 철저한 분석 없이는 일정한 추상화 수준을 유지한 유기적인 모델을 만들어 낼 수가 없다. 몇몇 책이나 발표 자료에서 설계 팁으로 이야기 하듯이 해당 도메인에서 반복적으로 등장하는 명사(nouns)를 클래스명으로 명명한다는 식으로 설계를 진행하다 보면 점점 헤어나지 못하는 미궁으로 빠져들게 된다. 결국에는 UML 2.0이라는 강력한 설계 도구를 가지고도 설계 따로, 코딩 따로라는 늪에서 벗어날 수 없다.

UML 표준화를 주도하는 OMG에 대해서 많은 사람들은 단순히 CORBA, ORB 등과 관련한 국제적인 기술 표준화 단체 정도로만 인식하고 있다. 하지만 앞서 주장한 도메인 지식 혹은 도메인 표준에 대한 중요성에 대해서는, 그러한 기술 표준화 단체로 출범한 OMG에서 2002부터 발족하여 추진하고 있는 DTF(Domain Task Forces) 위원회의 활동을 살펴보면 쉽게 이해할 수 있다.

이미 전략전술 통제(C4I), 재무(finance), 의료(healthcare), 제조(manufacturing), 우주항공(space), 통신(telecommunications), 운송(transportation) 등의 도메인을 필두로 그 표준화 작업을 진행 중에 있으며, 여러 표준화 단체들과 연합하여 다른 도메인으로까지 표준화 작업을 확장 중에 있다.

물론 아직까지 그 시도는 기술적인 관점에서의 접근이라는 한계를 크게 뛰어 넘고 있지는 못하지만 인터넷, 즉 IT 기술을 배제한 고전적 의미의 비즈니스는 점차 그 경쟁력을 잃어 가고 있는 현실을 생각할 때 OMG의 영향력은 쉽게 무시할 수 없는 것이 될 것이다.

원칙 둘, 모델의 추상 수준
사전적 의미로도 알 수 있듯이 모델은 본질적으로 어떤 특정 사물이나 현상에 비해 상대적으로 추상화되어 있는 무엇이기 때문에 똑같은 실체에 대한 서로 다른 모델은 서로 다른 추상화 수준(level of abstraction)을 가질 수밖에 없다.

사용자 삽입 이미지
<그림 5> 모델의 서로 다른 추상화 수준


<그림 5>를 보면 똑같은 자동차를 모델로 만든 것이지만, 상단의 자동차 그림(혹은 모델)은 추상화 수준이 높고 하단의 자동차는 추상화 수준이 낮다. 여기서 중요한 것은 추상화 수준의 높고 낮음은 상대적이라는 것이다. 우리가 UML에서 제시하는 여러 다이어그램을 가지고 모델을 제작한다는 것은 결국 목표하는 자동차나 건물 등과 마찬가지의 실체 즉, 특정 시스템 하나를 완성하기 위한 노력인 것이다.

즉, 설계 작업을 수행한다는 UML 1.4의 표기법을 동원하든 UML 2.0의 표기법을 동원하든 아니면 제3의 표기법을 활용하든 목표하는 시스템을 완성하기 위한 과정이지 다이어그램 혹은 표기법 자체가 목적이 되지는 않는다는 것이다. 이러한 똑같은 모델의 원리를 UML의 다이어그램을 가지고 설명할 수 있다. <그림 5>는 UML 1.4에서 제시하는 9개의 표준 다이어그램의 추상화 수준을 계량화하는 방안으로 방사형의 표로 도식해 본 것이다.

사용자 삽입 이미지
<그림 6> UML 1.4 다이어그램 추상화 분포


<그림 6>의 중앙에 위치한 지점을 설계자가 목적하는 목표 시스템의 코드 혹은 운영(run-time) 시스템이라고 한다면, 유스케이스 축에서 0.8으로 표시된 지점 정도의 추상화 수준으로 유스케이스를 작성한 것을 비즈니스 유스케이스라 할 수 있겠고, 0.4 정도의 지점 추상화 수준으로 작성한 것을 시스템 유스케이스라고 할 수 있을 것이다. 그렇게 가정해 본다면, 중앙에 가까운 지점의 추상화 수준으로 낮게 모델을 작성한다면 설계자가 목적하는 시스템은 보다 세세하게(detailed) 보이게 될 것이다.

유럽의 모든 길이 로마로 향하듯이, 어떠한 길(다이어그램)을 선택하더라도 종국에는 목적지(목표 시스템)에 도달할 수 있다. 하지만 각 다이어그램은 각자 목표하는 시스템으로 접근할 수 있는 추상화 수준의 한계를 가지고 있다.

가령, 유스케이스 다이어그램만을 가지고 시스템 설계를 완성할 수는 없는 것이다. 반면에, 클래스 다이어그램만 가지고 시스템 설계에 접근하다 보면 나무는 보고 숲을 보지 못하는 우를 범할 수 있다. 그러한 이유로 소프트웨어 설계에서 UML을 활용하여 목표 시스템을 설계할 때는 하나 이상의 다이어그램을 활용하게 된다.

대표적으로 많이 활용되는 다이어그램으로는 유스케이스, 클래스, 시퀀스 등을 들 수 있을 것이다. 문제는 여기서부터 시작 된다. 시스템 설계에 대표적인 3개의 다이어그램을 활용하든 아니면 9개의 다이어그램을 모두 활용하든 활용하는 다이어그램들이 각자 따로 존재하게 되는 것이다.

유스케이스 다이어그램 따로 클래스 다이어그램 따로 심지어는 동일한 시스템에 대한 유스케이스 다이어그램을 그리더라도 그리는 사람에 따라 서로 다른 추상화 수준(level of abstraction) 혹은 입도(granularity)의 유스케이스가 작성된다는 것이다. 이건 비즈니스 유스케이스니 이건 시스템 유스케이스니 하면서 무의미한 논쟁으로 치닫게 된다.

이러한 문제를 본질적으로 해결책하기 위해서는 그것이 UML 1.4이든 UML 2.0이든 각 다이어그램의 주된 용도(usage)와 목적(objectives), 그리고 그 한계를 충분히 이해하고, 각 다이어그램이 그러한 용도와 목적을 충족시키기 위해 제시하는 특성 표기법의 명확한 의미와 용도를 숙지해야 한다. 그 후에 활용하려는 다이어그램의 핵심 표기들 간의 추상화 수준에 대해 일관된 원칙(principle)을 우선 정립하고 설계 작업을 수행해야 한다.

가령 이러한 원칙 수립이 가능하다. 유스케이스 다이어그램을 통해 작성한 하나의 유스케이스를 하나의 활동도(Activity Diagram)로 도식하기로 했다면, 활동도의 활동(Activity)은 유스케이스 시나리오로 작성하는 사건 흐름(flow of event) 상의 단일 스텝(step)이라는 원칙을 설정하게 되면 일관된 설계 작업을 수행할 수 있다. 그러한 설계 전략을 위 <그림 6> 위에 상징적으로 표현해 보면, <그림 7>과 같이 도식할 수 있을 것이다.

사용자 삽입 이미지
<그림 7> 다이어그램 간의 추상화 수준 조정


지금까지 UML 1.4를 중심으로 모델의 추상 수준이라는 원리에 대해 살펴보았다. 그러한 모델의 추상 수준이라는 핵심 메커니즘은 본질적으로 UML 2.0이라고 해서 다르지 않다. 앞선 <그림 1>과 <그림 7>을 언뜻 비교해 보아도 UML 2.0에서는 표준 다이어그램의 개수로도 UML 1.4에 비해 수적으로 많이 늘어났으며(<그림 4>에서 빨간색으로 표시된 다이어그램), 이전부터 있었던 몇몇 다이어그램들은 명칭이 변경됐고(<그림 4>에서 초록색으로 표시된 다이어그램), 무엇보다도 전반적으로 모든 다이어그램들이 보다 섬세한 설계자의 의도를 반영할 수 있도록 세부적인 표기들이 많이 추가되고 세분화됐다. 즉, 사용할 수 있는 다이어그램 선택의 폭(width)이 넓어졌고, 설계자의 의도를 보다 정밀하게 반영할 수 있는 깊이(depth)도 깊어졌다.

원칙 셋, 모델 자체의 완성도를 높이자
앞서 소프트웨어 업계에서 최근 발생하고 있는 현상들을 통해 잠시 언급했지만, UML 관련 국내외 포럼이나 협회들을 중심으로 UML 자체 혹은 설계 능력 인증 제도가 점차 많아지고 있다. 필자가 인증 제도의 본질적인 목적이나 그 가치 자체를 부정하는 것은 아니지만, 올해 사회적으로 충격을 던져 주었던 대입 수능 시험에서의 대량 부정 사태라든지, 얼마 전부터 공공연하게 제기됐던 영어 관련 인증 제도 등에서 발생하고 있는 문제점 등에 비추어 UML 인증 제도에서도 충분히 발생할 수 있는 그 변별력 문제에 대해 우려를 감출 수 없다.

그러나 다행히도 UML 2.0이 가지고 있는 그 강력한 표현력(semantic expressiveness)과 섬세함(elements precision) 그리고 다이어그램들간의 유기적 연결성 지원(support for diagram interchange) 능력으로 인해 인증서를 가지고 있다고 들먹이지 않아도 모델 결과물 자체로 그 완성도를 검증(self verification)할 수 있다. 즉, 모델 결과물만으로도 충분히 설계자의모델링 역량을 충분히 증명할 수 있는기반을 제공하고 있는 것이다.

UML 2.0이 공식으로 발표되기 이전 특정 케이스 도구들을 중심으로 시도됐지만 UML 1.4의 제약으로 그 실효성(efficiency)을 의심받았던 코드 자동 생성(automatic code generation) 기능은 케이스 도구들이UML 2.0 엔진으로 교체함으로써 그 완성도를 높일 수 있게 됐다. 더 나아가 UML 2.0이 내포한 그 풍부한 표현력과 정교함은, 특정 플랫폼에 종속적인 코드를 생성해 내기 이전에 케이스 도구의 도움을