'분류 전체보기'에 해당되는 글 140건

  1. 2009.03.26 예외 수집기
  2. 2009.03.26 아키텍트 vs 트러블슈터 vs 컨설턴트
  3. 2009.03.26 튜닝
  4. 2009.03.26 Framework - client cursor
  5. 2009.03.25 interface
  6. 2009.03.25 Nice game
  7. 2009.03.24 Framework - 커서의 선택 .. and
  8. 2009.03.23 멘탈 2
  9. 2009.03.23 프로시저 vs SQL
  10. 2009.03.20 AL - Code Example
Framework/예외처리2009. 3. 26. 23:29

이전의 처리를 통해 예외를 한군데로 모을 수 있었으면 이제 다음 단계의 예외 처리 프레임워크로 들어갈 준비가 된 것이다. 프레임워크를 만든다는 것은 어찌보면 왼쪽 그림을 오른쪽 그림으로 만드는 것에 불과하다.



언뜻보기에 클래스의 무작위적인 메시지 교환에서 추상적인 공통점을 찾아내고 이를 단계적인 체인으로 풀어내는 것이다. 이를테면 웹 프레임워크는 브라우저에서 서버 프로그램까지의 과정을 쪼개고 공통점을 묶어서 몇단계의 연결된 과정으로 바꾼다. 이러한 연결된 과정으로 바꾸는 과정에서 중간중간 오른쪽의 세모 그림처럼 request의 접합점을 담당하는 클래스가 생기는데 - 웹프레임워크의 경우 Controller가 이 역활을 한다 - 이 세모 부분의 역할에 따라 프레임워크의 질이 결정된다. 여기서 제 5계를 말할 수 있는데 클래스간의 복잡한 메시지 교환을 횡으로 단계를 가지도록 바꾸면 복잡성이 대폭 감소한다. 이 단계의 과정에서 접합점 역할을 하는 단계에 주의해라.

다시 예외 얘기로 돌아가서 우리는 앞의 글에서 모든 예외가 거쳐가게 되는확장포인트를 만들었다. 중간에 현명한 처리를 할 수 있는 일부 checked exception을 제외하고 마땅한 처리방법이 없는 다른 모든 checked exception 예외와 runtime exception을 하나의 접함점으로 모으면 로그 형식이나 알람 정도 말고도 다양하게 할수 있는게 생긴다.

보통의 프로그램에서는 예외가 생각보다 많이 발생한다. 순간적으로 DB 네트웍이 막혀서 접속이 안될 수도 있고 정기적인 다운타임을 기다리기 귀찮은 누군가 몰래 프로그램을 고칠 수도 있다. "이봐 예외가 발생하지 않는 프로그램을 만들어야지" 라고 주장할 수도 있겠지만 아무리 노력해도 테스트환경에서는 잡히지 않았던 예외들이 사용자의 이상야릇한 PC환경에서는 발생하고 이러한 예외들은 실험실에서 재현하기가 아주 어렵고 사실 사용자는 귀찮기 때문에 웬만한 예외가 발생해도 보고하는 확률은 높지 않다.

보통의 경우 예외 처리 방안은 1)로그에 남긴다. 2) 어드민에게 이메일등을 통해 알린다 정도가 있을 수 있는데 이러한 방법은 모두 후속 처리에 해당한다. 즉 실제 예외가 발생한 후 상당한 시간이 지난후에야 확인이 가능하거나 혹은 지겹게 날라오는 같은 메시지에 질려서 관리자가 무시해 버리기도 해서 대응될때까지 상당한 시간이 흐른다.

두번째로 생각해 봐야 할 점은 수백메가의 예외 로그는 대부분이 중복이라는 사실이다. 넷스케이프 5.0이 처음 나왔을때 버그 리포팅 기능을 생각해보자. 전 세계 1억 2천만명이 매일 날리는 버그 리포팅을 사람이 일일히 확인해서 대응할 수 있을리가 없다.

로그에 남기거나 어드민에게 알리는 방법의 단점은 이렇게 후속처리이며 동시에 대부분의 예외는 아마도 대부분 같은 종류일터인데 사람이 일일이 확인하는 것은 비효율적 이라는 사실이다. 이런 문제를 해결하기 위해 예외 처리 프레임워크는 3가지의 주요 기능을 가져야 한다.

1) 즉시 처리가 되야 한다. 이 말은 수동적인 로그 남기기가 아닌 적극적인 처리를 말한다. 자기 수정같은 거창한 이야기가 아니라 예외가 발생했을때 과거 비슷한 패턴의 예외의 해결방안을 제공하는 시나리오를 제공한다는 말이다. 예외가 발생했을때 "알수 없는 예외가 발생했습니다." 따위는 사용자에게 전혀 도움이 되지 않는다. 사용자가 알고 싶은 것은 첫번째는 "왜 이런게 발생했지"이고 두번째는 "이걸 피하려면 어떻게 해야하나"의 이 두가지이다. 이러기 위해서는 과거 예외 발생 정보와 처리 방안이 어딘가에 저장되어 있어야 한다는 것을 말한다.

2) 예외의 발생 빈도등을 체크하여 예외를 트리아지(Triage) 분류가 가능해야 한다. 보통의 솔류션 제품이 판매되면 1개월의 로그만 모아도 수백메가의 로그 파일이 남는다. 이 로그파일에서 예외 정보는 대부분 중복된 내용일테고 그걸 일일히 살펴보는 것은 시간낭비이기 때문에 사람의 분류의 이전에 프로그램이 예외가 발생한 클래스의 패키지, 예외의 종류, 발생 빈도 등을 고려하여 오류 등급을 미리 분류해 줄 수 있어야 한다.

3) 예외가 발생했을때 자동으로 관련정보를 묶어서 제공해줄 수 있어야 한다. 이는 고객을 위해서가 아니라 이를 수정해야 하는 프로그래머를 위한 정보를 말한다. 해당 예외의 종류가 이전에도 발생한 경우가 있는가? 그에 대한 대처는 어땠는가? 해당 클래스가 이전에도 다른 예외가 발생하지 않았나? 그렇다면 그 클래스의 마지막 수정자는 누구였는가 등의 정보를 같이 제공해 주어야 한다. 또한 현재 수집할수 있는 사용자의 환경과 동작시킨 기능 등도 물론 포함되어야 한다. 사용자의 PC환경은 매우 다양하기 때문에 가능한 많은 정보를 수집해두는게 좋다. 실제로는 어떤 빌어먹을 유틸리티들이 다른 프로세스 영역에 침범함으로 오류를 발생시키기도 하기 때문에 충분하지는 않겠지만 말이다.

이 분야에 대해 조엘의 책에 따르면 자동으로 다음과 같은 자료를 수집하는걸 권장한다.
- 제품의 정확한 버전
- 운영체제 버전과 브라우저 버전
- 예외가 발생한 파일명과 행번호
- 오류 메시지
- 어떤 작업을 하고 있었는지 사용자 설명
- 필요하다면 연락 가능한 사용자 정보


단순한 분류는 사람보다 컴퓨터가 월등히 뛰어나다는 장점을 잘 활용해서 이런 과정은 자동으로 이루어져야 한다. 현재의 대부분의 버그 관리 소프트웨어는 수동으로 이루어지는데 어쩔수 없이 사람이 판단의 개입되어야 하는 일부를 제외하고 자동화 시킬수 있는 부분은 아주 많다. (사실 이 자동 예외 처리기는 AL로 만들 첫번째 소프트웨어로 생각한 것이지만 작업기간이 맞지 않아서 따로 만들고 있다.)

'Framework > 예외처리' 카테고리의 다른 글

GUI TEST  (0) 2009.06.08
exception framework  (0) 2009.03.10
checked vs runtime  (0) 2009.03.07
checked exception의 문제  (0) 2009.02.09
예외 처리 격언  (2) 2009.02.09
Posted by bleujin
IT 이야기2009. 3. 26. 18:39

아키텍트

나는 아키텍트란 평범한 말을 하는 사람이라고 정의한다. 대부분의 아키텍쳐 책을 봐도 그렇다. 읽다가 졸리지 않는게 이상할 정도로 당연한 말과 평범한 이야기를 한다.

아이러니한건 아키텍트가 절실히 필요하다고 생각할때는 프로젝트가 아주 위급한 상황일때가 대부분이다. 사실 그때는 트러블슈팅 전문가를 찾아야 하지만 사람들은 아키텍트가 그러한 역할도 해줄수 있다고 생각한다.

아키텍트의 역할은 프로젝트를 위급한 상황으로 만들지 않으려는 사람이지 위급한 상황에서 구할 수 있는 사람은 아니다.

그렇기 때문에 만약 당신이 풀 포기를 잡고 절벽에 간신히 매달려 있을때

프로그래머 : 도와주세요~
아키텍트 : 일단 그 플포기는 당신의 질량을 감당할 수 없어요 당신의 질량과 현재 절벽의 각도, 바람의 세기를 고려하면 최소 굵기 10cm의 밧줄이 필요하죠.

프로그래머 : 저도 풀포기에 의존하고 싶진 않아요 밧줄 좀 주세요
아키텍트 : 아뇨 지금은 밧줄이 없어요. 밧줄은 당신이 등산을 오기전 준비를 했어야 합니다.

프로그래머 : 일단 머 붙잡을거라도 좀 내려 주세요
아키텍트 : 그전에 당신은 거길 왜 내려갔나요?

.. 라는 소리를 듣게 될것이다.

그런데 사람들은 평범한 걸 쉽다고 착각한다. 그렇다. 그건 착각이다. 좀더 정확하게 말하면 평범은 말하기는 무척 쉽지만 지키는 건 무척이나 어렵다.

일일 빌드를 하고, CVS를 사용하고, 명세서를 작성하고, 코드를 작성하기전에 유닛 테스트를 수행하며, 회귀 테스트가 가능해야 하며 테스트 팀의 분리와 .... 등등 모두 평범한 소리지만 이 평범한 것들을 지키는 개발조직은 거의 없다. 조금 생각해 보면 이는 당연한 일일지도 모른다. 누구나 건강이 중요하다고 하지만 건강을 위해서 하루에 4km를 걷고 45분 작업후 10분 정도 스트레칭으로 근육을 풀어주고 술과 담배는 하지 않으며, 정해진 시간에 균형있는 영양 섭취의 식사 등을 하는 사람을 발견하기 어려운 것과 같다.



트러블슈터

트러블슈터는 앞서 말했듯 아키텍트와는 다르다. 트러블슈터는 장애가 발생했을 때 아키텍트와는 반대로 짧은 시간안에 결과를 만들어 내야 하는 사람이다. 따라서 커뮤니케이션 능력이 중요한 아키텍트보다는 조금 더 독단적인 성격이 강하다.

트러블슈팅은 많은 장애 요인을 고려하고 넓은 각도에서 접근해야 하는 원인 분석과정과 해당 장애를 복구하는 2가지 과정으로 나눌 수 있는데 이 중 장애 복구는 true or false 성격이 강하기 때문에 주로 전문 기술직인 경우가 많다.

다만 와인버그의 이 말은 항상 기억해 두어야 한다.
"처음에 어떻게 보이든 문제는 항상 사람이다."




컨설턴트

자기도 할 줄 모르는(혹은 안해본) - 아마도 아무런 도움도 되지 않는 - 두꺼운 문서와 솔루션을 대책없이 제안하는 컨설턴트가 아주 많기 때문에 컨설턴트에 대한 조롱섞인 유머는 아주 많지만 잘 알려진 유머는 아래의 글이다.


어느 마을에 목장을 운영하는 사람이 있었다.
어느날 정장을 잘 차려입은 한 신사가 마을에 나타나서 목장 주인에게 찾아가 다음과 같이 말했다.

"내가 당신 목장에 있는 소 숫자를 정확히 맞추면 당신 소 한마리를 가져가겠소"
목장 주인인 "알겠소. 그럼 한번 해보시오." 라고 하였다.

이윽고 셈을 마친 신사는 목장 주인에게 "당신 목장에 있는 소는 총 XX마리요." 라고 했고
목장 주인은 "당신 정말 대단하오. 정확히 맞추었소. 자, 소는 여기 있소." 라고 말하였다.

그러자 신사는 "그럼 잘 있으시오. 난 이만 가보겠소." 라며가려고 하는데
목장 주인이 신사를 부르며
"신사양반. 잠깐만 멈추어보시오. 내가 당신의 직업을 맞추어 보겠소. 만약 맞추면 그 소를 도로 놓고 가시오" 라고 했다.

신사도 동의하였고 목장주인은 말하기를 "당신 직업은 컨설턴트요." 라고 말했고
신사는 "정확히 맞추었소. 자, 소는 여기있소. 근데 어떻게 알았소?" 라고 물었다.


그러자 목장주인은 다음과 같이 말하였다.

"나는 3가지 점을 통해 당신의 직업이 컨설턴트인지 알았소.
첫째는, 당신은 부르지도 않았는데 나타났다는 점이오.
둘째는, 당신은 내가 알고 있는 것을 알려준다는 점이오. 목장 주인인 내가 기르는 동물 숫자도 모르겠소?
셋째는, 당신은 틀린 것을 알려준다는 점이오. 내가 기르고 있는 것은 소가 아니라 염소요."

그밖에도 "지금이 몇 시인가요?"하고 묻자 "당신 시계를 주시면 내가 몇 시인지 알려주겠소"라고 답하면 컨설턴트인지 알수 있다는 유머도 있다.

컨설턴트라는 직업은 많은 사람들에게 인기를 끌고 있다. 직업 자체에서 풍기는 전문적 이미지와 폭 넓은 관점에서 문제를 조망하면서 조직에 대한 조언을 하는 업의 속성이 매력적으로 보이는 것 같다. 이런 인기에도 불구하고 정작 컨설팅을 받아 본 사람들이 느끼는 가치는 편차가 심한 것 같다.

조금 냉소적으로 정의한다면 일종의 외부에서 데려온 아키텍트로, 평범한 것을 평범하게 말하는 아키텍트와는 달리 평범한 것을 어렵게 말 할수 있는 재주를 가진 사람이다. 악의적으로 들렸을지도 모르지만 사실 개인적으로는 컨설턴트를 좋아하고 컨설팅은 사고의 다른점을 볼 수 있다는 점에서 아주 흥미있다.

IT 컨설턴트로 잘 알려진 Weinberg의 "컨설팅의 비밀"이나 Peter Block의 "완벽한 컨설팅" 책에는 복잡한것을 간단하게 혹은 우아하게 말하는 재능있는 컨설턴트와 번쩍이는 위트의 말들을 볼 수 있다.

'IT 이야기' 카테고리의 다른 글

아키텍트의 역할  (0) 2012.06.19
다시 성능  (0) 2009.04.02
튜닝  (0) 2009.03.26
interface  (0) 2009.03.25
Nice game  (0) 2009.03.25
Posted by bleujin
IT 이야기2009. 3. 26. 00:39


아래글은 그러니까 2003년에 작성한 글인데 지금와서 다시 읽어봐도 새롭다-ㅅ-. 이 글은 너무 길기 때문에 첫번째 조언과 첫번째 행동강령만 읽어도 충분.

이 글의 첫번째 조언에 따르면 이전글의 클라이언트 모델이 서버 커서모델보다 빠르다라는 주장은 아무 쓰잘데기가 없다. 빠르다라는 근거가 메카니즘이고 또 얼마나 빠르다라는 수치를 제공하고 있지 않기 때문이다. 약간의 테스트와 체감으로 수치화 할수는 없고 대략이라고 밖에 말할 수 없을정도로 환경이 다양하다는 이유도 있지만 사실 클라이언트 커서 모델은 단순히 빠르다라는 이유로 선택한 모델이 아니라 구조의 중복을 없애고자 선택하였기 때문이다. 

뒷부분의 행동강령의 첫번째 조언은 기준이 있어야 한다 인데 최근에 로그 분석 프로그램을 만들고 있는 지인으로부터 질문때문에 다시 생각났다. 로그의 특성상 하루에 수십만개 이상의 데이타가 쌓이는데 다양한 시나리오에서 실시간 분석이 가능한 적절한 모델에 대한 질문이었는데 사실 이러한 질문은 우문에 가깝다. 프로그래머라면 자신이 사용하고 잇는 환경에서 10만건 풀스캔과 100만 풀스캔 그리고 1억건의 풀스캔 속도를 알고 있어야 하고 이러한 근거가 있다면 현재 자신이 사용하는 방식의 문제점과 한계점 그리고 이를 극복하기 위한 방안은 이미 명약관화하기 때문이다.


-------------- 이하.

개발자의 대부분은 프로젝트 수행에 있어 성능과 견고성에 많은 관심을 가지고 있습니다. 운 좋게도 이러한 걸 하기 위해 많은 훌륭한 제안이나 권고사항이 책이나 인터넷등에 있습니다. DB 혹은 네트웍 혹은 언어별 관련된 많은 관련사이트와 책들이 있으며 약간의 시간과 비용을 들인다면 감당해내지 못할 정도의 많은 내용을 얻을 수 있습니다.
그러나 아쉽게도 많은 개발자들은 튜닝에 대해 환상을 가지고 있는 듯 합니다. 그동안 튜닝은 오랫동안 시스템 개발을 해왔고 경험도 많은 소위 "전문가" 들의 영역으로 알려져 왔기 때문에 그러한 내용들은 마치 진리인양 위장되기 일쑤입니다. 그렇지만 상당히 많이 알려진 튜닝기법들이 어떤 이론적인 메커니즘에 근거하고 있는 경우가 많으며 전달과정에서 여러가지 오해와 소문의 의해 부풀려진 경우가 많습니다.

 

비록 전문가는 아니지만 제가 하는 튜닝에 대해 첫 번째의 조언은 튜닝에 있어 가장 중요한 것은 성능이 아니라 "얼마만큼"의 성능인가라는 점입니다.


튜닝을 2가지로 나눈다면 첫째로 튜닝을 함으로 무조건 이득을 얻는 경우입니다. 하지만 그 경우의 수는 사실상 많지 않고 이는 사실상 튜닝이라기 보다 어느 하나의 원칙이라고 불려져야 마땅한 경우입니다. 개발자들이 알지 못해서 혹은 잊어버려서 아니면 개발자들의 공통적인 특성인 단지 게을러서 라는 이유로 적용하지 못했을 뿐인 아주 단순한 경우가 대부분입니다. 이를테면 다수사용자의 릴리즈 프로그램에서는 동적 SQL 대신 프로시저를 사용하라는 것은 사실상 원칙입니다. 그 밖에도 이러한 예제는 주로 하드웨어적인 튜닝이나 설정에 관련된 경우가 많습니다.

튜닝에 있어서 두 번째 경우인 대부분의 튜닝이란 무언가를 잃는 대신 그 이상의 효과를 얻는 것입니다. 그렇기 때문에 튜닝을 함에 있어서 가장 중요한 점은 이걸 함으로써 빨라지느냐 혹은 느려지느냐가 아닙니다. 중요한 것은 "얼마"만큼 빨라지느냐? 혹은 "얼마"만큼의 손실을 감수해야 하는가의 그 "얼마"입니다.

예를 들어 '이런 방법을 쓰면 빨라진다더라'는 사실상 전혀 의미가 없습니다. 이런 환경에서 이런 기법을 쓰면 12% 빨라진다 라는 테스트와 양적인 수치가 없으면 이게 과연 가독성 혹은 유지보수에 있어서의 어려움을 포기하면서까지 고려의 가치가 있는지를 판단할 수가 없습니다. 얼마전 어떤 책을 보니 ASP에서 성능을 이유로 주석을 가능한 자제하라라는 구절을 보았습니다. 사실상 이 말은 전혀 도움이 안되는 말일뿐더러 어떤 의미에서는 오히려 나쁜 영향을 줄수도 있습니다. HTML의 주석이 아닌 ASP의 주석은 클라이언트에게 다운로드 되지 않습니다 다음은 이전의 외국 사이트에서 발표된 테스트 결과입니다. 테스트를 위해서 각라인에다 "-" 글자를 80개씩 총 20라인 1600char의 주석을 첨가했습니다.

Benchmark = 5.57 msec/page(주석을 넣지 않았을때)
Response Time = 5.58 msec/page(주석을 넣었을때)
Difference = +0.01 msec (increase 0.1%)

결과는 꽤 주목할만 합니다. 즉 주석을 첨가하는 것은 HTML과 달리 거의 영향을 미치지 않는다는 겁니다. 파일 사이즈는 거의 2배 이상으로 늘어났는데도 불구하고 성능저조는 단지 0.1%에 불과합니다. 사실상 여기서 주목해야 할 것은 느려졌다 빨라졌다가 아닙니다. 얼마만큼 이냐가 중요합니다. 성능을 이유로 주석을 포기 혹은 가능한 자제해야 하는가를 판단하기 위해서는 이 0.1%라는 수치가 중요합니다. 수치가 나오지 않은 튜닝은 사실상 판단에 전혀 도움이 되지 않습니다. 우리는 튜닝에 있어서 가독성 이라든지 간결성 유지 보수성 등의 비수치적 영향도 고려해야 하는데 그러기 위해서는 수량적으로 판단할수 있는 것은 양적인 결과로 이끌어 낼수 있어야 합니다. 우리는 신학을 하는게 아니라 공학을 하고 있기 때문입니다.

 


튜닝에 관련된 두 번째 조언은 직접적인 테스트에 의한 결과가 아닌 단순 메카니즘의 원리에 의한 분석은 믿지 말아라입니다. 많이 알려진 오해의 예를 하나 들어보면 ASP에서 VB Script는 인터프리터 방식으로 실행되므로 컴파일되는 COM 프로그래밍으로 하는것보다 느리다. 라는 것입니다. 언뜻보면 컴파일된 컴이 빠르다는건 당연한 듯 보입니다. 최소한 NT4.0까지는 비교적 맞는 말이었습니다. 하지만 Window2000에 IIS5.0이 사용된 이후부터는 ASP 엔진과 스크립트 엔진의 발달로 오히려 반대의 결과를 내는 경우가 더 많아졌습니다. COM을 사용하는 이유가 단지 성능때문은 아니지만 주요한 이유중의 하나였던 성능은 꼭 그렇다고는 할수 없는 이유가 되어 버렸습니다. 사실상 아주 복잡한 함수등이 아니라면 오히려 더 높은 확률로 COM이 성능이 느렸습니다. 주로 COM 객체의 로드와 해제에 관련되어서 보다 많은 시간이 걸리기 때문이었습니다.

 

우리가 위에서 배울수 있는 세번째 교휸은 그러한 수치는 OS에 따라서 사용하는 언어에 따라서 심지어는 버전에 따라서 전혀 반대의 결과를 내기도 한다는 겁니다. IIS6이 나온지 얼마되지 않았고 아마도 5.0에서의 많은 사실들이 이전의 IIS4에서 IIS5에서 변동이 그랬듯이 IIS6에서는 다른 결과를 내리라 생각합니다. 즉 튜닝에 대한 3번째의 조언은 책을 믿지 말아라-_-입니다. 책이 발표된 시점과 그리고 책에서 사용하고 있는 환경과 지금 내가 사용하고 있는 환경은 다르며 이 차이는 전혀 다른 결론을 이끌어 낼수 있는 정도의 차이입니다. 지구상에 수만 이상의 수많은 직업이 있지만 경험이 별로 도움이 되지 않은 몇 개의 직업을 꼽으라면 그중의 하나는 IT 관련 직업이 꽤 많은 비중을 차지하리라 생각합니다. 경험은 때대로 독이되며 판단에 있어서의 장애요인이 됩니다. 아마도 튜닝에 있어서의 경험으로부터 배울수 있는 확실한 한가지는 이전의 경험은 별로 도움이 되지 않는다는 유연한 사고방식 정도(?) 일것입니다.

 

튜닝에 관련된 네 번째 조언은 잘못된 테스트는 잘못된 결과를 이끌어 낼수 있다입니다. 3번째의 책을 믿지 말아라-_-라는 것과 약간의 관련이 있는데 아마도 대부분의 책에서는 ADO.NET에서 Reader객체가 DataSet객체보다 읽기 성능이 좋다라고 하며 읽기 전용 페이지나 모듈에서는 가능한 Reader 객체를 쓸 것을 권하고 있습니다. C#강좌란에 ADO.NET의 황당함을 올리고 나서 이런저런 테스트를 해보고 나서 이것은 사실상 전혀 의미가 없다는걸 말하고 싶습니다. C# 강좌란에 올렸다시피 Reader와 DataSet의 I/O양은 같고 그렇다면 DB에서의 I/O가 미치는 전체 성능에서의 퍼센테이지를 감안한다면 그 어떤 다른 추가 메커니즘이 결합되었다 하더라도 1% 이하라고 결론지었습니다. 우리나라에서 발간 혹은 번역된 책 그리고 얼마전 본 외국잡지에서 이 두가지 성능을 비교한 결과를 본적이 있는데 500row 까지는 거의 차이가 없다가 1000행쯤 될 때쯤 의미있는 차이(1.5배 정도의)가 생기는 그래프를 보여주며 읽기전용에서 Reade를 쓰라는 권고를 읽은 적이 있는데 이 테스트는 방법에 있어서의 문제를 가지고 있습니다. 정상적이고 튜닝이 잘된 사이트 혹은 모듈이라면 천행을 리턴하는 것 자체에 문제가 있기 때문입니다. 온라인환경에서라면 99.9% 천행이상을 한꺼번에 보지 않고 일정단위의 페이지로 보게 됩니다. 설사 DB에서 천만행을 읽어 집계를 내더라도 그 반환결과는 천행 이상을 리턴한다는 개념 자체가 잘못된 것이며 잘된 시스템이라면 한모듈에서 500개 이상의 로우를 리턴받지 않는게 정상입니다. 즉 테스트에 있어서 문제의 책임을 전혀 엉뚱한데로 돌리고 있는것에 불과하며 두 번째로 다중 사용자인 환경에서 Reader가 가지는 접속유지시간이 더 길다.에는 전혀 언급이 없기 때문에 현실적인 테스트라고 할수 없습니다.

 

튜닝에 있어서의 5번째 조언은 절대원칙을 믿지 마라입니다. 아래 글중의 어떤 글에서 Select a.* From a, b Where a.id = b.id and b.col='aaa'와 같은 쿼리보다는 Select * From a Where id in (select id From b Where col = 'aaa') 방식을 사용하라는 조언을 보았는데 이 2개의 쿼리는 결과는 같지만 사용에 있어서 어떤 것이 좋다라는 것은 말을 결코 할수 없는 각자의 역할을 가지고 있습니다. 이 두 쿼리가 어떤 차이와 역할을 가지고 있는가에 여기에 적기에는 너무 많고 게다가 종종 옵티마이저는 이 2개의 쿼리를 같은 방식(실행계획)으로 처리해버리곤 합니다. 만물의 모든 존재가 이유가 있다 하듯이 쿼리의 사용방식에도 하나의 존재 이유가 있습니다. 중요한건 그 존재이유를 알아 상황에 맞게 적절히 사용하는 것이지 우열을 따질수 있는 문제가 아닙니다. 앞에서 원칙이라고 말한 동적쿼리대신 프로시저를 사용하라는 것도 일부의 상황에서는 예외가 될 수 있습니다. SQL 7.0시절에는 동적 SQL이 프로시저보다 빠른 경우도 있었습니다. 실행계획과 관련하여 분포도와 관련된 문제인데 이야기하기에는 너무 길어지므로 역시 넘어가겠습니다. -_)

 


튜닝에 관련된 6번째 조언은 하나의 튜닝은 다른 하나이상의 결과에 영향을 미친다입니다. 대부분의 고급 개발자들이 조언하듯이 튜닝을 할 때는 하나씩 하고 각각의 테스트를 비교하라고 합니다. 튜닝에 있어서 가장 중요한 것 중의 하나는 중용 즉 균형감각입니다. 앞에서의 조언에서 말했다시피 튜닝은 기본적으로 Trade Off이며 단순히 튜닝에 있어서의 다른쪽의 성능 문제뿐 아니라 가독성, 유지보수, 설계, 안전 등의 상호 다른 요인과 밀접한 관련을 맺고 있기 때문에 조그만 지식을 추구하지 말고 전체적인 지혜의 관점에서 봐야 한다는 겁니다.

 

그렇다고 해서 튜닝에 관련된 책은 사기-_-니 읽지마라라든가 고려할 필요가 없다라는 것은 물론 아닙니다. 저 자신도 사실상 읽는 가장 많은 비중을 차지하는 도서가 설계에 관련된 책 다음으로 튜닝에 관련된 책이며 종종 튜닝에 관련된 책에서는 성능 그 자체보다도 코드 품질에 대한 지식을 얻기도 하기 때문입니다. 또한 자신이 그 많은 상황을 직접 테스트 하지 않고도 상대적으로 짧은 시간에 저자의 다른 많은 지식을 얻을수 있기 때문입니다. 단지 강조하고 싶은건 튜닝에 관련된 책들은 성경이 아니며 그 걸 스스로가 판단하여 적절히(무척 무책임한 말임에도 불구하고) 사용할수 있는 균형감각이라는 것입니다.

 

 

만약에 이쯤에서 이 글에 사용된 여러 가지 예의 진의여부가 의심나서 직접 테스트를 하고자 하는 맘이 들었다면 이 글의 의미를 제대로 읽은 것입니다.

 

제가 다니던 대학교 컴퓨터 동아리에서 한때 "잘~"이라는 말이 유행(?)을 탄적이 있었습니다.
"선배님, 이거 어떻게 하죠?"... "잘~... "
"야~ 너 이거 어떻게 해결하는지 아냐"... "잘~ "

질문은 모두 틀리지만 대답은 오직 한마디 '잘~' 이면 모두 통과였습니다. -_-


앞에서의 튜닝의 진실 혹은 거짓말 1을 요약하자면 세상만사를 의심하고-_- 적절히 '잘~' 사용하란 얘기입니다.

조언이란게 대부분 그렇듯 일주일에 70억 벌기 유머처럼 (일주일에 70억을 어떻게 버냐구요? 하루에 10억씩 벌면 됩니다. 쿨럭~ -_-) 문제의 요지를 교묘히(?) 피해가는 거죠..


그동안 믿고 있었던 성능에 관련한 Myth에 대해 그럴듯한 경고는 해 주지만 막상 튜닝을 해야겠다 하면 무얼 어떻게 해야 하는지 어디서부터 시작해야 하는지에 대한 현실적인 관점에서 앞글은 도움이 안되기 때문에 다음은 좀 구체적인 행동강령(?)을 적어보았습니다. 다음의 행동강령들은 이미 여러 양서에서 암시적이든 아니든 반복 강조된 내용이고 항목 단위로 명확히 쪼갤수 있다기보다 서로간에 긴밀한 관계로 묶여져 있습니다. 

 

1. 목표와 비교기준이 있어야 한다.
마라토너가 달리기위해서는 골인지점이 있어야 하고 줄을 맞추기 위해서는 기준이 있어야 합니다. 자신이 제대로 하고 있다는 것 혹은 잘못 했다는 것을 명확하게 일깨워 줄수 있는 비교기준이 있어야 한다는 겁니다. 쿠베르텡이 주장한 올림픽 표어 "빨리 더 빨리"는 튜닝에 있어서는 허망한 소리에 불과합니다. 예를 들어 사이트 개발에 관해서는 가장 잘 만들어진 사이트를 비교 기준으로 삼아야 합니다. 가장 잘 만들어진 사이트는 어디서 구할까요? 많은 경우 MS나 Sun은 예제사이트 이를테면 PetShop 같은 벤치마크용 샘플을 제공합니다. 그러한 것을 비교기준으로 삼고 현재의 컴퓨터에 설치를 해서 같은 하드웨어 사양에서 같은 - 최소한 비슷한 속력이 나는지 성능테스트 프로그램으로 테스트해봐야 합니다. 같은 의미로 성능이 좋은 사이트를 만들자.. 라는건 그냥 하는말이고-_- 현재의 사양에서 이 테스트 프로그램을 써서 순간 동시접속자 50명 기준으로 rps(Requests per Second)가 200이 나와야 하며 TTLB가 1초 이내여야 한다.. 는 등의 목표가 있어야 합니다.


물론 더 빠르다면 더할나위 없는거고-_- 느리다면 최소한 그 느린 이유를 객관적이며 공학적으로 증명해낼수 있어야 합니다. 그 느린이유가 정당하다면 괜찮지만 느린이유를 잘 모르겠다거나 애매하거나 스스로에게나 다른 이에게나 납득이 안된다면 자신이 잘못 하고 있는 겁니다. 같은 하드웨어 사양에 같은 조건으로 테스트를 하는 입장에서 펫샵도 10건을 가져와서 10건을 화면에 뿌려주는거고 자신이 만든것도 10건을 가져와서 10건을 뿌리는건데 몇배씩 느려질 이유가 없습니다.


그리고 이러한 성능에 관계된 목표들은 '개발을 시작하기 전'에 요구사항 명세서에 이미 정리되어 있어야 합니다. 우리나라의 클라이언트는 '고객이 OK할때까지~'의 막무가내의 인식을 가지고 있기 때문에 초기에 이걸 정의하고 그들을 이해시켜야 합니다. 물론 그러기 위해서는 프로그래머나 PM이 어느정도의 선이 적절한지에 대해 알고 있어야 합니다. 이를테면 무작정 그럴듯해 보인다 하여 비용에 대한 고려없이 '순간 동시사용자 500명을 지원'하겠다든가 '24시간 무정전 시스템을 만들겠다' 적어논다면 이후에 큰 낭패를 겪게 될것입니다.

 


2. 성능 테스트 하는 방법을 알자
앞글의 목표와 비교기준을 설정하기 위해서는 성능테스트를 할 줄 알아야 합니다. 최소한 사이트 개발자라면 MS WAST(MicroSoft Web Application Stress Tool)와 닷넷의 ACT(Application Center Test)등의 툴이나 랭귀지에서 제공하는 방법을 통해 간단한 성능테스트를 할줄 알아야 하니다. Java계열에는 JUnit(자바의 JUnit이나 닷넷의 NUnit 시리즈는 테스트 툴이라기 보담 TDD 툴로 분류하는게 적당하겠지만..)이나 HttpUnit등의 구루(Guru) 개발자들의 공개툴을 이용할수 있습니다. 이들 툴은 대부분 설명서가 영어로 되어 있다는것만 뺀다면 메모장을 다루는 만큼이나 쉽지만 잘 알지 못해서 혹은 시간에 쫓긴다는 이유를 들어 많이 사용되지 않는듯 합니다.

자신이 그러한 툴을 직접 만들수 있을만한 실력이 된다면야 사실 이 말을 할필요도 없고 그렇지 않다면 코드의 전후에 밀리초를 계산하는것보다 위에 언급된 툴을 사용해보길 권합니다. 보통 대부분의 성능테스트 툴은 버그의 존재에 대해서도 경고를 해주며 성능테스트는 한번 하고 그만인 것이 아니기 때문에 여러번 테스트를 해보면서 내가 고친부분으로 인해 어떠한 변화가 있는지에 대한 성능테스트 결과에 대한 리포트 관리등을 해주는 여러가지 유용한 기능을 가지고 있습니다.

예를 들어 새로이 customer_history.aspx를 만들어서 custId로 VICTE를 넘기는 /SampleWeb/customer_history.aspx?custId=VICTE Path를 테스트를 하여 등록할 당시에는 에러가 없었는데 자신이나 혹은 누군가가 모르고 잘못된 수정을 하여 500 에러가 발생하였다면(자신은 이런 에러가 발생하는지 모른 상태에서) 테스트를 시작하는 버튼을 눌러놓고 여유있게 커피를 마시는 동안에 성능테스트 툴은 해당페이지에 에러가 발생하였다고 자동으로 경고를 해줄 것입니다.

 

3. 균형감각
오에 겐자부로의 세븐틴이라는 소설의 주인공처럼 세상을 단순명료 이분법으로 구분하면 적과 아군을 구분하기 쉬우므로 자기 살기에는 편하고 행복할지 몰라도 프로그래머로서는 영 아니올시다입니다. 우리는 절대선, 절대방법의 '절대'가 존재하는 신들의 영역에 살고 있지 않습니다. 우리는 '캘리포니아에 나비가 날자 중국에 태풍이 일어나는 카오스의 세계'에 살고 있으며 프로그래머는 성능에 있어서 외줄을 타고 있는 삐에로처럼 쉴새없이 장대를 조정하며 균형을 유지해야 합니다.

하지만 이것이 한걸음 한걸음 걸을때마다 장대의 크기를 바꾸어야 한다는 의미는 아닙니다. 우리는 프로젝트에 대하여 빠른 코드와 테스트가 쉬운 코드, 또는 빠르지만 위험한 코드와 느리지만 안전한 코드 가운데 선택을 해야 할 상황에 직면했을때 어느쪽의 손을 들어줄것인가에 대한 스스로의 우선 순위를 가지고 있어야 합니다. 팀원의 다른 누군가가 자신이 작성한 코드에 대해 '좀더 빠른.. 혹은 좀더 그럴듯한..' 코드를 보여주며 이렇게 작성한 이유를 물었을때 "글쎄요, 그냥 그렇게 했는데요"라고 대답한다면 혹은 전날에 스타크래프트를 하느라 잠을 잘 못잔 이유로 코드의 형태가 변하거나 아침에 먹은 반찬의 종류에 따라 코드의 우선 순위가 바뀐다면 먼저 잠시 코딩을 멈추고 자신의 우선순위에 대해 정립할 필요가 있습니다.

 

 

4. 생각을 해라
흔히 개발자들끼리는 농당삼아 손가락이 생각을 한다는 표현을 씁니다-_- 그만큼 저를 포함한 많은 프로그래머들이 생각을 하지 않고 프로그램을 짭니다. 생각의 가장 많은 비중을 차지한다는게 "기억력"정도입니다. 95년 7월 27일날의 과거 판례날짜라든가 형법 12조 27항(그게 머냐구요? 저도 모릅니다 -_)을 용케도 기억하고 있는 검사나 변호사에게는 모르겠지만 프로그래머에게는 기억력이라는 건 그렇게 큰 도움이 안됩니다. 자바의 API만 봐도 최소한 그 두껍다는 헌법과 판례책을 모두 합친것보다도 많고 '소년 탐정 김전일'의 작가가 새로 연재하는 'Q 클래스'라는 만화의 소녀탐정의 순간기억능력을 가지지 않는 이상 이전의 그 모든것과 앞으로 나올 그 모든 것을 기억하기란 불가능합니다.

'망각은 신이 인간에게 내린 최고의 선물'이라는 말이 과연 프로그래머에게는 적당한지를 떠나서 그러한 것은 피할수가 없으며 그렇기에 우리는 기억력을 보조하기 위한 많은 책과 저장매체 그리고 정보의 바다라는 인터넷을 활용할수 밖에 없습니다. 이런 이유로 누가 얼마나 많은 함수를 기억하고 있느냐는 오픈북으로 시험을 보고 있는 학생들의 차이처럼 아주 작은 차이입니다.

다음의 5번항에서도 언급하듯이 깊이 있는 생각을 반복하게 되면 그것은 하나의 좋은 습관이 됩니다. 그리고 그 습관은 이후에 우리가 굳이 생각하지 않고도 무의식인 발휘가 가능하도록 해 줍니다. 예를 들어 패턴 카탈로그에 적힌 20-30가지의 객체 프로그래밍 패턴을 읽고 차근차근 이해하기는 어느정도 경험이 있는 프로그래머에게 그리 어려운 일이 아닙니다. 우리는 수십명의 괴한에 둘러싸인 무협지의 주인공이 무공을 펼치때 무의식적인 손짓 발짓 하나가 효과적인 공격과 방어가 되는 것처럼 생각하는 훈련을 토대로 한 무의식적인 적절한 패턴의 사용경지에 이르기 것은 무척이나 어려운 일이지만 그렇기 하기 위한 노력을 게을리 해서는 안됩니다. 소프트웨어 방법론의 전문가인 엘리스테어 코번은 커크 패트릭의 4단계 모델을 예로 들면서 다음과 같은 발전 단계를 이야기 하였습니다. 무의식적 무능력 -> 의식적 무능력 -> 의식적 능력 -> 무의식적 능력

 


5. 습관을 잘 들여라
바둑을 둘줄 아는분은 이해하겠지만 바둑을 잘 두기 위해서 기원에 반만년-_-을 출근해서 날마다 아저씨 바둑을 둔다해서 절대 늘지 않습니다. 고작 5-6급 정도의 어느 선에서 맴돌 뿐이죠 차라리 10년동안 프로대국의 기보를 복기하는게 더 도움이 됩니다. 늦게나마 프로에게 지도바둑을 배운다고 해도 초기 배웠던 '어설픈 기풍'을 버리기 위해서는 그 들였던 시간보다 몇배의 오랜 시간이 흘러야 가능하며 어떤이는 바둑에 있어서 초기교육은 그 사람의 평생에 걸쳐 영향을 미친다고 하기도 합니다.(바둑에 대해 잘 상상이 되지 않는다면 당구에 대해서 생각하셔도 됩니다.)

그러나 프로그래밍에 있어서 프로그래밍 9단에게서 조기교육으로 사사를 받는것은 바둑 9단에게서 사사를 받는 것보다 더욱 힘든 일입니다. 그들은 대부분 매우 바쁘며 그들에게 직접 교육을 받는 다는 것은 엄청나게 많은 비용이 들기 때문에 우리는 '좋은 책'과 '좋은 공부방법'에 대해서 생각해야 합니다.

예전에 Turbo C를 배울때 제가 선배에게 그렇게 배웠듯이 C를 배우고 있는 후배들에게 항상 하는 말은 기초문법을 익히고 난후 다른 따라하기식의 초보자용 책보다는 strcpy등의 C의 기본 라이브러리 함수를 분석해보라고 조언합니다. 좀더 여유가 있다면 자신이 먼저 그러한 함수를 짜보고 라이브러리와 비교해 보면서 무엇이 틀린가에 대해 고민해보라고 합니다. 내가 서른 다섯줄로 구현한 함수와 단 열두줄로 구현된 라이브러리 함수와 도대체 무슨 차이가 있는걸까에 오래 생각해서 자신의 코드를 작성할때 라이브러리 코드식의 흉내를 내 보라고 하였습니다. 그러한 초기에 배우는 작은 습관은 당시에 그들이 생각했던 차이보다 훨씬 더 많은 차이를 가져오게 됩니다. 우리는 '알고리즘'이라며 매우 거창한듯 말하지만 알고리즘이란 그렇게 거창하며 접근하기 어려운 것이 아닙니다. 좋은 예제를 통한 좋은 습관을 들이는 것이 자신의 알고리즘 능력을 향상시키는 지름길이며, 동시에 유일한 길입니다.

 

 

6. 집중할곳에 집중하자
많은 연구결과가 증명하듯이 빠레또의 2:8의 원칙은 튜닝에 있어서도 여전히 유효합니다. 2:8의 원칙은 사회학이나 경제학등의 여러학문에서 약간씩 번형되어 인용되지만 튜닝에 있어서의 2:8의 의미는 코드 전체량의 20%가 전체 성능의 80%를 차지한다로 주장되어집니다. 예를 들어 로그파일의 버틀넥(Bottle Neck)은 전체성능에 큰 영향을 미치기도 합니다. 우리가 매번 메인페이지의 중요성를 강조하는 이유는 불행하게도 모든 메소드와 페이지가 평등하지는 않다는 사실을 인정하면서 부터입니다. 물론 당신이 완전주의자라서 100% 완전 튜닝을 하지않고는 뒤통수가 근질근질해서 밤에 잠을 이루지 못한다고 말한다면 아마도 당신은 죽을때까지 잠을 이루지 못하리라고 생각합니다. 그러한 모든 것을 하기전에 사이트가 바뀌거나 기술이 바뀌거나 DB환경이나 OS가 바뀌거나 하기 때문입니다. 앞마당의 잔디를 모두 손톱깍기로 깍겠다는 생각은 경제적이지 못하며 그것을 제외하더라도 이미 현실성이 떨어집니다. 100% 완전 튜닝이란 '아무리 배부른 사람도 쌀 한톨은 더 먹을수 있다. 그러므로 사람은 무한대의 쌀을 먹을수 있다'라는 논리의 허구성처럼 존재할수 없는 것입니다.

저 같은 경우 사이트 제작시 성능에 집중하는 곳은 오직 2가지입니다. DB 커넥션 담당하는 부분과 DB의 SP입니다. 그 외를 제외한 모든부분에 있어서는 가독성과 유지보수성을 우선합니다.물론 그렇다고 해서 다른 부분에 있어서의 성능을 전혀 고려하지 않는다는 의미는 아닙니다. 우리는 성능과 간결성의 두마리 토끼를 잡을수 있는 효율적인 알고리즘을 사용할수도 있으며 효율적이며 유지보수성도 좋아지는 코드에 대해 연구할 필요가 있습니다. 본질적으로는 성능과 가독성 혹은 성능과 유지보수성은 흑백논리식의 그 시소의 양쪽 끝에 위치하는 관계가 아닙니다. 그러함에도 가끔 특정한 상황에서 서로의 가치가 충돌할때가 있으며 그럴때 저는 주로 가독성과 유지보수성 혹은 테스트 용이성의 손을 들어줍니다.

 


7. 성능보다 설계를 우선해라
일찌기 자바를 개발한 제임스 고슬링은 "시간은 우리편이다" 라고 말한적이 있습니다. 자바가 나온지 꽤 오랜시간이 지나고도 아직까지 기본 아키텍쳐에 있어서의 객체지향언어로서의 그 훌륭함을 유지하고 있는 이유는 성능보다는 아키텍쳐의 설계의 그 우선을 두었기 때문입니다. 초기의 굼뱅이속도-_-는 시간이 감에 따라 하드웨어의 발달, 통신속도의 발달, 그리고 자체적인 가상머신의 발달과 JIT 등의 도입으로 인해 상당히 많은 향상을 이루어 냈습니다. 특히나 서버관련 기술에 있어서의 자바는 사이트의 느린 속도에 대한 일차적인 책임의 멍에를 벗어나게 되었습니다. 만약에 고슬링이 초기의 그 느린속도에 질린 개발자들의 불평을 해결하고자 자바의 아키텍쳐를 번형해서 성능위주로 버전업이 되었다면 지금의 자바가 가지는 그 무게감은 아마도 없을 것입니다.

물론 자바야 몇년동안 발전해왔으니 그렇다 치고 프로젝트가 몇년동안 하드웨어 발전하길 기다릴수는 없겠지만 그래도 기본적으로 설계는 성능보다 우선합니다. 설계를 하는 가장 큰 이유는 우리가 프로젝트의 미래를 예측하기 위해서이지만 또한 이 뜻은 우리는 기본적으로 미래를 전부 다 예측할수 없다는 뜻이기도 합니다. 과거의 단방향적인 폭포수 방법론(WaterFall) 보다 Iteration Design이 보다 환영을 받는 것처럼 요구사항의 변동과 더불어 설계는 부분적으로 변할것이고 그 변화에 빠르고 적절하게 대응하기 위해서는 단순하며 가독성이 뛰어난 코드여야 합니다. 프로젝트 진행중에 성능에 대한 지나친 집착은 코드를 복잡하게 만들며 가독성이 어렵게 만들고 그로 인해 많은 처리하기 어려운 버그를 낳습니다. 요구된 기능이 모두 구현되고 알려진 모든 버그를 모두 잡고 난 이후에 오직 성능만이 문제일때 코드최적화 기법을 쓰십시요.

그러나 주의해야 할 또 하나의 사항은 DB 커넥션과 Query 최적화는 마지막에 해서는 안됩니다. DB에 관해서만은 단지 예제 몇십개의 데이타만을 입력한 상태에서 프로젝트를 진행한다거나 대충 짠 Query로 나중에 해야지라고 하는것은 큰 재앙을 초래할 것입니다. DB에는 현실과 비슷한 량의 샘플데이타를 입력하여 프로젝트를 진행해야 하며 쿼리 하나 하나에는 코드 이상의 많은 노력을 기울여야 합니다. DB커넥션은 성능이라고 보다 프레임웍의 문제이며 적절하지 못한 쿼리에 늦은 발견은 오히려 DB의 설계등에 영향을 미치며 이의 파급효과는 코드 몇줄 변경으로 해결되지 않기 때문입니다. 또한 SP로 제작된 DB Query는 가독성을 해치지 않으며 엄밀하게 Trade Off의 최적화가 아니기 때문입니다.


슬금... -_)

 

'IT 이야기' 카테고리의 다른 글

다시 성능  (0) 2009.04.02
아키텍트 vs 트러블슈터 vs 컨설턴트  (0) 2009.03.26
interface  (0) 2009.03.25
Nice game  (0) 2009.03.25
멘탈 2  (0) 2009.03.23
Posted by bleujin
Framework/Database2009. 3. 26. 00:11

앞글에서 이야기한바와 같이 서버커서 선택의 제 1조건은 결과셋의 크기와 결과 셋에서 정말 사용할 비율이다.
이중 결과셋의 크기는 정상인 사람이 인터페이스를 고민하였다면 문제되는 바가 아니고 보다 중요한 것은 결과셋에서 실제 사용할 - 화면에 뿌릴 - 비율이다.

그렇다면 이렇게 생각해보자. 만약 애초에 정확히 사용할 데이타만을 결과셋으로 선택할 수 있다면 - 그렇게 쿼리를 작성할 수 있다면 - 굳이 서버 커서를 사용할 필요가 있을까?
일단 ForwardOnly와 Anonymous 종류는 커서의 이동이 안되고
Static과 Anonymous는 네트워크의 패킷 통신이 비효율적이며 서버의 메모리 자원을 많이 소모한다.

그리고 서버 커서 모두 연결 정리 작업을 이후에 해줘야 하는 단점이 있다.



클라이언트 커서 모델은 위와 같이 커서정보가 클라이언트에 있는 모델을 말한다. (당연히 기존의 커서는 커서가 모두 서버에 위치하였다.)

1. 쿼리 실행을 요청한다.
2. 쿼리를 실행하여 모든 결과 셋을 클라이언트에게 전송한후 연결을 끊는다.
3. 자신의 메모리에 로드된 결과셋을 사용한다.

클라이언트 커서의 주요 장점은 2단계에 있다. 결과셋을 가능한 모아서 던지며 모두 전송한후 클라이언트와 연결을 끊을 수 있다. (실제로는 이 과정을 soft close라고 하는데 실제로 바로 끊는게 아니라 언제든 자동으로 끊어 질수 있는 단계라고 생각하면 된다. 바로 끊어버리지 않는 이유는 clob이나 text등의 lob 객체는 결과셋 전송시 같이 이루어지지 않고 다시 요청이 오면 앞의 inner connection을 재연결해서 실제 데이타를 가져와야 하기 때문이다. 모든 DB는 lob 데이타를 다루는데 이러한 address 방식을 사용하기 때문에 모델링시 신중하게 결정해야 한다. 만약 자신의 환경이 이런 lob 데이타를 하나의 결과셋에 많이 포함하는 특수한 구조라면 서버커서도 마찬가지이니 이에 해당하는 클라이언트 커서 모델을 별도로 고려해보는게 좋다.)

일단 전송이 완료되면 클라이언트에 있는 결과셋은 기존의 서버에 있던 결과셋의 일종의 복제이므로 커서의 컨트롤 방식은 같고 커서의 전후진과 absolute 이동이 가능하다는 장점이 있다. 또한 보통의 경우 메모리 자원이 많이 요구되는 DB의 메모리를 보다 절약할 수 있기 때문에 자원의 균형적인 사용에도 도움이 된다. 


이 방식의 유일한 단점은 앞서 말한바와 같이  정확히 사용할 데이타만을 결과셋으로 선택할 수 있는 SQL 쿼리 능력을 갖추는 일이다. 극한 성능을 위해 좀더 정확한 selection을 원한다면 쿼리가 좀 복잡하지만 만약 주로 앞부분의 데이타가 사용되는 페이징 인터페이스라면 단순히

(v_pageNo : 페이지 번호, v_listNum : 페이지당 리스트건수)
select columns
from
     (select columns, rownum rnum from table where condition and rownum <= v_pageNo * v_listNum ) base
where rnum between v_listNum * (v_pageNo - 1) + 1 and v_pageNo * v_listNum and rownum <= v_listNum

로 정도로 사용(만약 MSSQL이라면 TOP N 형식으로는 N을 동적으로 사용할 수 없기 때문에 Set rowcount 를 이용해야 한다. ) 해도 기존의 서버 커서모델보다는 빠르니 그다지 미리 걱정할 필요는 없다. (클라인언트 커서 방식일때 좀 더 빠른 이유는 네트워크의 효율적 전송과 다중 사용자 환경에서 DB 서버의 메모리를 더 작게 그리고 더 적은 시간동안 사용하기 때문이다. )

클라이언트 커서 모델은 어쩌면 낳설게 들릴지 모르지만 이전의 POJO방식의 인터페이스의 기본 바탕이 되는 모델이다. 다만 OR-Mapping 프레임워크나 EJB에서는 row 단위 억세스가 일어나기 때문에 클라이언트 커서의 장점이 거의 나타나지 않는다. 이 블로그의 DB Framework는 클라이언트 커서 모델을 기반으로한 DB Framework이기 때문에 결과셋인 Rows는 클라이언트 커서를 사용한다.  




'Framework > Database' 카테고리의 다른 글

DB Framework 2.0 Short Explain  (3) 2010.03.09
Framework Cursor (cursor in MySql)  (1) 2010.02.24
Framework - 커서의 선택 .. and  (0) 2009.03.24
프로시저 vs SQL  (0) 2009.03.23
Framework - 커서(Anonymous)  (0) 2009.03.19
Posted by bleujin
IT 이야기2009. 3. 25. 22:50


- 부장 : 이쪽은 필이라고 하네, 새로오게 된 법무담당 사외 이사네.
           필은 우리제품의 인터페이스를 더욱더 혼란스럽게 만들어서 고객들이 교육을 받기 위해 돈을 지불하도록 하는 일을 담당하게 될걸세

- Dilbert : 고의는 아니지만 이미 그러고 있는데요

- 부장 : 그렇지. 하지만 언제까지 운에 의존할 수는 없지 않나.



인터페이스는 일반적으로 시스템의 비기능적 요구사항에 속한다. 그래서 테스트와 더불어 프로젝트에 여유가 없을 경우 가장 먼저 제외되는 분야이다. 사실 대부분의 프로젝트에서 좋은 인터페이스란 무언인가에 대해 고민을 해본 경험조차 거의 없기 때문에 시간의 여유가 있더라도 무엇을 해야 할지 모르는 분야이기도 하다.


인터페이스에 관련하여 가장 추천할 말은 Eat your dog food 라는 격언이다. 프로그램을 만든 사람이 프로그램을 사용해보지 않으면 좋은 인터페이스에 대해 고민을 하지 않게 되므로 프로그래머와 기획자 디자이너 등 프로그램에 관여하는 모든 사람들은 자신이 만든 개밥을 매일 먹어봐야 한다.


좋은 인터페이스를 고민할때 두번째로 알아야 할 사실은 무조건 쉽게 만드는게 능사가 아니라는 사실이다. 비난도 많이 듣고 있긴 하지만 MS의 제품은 인터페이스에 관한한 가장 많은 고민을 하는 제품이다. 엑셀의 경우를 보면 초보자가 거의 쓸일 없는 메뉴가 거의 쓰지 않는 메뉴와 혼란스럽게 섞여 있다는게 비판의 주 요지이다. 이른바 80:20의 이론에 따라 자주 사용하는 20%의 메뉴만으로도 충분하지 않겠는가 라는 소리이다. 그럴듯해 보이지만 사실 20%는 엑셀을 사용하는 사람마다 다르기 때문에 어떤 기능이 20%인가에 대해 확실히 규정지울 수 없다는 문제를 가진다.


MS 제품의 인터페이스를 긍정하는 이유는 사용자의 분포에 맞는 인터페이스라고 생각하기 때문이다. 다시 엑셀의 예를 들자면 처음 엑셀을 다를때 지나치게 복잡해 보이는 엑셀의 메뉴와 어렵게 보이는 인터페이스들은 불편하기 짝이없다. 하지만 조금 더 시간이 지나고 좀더 익숙해지면 아 이런 인터페이스도 있었구나 진작 알았으면 편했을껄 이라는 소리를 슬슬 하게 되고 이런 단계를 거쳐 단축키와 매크로등을 사용하는 중급 사용자가 된다. 보통의 제품에서 일반적인 사용자의 분포는 아래 Unability의 역설의 노란 곡선처럼 입문자와 고급 사용자는 적고 중초급의 사용자의 수가 가장많지만 기능의 난이도는 반대로 중급용 기능이 적고 고급과 초급기능이 더 많다.


그래서 단지 쉬운 인터페이스 - 입문자만을 고려한 인터페이스는 초반에 접근하기에는 쉬울지 모르지만 이후 쉽지만 반복적인 인터페이스(쉽고 반복적이도 않는 인터페이스는 당연히 적극 고려해야 하지만 그런건 매우 어렵다.)에 질려하게 된다. 물론 모든 인터페이스를 어렵게 만들어서는 막 새로운 프로그램을 접하는 사람들을 쫓아내서도 안된다. 다만 다소 어려운 인터페이스일지라도 중급자용의 고급 기능을 할 수 잇는 부분은 꼭 필요하다는 얘기이다.


[그림 : Usabiliby의 역설]

'IT 이야기' 카테고리의 다른 글

아키텍트 vs 트러블슈터 vs 컨설턴트  (0) 2009.03.26
튜닝  (0) 2009.03.26
Nice game  (0) 2009.03.25
멘탈 2  (0) 2009.03.23
How vs Who  (0) 2009.03.16
Posted by bleujin
IT 이야기2009. 3. 25. 02:27

이웃의 Samurai-J라는 팀명 아래 뛰어난 팀원들의 자발적인 팀 합류와, 그리고 몇개월간의 준비등의 의욕적인 출발과는 달리 W-K프로젝트는 시작하기 전부터 위기였다.

지난해에 최고의 실적을 올린 PM은 명확히 거부 의사를 밝혔고
이전의 DeathMarch 였던 O-K프로젝트를 성공적으로 마쳤던 신임 스타PM도 부담감을 이유로 난색을 표함에 따라
공식적인 절차도 아니고 사무총장 친분을 앞세워 그넘의 '대의'라는 이유로 거의 떠맡다시피 억지로 맡게 된 PM 자리

CEO도 없는 어수선한 상황에서 충분한 지원은 기대하기 어려웠고 이전의 같이했던 스타 프로그래머들은 나름의 사정으로 모두 합류하기 어려운 상황, 중간관리자 선임에 대한 전권을 달라는 그의 소박한 조건은 되려 자신이 지목한 관리자들의 합류 거절로 무산되고 결국에는 누구나 그렇개 생각하는 한물 간 과거의 인물들로 중간관리자를 꾸려가야 했다.

대규모 프로젝트의 경험부족이 문제라고 생각되어 얼마전 회사와 감정 싸움등으로 나간 백모씨와 지난 1년간 쉬다시피한 김모군등을 반대와 우려속에서도 합류시키고 이전의 O-K 프로젝트의 신입 프로그래머를 위주로 팀을 꾸릴수 밖에 없었다.


옆 회사의 프로젝트들이 일사천리로 진행하고 있을때 해를 넘기면서 새 CEO로 지목되던 사람이 자신해서 물러나는 등의 혼잡스런 상황에서 주축이라고 생각했던 백모씨와 김모군 그리고 베테랑 프로그래머들중 몇몇이 마지막에 합류하지 못하는 등 최악으로 치닿고 상황

외로운 노PM은 묵묵히 자신이 그 모든 부담을 져가며 그다지 이익이 없음에도 자신의 요청에 응해준 팀원들과
"국가가 있고 야구가 있다"라는 촌스러운 말을 하면서 스스로의 말을 지키고자 보름의 짧은 일정동안 자신의 할일을 다했다.


사실 이런 Suicide Project가 제대로 굴러가는 확률은 너구리 라면에서 5개의 다시마 보기처럼 극히 희박하지만 팀원의 자발적인 노력으로 mission impossible project형으로 성격을 바꿀수 있었고, 진행중 예기치 못했던 성과에 환호도 있었고 실수에 대한 탄식도 있었지만 그럼에도 불구하고 최고의 성과를 이끌어넨 W-K 프로젝트 팀원들에게 한마디..

Nice Game....

'IT 이야기' 카테고리의 다른 글

튜닝  (0) 2009.03.26
interface  (0) 2009.03.25
멘탈 2  (0) 2009.03.23
How vs Who  (0) 2009.03.16
프로젝트의 예측  (0) 2009.03.12
Posted by bleujin
Framework/Database2009. 3. 24. 00:45

클라이어트 프로그램이 웹이라면 아마 Keyset이나 Dynamic 커서는 99.9%의 확률로 써야 할 경우가 없을 것이다. connectionl less한 웹에서 사실 동시성은 거의 의미가 없다. 사실 별도의 어드민 작업이 없다고 확신할 수 있다면 굳이 commited data만을 읽을 필요조차 없다.

따라서 대부분 사용하는 커서는 Forward Only, Static, Anonymous(가칭) 3가지이다. 프로그래머가 의도하든 의도하지 않았든 말이다.

Forward Only는 쿼리의 결과셋 모두가 클라이언트 프로그램에 필요할경우 사용하며, 셋을 유지하지 않아도 되고 네트워크 패킷도 여러 로우를 묶어서 던지기 때문에 효율적이다.

Stati은 쿼리의 결과셋 모두 혹은 대부분이 클라이언트에 필요할경우 사용하며, 셋을 임시 영역에 유지하는데 메모리 비용과 패킷수량이 많아지는 단점이 있지만 커서의 앞뒤 이동이 가능하다는 점이 장점이다.

Anonymous는 쿼리의 결과셋의 처음 일부만 필요할 경우 사용하며, 패킷 수량이 많아지는 단점이 있지만 부분범위 처리가 가능하다는 장점이 있다.


커서를 선택하는 일반적인 기준은 아래와 같다.
1. result Size : 결과 셋의 전체 사이즈가 크면 Static은 쓰지 않아야 한다.
2. result Size에서 필요한 Data의 비율 : 퀴리 결과에 비해 클라이언트 필요한 부분이 아주 일부분에 불과하다면 Anonymous 커서를 사용해야 한다.
3. 필요한 커서 행동 (스크롤링 여부, 업데이트 가능 여부) : 쿼리결과 대부분이 사용될경우 스크롤링이 필요없다면 ForwardOnly, 스크롤링이 필요하다면 Static을 고려해볼수 있다. 단 단순히 갯수만을 알고자 한다면 굳이 Static을 선택하지 않고 차라리 select count(*) 쿼리를 별도로 던지는게 더 빠를수도 있다.
4. 커서 자체의 속도(예컨데 open 시) : 커서 자체의 속도는 필요한 정보가 가장 적기 때문에Forward Only가 다른 방식보다 빠르다.
5. 다른 유저가 변경했을때의 변경의 visibility level : 앞에서 말했듯이 connection less 환경에서는 거의 의미가 없지만 특이 케이스일경우 고려해 볼 수 있다.


쿼리셋의 전체 혹은 일부만을 원하는지의 여부가 가장 결정적인 선택 기준이 된다. 만약 select의 결과가 단지 한개의 row이거나 small Set이고 전체 셋을 모두 사용할 것이라면 그냥 default 커서(Forward Only)을 사용한다. 그러나 만약 update가 가능해야 한다면  default커서는 사용할 수 없다. 디폴트 커서는 커서의 행의 수를 미리 알 수 없고 absolute 등의 이동도 불가능하다.

여기서는 상세하게 적지 않겠지만 다이나믹 커서는 내부의 임시 영역에 Set 형태를 만들지 않기 때문에 처음 몇개의 row만 사용한다면 스태틱이나 키셋 커서에 비해 빠를 수 있다. 단 조인을 사용하는 경우 다이나믹 커서는 락킹 처리 문제로 더 느려진다. 키셋이나 스태틱 커서만이 absolute fetch가 가능하다. 반면에 이 두 방식의 커서는 Set을 tempDB에서 build 하기 때문에 tempDB 사이즈에 영향을 받는다.
 
위 기준에 맞춰 커서의 종류를 선택하였으면 앞글에서 적었듯이 쿼리를 전체범위처리냐 부분범위처리냐에 맞게 바꿀수 잇는 능력이 필요하다.


.... 이게 커서의 끝이 아니다.

프레임워크를 개발하는 입장에서 본다면 위 방식은 심각한 문제가 있다. 커서를 사용하는 방식은 DB마다 상이하며 또 모든 DB가 이를 지원하지도 않는다. MSSQL의 경우처럼 어떤 커서를 선택하느냐에 따라 JDBC URL을 바꿔야 한다면 모든 프로그래머가 이를 기억하고 있을리가 없다. 게다가 2005ver에서는 또 다르다!. 프레임워크는 어려운걸 쉽게 만들수는 없더라도 복잡한걸 간결하게는 만들어줘야 하는데 설사 그게 성능등의 이유로 어쩔수 없다고 하여도 위의 선택기준은 지나치게 문제가 복잡해진다.

그래서 위의 커서를 이해하였다면 그 내용을 모두 잊어버려야 한다. 농담이 아니다. 위 커서방식들은 당신이 아주 전문가이고 개별적인 환경하에서의 특이한 케이스가 아니라면 쓸수가 없다. 물론 그렇다고 과거의 무지의 상태로 돌아가서 우연히 좋은 방식이 선택이 되기를 혹은 드라이버가 알아서 좋은걸 선택해주지 않을까 하며 기도하는 것도 방법은 아니다.


사실 앞에서 커서의 모든 종류를 얘기한 것이 아니다. 단지 "서버커서"의 모든 종류를 얘기했을 뿐이다. 서버커서는 앞의 PPT에서 보이듯이 커서 - 일종의 포인터 -가 DB 서버에 위치한다.

Client Cursor는 말 그대로 Cursor의 위치가 데이타베이스가 아닌 클라이언트에 위치하는 모델이다. 후에 좀더 자세히 설명하겠지만 초기의 데이타베이스는 서버 커서를 지원하지 않았고 프로그래머는 사용하는 언어로 DBMS 벤더가 제공하는 DB-Library 커서 함수들을 사용하여 각자 구현하여야만 했다.

이후 각 DBMS 업체가 Server Cursor를 제공함으로써 Client Cursor 모델 방식은 한동안 잊혀졌으나 최근의 인터넷 환경과 맞물려 다시 사용되고 있는 모델이다. Client Cursor는 결과셋 전체를 한꺼번에 클라이언트에게 전송하며 이후 서버와 연결과 무관하게 클라이언트는 커서를 동장시킬수 있다. 즉 데이타베이스는 일단 결과셋 모두를 클라이언트게 전송하면 더이상 클라이언트와 연결을 유지할 필요가 없고 이후 커서 동작은 모두 클라이언트에 버퍼링된 결과 셋에서 이루어지게 된다. 이는 인터넷의 Stateless 환경과 매우 잘 맞기 때문에 ADO.NET의 Reader나 DataSet 그리고 JDBC의 RowSet이 클라이언트 커서 모델을 사용한다. 현재는 Server Cursor가 더 많이 사용되고 있지만 앞으로 점점 더 Client 커서를 사용하는 경우가 많으리라 생각된다.

클라이언트 커서를 사용하기 위한 가장 중요한 서버 커서의 문제와 관련이 있다. 앞의 서버 커서는 쿼리의 결과셋의 크기와 실제 클라이언트가 사용하는 비율이 커서 선택의 제 1기준이었지만 클라이언트 커서는 쿼리의 결과셋 모두를 사용해야 의미가 있고(그렇지 않으면 Forward Only 커서의 문제점을 답습하게 된다.) 이는 달리 말해 페이징 처리등의 이유로 결과셋의 일부만 사용된다면 애초에 쿼리를 페이지 기반으로 수정해야 하고 할 수 있어야 한다.



이글과 다음 글들을 처음 생각했던 7년전에 올렸다면 어떻게 됐을까? 하고 가끔 생각한다. 그때에 나는 클라이언트 커서 방식이 앞으로 가장 효율적이기에 가장 널리 사용될것이라고 생각했지만 7년동안 내가 참여한 프로젝트들을 제외하면 사실 위와같은 방식을 사용하는 경우를 보지 못했다. (그렇다고 상황에 맞게 서버 커서를 적절하게 사용하는 경우도 못봤다.)

그렇기에 아마도 이글과 다음의 커서 글들은 사실이 아니다. 무슨 말이냐면 클라이언트 커서에 대한 이야기와 사용의 장점은 상대적이고 주관적이며 그리고 아마도 소수이다. common is not common 상식이 보편이 아닌것처럼 보편 또한 사실이 아니지만 우리는 흔히 보편이 사실이라고 생각한다. 대부분의 책이나 인터넷등에서 아예 커서에 대한 언급 자체가 거의 없다시피 하기 때문에 자체 실험 데이타를 제외하면 충분한 근거를 찾기가 어렵다. 그래서 아마도 이글들은 사실이 아니고 보편적이지 않다.

'Framework > Database' 카테고리의 다른 글

Framework Cursor (cursor in MySql)  (1) 2010.02.24
Framework - client cursor  (0) 2009.03.26
프로시저 vs SQL  (0) 2009.03.23
Framework - 커서(Anonymous)  (0) 2009.03.19
Framework - 커서(Keyset, Dynamic)  (0) 2009.03.13
Posted by bleujin
IT 이야기2009. 3. 23. 00:31

이승엽 "한국팀의 강한 정신력 믿고 있다"
http://www.viewsnnews.com/article/view.jsp?seq=48129

개인 능력의 열세를 한국 야구 특유의 조직력과 집중력으로 극복한다면 승산은 충분합니다.
http://news.kbs.co.kr/article/baseball/200903/20090322/1743921.html


웬지 이 두기사를 보고 궁금함이 들었다.
첫번째 기사는 그냥 읽었지만 두번째 기사는 웬지 모를 위화감이 들었다.


자발적 헌신과 정신력의 다른 뜻인 집중력과 의욕은 프로젝트에 꼭 필요한 정치요소이자, 프로젝트 관리자가 중점 관리해야 하는 팀 활력의 핵심 요소이다. 하지만 그렇다고 해서 프로젝트 관리자에게 직접적으로 "정신력을 발휘해봐" 라는 말을 듣는 건 그닥 유쾌한 기분이 들지 않는다. 특히 "요즘 팀원들의 정신력이 해이하다" 라고 듣는건 최악이다.


개인적으로 정신력 따위로 프로그래밍을 하는건 아니라고 생각한다. 오랫동안 나는 프로젝트에서 자신의 능력(그게 시간이든 지식이든간에)을 120% 발휘해야 하는게 아닌 80% 정도로 해야 한다고 생각해왔다. 사람이 집중력을 유지할 수 있는 시간은 그리 길지 않고 이 프로젝트가 끝나면 지구가 망하지 않는 이상 다음의 프로젝트나 혹은 지금 당장의 프로젝트를 위해서도 끊임없이 자신의 지식을 쌓고 자기 계발의 시간이 있어야 하기 때문이다. 결국 프로젝트를 성공시키기 위해서는 안정된 능력이 필요하다.


피플웨어에서 톰 디마르코는 개발자들은 대부분이 이미 동기 부여되어 있기 때문에 이런 이야기가 적절하지 않다고 한다.
 " 개발자는 스스로 동기부여할 수 없으며 프로젝트 관리자가 동기부여를 해주어야 한다는 생각만큼 작업자의 의욕을 꺽는 일은 없다. 프로젝트 관리자는 사람들이 얼마나 일을 열심히 하는지 일일이 평가할 필요가 거의 없다. 왜냐하면 그들은 대부분 자신의 일을 좋아하기 때문이다. "


프로그래머와 마찬가지로 소위 국대라고 불리는 스포츠 선수들도 마찬가지라고 생각하기 때문에 경기에 질때 흔히 나오는 정신력 부재 - 단순히 기사량을 채우는 의미 이상이 없는 - 등의 기사에 동의하지 않았다. 그러나 첫번째 기사에서 위화감이 들지 않았던 이유는 무엇일까 ?

그냥 "비를 드니 마당 쓸라 한다" 정도의 의미인걸까? 하루동안 생각하고 난뒤에야 그 미묘한 차이를 의식할 수 있게 되었다. 일단 어휘의 미묘한 차이와 ( "믿고 있다"와 "~면 할수 있다"의 차이) 말하는 사람의 다르면서 생기는 차이이다.


어쨌거나 프로젝트의 성공에 있어서 "긍정적인 자세"와  정신력 - 소위 집중력과 의욕-은 분명 효과가 있고 개발자의 자기 헌신도 필요하다. 하지만 결코 프로젝트 관리자가 입으로 이런걸 직접적으로 요구해서는 안되고 그렇지 않다고 비난하는 말은 더더욱 해서는 안된다. (그런점에서 최근의 MB의 긍정적 사고가 모자라서 그런다라는 말은 역효과만 불러 일으킨다.)


팀원이 충성심을 느끼고 헌신하려는 자세는 프로젝트 관리자의 구호가 아닌 미묘한 동기부여 능력에 많이 달려있다. 카리스마도 어느 정도 중요하다. 프로젝트에 어마어마한 위험이 도사리고 있다고 말해도 팀원들이 지구 끝까지라도 따라가겠다며 의욕을 보이는 경우도 있다. 그러나 무능력한 관리자 밑에서는 외계인으로부터 인류를 구하는 것이 프로젝트의 목표라고 하여도 팀원들은 노력하려고 애쓰지 않는다.



'IT 이야기' 카테고리의 다른 글

interface  (0) 2009.03.25
Nice game  (0) 2009.03.25
How vs Who  (0) 2009.03.16
프로젝트의 예측  (0) 2009.03.12
Scott Adams  (0) 2009.03.11
Posted by bleujin
Framework/Database2009. 3. 23. 00:29

이전 글에도 쓴적이 있지만 없다면 할 수 없겠지만 있다면 가능하면 이용하자는 주의여서 DB의 프로시저도 적극적으로 활용한다. 물론 DB의 다른 기능들도 마찬가지로 주의깊게 살펴보면서 가능하면 사용하려고 노력하는 편이다.

보통의 경우 프로시저라 함은 IF ELSE나 FOR 등의 구문이 섞여서, 절차형 패러다임의  SQL 스파게티로 오해하는 경향이 있는데 여기서는 그냥 간단한 SQL이 프로시저 형태로 저장되는 것으로 한정해서 말하기로 한다.

프로시저가 일반 SQL에 비해서 가지는 장점은 여러가지가 있다.

가장 대표적으로 성능의 경우 저장프로시저는 쿼리 실행계획을 메모리에 저장하여 저장된 실행계획을 사용하기 때문에 구문 분석이나 최적화 과정을 반복하지 않기 때문에 빠른 실행을 할수 있고 설사 캐시에 없더라도 표준화 등의 작업을 하지 않기에 좀더 빠르다. 이 차이는 쿼리의 전체 속도의 부분이기 때문에 상황에 따라 조금 다르긴 하지만 대부분의 OLTP에서의 0.1s 미만의 쿼리의 경우 체감적으로는 50-100% 정도의 차이가 있다. (일반 Statement의 SQL이라도 자주 실행되는 구문이라면 역시 마찬가지로 실행계획의 재사용이 되지만 조금 차이가 있다.)

그밖에도 긴양의 SQL이나 2번 보내는 대신 프로시저명만 보내면 되기 때문에 네트워크 전송속도에도 미묘한 향상이 있다.

두번째의 이유로는 보안이 강화된다는 장점이 있다. 저장 프로시저를 사용하면 특정 종류의 SQL 인젝션 공격(특히 AND나 OR등의 연산자를 사용해 유효한 입력 매개 변수 값에 명령을 추가하는 공격)을 저지할 수 있고 프로그램이 사용하는 로그인 아이디에 테이블등에 직접 권한을 주지않고 프로시저 실행권한만을 주는 간접적인 보안계층을 관리할 수 있으므로서 생기는 프로그램 손상가능성을 줄여주는 장점도 있다.

그밖에도 몇가지 세세한 장점에 대해 얘기할 수 있지만 이는 인터넷 조금만 찾아보면 나오는 얘기이니 대충 생략하기로 하자. 사실 나는 이러한 장점이 중요하다고 생각하지 않는다. 정치학의 기본적인 원리중 하나는 아무리 변화가 필요하고 중요하다는 이성적 확신이 있더라도 개인과 조직의 문화는 변화를 거부하기 때문에 이러한 이유로 프로시저를 사용하는 이유에 대한 동의를 이끌어내기 힘들다는걸 여러번 절감해 왔다.


개인적으로 프로시저의 진정한 장점은 위와 같은 수치적인 측면이 아니라 다른 점에 있다고 생각한다.

그 이유중 하나로 컴파일의 문제를 들 수 있다. 초등학생 시절 베이직 언어를 배웠던 시절을 생각해보면 1000라인 이상의 프로그램을 짜는게 무척 힘들었었다. 물론 실력이 미숙하기도 하고 베이직의 구조적 한계의 문제도 있겠지만 되돌아보면 베이직이 컴파일이 되지 않는 인터프리터인 이유도 컸다고 생각한다. 컴파일 과정이 없이 매번 실행시켜서 그닥 도움이 되지 않는 에러 메시지로 버그의 원인을 찾는 과정은 고통스러웠고 찾았을때 기쁘기도 했지만 지금 생각해보면 시간낭비에 가깝다.

프로그램의 String이 아니라 저장 프로시저 형태로 저장되었을때 이러한 단순한 코딩 실수 방지 뿐 아니라 보다 장기적인 유지보수적인 장점이 있다. DB의 스키마 등은 변경되지 않는 것이 이상적이지만 현실적으로는 프로그램의 생명주기동안 계속 변경이 발생한다. 컬럼 정보같은 변경(추가/삭제/수정) 변경이 발생했을때 프로시저는 의존관계를 훨씬 더 정확하게 확인할 수 있고 동시에 검사와 테스트가 가능하다는 장점이 있다. 그리고 일반적으로 저장 프로시저를 변경하는 방법이 코드의 수정, 테스트, 배포를 다시하는 것보다는 시간과 노력을 절약할 수 있다.


두번째의 잘 알려지지 않는 장점중의 하나는 추상화에 있다. 다른 글에도 언급한적이 있지만 나는 SQL 구문자체가 비즈니스 로직이라고 생각하지 않는다. (아주 복잡한 로직이 결합된 프로시저는 앞에서 제외한다고 말하였다.) 오히려 클라이언트 로직 입장에서 본다면 viewArticle이라는 프로시저명만으로 충분하지 세세한 SQL이나 어떤 테이블을 참조하는 지에 대한 정보는 오히려 번거롭기만 하다.

예컨데 위의 viewArticle의 경우 조회수의 증가와 해당 Article의 정보 2가지의 결합이다. 하지만 클라이언트 로직 입장에서 본다면 viewArticle의 세부 과정이 2단계이든 3단계이든 굳이 알 필요가 없다고 생각하고 그럴경우 update문 하나와 select 문을 하나 던지는 로직보다 그냥 viewArticle이라는 프로시저를 실행하면 된다고 생각하는게 도움이 된다. 즉 좀더 추상화를 잘 활용하게 된다.



위의 장점에도 불구하고 저장 프로시저의 단점이 있다면 숙련된 전문가가 필요하다는 점이다. 개발자가 프로시저를 숙련되게 사용할 수 있다면 더할 나위 없지만 그렇지 않다면 일방적으로 DBA에게 위임하는 것보다 차라리 교육을 통해 개발자가 관련 지식을 습득하는 방법이 낫다고 생각한다. A분야의 전문가와 B분야의 전문가 협력하는 식의 방법이 겉으로 보이기에는 멋져보일지 모르지만 실제 커뮤니케이션에는 대부분의 엔트로피 손실로 오랫동안 팀을 이룬게 아니라면 오히려 부정적이다.

'Framework > Database' 카테고리의 다른 글

Framework - client cursor  (0) 2009.03.26
Framework - 커서의 선택 .. and  (0) 2009.03.24
Framework - 커서(Anonymous)  (0) 2009.03.19
Framework - 커서(Keyset, Dynamic)  (0) 2009.03.13
Framework (Servant)  (0) 2009.03.12
Posted by bleujin
Framework/Another Lore2009. 3. 20. 14:06

AL의 간단한 코드 Samle을 보면 아래와 같다. 공지사항 Application을 만든다고 생각해보자. 웹이어도 상관없고 웹이 아니어도 상관없다. 가장 첫번째 해야 할일은 모델을 만드는 일이다. 이전에는 ERD를 그리고 - 종이에 그리든 마음속으로 그리든 - ERD에 맞춰 DB 테이블을 설계한다.

AL은 DB 테이블을 만들지 않고 오직 코드로 모델을 만든다. 기존의 OR-Mapping 툴과 달리 이미 존재하는 테이블과 매핑과정을 설정하는게 아니라 아예 테이블을 만들지 않는다. 실제로 구현되는 물리적 과정은 철저히 숨겨져 있다.


package com.bleujin.lore.impl.board.init;

import 생략

public class BoardInitializer implements INotice, IBoard, IComment{

  
  private AnotherLore lore ;
  private IGlobalPersistence globalPersistence ;
  public AnotherLore init() throws RepositoryException{
    lore = new AnotherLore() ;
    
    UserSession session = lore.login(new TestCredential("admin")"localhost";
    globalPersistence = session.getWorkspace().getGlobalPersistence() ;

    NodeType objectType = globalPersistence.createNodeType(NodeType.NO_SUPERTYPE, "_object"new PropertyDefinition[0]) ;
    Node root = session.createNode(Node.NO_PARENT, objectType, "/";
    Node anonymousRoot = session.createNode(root, objectType, "anonymous";

    
    // notice
    NodeType noticeBoardType = globalPersistence.createNodeType(objectType, "notice_board"new PropertyDefinition[0]) ;


    PropertyDefinition[] noticeProperties = new PropertyDefinition[]{
          createProperty(BOARDNO, PropertyType.LONG)
          createProperty(SUBJECT, PropertyType.STRING)
          createProperty(REGUSERID, PropertyType.STRING)
          createProperty(REGDATE, PropertyType.DATE)
          createProperty(CONTENT, PropertyType.STRING
        ;
    NodeType noticeType = globalPersistence.createNodeType(objectType, "notice", noticeProperties;

    noticeType.addPropertyConstraint(BOARDNO, new NumberConstraint()) ;
    noticeType.addPropertyConstraint(SUBJECT, new AndConstraint(new RequireConstraint()new UnderByteLengthConstraint(200))) ;
    noticeType.addPropertyConstraint(REGUSERID, new RequireConstraint()) ;
    noticeType.addPropertyConstraint(REGDATE, new RequireConstraint()) ;

    noticeBoardType.setMemberType(noticeType;

    
    Node noticeBoardRootNode = session.createNode(root, noticeBoardType, "noticeboard";
    
    session.save() ;
    session.logout() ;
    return lore ;
  }
  
  private PropertyDefinition createProperty(String pid, int requireTypethrows RepositoryException {
      return globalPersistence.createPropertyDefinition(pid, requireType);
    }

}



공지사항 그자체도 컨텐트 - 즉 Node - 이고 공지사항에 올려지는 글들도 컨텐트 이기 때문에 2가지의 타입이 필요하다.

globalPersistence.createNodeType(objectType, "notice_board"new PropertyDefinition[0]) ;
먼저 noticeBoardType(공지사항게시판타입)을 만든다.
공지사항은 특별한 속성을 가지지 않아도 상관없어서 속성타입을 정의하지 않았다. 만약 공지사항마다 인삿말이 필요하다거나 StyleSheet를 정의해야 한다면 공지사항도 속성타입을 가질 수 있지만 위 예제는 가장 간단한 예제이므로 생략한다.

noticeProperties = new PropertyDefinition[]{.... }
속성타입을 만든다. Table의 Column과 비슷한 것이라고 생각하면 된다. 5개의 속성타입을 정의했고

noticeType = globalPersistence.createNodeType(objectType, "notice", noticeProperties;
5가지 속성을 가진 공지사항글타입을 만든다. DB에 비교하자면 테이블 그 자체이다.

noticeType.addPropertyConstraint(BOARDNO, new NumberConstraint()) ;
공지사항글타입에 Constraint를 정의한다.

noticeBoardType.setMemberType(noticeType;
공지시항타입의 멤버타입으로 공지사항글타입을 지정했다. memberType은 이미 정의된 LinkType중 하나로 공지사항타입은 공지사항글타입이나 하위 타입만을 멤버로 가질수 있게 된다.

위 코드는 타입을 만드는 과정이므로 실제로는 수명중 단 한번만 실행된다. 재시작해도 재실행되지 않아야 한다.


실제 글을 등록하고 보는 과정은 간단하다. 

private void listPage(HttpServletRequest request, NoticeForm formthrows RepositoryException {
    UserSession session = getUserSession() ;
    Node noticeBoard = session.getNode("/noticeboard";
    request.setAttribute(LIST, noticeBoard.getChildNode()) ;
    
    form.setRowCount((int)noticeBoard.getChildNode().getSize()) ;
    }
<List>

 private void addNotice(HttpServletRequest request, NoticeForm formthrows RepositoryException{
    UserSession session = getUserSession() ;
    Node noticeBoard = session.getNode("/noticeboard";
    NodeType noticeType = getNodeType("notice");

    Node article = session.createNode(noticeBoard, noticeType, form.getSubject()) ;
    article.setProperty(BOARDNO, noticeBoard.getChildNode().getSize()+1;
    article.setProperty(SUBJECT, form.getSubject()) ;
    article.setProperty(REGUSERID, session.getUserId()) ;
    Calendar current = Calendar.getInstance() ;
    current.setTime(new Date()) ;
    article.setProperty(REGDATE, current;
    article.setProperty(CONTENT, form.getContent()) ;
    
    session.save() ;
    }

<Add>

private void delNotice(HttpServletRequest request, NoticeForm formthrows RepositoryException {
    Node node = getUserSession().getNodeByUUID(form.getUUID());
      node.delNode() ;
      getUserSession().save() ;
    }
<Del>

private void editNotice(HttpServletRequest request, NoticeForm formthrows RepositoryException {
    Node node = getUserSession().getNodeByUUID(form.getUUID());
    node.setProperty(SUBJECT, form.getSubject()) ;
    node.setProperty(CONTENT, form.getContent()) ;

    getUserSession().save() ;
    }

<Edit>

private 
void viewPage(HttpServletRequest request, NoticeForm formthrows IOException, RepositoryException {
    Node node = getUserSession().getNodeByUUID(form.getUUID());
    node.getBean().increaseViewCount() ;
    getUserSession().save() ;
    
    NodeHandler handler = new NodeHandler() ;
    handler.saveFormBean(node, form;
    }

<View>


AL은 EJB3나 DB매핑류 프레임워크가 별로여서 개인적인 대안으로서의 프레임워크이다. 다만 같은 문제를 고민하기보단 문제의 영역을 바꿔버렸다. AL은 그밖에도 DB에서 하지말아야 하는 모델링을 하는등 대부분의 격언을 대놓고 반대로 하고있는 Extreme 프레임워크이다. 프로그램의 변증법에서 말했듯이 이게 하나의 과정일지 결과물이 될지는 아직 알 수 없다.


'Framework > Another Lore' 카테고리의 다른 글

와~~~  (0) 2009.04.09
AL - Extreme  (0) 2009.04.04
AL - Abstraction & Model  (0) 2009.03.13
AL - 배경  (0) 2009.03.07
Framework - AL(개요)  (0) 2009.03.06
Posted by bleujin