'사는 이야기 > 5dols story' 카테고리의 다른 글

겨울 아침엔 늘...  (0) 2009.04.06
아침이란..;  (0) 2009.02.17
군대가는 녀석  (0) 2009.02.17
우리 엄마  (0) 2009.02.17
인턴  (0) 2009.02.17
Posted by 서오석
,

'사는 이야기 > 5dols story' 카테고리의 다른 글

아침이란..;  (0) 2009.02.17
모닝콜  (0) 2009.02.17
우리 엄마  (0) 2009.02.17
인턴  (0) 2009.02.17
좋은 사람이란?  (0) 2009.02.17
Posted by 서오석
,

'사는 이야기 > 5dols story' 카테고리의 다른 글

모닝콜  (0) 2009.02.17
군대가는 녀석  (0) 2009.02.17
인턴  (0) 2009.02.17
좋은 사람이란?  (0) 2009.02.17
시험  (0) 2009.02.17
Posted by 서오석
,

'사는 이야기 > 5dols story' 카테고리의 다른 글

군대가는 녀석  (0) 2009.02.17
우리 엄마  (0) 2009.02.17
좋은 사람이란?  (0) 2009.02.17
시험  (0) 2009.02.17
핸드폰끄기  (0) 2009.02.17
Posted by 서오석
,

'사는 이야기 > 5dols story' 카테고리의 다른 글

우리 엄마  (0) 2009.02.17
인턴  (0) 2009.02.17
시험  (0) 2009.02.17
핸드폰끄기  (0) 2009.02.17
마술  (0) 2009.02.17
Posted by 서오석
,

'사는 이야기 > 5dols story' 카테고리의 다른 글

인턴  (0) 2009.02.17
좋은 사람이란?  (0) 2009.02.17
핸드폰끄기  (0) 2009.02.17
마술  (0) 2009.02.17
공대생과 영어  (0) 2009.02.17
Posted by 서오석
,

'사는 이야기 > 5dols story' 카테고리의 다른 글

좋은 사람이란?  (0) 2009.02.17
시험  (0) 2009.02.17
마술  (0) 2009.02.17
공대생과 영어  (0) 2009.02.17
괴물  (0) 2009.02.17
Posted by 서오석
,

'사는 이야기 > 5dols story' 카테고리의 다른 글

시험  (0) 2009.02.17
핸드폰끄기  (0) 2009.02.17
공대생과 영어  (0) 2009.02.17
괴물  (0) 2009.02.17
전화받기  (0) 2009.02.17
Posted by 서오석
,

'사는 이야기 > 5dols story' 카테고리의 다른 글

핸드폰끄기  (0) 2009.02.17
마술  (0) 2009.02.17
괴물  (0) 2009.02.17
전화받기  (0) 2009.02.17
  (0) 2009.02.17
Posted by 서오석
,

'사는 이야기 > 5dols story' 카테고리의 다른 글

마술  (0) 2009.02.17
공대생과 영어  (0) 2009.02.17
전화받기  (0) 2009.02.17
  (0) 2009.02.17
그날이 오면..!?  (0) 2009.02.17
Posted by 서오석
,

'사는 이야기 > 5dols story' 카테고리의 다른 글

공대생과 영어  (0) 2009.02.17
괴물  (0) 2009.02.17
  (0) 2009.02.17
그날이 오면..!?  (0) 2009.02.17
설날에 듣기 싫은 말  (0) 2009.02.17
Posted by 서오석
,

사는 이야기/5dols story 2009. 2. 17. 10:22

'사는 이야기 > 5dols story' 카테고리의 다른 글

괴물  (0) 2009.02.17
전화받기  (0) 2009.02.17
그날이 오면..!?  (0) 2009.02.17
설날에 듣기 싫은 말  (0) 2009.02.17
발렌타인데이는 먹는거다.  (0) 2009.02.17
Posted by 서오석
,

'사는 이야기 > 5dols story' 카테고리의 다른 글

전화받기  (0) 2009.02.17
  (0) 2009.02.17
설날에 듣기 싫은 말  (0) 2009.02.17
발렌타인데이는 먹는거다.  (0) 2009.02.17
인연의 끈  (0) 2009.02.17
Posted by 서오석
,

'사는 이야기 > 5dols story' 카테고리의 다른 글

  (0) 2009.02.17
그날이 오면..!?  (0) 2009.02.17
발렌타인데이는 먹는거다.  (0) 2009.02.17
인연의 끈  (0) 2009.02.17
철들기  (0) 2009.02.17
Posted by 서오석
,


음..

발렌타인데이가 뭐지?

먹는건가.. 우걱우걱

'사는 이야기 > 5dols story' 카테고리의 다른 글

그날이 오면..!?  (0) 2009.02.17
설날에 듣기 싫은 말  (0) 2009.02.17
인연의 끈  (0) 2009.02.17
철들기  (0) 2009.02.17
자취방  (0) 2009.02.17
Posted by 서오석
,

'사는 이야기 > 5dols story' 카테고리의 다른 글

설날에 듣기 싫은 말  (0) 2009.02.17
발렌타인데이는 먹는거다.  (0) 2009.02.17
철들기  (0) 2009.02.17
자취방  (0) 2009.02.17
양치질  (0) 2008.10.29
Posted by 서오석
,

뭐..

학비가 또 오르는군..

휴..

'사는 이야기 > 5dols story' 카테고리의 다른 글

발렌타인데이는 먹는거다.  (0) 2009.02.17
인연의 끈  (0) 2009.02.17
자취방  (0) 2009.02.17
양치질  (0) 2008.10.29
일촌명  (0) 2008.10.29
Posted by 서오석
,


'사는 이야기 > 5dols story' 카테고리의 다른 글

인연의 끈  (0) 2009.02.17
철들기  (0) 2009.02.17
양치질  (0) 2008.10.29
일촌명  (0) 2008.10.29
작심삼일  (0) 2008.10.29
Posted by 서오석
,

가끔 인터넷 서핑이나 작업을 할 때 창을 마구 띄워놓고 작업 할 때가 있다.
그때 바탕화면의 아이콘이나 혹은 바로 뒤의 화면을 잠깐 보고 싶을 때가 있다. 그때 유용하게 쓸 수 있는 프로그램이 바로 ShockCaption이다.



해당 자료에 대해 상세한 데이터를 원한다면 아래 사이트를 이용한다.
프로그램 출처: http://www.docs.kr/entry/Download-Shock-Caption-en

1. 우선 프로그램을 다운 받는다.

2. 인스톨을 시작한다.


그냥 "Next"버튼을 누른다.

3. 해당 프로그램의 라이센스 정보가 나온다.

라이센스를 보면 본 프로그램은 Freeware라는 것을 알 수 있다. 그냥 "Next"버튼을 누른다.

4. 설치할 폴더를 지정하는 화면이 나온다.

특별히 설치할 곳이 없지 않으면 그냥 "Install" 버튼을 누르면 인스톨이 된다.

5. 인스톨 후에 프로그램을 바로 실행시킬지 묻는다.


프로그램을 바로 실행시키지 않고 나중에 실행시키려면 체크박스를 해제하고
그냥 바로 해보고 싶으면 "OK"버튼을 누른다.

6. 바탕화면 작업표시줄 우측 하단에 아이콘이 생긴걸 볼 수 있다.

설정을 원한다면 마우스 오른쪽을 눌러 환경설정을 하면 된다.

7. 환경설정을 해보자.(굳이 안해도 된다. 귀찮으면 8번으로 넘어가자.)

특별하게 설정할 것은 없으나 개인취향대로 설정한다. (기본 설정으로 둬도 별로 불편함이 없다..;)

8. 이제 테스트 해보자.


아무 창이나 하나 띄워놓고 캡션바에서  마우스 오른쪽버튼을 클릭하면 창이 접히는 것을 볼 수 있다.


단점은 마우스 오른쪽 버튼을 누르는 거라서 그런지 위에처럼 창만 접히는게 아니라 저렇게 메뉴창이 나와버린다.

활용하는 법은 여러가지가 있으리라 생각된다.^^







 

Posted by 서오석
,

한글이랑 워드를 쓰다보면 가끔 이 파일을 PDF로 만들고 싶을 때가 있다.
예를 들어 보고서를 공유하고 싶은데 문서파일을 그대로 주면 막 수정하거나 할 수도 있고 그냥 출력용으로 가지고 다니거나 등등 PDF파일은 꽤나 이리저리 많이 쓰이기 때문이다.

그래서 나온게 바로 이 프로그램이다. 간단하게 문서 파일을 pdf파일로 바꿔준다.


그럼 이 프로그램의 사용법을 한번 익혀보자~

1. 우선 다운 받은 프로그램을 실행시키자.

이렇게 설치 화면이 뜬다.
우린 한국 사람이니까 한국어를 선택한다.
그리고 "확인"버튼을 누른다.







2. 프로그램에 대한 간단한 설치화면이 나온다.

여기서도 역시 "다음" 버튼을 클릭한다.

3. 라이센스에 대한 글이 주루룩 나온다.
이 프로그램은 개인 사용자에게는 프리웨어이다. 그러니 "계약에 동의 합니다." 를 선택 후 다음 버튼을 클릭한다.

4. 설치할 디렉토리를 선택하라고 나온다.
기본적으로 선택되어 있는 디렉토리에 설치를 할 것이기 때문에 "다음" 버튼을 누른다.
(자신이 다른 디렉토리로 변경하고 싶다면 "찾아보기"버튼을 누른 후 디렉토리를 선택한 후 "다음" 버튼을 누른다.)
5. 이건 시작 프로그램에 등록하는 것이다.
별 것이 없으니 그냥 "다음" 버튼을 누른다.

 
6. 이것은 현재 프린터를 설정하는 것이다.
자신의 컴퓨터가 프린터가 없다면 체크 박스에 체크를 해서 기본 프린터로 지정하고
만약 프린터가 있는 컴퓨터라면 체크를 하지 않고 다음 버튼을 클릭한다.
7. 설치 후에 doPDF를 사용할 언어들을 선택한다.
기본적으로 Korean은 선택이 되어 있다. 하지만 혹시 모르니 확인 후 "다음"버튼을 클릭한다.
만약 다른 언어를 사용하고 싶다면 해당언어에 체크를 한다.
8. doPDF를 사용할 언어를 선택한다.
우선 아까 위에 한국어를 설정하였으니 Korean을 선택한 후 "다음"버튼을 클릭한다.

9. 설치를 시작한다.
 
"설치" 버튼을 누르면 설치가 시작된다.

10. 설치가 완료 되었다.
재부팅을 시작하겠냐고 묻는데 재부팅을 한다.
(꼭 해야하는지는 확인을 안해봤다. 하라니 하자 그냥..;;)

11. 재부팅 완료 후 자신의 컴퓨터에 "제어판"->"프린터 및 팩스"에 들어간다.
그럼 프린터 중에 doPDF v6라는 프린터가 생겼을 것이다.

12. 그럼 문서 하나를 만들어서 PDF로 변환시켜보는 테스트를 해보자.
워드2003이나 2007, 혹은 한글2005,6,7과 같은 워드 프로세서 프로그램을 실행시킨 후 아무거나 대충 쓴다.

13. 해당 문서를 프린트 하기 위해 인쇄하기 버튼을 클릭한다.
위의 화면은 마이크로소프트 워드2007에서 인쇄버튼을 누른 것이다.
프린터 목록에 doPDF v6을 선택한 후 "확인" 버튼을 클릭한다.

14. 그럼 이런 화면이 뜰 것이다. 이건 변환된 문서가 담긴 PDF 파일의 저장 위치를 설정하는 것이다.
변환된 PDF를 저장할 곳을 선택한 다음 "OK" 버튼을 클릭한다.
(현재 위의 이미지는 바탕화면에 PDF를 저장하는 것이다.)

15. 바탕화면에 문서1.pdf가 생성된 것을 확인할 수 있다.



아주 간단한 프로그램이지만 꽤나 여러모로 유용하게 사용할 수 있기 때문에 
혹시 모르는 사용자들은 유용하게 쓰길 바란다.^^

 
Posted by 서오석
,

표기법

이 글은 UML 다이어그램에 대한 첫 번째 글이기 때문에 UML 2 다이어그램의 표기법에 추가된 부분, 즉 프레임이라고 하는 표기법 엘리먼트를 먼저 다뤄야겠다. 이 프레임 엘리먼트는 UML 2의 다른 많은 다이어그램 엘리먼트의 기초로 쓰이지만, 처음에 대부분의 사람들은 이 프레임 엘리먼트를 다이어그램의 그래픽 영역이라고 생각한다. 프레임 엘리먼트는 다이어그램의 레이블을 위한 지정된 장소를 제공하고, 다이어그램의 그래픽 영역을 제공한다. 프레임 엘리먼트는 UML 다이어그램에서는 선택 사항이다. 그림 1과 2에서 보듯, 다이어그램의 레이블은 프레임의 "네임박스(namebox)" 라고 부르게 될 왼쪽 코너의 상단에 놓인다. 실제 UML 다이어그램은 더 큰 직사각형 안에서 정의된다.

그림 1: 비어있는 UML 2 프레임 엘리먼트

 

시각적으로 경계선을 표시하는 것 외에도 이 프레임 엘리먼트는 인터랙션을 설명하는 다이어그램(시퀀스 다이어그램)에서도 중요한 기능도 한다. 시퀀스 다이어그램에서 시퀀스에 대한 인커밍 메시지와 아웃고잉 메시지(인터랙션)는, 이 메시지들을 프레임 엘리먼트의 경계선에 연결하여 모델링 된다. (그림 2). "기초를 넘어서" 섹션에서 설명하도록 하겠다.

그림 2: 인커밍 메시지와 아웃고잉 메시지가 있는 시퀀스 다이어그램

 

그림 2에서, 다이어그램 레이블이 Sequence Diagram을 의미하는 "sd" 로 시작한다는 것에 주목하라. 다이어그램을 위한 프레임 엘리먼트를 사용할 때 다이어그램의 레이블은 다음 포맷을 따라야 한다.

 

Diagram Type Diagram Name

 

UML 스팩은 다이어그램 유형마다 특정 텍스트 값을 준다. (sd = Sequence Diagram, activity = Activity Diagram, use case = Use Case Diagram).

 

 

 

기초

시퀀스 다이어그램의 주요 목적은 어떤 결과를 만들어내는 이벤트 시퀀스를 정의하는 것이다. 메시지 보다는 메시지가 발생하는 순서에 초점이 더 맞춰진다. 대부분 시퀀스 다이어그램은 system 객체들 간 어떤 메시지들이 보내지는지, 그리고 어떤 순서로 발생하는지를 나타낸다. 다이어그램은 이 정보를 수직적 측면과 수평적 측면으로 전달한다. 수직 측면에서는 탑다운(top down) 방식으로 메시지/호출이 발생한 시간 순서를 나타내고, 수평 측면에서는 왼쪽에서 오른쪽으로 메시지가 보내진 객체 인스턴스를 보여준다.

 

Lifelines

시퀀스 다이어그램을 그릴 때 Lifeline 표기법 엘리먼트는 다이어그램 상단에 놓인다. Lifeline은 모델링되는 시퀀스에 개입된 역할 또는 개게 인스턴스들을 나타낸다.

1 Lifeline은 박스의 아래쪽 중심에서 대시(dash) 라인을 그리며 내려간다. (그림 3). 이 Lifeline의 이름은 박스 내부에 있다

그림 3: 인스턴스 이름이 freshman인 Student 클래스 예제

 

Lifeline의 UML의 네이밍 표준은 다음 포맷은 따른다.

Instance Name : Class Name

 

그림 3의 예제에서, Lifeline은 Student 클래스의 인스턴스를 나타낸다. 이것의 인스턴스 이름은 freshman이다. Lifeline 이름 밑에 그어진 밑줄에 주목하라. 밑줄이 사용될 때는 Lifeline이 한 시퀀스 다이어그램에서 클래스의 특정 인스턴스를 나타낸다는 것을 의미한다. 특정 종류의 인스턴스(예를 들어, '역할')가 아니다. 구조 모델링에 대해서도 살펴볼 것이다. 지금까지 누가(BillFred) 그 역할을 수행하는지를 지정하지 않은 시퀀스 다이어그램에는 buyerseller 등의 역할이 포함되어 있다는 것을 알 수 있다. 이런 경우 다이어그램은 다른 정황에서도 재사용된다. 시퀀스 다이어그램에 역할 이름이 아닌 인스턴스 이름에 밑줄을 긋는다.

그림 3의 Lifeline 예제는 네임드 객체이다. 하지만 모든 Lifeline이 네임드 객체를 나타내는 것은 아니다. 대신 익명 또는 이름없는 인스턴스를 나타내는데도 Lifeline이 사용될 수 있다. 시퀀스 다이어그램에 이름없는 인스턴스를 모델링 할 때, Lifeline의 이름은 네임드 인스턴스와 같은 패턴을 따른다. 그러나 인스턴스 이름을 주는 대신에, Lifeline의 이름의 부분이 공백으로 된다. 그림 3을 다시 보자. 만약 이 Lifeline이 Student 클래스의 익명 인스턴스를 나타낸다면, Lifeline은 " Student." 이다. 또한 시퀀스 다이어그램은 프로젝트의 디자인 단계에서 사용되기 때문에 유형이 지정되지 않은 객체를 갖고 있는 것이 맞다. 예를 들어 "freshman."이 바로 그것이다.

 

메시지

시퀀스 다이어그램의 첫 번째 메시지는 언제나 상단에서 시작하고 다이어그램의 왼쪽에 위치한다. 뒤따르는 메시지들은 이전 메시지보다 약간 낮게 다이어그램에 추가된다.

메시지를 또 다른 객체에 보내는 객체(lifeline)를 나타내기 위해서 수신 객체에 실선 화살표(동기식 호출일 경우)를 긋는다. 또는 (비동기식일 경우) 막대 화살표를 긋는다. 메시지/메소드 이름은 화살표 위에 놓인다. 수신 객체로 보내지는 메시지는 수신 객체의 클래스가 구현하는 작동/메소드를 나타낸다. 그림 4의 예제에서, analyst 객체는 ReportingSystem 클래스의 인스턴스인 system 객체를 호출한다. analyst 객체는 system 객체의 getAvailableReports 메소드를 호출한다. system 객체는 secSystem 객체에 userId의 인자와 함께 getSecurityClearance 메소드를 호출한다. 이것이 바로 SecuritySystem 클래스 유형이다.

 

그림 4: 객체들 간 보내지는 메시지 예제

 

시퀀스 다이어그램에 대한 메시지 호출을 보여주는 것 외에도 그림 4 다이어그램에는 리턴 메시지가 포함되어 있다. 이 리턴 메시지들은 필수요소는 아니다. 리턴 메시지는 원래 lifeline을 향하도록 점선 화살표로 그려지고 그 위에 리턴 값을 배치한다. 그림 4에서, getSecurityClearance 메소드가 호출될 때 secSystem 객체는 system 객체에 userClearance를 리턴한다. 이 system 객체는 getAvailableReports 메소드가 호출되면 availableReports를 리턴한다.

다시 말하지만, 리턴 메시지는 시퀀스 다이어그램의 선택 사항이다. 리턴 메시지의 사용 여부는 모델링되는 것의 상세함 정도에 달려있다. 리턴 메시지는 보다 상세한 것을 원할 때 유용하다. 하지만 호출 메시지로도 충분하다. 개인적으로는 값이 리턴될 때마다 리턴 메시지를 삽입한다.

시퀀스 다이어그램을 모델링 할 때, 객체가 자신에게 메시지를 보내야 할 때가 있다. 언제 객체가 자기자신을 호출할까? 순수주의자들은 객체는 메시지를 객체 자신에게 보내서는 안된다고 주장한다. 하지만 자신에게 메시지를 보내는 객체를 모델링 하는 것도 어떤 경우에는 유용하다. 그림 5는 그림 4를 개선한 것이다. 그림 5는 determineAvailableReports 메소드를 호출하는 system 객체를 보여준다. 그 system 객체에 "determineAvailableReports," 메시지를 보여줌으로써 모델은 이 프로세스가 system 객체에서 발생한다는 사실에 주목할 수 있다.

자기자신을 호출하는 객체를 그리기 위해서는 정상적인 방법으로 메시지를 그리되 또 다른 객체로 연결하는 대신, 메시지를 다시 객체 자신으로 연결한다.

그림 5: determineAvailableReports 메소드를 호출하는 system 객체

 

그림 5의 예제 메시지는 동기식 메시지이다. 하지만 시퀀스 다이어그램에서는 비동기식 메시지도 모델링 할 수 있다. 비동기식 메시지는 동기식 메시지와 비슷하게 그려지지만 메시지 라인은 막대 화살표로 표시된다. (그림 6)

그림 6: instance2로 보내지는 비동기식 메시지를 나타내는 시퀀스 다이어그램

 

가드(guard)

객체 인터랙션을 모델링 할 때 객체로 보내지는 메시지 조건이 부합해야 할 때도 있다. 가드(guard)는 흐름을 제어하는 UML 다이어그램에서 쓰인다. UML 1.x 와 UML 2.0 모두 가드를 언급했다. UML 1.x에서 보호는 하나의 메시지에만 할당될 수 있었다. UML 1.x의 시퀀스 다이어그램에 가드를 그리려면 보호되고 있는 메시지 라인 위, 메시지 이름 앞에 guard 엘리먼트를 둔다. 그림 7은 메시지 addStudent 메소드에 대한 가드가 있는 시퀀스 다이어그램이다.

그림 7: 가드가 포함된 addStudent 메시지

 

그림 7에서 가드는 텍스트 "[pastDueBalance = 0]" 이다. 이 메시지에 가드가 있기 때문에 addStudent 메시지는 시스템 계정이 [pastDueBalance = 0]을 리턴할 경우에만 보내진다.

[Boolean Test]

 

예를 들어,

[pastDueBalance = 0]

 

Combined fragments (대안, 옵션, 루프)

대부분의 시퀀스 다이어그램에서 UML 1.x "in-line" 가드는 모델링 되는 시퀀스에 필요한 로직을 핸들하기엔 조금 부족했다. 그러한 기능이 부족하다는 점이 UML 1.x에서 문제가 되었다. UML 2는 "in-line" 가드를 없애고, Combined FFragment라고 하는 표기법 엘리먼트를 추가하여 이러한 문제를 다루고 있다. Combined Fragment는 시퀀스 다이어그램에서 조건의 흐름을 보여주기 위해 메시지들을 하나로 그룹핑하는데 사용된다. UML 2 스팩은 Combined Fragment에 11 개의 인터랙션 유형을 정의하고 있다. 이 중 세 가지는 "기초" 섹션에서 다룰 것이고, 두 가지 유형은 "기초를 넘어서" 섹션에서 설명할 것이다. 나머지 여섯 개는 다음 기회에 다루고자 한다. (나는 책을 집필하는 것이 아니다. 오늘 안으로 이 글을 마무리 해야 한다.)

 

대안

대안은 두 개 이상의 메시지 시퀀스들간 상호 배타적인 선택을 나타낼 때 사용된다.

3 대안은 전통적인 "if then else" 직 (만일 내가 세 개의 아이템을 구매하면 구매금액의 20%를 할인 받는다; 그 외에는 10%의 할인을 받는다.)의 모델링이 가능하다.

그림 8에서 보듯, 대안 엘리먼트는 프레임을 사용하여 그려진다. "alt" 라는 단어는 이 프레임의 네임박스 안에 놓인다. 더 큰 직사각형은 피연산함수로 나누어진다.

4피연산 함수는 대시(dash) 라인으로 분리된다. 각 피연산 함수에는 가드가 주어지고 이 가드는 lifeline 상단에 피연산 함수의 왼쪽 상단 부분을 향해 배치된다.

5피연산함수의 가드가 "true,"로 되면 그 피연산함수를 따라야 한다.

그림 8: 대안 Combined Fragment를 포함하고 있는 시퀀스 다이어그램

 

대안이 어떻게 읽혀지는지를 보여주는 예제로서 그림 8은 상단에서 시작하는 시퀀스를 보여준다. check amount와 account의 balance 정보가 있는 bank 객체가 있다. 이 부분에서 대안이 사용된다. 가드 "[balance >= amount]" 때문에 account의 balance이 보다 크거나 같을 때 시퀀스는 addDebitTransaction과 storePhotoOfCheck 메시지를 account 객체로 보내는 bank 객체를 사용하여 시퀀스를 지속시킨다. 하지만 balance가 amount 보다 작거나 같을 때 시퀀스는 addInsuffientFundFee와 noteReturnedCheck 메시지를 account 객체로 보내고, returnCheck 메시지를 자기 자신에게 보내는 bank 객체로 처리한다. "[else]" 가드 때문에 balance가 amount 보다 작거나 같을 때 두 번째 시퀀스가 호출된다. 대안을 사용하면 "[else]" 가드가 필요 없다. 하지만 피연산함수가 이것에 대한 명확한 가드를 갖고 있지 않다면 "[else]" 가드가 필요하다.

대안은 "if then else"에만 국한되지 않는다. 필요한 만큼 대안 경로를 취할 수 있다. 더 많은 대안이 필요하면 시퀀스의 가드와 메시지를 포함한 직사각형에 피연산함수를 추가하면 된다.

 

옵션

옵션 Combined Fragment는 특정 상황에서 발생하는 시퀀스를 모델링 할 때 사용된다. 다른 경우, 이 시퀀스는 발생하지 않는다. 이 옵션은 간단한 "if then"문장을 모델링 하는데 쓰인다. (찬장에 5개 미만의 도넛이 있다면 24개 이상의 도넛을 만든다.)

옵션 표기법은 대안과 비슷하다. 단 한 개의 피연산 함수를 가져야 하고, "else" 가드가 전혀 없다는 것을 제외하고는 말이다. 옵션을 그리려면 프레임을 그려야 한다. "opt" 텍스트가 이 프레임의 네임박스 안에 배치되고, 이 프레임의 콘텐트 영역에 옵션의 가드가 lifeline의 상단에, 왼쪽 상단 코너를 향해 배치된다. 그런 다음 옵션의 메시지 시퀀스가 나머지 영역에 배치된다. (그림 9)

 

그림 9: 옵션 Combined Fragment

 

옵션 Combined Fragment는 읽기 쉽다. 그림 9는 그림 7의 시퀀스 다이어그램을 재구성 한 것이다. 하지만 여기에서는 student의 과거 해당 balance가 0일 경우 보내져야 하는 메시지가 더 많기 때문에 옵션을 사용한다. 그림 9의 시퀀스 다이어그램을 보면, student의 과거 balance가 0 이면 addStudent, getCostOfClass, chargeForClass 메시지들이 보내진다. student의 과거 balance가 0이 아니라면 시퀀스는 어떤 메시지도 보내지 않는다.

그림 9의 시퀀스 다이어그램에는 이 옵션용 가드가 포함되어 있다. 하지만 이 가드는 필수 엘리먼트는 아니다. 추상 시퀀스 다이어그램에서는 이 옵션의 조건을 지정한다. 이것이 옵션 fragment 라는 것을 가리키면 된다.

 

루프(loop)

가끔 반복적인 시퀀스를 모델링 해야 할 때도 있다. UML 2에서 반복되는 시퀀스의 모델에 루프 Combined Fragment를 사용한다.

루프는 외형상 옵션과 매우 흡사하다. 프레임을 그리고 그 프레임의 네임박스에 "loop"라고 쓴다. 프레임의 콘텐트 영역 안에서 루프의 가드는

6 lifeline의 상단에, 왼쪽 상단 코너 쪽을 향하여 놓인다. 그런 다음 루프의 메시지 시퀀스는 프레임의 나머지 콘텐트 영역에 배치된다. 루프에서 가드는 두 가지 특별한 조건을 가질 수 있다. 이 특별 가드 조건들은 "minint = [the number]" ("minint = 1")라고 하는 최소 반복과 and maximum iterations written as "maxint = [the number]" ("maxint = 5")라고 하는 최대 반복이다. 최소 반복 가드를 사용하여, 루프는 지정된 최소한의 수만큼 실행해야 하고 최대 또한 마찬가지이다.

그림 10: loop Combined Fragment

 

그림 10(

크게 보기)에서, 루프는 reportsEnu 객체의 hasAnotherReport 메시지가 false를 리턴할 때까지 실행된다. 이 시퀀스 다이어그램의 루프는 루프 시퀀스가 실행되는지를 확인할 때 부울 테스트를 사용한다. 이 다이어그램은 위에서부터 읽어 내려간다. 루프에 다다르면 hasAnotherReport 값이 true 인지를 확인하기 위해 테스트가 실행된다. HasAnotherReport 값이 true 면 시퀀스는 루프로 간다.

 

 

 

기초를 넘어서

 

지금까지 시퀀스 다이어그램의 기초를 설명했다. 다음 섹션에서는 수준 높은 표기법에 대해서 알아보자.

또 다른 시퀀스 다이어그램

시퀀스 다이어그램을 만들 때, 개발자는 기존 시퀀스 다이어그램을 재사용하는 경우가 많다.

7 UML 2부터, "Interaction Occurrence" 엘리먼트가 도입되었다. Interaction Occurrence가 추가되었다는 것은 UML 2의 인터랙션 모델링의 가장 중요한 혁신이다. Interaction Occurrence는 기본적인 시퀀스 다이어그램을 복잡한 시퀀스 다이어그램으로 만드는 기능이다. 이것을 사용하여 간단한 시퀀스를 조합(재사용)하여 보다 복잡한 시퀀스를 만들 수 있다. 보다 복잡하고 완벽한 시퀀스의 가능성이 커진 것이다.

Interaction Occurrence 엘리먼트는 프레임을 사용하여 그려진다. "ref" 텍스트가 프레임 네임박스 안에 놓이고 참조되는 시퀀스 다이어그램의 이름이 프레임의 콘텐트 영역 내부에 놓인다. 여기에 더불어 시퀀스 다이어그램에 대한 매개변수도 함께 배치된다. 참조되는 시퀀스 다이어그램의 표기법은 다음 패턴을 따른다.

sequence diagram name[(arguments)] [: return value]

 

두 가지 예제를 보자.

1. Retrieve Borrower Credit Report(ssn) : borrowerCreditReport

또는

2. Process Credit Card(name, number, expirationDate, amount : 100)

예제 1에서, 이 신택스는 Retrieve Borrower Credit Report라고 하는 시퀀스 다이어그램을 호출하여 이를 ssn 매개변수로 보낸다. Retreive Borrower Credit Report 시퀀스는 borrowerCreditReport 변수를 리턴한다.

예제 2에서는 Process Credit Card 라고 하는 시퀀스 다이어그램을 호출하고 이를 매개변수인 name, number, expiration date, amount로 전달한다. 하지만 예제 2에서 amount 매개변수는 100이 될 것이다. 예제 2에 레이블이 붙은 리턴 값이 없기 때문에 시퀀스는 값을 리턴하지 않는다. (모델링되는 이 시퀀스는 리턴 값이 필요 없다.)

그림 11: 두 개의 다른 시퀀스 다이어그램을 참조하는 시퀀스 다이어그램

 

그림 11은 시퀀스 다이어그램 "Balance Lookup"과 "Debit Account."를 참조하는 시퀀스 다이어그램이다. 이 시퀀스는 왼쪽 상단에서 Customer가 메시지를 teller 객체로 보내는 것으로 시작한다. 이 teller 객체는 theirBank 객체로 메시지를 보낸다. 그 지점에서 Balance Lookup 시퀀스 다이어그램이 매개변수로서 전달된 accountNumber와 함께 호출된다. Balance Lookup 시퀀스 다이어그램은 balance 변수를 리턴한다. 그런 다음, 이 옵션의 가드 조건은 balance가 amount 변수보다 큰 지를 확인하기 위해 검사된다. balance가 amount 보다 클 경우 Debit Account 시퀀스 다이어그램이 호출되면서 이것을 accountNumber로 보내고 매개변수로서 amount를 전달한다. 시퀀스가 완료된 후에 withdrawCash 메시지가 customer에게 cash를 리턴한다.

그림 11에서, theirBank의 lifeline은 "Balance Lookup" 인터랙션 뒤에 숨겨진다. 인터랙션이 이 lifeline을 숨기기 때문에 theirBank lifeline은 "Balance Lookup" 시퀀스 다이어그램에서 참조된다. 인터랙션 발생에서 lifeline을 숨기는 것 외에도 UML 2는 lifeline이 "Balance Lookup" 시퀀스에 같은 theirBank를 갖도록 지정한다.

인터랙션 발생에서 참조되지 않는 lifeline들을 중첩하는 시퀀스 다이어그램을 모델링 할 때가 있다. 이 같은 경우, lifeline은 정상적인 lifeline으로 나타나고 인터랙션 발생에 의해 숨겨지지 않는다.

그림 11에서 이 시퀀스는 "Balance Lookup" 시퀀스 다이어그램을 참조한다. "Balance Lookup" 시퀀스 다이어그램은 그림 12에서 볼 수 있다. 이 예제 시퀀스는 매개변수들과 리턴 값을 갖고 있기 때문에 다이어그램의 네임박스에 있는 레이블은 특정 패턴을 따른다.

Diagram Type Diagram Name [(Parameter Type : Parameter Name)] :

 

 

[: Return Value Type]

 

예제

1. SD Balance Lookup(Integer : accountNumber) : Real

또는

2. SD Available Reports(Financial Analyst : analyst) : Reports

그림 12는 예제 1을 설명하고 있다. Balance Lookup 시퀀스가 accountNumber 매개변수를 이 시퀀스의 변수로서 사용하고, 시퀀스 다이어그램은 리턴되는 Real 객체를 보여준다. 이 같은 경우 시퀀스가 객체를 리턴하는 곳에서, 리턴되는 객체에는 시퀀스 다이어그램의 인스턴스 이름이 부여된다.

그림 12: accountNumber의 매개변수를 취하고 Real 객체를 리턴하는 시퀀스 다이어그램

 

그림 13은 시퀀스가 매개변수를 취하고 객체를 리턴하는 예제 2를 묘사하고 있다. 그림 13에서, 이 매개변수는 시퀀스의 인터랙션에 사용된다.

그림 13: 인터랙션에 매개변수를 사용하고 Reports 객체를 리턴하는 시퀀스 다이어그램

게이트(Gate)

 

이전 섹션에서는 매개변수와 리턴 값을 통해 정보를 전달하여 또 다른 시퀀스 다이어그램을 참조하는 방법을 설명했다. 그러나 시퀀스 다이어그램들 간 정보를 전달하는 또 다른 방법이 있다. 게이트(gate)는 시퀀스 다이어그램과 내용들 간 정보 전달을 모델링 할 수 있는 쉬운 방법이다. 게이트는 시퀀스 다이어그램의 프레임의 끝에 연결된 한쪽 끝과 lifeline에 연결된 또 다른 끝으로 설명되는 메시지이다. 게이트를 사용하여 그림 11과 12를 다시 만들어 그림 14와 15로 변형시켰다. 그림 15의 예제 다이어그램은 accountNumber의 매개변수를 취하는 getBalance라고 하는 엔트리 게이트를 갖고 있다. getBalance 메시지는 엔트리 게이트이다. 다이어그램의 프레임에 연결된 화살표가 lifeline을 향하기 때문이다. 이 시퀀스 다이어그램에는 종료 게이트도 있다. 이것은 balance 변수를 리턴한다. 종료 게이트는 lifeline에서 다이어그램의 프레임으로 연결된 리턴 메시지이기 때문에 인식된다. 화살표는 프레임으로 향한다.

그림 14: 게이트를 사용한 그림 11

 

그림 15: 게이트를 사용한 그림 12

 

Combined Fragment (중지(break)와 병렬(parallel))

이 글 도입부에서 다루었던 "기초" 섹션에서 "대안", "옵션", "루프"로 알려진 Combined Fragment를 다루었다. 이 세 가지 Combined Fragment는 대부분의 사람들이 가장 많이 사용하는 것들이다. 하지만 더욱 유용한 Combined Fragment 두 가지가 더 있다. 바로 중지(break)와 병렬(parallel)이다.

 

중지(break)

중지는 거의 모든 면에서 옵션(option)과 동일하다. 두 가지 예외를 제외하고는 말이다. 우선, 중지의 프레임에는 네임박스가 "옵션" 대신 "중지"이다. 둘째, 중지의 메시지가 실행될 때 끝내기 인터랙션의 나머지 메시지들은 시퀀스가 끝내기 인터랙션에서 정지되기 때문에 실행되지 않는다. 이러한 방식으로 중지는 C++ 또는 Java 같은 프로그래밍 언어의 중지 키워드와 흡사하다.

그림 16: 그림 8의 시퀀스 다이어그램 재구성- 대안(alternative) 대신 중지 사용

 

중지는 예외 핸들링을 모델링 할 때 사용된다. 그림 16은 그림 8을 재구성 한 것이다. 이것은 balance < amount 조건을 대안 플로우 대신 예외로 처리한다. 그림 16을 읽는 방법은 시퀀스의 왼쪽 상단 코너부터 읽어 내려간다. 이 시퀀스가 리턴 값 "balance," 에 다다르면 balance가 amount 보다 적은지를 확인한다. balance가 amount 보다 작지 않으면 그 다음 메시지가 addDebitTransaction 메시지로 보내지고, 이 시퀀스는 지속된다. 하지만 balance가 amount 보다 작으면 이 시퀀스는 중지로 들어가고 해당 메시지가 보내진다. 중지의 모든 메시지들이 보내지면 이 시퀀스는 남아있는 메시지(addDebitTransaction)를 보내지 않고 종료된다.

중지는 마무리 인터랙션의 시퀀스를 종료한다. 그 다이어그램에 설명된 모든 시퀀스를 종료하지는 않는다. 중지가 대안 또는 루프의 일부일 경우 오직 대안 또는 루프만 종료된다.

 

병렬(Parallel)

현대적 컴퓨터 시스템은 더 복잡해지고 때때로 동시 태스크도 수행한다. 복잡한 태스크의 일부를 종료하는데 드는 프로세싱 시간이 생각 보다 길 때 어떤 시스템은 프로세싱의 일부를 병렬(parallel)로 처리한다. 병렬 엘리먼트는 병렬 프로세싱 작동을 보여주는 시퀀스 다이어그램에 사용한다.

병렬은 프레임을 사용하여 그려지고 프레임의 네임박스에 "par"로 표시한다. 프레임의 콘텐트 섹션을 점선으로 구분된 수평 피연산 함수로 나눈다. 이 프레임의 각 피연산 함수는 병렬로 수행되는 실행 쓰레드이다.

그림 17: 두 가지 태스크를 병렬로 수행하는 객체 예제

 

그림 17에는 병렬로 작동하는 객체 예제로서 그다지 훌륭한 것은 아니지만 이해하기는 쉽다. 이 시퀀스는 이렇게 진행된다. hungryPerson이 cookFood 메시지를 oven 객체로 보낸다. oven 객체가 그 메시지를 받으면 두 개의 메시지를 nukeFood와 rotateFood로 동시에 보낸다. 이들 메시지 모두 실행된 후에 hungryPerson 객체에 oven 객체에서 yummyFood가 리턴된다.

 

   

 

결론

이 시퀀스 다이어그램은 시스템 요구사항들을 문서화하고 시스템 디자인을 한꺼번에 볼 수 있는 좋은 다이어그램이다. 시퀀스 다이어그램이 유용한 이유는 인터랙션이 발생하는 시간 순서로, 시스템의 객체들간 인터랙션 로직을 보여주기 때문이다.

 

   

 

참조

  • http://www.omg.org/cgi-bin/doc?ptc/2003-08-02
  • UML 2 Sequence Diagram Overview
  • http://www.agilemodeling.com/artifacts/sequenceDiagram.htm
  • UML 2 Tutorial
  •  

     

    1 완전히 모델링 된 시스템에서 이 객체들(클래스의 인스턴스들)도 시스템의 클래스 다이어그램에서 모델링 된다.

    2 분석가가 이 시퀀스 다이어그램을 읽을 때 이 시스템에 이미 로그인 된 것으로 간주한다.

    3 다양한 대안 피연산 함수에 첨부된 두 개 이상의 가드 조건들을 동시에 true로 만드는 것이 가능하다. 하지만 대부분의 경우, 피연산 함수가 런타임 시 실제로 발생하는 피연산 함수는 단 한 개이다. (대안 "wins" 는 UML 표준으로 정의되지 않았다.)

    4 피연산 함수가 고속도로의 차선(lane)처럼 보이겠지만, 그렇다고 해서 차선으로 부르지 않는다. 수영 레인(swim lane)이 액티비티 다이어그램에 사용되는 UML 표기법이다. The Rational Edge's

    액티비티 다이어그램을 참조하라.

    5 가드가 부착된 lifeline은 가드 식에 포함된 변수를 갖고 있다.

    6 옵션과 마찬가지로 루프 역시 가드 조건이 배치될 필요가 없다.

    7 어떤 유형의 시퀀스 다이어그램도 재사용 가능하다.

    출처: 한국 IBM

    '소프트웨어공학 > UML이야기' 카테고리의 다른 글

    6. Deployment Diagram  (0) 2009.05.26
    3. B Usecase Discription  (0) 2009.05.26
    4. Class Diagram  (0) 2008.10.26
    3. A. Usecase Diagram  (0) 2008.06.23
    2. UML의 구성  (0) 2008.06.16
    Posted by 서오석
    ,

    저자 - Tom Kyte

    오라클 전문가 Tom Kyte가 ROWNUM의 동작 원리와 활용 방법에 대해 설명합니다.

    이번 호의 Ask Tom 컬럼은 지금까지와는 조금 다른 내용을 담고 있습니다. 필자는 오라클 데이터베이스에서 Top-N 쿼리와 페이지네이션(pagination) 쿼리를 구현하는 방법에 대해 자주 질문을 받곤 합니다. 하나의 컬럼을 통해 이러한 질문에 한꺼번에 대답하기 위한 방편으로, < Effective Oracle by Design (Oracle Press, 2003)> 의 내용을 인용하기로 했습니다. 컬럼의 포맷에 맞게 책의 내용이 다소 수정되었음을 참고하시기 바랍니다.

    결과 셋의 제한

    ROWNUM은 오라클 데이터베이스가 제공하는 마술과도 같은 컬럼입니다. 이 때문에 많은 사용자들이 문제를 겪기도 합니다. 하지만 그 원리와 활용 방법을 이해한다면 매우 유용하게 사용할 수 있습니다. 필자는 주로 두 가지 목적으로 ROWNUM을 사용합니다.

    • Top-N 프로세싱: 이 기능은 다른 일부 데이터베이스가 제공하는 LIMIT 구문과 유사합니다.
    • 쿼리 내에서의 페이지네이션(pagination) – 특히 웹과 같은 "stateless" 환경에서 자주 활용됩니다. 필자는 asktom.oracle.com 웹 사이트에서도 이 테크닉을 사용하고 있습니다.

    두 가지 활용 방안을 설명하기 전에, 먼저 ROWNUM의 동작 원리에 대해 살펴 보기로 하겠습니다

    ROWNUM의 동작 원리

    ROWNUM은 쿼리 내에서 사용 가능한 (실제 컬럼이 아닌) 가상 컬럼(pseudocolumn)입니다. ROWNUM에는 숫자 1, 2, 3, 4, ... N의 값이 할당됩니다. 여기서 N 은 ROWNUM과 함께 사용하는 로우의 수를 의미합니다. ROWNUM의 값은 로우에 영구적으로 할당되지 않습니다(이는 사람들이 많이 오해하는 부분이기도 합니다). 테이블의 로우는 숫자와 연계되어 참조될 수 없습니다. 따라서 테이블에서 "row 5"를 요청할 수 있는 방법은 없습니다. "row 5"라는 것은 존재하지 않기 때문입니다.

    또 ROWNUM 값이 실제로 할당되는 방법에 대해서도 많은 사람들이 오해를 하고 있습니다. ROWNUM 값은 쿼리의 조건절이 처리되고 난 이후, 그리고 sort, aggregation이 수행되기 이전에 할당됩니다. 또 ROWNUM 값은 할당된 이후에만 증가(increment) 됩니다. 따라서 아래 쿼리는 로우를 반환하지 않습니다.

    select * 
      from t 
     where ROWNUM > 1;
    

    첫 번째 로우에 대해 ROWNUM > 1의 조건이 True가 아니기 때문에, ROWNUM은 2로 증가하지 않습니다. 아래와 같은 쿼리를 생각해 봅시다.

    select ..., ROWNUM
      from t
     where <where clause>
     group by <columns>
    having <having clause>
     order by <columns>;
    

    이 쿼리는 다음과 같은 순서로 처리됩니다.

    1. FROM/WHERE 절이 먼저 처리됩니다.
    2. ROWNUM이 할당되고 FROM/WHERE 절에서 전달되는 각각의 출력 로우에 대해 증가(increment) 됩니다.
    3. SELECT가 적용됩니다.
    4. GROUP BY 조건이 적용됩니다.
    5. HAVING이 적용됩니다.
    6. ORDER BY 조건이 적용됩니다.

    따라서 아래와 같은 쿼리는 에러가 발생할 수 밖에 없습니다.

    select * 
      from emp 
     where ROWNUM <= 5 
     order by sal desc;
    

    이 쿼리는 가장 높은 연봉을 받는 다섯 명의 직원을 조회하기 위한 Top-N 쿼리로 작성되었습니다. 하지만 실제로 쿼리는 5 개의 레코드를 랜덤하게(조회되는 순서대로) 반환하고 salary를 기준으로 정렬합니다. 이 쿼리를 위해서 사용되는 가상코드(pseudocode)가 아래와 같습니다.

    ROWNUM = 1
    for x in 
    ( select * from emp )
    loop
        exit when NOT(ROWNUM <= 5)
        OUTPUT record to temp
        ROWNUM = ROWNUM+1
    end loop
    SORT TEMP
    

    위에서 볼 수 있듯 처음의 5 개 레코드를 가져 온후 바로 sorting이 수행됩니다. 쿼리에서 "WHERE ROWNUM = 5" 또는 "WHERE ROWNUM > 5"와 같은 조건은 의미가 없습니다. 이는 ROWNUM 값이 조건자(predicate) 실행 과정에서 로우에 할당되며, 로우가 WHERE 조건에 의해 처리된 이후에만 increment 되기 때문입니다.

    올바르게 작성된 쿼리가 아래와 같습니다.

    select *
      from  
    ( select * 
        from emp 
       order by sal desc ) 
     where ROWNUM <= 5;
    

    위 쿼리는 salary를 기준으로 EMP를 내림차순으로 정렬한 후, 상위의 5 개 레코드(Top-5 레코드)를 반환합니다. 아래에서 다시 설명되겠지만, 오라클 데이터베이스가 실제로 전체 결과 셋을 정렬하지 않습니다. (오라클 데이터베이스는 좀 더 지능적인 방식으로 동작합니다.) 하지만 사용자가 얻는 결과는 동일합니다.

    ROWNUM을 이용한 Top-N 쿼리 프로세싱

    일반적으로 Top-N 쿼리를 실행하는 사용자는 다소 복잡한 쿼리를 실행하고, 그 결과를 정렬한 뒤 상위의 N 개 로우만을 반환하는 방식을 사용합니다. ROWNUM은 Top- N쿼리를 위해 최적화된 기능을 제공합니다. ROWNUM을 사용하면 대량의 결과 셋을 정렬하는 번거로운 과정을 피할 수 있습니다. 먼저 그 개념을 살펴보고 예제를 통해 설명하기로 하겠습니다.

    아래와 같은 쿼리가 있다고 가정해 봅시다.

    select ... 
      from ... 
     where ... 
     order by columns;
    

    또 이 쿼리가 반환하는 데이터가 수천 개, 수십만 개, 또는 그 이상에 달한다고 가정해 봅시다. 하지만 사용자가 실제로 관심 있는 것은 상위 N개(Top 10, Top 100)의 값입니다. 이 결과를 얻기 위한 방법에는 두 가지가 있습니다.

    • 클라이언트 애플리케이션에서 쿼리를 실행하고 상위 N 개의 로우만을 가져오도록 명령
    • • 쿼리를 인라인 뷰(inline view)로 활용하고, ROWNUM을 이용하여 결과 셋을 제한 (예: SELECT * FROM (your_query_here) WHERE ROWNUM <= N)

    두 번째 접근법은 첫 번째에 비해 월등한 장점을 제공합니다. 그 이유는 두 가지입니다. 첫 번째로, ROWNUM을 사용하면 클라이언트의 부담이 줄어듭니다. 데이터베이스에서 제한된 결과 값만을 전송하기 때문입니다. 두 번째로, 데이터베이스에서 최적화된 프로세싱 방법을 이용하여 Top N 로우를 산출할 수 있습니다. Top-N 쿼리를 실행함으로써, 사용자는 데이터베이스에 추가적인 정보를 전달하게 됩니다. 그 정보란 바로 "나는N 개의 로우에만 관심이 있고, 나머지에 대해서는 관심이 없다"는 메시지입니다. 이제, 정렬(sorting) 작업이 데이터베이스 서버에서 어떤 원리로 실행되는지 설명을 듣고 나면 그 의미를 이해하실 수 있을 것입니다. 샘플 쿼리에 위에서 설명한 두 가지 접근법을 적용해 보기로 합시다.

    select * 
      from t 
     order by unindexed_column;
    

    여기서 T가 1백만 개 이상의 레코드를 저장한 큰 테이블이라고, 그리고 각각의 레코드가 100 바이트 이상으로 구성되어 있다고 가정해 봅시다. 그리고 UNINDEXED_COLUMN은 인덱스가 적용되지 않은 컬럼이라고, 또 사용자는 상위 10 개의 로우에만 관심이 있다고 가정하겠습니다. 오라클 데이터베이스는 아래와 같은 순서로 쿼리를 처리합니다.

    1. T에 대해 풀 테이블 스캔을 실행합니다.
    2. UNINDEXED_COLUMN을 기준으로 T를 정렬합니다. 이 작업은 "full sort"로 진행됩니다.
    3. Sort 영역의 메모리가 부족한 경우 임시 익스텐트를 디스크에 스왑하는 작업이 수행됩니다.
    4. 임시 익스텐트를 병합하여 상위 10 개의 레코드를 확인합니다.
    5.쿼리가 종료되면 임시 익스텐트에 대한 클린업 작업을 수행합니다. .

    결과적으로 매우 많은 I/O 작업이 발생합니다. 오라클 데이터베이스가 상위 10 개의 로우를 얻기 위해 전체 테이블을 TEMP 영역으로 복사했을 가능성이 높습니다.

    그럼 다음으로, Top-N 쿼리를 오라클 데이터베이스가 개념적으로 어떻게 처리할 수 있는지 살펴 보기로 합시다.

    select *
      from 
    (select * 
       from t 
      order by unindexed_column)
     where ROWNUM < :N;
    

    오라클 데이터베이스가 위 쿼리를 처리하는 방법이 아래와 같습니다.

    1. 앞에서와 마찬가지로 T에 대해 풀-테이블 스캔을 수행합니다(이 과정은 피할 수 없습니다).
    2. :N 엘리먼트의 어레이(이 어레이는 메모리에 저장되어 있을 가능성이 높습니다)에서 :N 로우만을 정렬합니다.

    상위N 개의 로우는 이 어레이에 정렬된 순서로 입력됩니다. N +1 로우를 가져온 경우, 이 로우를 어레이의 마지막 로우와 비교합니다. 이 로우가 어레이의 N +1 슬롯에 들어가야 하는 것으로 판명되는 경우, 로우는 버려집니다. 그렇지 않은 경우, 로우를 어레이에 추가하여 정렬한 후 기존 로우 중 하나를 삭제합니다. Sort 영역에는 최대 N 개의 로우만이 저장되며, 따라서 1 백만 개의 로우를 정렬하는 대신N 개의 로우만을 정렬하면 됩니다.

    이처럼 간단한 개념(어레이의 활용, N개 로우의 정렬)을 이용하여 성능 및 리소스 활용도 면에서 큰 이익을 볼 수 있습니다. (TEMP 공간을 사용하지 않아도 된다는 것을 차치하더라도) 1 백만 개의 로우를 정렬하는 것보다 10 개의 로우를 정렬하는 것이 메모리를 덜 먹는다는 것은 당연합니다.

    아래의 테이블 T를 이용하면, 두 가지 접근법이 모두 동일한 결과를 제공하지만 사용되는 리소스는 극적인 차이를 보임을 확인할 수 있습니다.

    create table t
    as
    select dbms_random.value(1,1000000) 
    id, 
           rpad('*',40,'*' ) data
      from dual
    connect by level <= 100000;
    
    begin
    dbms_stats.gather_table_stats
    ( user, 'T');
    end;
    /
    
    Now enable tracing, via
    
    exec 
    dbms_monitor.session_trace_enable
    (waits=>true);
    

    And then run your top-N query with ROWNUM:

    select *
      from
    (select *
       from t
      order by id)
    where rownum <= 10;
     

    마지막으로 상위 10 개의 레코드만을 반환하는 쿼리를 실행합니다.

    declare
    cursor c is
    select *
      from t
     order by id;
    l_rec c%rowtype;
    begin
        open c;
        for i in 1 .. 10
        loop
            fetch c into l_rec;
            exit when c%notfound;
        end loop;
        close c;
    end;
    /
    

    이 쿼리를 실행한 후, TKPROF를 사용해서 트레이스 결과를 확인할 수 있습니다. 먼저 Top-N 쿼리 수행 후 확인한 트레이스 결과가 Listing 1과 같습니다.

    Code Listing 1: ROWNUM을 이용한 Top-N 쿼리

    select *
      from
    (select *
       from t
      order by id)
    where rownum <= 10
    
    call         count     cpu	elapsed   disk     query      current    rows
    --------     --------  -------  -------   -------  --------   --------   ------ 
    Parse        1         0.00     0.00      0          0        0           0
    Execute      1         0.00     0.00      0          0        0           0
    Fetch        2         0.04     0.04      0        949        0          10
    --------     --------  -------  -------   -------  --------   --------   ------ 
    total        4         0.04     0.04      0        949        0          10
    
    Rows                         Row          Source Operation
    -----------------            ---------------------------------------------------
    10                           COUNT STOPKEY (cr=949 pr=0 pw=0 time=46997 us)
    10                           VIEW  (cr=949 pr=0 pw=0 time=46979 us)
    10                           SORT ORDER BY STOPKEY (cr=949 pr=0 pw=0 time=46961 us)
    100000                       TABLE ACCESS FULL T (cr=949 pr=0 pw=0 time=400066 us)
    

    이 쿼리는 전체 테이블을 읽어 들인 후, SORT ORDER BY STOPKEY 단계를 이용해서 임시 공간에서 사용되는 로우를 10 개로 제한하고 있습니다. 마지막 Row Source Operation 라인을 주목하시기 바랍니다. 쿼리가 949 번의 논리적 I/O를 수행했으며(cr=949), 물리적 읽기/쓰기는 전혀 발생하지 않았고(pr=0, pw=0), 불과 400066 백만 분의 일초 (0.04 초) 밖에 걸리지 않았습니다. 이 결과를 Listing 2의 실행 결과와 비교해 보시기 바랍니다.

    Code Listing 2: ROWNUM을 사용하지 않은 쿼리

    SELECT * FROM T ORDER BY ID
    call         count     cpu	elapsed   disk     query      current    rows
    --------     --------  -------  -------   -------  --------   --------   ------ 
    Parse         1        0.00     0.00        0        0        0           0
    Execute       2        0.00     0.00        0        0        0           0
    Fetch        10        0.35     0.40      155      949        6          10
    --------     --------  -------  -------   -------  --------   --------   ------ 
    total        13        0.36     0.40      155      949        6          10
    
    Rows                         Row          Source Operation
    -----------------            ---------------------------------------------------
    10                           SORT ORDER BY (cr=949 pr=155 pw=891 time=401610 us)
    100000                       TABLE ACCESS FULL T (cr=949 pr=0 pw=0 time=400060 us)
    
    Elapsed times include waiting for the following events:
    
    Event waited on                  Times
    ------------------------------   ------------
    direct path write temp           33
    direct path read temp             5
    

    결과가 완전히 다른 것을 확인하실 수 있습니다. "elapsed/CPU time"이 크게 증가했으며, 마지막 Row Source Operation 라인을 보면 그 이유를 이해할 수 있습니다. 정렬 작업은 디스크 상에서 수행되었으며, 물리적 쓰기(physical write) 작업이 "pw=891"회 발생했습니다. 또 다이렉트 경로를 통한 읽기/쓰기 작업이 발생했습니다. (10 개가 아닌) 100,000 개의 레코드가 디스크 상에서 정렬되었으며, 이로 인해 쿼리의 실행 시간과 런타임 리소스가 급증하였습니다.

    ROWNUM을 이용한 페이지네이션

    필자가 ROWNUM을 가장 즐겨 사용하는 대상이 바로 페이지네이션(pagination)입니다. 필자는 결과 셋의 로우 N 에서 로우 M까지를 가져오기 위해 ROWNUM을 사용합니다. 쿼리의 일반적인 형식이 아래와 같습니다.

    select * 
      from ( select /*+ FIRST_ROWS(n) */ 
      a.*, ROWNUM rnum 
          from ( your_query_goes_here, 
          with order by ) a 
          where ROWNUM <= 
          :MAX_ROW_TO_FETCH ) 
    where rnum  >= :MIN_ROW_TO_FETCH;
    
    where
    

    여기서,

    • FIRST_ROWS(N)는 옵티마이저에게 "나는 앞부분의 로우에만 관심이 있고, 그 중 N 개를 최대한 빨리 가져오기를 원한다"는 메시지를 전달하는 의미를 갖습니다.
    • :MAX_ROW_TO_FETCH는 결과 셋에서 가져올 마지막 로우로 설정됩니다. 결과 셋에서 50 번째 – 60 번째 로우만을 가져오려 한다면 이 값은 60이 됩니다.
    • :MIN_ROW_TO_FETCH는 결과 셋에서 가져올 첫 번째 로우로 설정됩니다. 결과 셋에서 50 번째 – 60 번째 로우만을 가져오려 한다면 이 값은 50이 됩니다.

    이 시나리오는 웹 브라우저를 통해 접속한 사용자가 검색을 마치고 그 결과를 기다리고 있는 상황을 가정하고 있습니다. 따라서 첫 번째 결과 페이지(그리고 이어서 두 번째, 세 번째 결과 페이지)를 최대한 빨리 반환해야 할 것입니다. 쿼리를 자세히 살펴 보면, (처음의 :MAX_ROW_TO_FETCH 로우를 반환하는) Top-N 쿼리가 사용되고 있으며, 따라서 위에서 설명한 최적화된 기능을 이용할 수 있음을 알 수 있습니다. 또 네트워크를 통해 클라이언트가 관심을 갖는 로우만을 반환하며, 조회 대상이 아닌 로우는 네트워크로 전송되지 않습니다.

    페이지네이션 쿼리를 사용할 때 주의할 점이 하나 있습니다. ORDER BY 구문은 유니크한 컬럼을 대상으로 적용되어야 합니다. 유니크하지 않은 컬럼 값을 대상으로 정렬을 수행해야 한다면 ORDER BY 조건에 별도의 조건을 추가해 주어야 합니다. 예를 들어 SALARY를 기준으로 100 개의 레코드를 정렬하는 상황에서 100 개의 레코드가 모두 동일한 SALARY 값을 갖는다면, 로우의 수를 20-25 개로 제한하는 것은 의미가 없을 것입니다. 여러 개의 중복된 ID 값을 갖는 작은 테이블을 예로 들어 설명해 보겠습니다.

    SQL> create table t
      2  as
      3  select mod(level,5) id, 
         trunc(dbms_random.value(1,100)) data 
      4    from dual
      5  connect by level <= 10000;
    Table created.
    

    ID 컬럼을 정렬한 후 148-150 번째 로우, 그리고 148–151 번째 로우를 쿼리해 보겠습니다.

    SQL> select *
      2    from
      3  (select a.*, rownum rnum
      4     from
      5  (select id, data
      6     from t
      7   order by id) a
      8   where rownum <= 150
      9  )
     10   where rnum >= 148;
    
     ID           DATA           RNUM
    -------       ----------     -----------
    0             38             148
    0             64             149
    0             53             150
    
    SQL>
    SQL> select *
      2    from
      3  (select a.*, rownum rnum
      4     from
      5  (select id, data
      6     from t
      7   order by id) a
      8   where rownum <= 151
      9  )
     10   where rnum >= 148;
    
     ID           DATA           RNUM
    -------       ----------     -----------
    0             59             148
    0             38             149
    0             64             150
    0             53             151
    

    로우 148의 경우 DATA=38의 결과가 반환되었습니다. 두 번째 쿼리에서는 DATA=59의 결과가 반환되었습니다. 두 가지 쿼리 모두 올바른 결과를 반환하고 있습니다. 쿼리는 데이터를 ID 기준으로 정렬한 후 앞부분의 147 개 로우를 버린 후 그 다음의 3 개 또는 4 개의 로우를 반환합니다. 하지만 ID에 중복값이 너무 많기 때문에, 쿼리는 항상 동일한 결과를 반환함을 보장할 수 없습니다. 이 문제를 해결하려면 ORDER BY 조건에 유니크한 값을 추가해 주어야 합니다. 위의 경우에는 ROWID를 사용하면 됩니다.

    SQL> select *
      2    from
      3  (select a.*, rownum rnum
      4     from
      5  (select id, data
      6     from t
      7   order by id, rowid) a
      8   where rownum <= 150
      9  )
     10   where rnum >= 148;
    
     ID           DATA           RNUM
    -------       ----------     -----------
    0             45             148
    0             99             149
    0             41             150
    
    SQL>
    SQL> select *
      2    from
      3  (select a.*, rownum rnum
      4     from
      5  (select id, data
      6     from t
      7   order by id, rowid) a
      8   where rownum <= 151
      9  )
     10   where rnum >= 148;
    
     ID           DATA           RNUM
    -------       ----------     -----------
    0             45             148
    0             99             149
    0             41             150
    0             45             151
    

    이제 쿼리를 반복 실행해도 동일한 결과를 보장할 수 있게 되었습니다. ROWID는 테이블 내에서 유니크한 값을 가집니다. 따라서 ORDER BY ID 조건과 ORDER BY ROWID 기준을 함께 사용함으로써 사용자가 기대한 순서대로 페이지네이션 쿼리의 결과를 확인할 수 있습니다.

    출처 : http://www.oracle.com/technology/global/kr/oramag/oracle/06-sep/o56asktom.html

    Posted by 서오석
    ,

    Struts2하고 Spring2.0하고 엮어서 presentation Layer를 Struts로 사용하고 Business Layer를 Spring으로 사용하려고 세팅을 하고 Action을 만든 후에 Action에서 Spring bean을 사용하려고 하면 아래와 같은 에러가 발생하는 경우가 있다. 

    에러 메시지
    이 에러를 고치는데 별 짓을 다 해보다가 결국 struts 설정에 에러가 있다는 걸 알았다.. ㅠㅠ(이틀을 날려버린..--;)

    우선 struts랑 spring이랑 붙이려면 라이브러리 파일이 하나 필요하다. (라이브러리가 struts2 버젼과 같아야 한다.)

    이 라이브러리를 추가해주고 나서

    struts.properties 안에 "struts.objectFactory" 활성화 해 준 후에

    struts.objectFactory = org.apache.struts2.spring.StrutsSpringObjectFactory

    이렇게 명시해준다. 이건 object를 스프링이 관리해주도록 하는 거이란다.

    그리고 중요한 것! 저 에러가나는 원인은

    struts.objectFactory.spring.autoWire = name   <- 이 부분 때문에 그렇다.

    저 autoWire를 name으로 설정해서 에러가 나는 것이다. 이걸 type으로 바꾸면 된다. 

    struts.objectFactory.spring.autoWire = type 

    으로 변경해주면 제대로 에러없이 돌아간다.

    이거 몰라서 개고생 했다..--;;
    Posted by 서오석
    ,

    컴퓨터를 사용하다보면 한 폴더안에 수십개의 폴더들이 들어있어서 자신이 찾고 싶은 폴더가 어디있는지 확 눈에 띄지 않아 헷갈릴 때가 많다.
    특히 비슷한 이름의 폴더들이 넘쳐나면 더욱 그렇다.

    이럴 때 사용하는 것이 바로 iColor Folder란 프로그램이다. 이 프로그램을 사용하면 아래와 같이 특정 폴더에 색상을 지정해 줄 수 있다.

    (Resource, Sun, Network Diagnostic 폴더를 다른 색으로 변경하였다.)

    주의: 본 프로그램은 XP에서만 제대로 실행된다. 윈도우 비스타의 경우 본 프로그램을 인스톨해서는 안된다.
    프로그램을 다운받을 수 있는 곳은 http://icolorfolder.sourceforge.net/ 이며 파일은 바로 받을 수 있도록 같이 올려 놓았다.
    첫번째 파일 iCF_142.exe 파일이 인스톨할 프로그램이고  iCF_skinpack_121.exe는 add-on으로 윈도우 기본 폴더를 다른 스킨으로 변경해준다.

    컴퓨터에 아직 익숙하지 않은 사용자를 위해 한단계씩 밟아보자.~!

    1. 우선 위의 프로그램을 다운받은 후 iCF_142.exe를 실행시키자.

    다운받은 iCF_142.exe를 더블클릭해서 실행시킨다.












    2.
    실행시키면 아래와 같이 인스톨할 때의 언어를 선택하라고 나온다.
    아래 OK 버튼을 누른다.
    (한글 언어는 지원하지 않는다.)













    3. 그럼 Welcome to the iColorFolder 1.4.2 Setup Wizard라고 나오는데 그냥 Next 버튼을 누른다.

    4. 약관 동의 페이지가 나온다. 본 프로그램은 프리웨어로 어디나 사용할 수 있다. 
       I Agree 버튼을 누른다.
























    5. iColor Folder 프로그램을 설치할 폴더를 선택하라고 나온다. 특별히 다른 곳에 인스톨 할 것이 아니라면 
       그냥 Next버튼을 누른다.


    6. 이제 변경할 스킨을 선택하라고 나온다. 기본으로 제공되는 스킨은 4개로 여기서 선택하는 스킨으로 폴더들이 변한다. 이건 나중에 Skin Selector로 변경이 가능하기 때문에 우선 그냥 Install 버튼을 누른다.



    7. 인스톨이 진행된 후 완료되면 Finish 버튼을 누른다.

    8. 이제 제대로 인스톨되었는지 확인을 해보자. 아무 폴더를 하나 선택한 후 마우스 오른쪽을 누르자.

    옆에 처럼 Color Label이란
    항목이 생기면 제대로 인스톨
    된 것이다.






























    9.
    마우스를 옆으로 이동시키면 폴더 색깔을 변경할 수 있는 항목들이 나온다. 기본적으로 7가지 색을 지원한다.


    목록 중에 자신이
    원하는 색을 선택한다.












    10.
    해당 폴더의 색상이 변경된 것을 확인할 수 있다.





    색상이 붉은색으로 변경되었다.






    자 그럼 이제 끝이냐.. 그게 아니다. 기본 프로그램만 인스톨하면 바탕화면의 폴더 이미지가 깨진다.



    옆에 바탕화면에 보면 폴더 주변이 하얀색으로 나오는 것을 볼 수 있다.
    이것은 폴더이미지를 제대로 만들지 않아서 생기는 문제이다. 이걸 변경해주려면 다른 폴더 스킨을 사용해야 한다.
     
    다른 폴더 스킨 적용법은 하단에 계속 설명해 나가겠다.

    (만약 배경화면 이미지의 색상이 흰색이라면 이런 문제가 발생하지 않는다.)








    Add-on Skin 설치하기


    에드온 Skin을 설치하는 방법은 위와 비슷하다. 그래서 설치하는 부분 중 다른 부분만 설명하도록 하겠다.

    1. iCF_skinpack_121.exe을 설치한다.

    2. 설치 도중 다음과 같은 화면이 나온다. 이것은 새로 추가하는 신규 폴더 스킨으로 자신이 원하는 스킨을
       선택하여 인스톨 할 수 있도록한다. 여러 스킨을 사용하기 위해 전부 선택하였다.

    3. 인스톨이 완료되면 시작->모든 프로그램 -> iColor Folder -> Skin Selector를 선택한다.

    4. Skin Selector에서 자신이 원하는 폴더 스킨을 선택한다.

    Generic folder icon(all sessions) 체크한다.

    자신이 원하는 폴더 스킨을 선택한 후 OK나 Apply를 누른다.

    바탕화면의 폴더 아이콘이 깨지지 않는 스킨은
    CrystalXP, Agua, icOSX, Mac OS X, Virtual Folder 4종류이다.

    이 스킨 외에 스킨은 폴더가 깔끔하지 않다.















    이상 폴더 색상을 변경할 수 있는 iColor Folder 프로그램을 알아보았다. ^^

    참고로 이 프로그램의 경우 GNU 서약을 한 프로그램이기도 하고 개발자가 소스를 오픈하여

    https://icolorfolder.svn.sourceforge.net/svnroot/icolorfolder/ 

    에서 SVN으로 다운받아 수정할 수 있도록 되어있다.

    iColorFolder의 바이러스 이야기



    Posted by 서오석
    ,

    이 문서들은 내가 예전에 소프트웨어 설계 프로젝트를 할 때 초안으로 만든 문서이다.

    프로젝트의 주제는 파일 관리 시스템을 만드는 것으로 시스템 구축에 필요한 요구사항 정의 및 설계까지가 목표였다.

    대략 내용들의 흐름이 잘 이어지지 않지만 프로젝트 수행 중 문서화에 대하여 익숙치 않은 분들을 위해 나름 대학을 다닐 때 만들었던 문서들을 공유하려고 이렇게 올린다. 문서의 목차만 봐도 소프트웨어 공학을 공부하는데 도움이 될 것이라 생각된다.
    (문서는 프로젝트 정의, 설계까지이고 구현한 구현물은 어따뒀는지 사라져 버렸다..--;; 문서 초안만 남아서 있는 것만 모아서 올린다..;;)

    아래 번호는 대략적인 순서에 맞게 작성한거라 프로젝트 진행에 순서가 다른 경우도 있다. 순서에 너무 신경쓰지 말 것!


    프로젝트 정의단계

    1.  Software Guide Line 
         프로젝트 수행을 위한 가이드라인을 제시한 문서이다.(코딩표준은 제외)

    2.  Software Project Management Plan 
        프로젝트가 수행되기 위한 각종 계획 및 기간을 설정한다. 수행 단계마다 나와야 하는 문서들도 정의하고
        시스템구축의 초기모형도 설정한다.
    3.  Software Requirement Specification (SRS)
         프로젝트가 시작이 되면 고객(Client)로부터 해당 프로젝트가 가져야할 다양한 기능들에 대하여 요구사항을
         뽑아내어야 한다. 이때 요구사항은 잘 정리해서 문서화해야만 설계 및 구현 단계에서 문제가 발생하지 않는다.
         요구사항정의서는 해당 내용이 방대한 경우 Sub 문서로 분류하기도 하는데 해당 문서의 경우 Glossary 및 상세
         요구사항정의서를 Sub 문서로 만들었고 간략한 유스케이스 기술서를 요구사항정의서에 포함시켰다. 
         본 문서는 EEE standard의 SRS 표준을 따르고 있다.
    4. Glossary
       SRS Sub의 문서로 문서에 사용되는 각종 단어를 정의한 문서이다. 단어사전 같은 것이다.

    5. Use Case Modeling 
       요구사항을 분석하여 해당 기능을 유스케이스로 나타낸다. 유스케이스는 starUML로 그렸고 규모가 작아서
       시퀀스 다이어그램을 포함 시켰다. 규모가 큰 프로젝트의 경우 시퀀스 다이어그램만 따로 빼내서 문서화 한다.
     
    프로젝트 설계 단계

    6. Architecture Specification 
       시스템이 구축되기 전에 시스템 전체의 구성을 정의한다. 서버 구성 및 Layer 구성들을 표기한다.
    7. Statement Designed
        상태다이어그램이라고 시퀀스 다이어그램을 그리면서 작성하는 문서가 있는데 파일이 초안도 안남아 있어서
        올리지는 못했다.;;

    8. Component Design
       요구사항에 따른 프로젝트의 세부 컴포넌트를 설계하는 단계이다.
       (문서에 있는 설계는 잘못 설계되었다..ㅡ.ㅡ;; 그냥 참고만 부탁..)
     
    10. Class Design
         실제 코드를 개발하기 위한 인터페이스를 기술하는 문서로 Java Doc과 같이 클래스와 메소드에 대한 주석들을
         모아놓은 문서라고 생각하면 쉬울 것 같다.

    11. Screen Design
        이건 UI 기술서인데 요구사항에 대한 스토리보드라고 생각하면 된다. 미리 프로토타입을 만드는 경우도 있고
        디자인만해서 개발의 UI를 가시화 시키려는 경우도 있다.
     
    12. DataBase Design
       말 그대로 데이터베이스를 기술한 문서이다. 물리설계 및 논리설계를 ERD로 표기하고 각 테이블에 대한 정보를
       기술한다. 그리고 해당 테이블이 어떤 유스케이스과 관계가 있는지(혹은 시퀀스와 관계가 있는지) 표기한다.


    대략 12개의 파일로 구성되었고 원래 잘 만들어진 소프트웨어 프로젝트는 각 프로젝트 문서가 서로 연결이 되어야 한다. 즉 설계 문서를 보다가 해당 내용이 어디서 나온 건지 모르면 요구사항 정의 문서에서 찾을 수 있게 되어 있어야 하는 것이다. 문서화의 목적이 프로젝트 수행에 이루어지는 다양한 변화를 반영하여 이를 문서화 하므로 후에 유지보수가 쉽도록 하기 위한 것이기 때문이다. 너무 어렵거나 난해한 말로만 기술하여 이해를 하는 사람이 적거나 결과물과 차이를 보인다면 그 문서는 어딘가 잘못된 것이다.
     위의 12개 문서의 경우 사실 연결관계가 잘 설정되지는 않았다. 해당 문서의 요구사항 코드 및 분류 번호가 제대로 들어가지 못했기 때문이다. 만약 이 글을 보는 유저는 충분히 저 문서들 보다 나은 문서를 만들 것이라 생각하며 마치겠다.  




     

     
    Posted by 서오석
    ,