Book2009. 2. 10. 12:01
소프트웨어 컨플릭트 2.0: 시대를 뛰어넘는 즐거운 논쟁
ㆍ국내서 | 2007-01-03
위키북스
로버트 L. 글래스 I 박재호
위 도서의 다른 서평 보기 (3편)
몇년전 소프트웨어공학의 사실과 오해라는 책을 꽤 감명깊게 보았던 지라.
예약서적에 올라온 때부터 기대하고 있었습니다.
 
다만. 이책이 십몇년전에 쓰여졌다는 사실을 몰랐습니다-_-
 
생산성을 극단적으로 높일 수 없는 은총알은 없으며 그러함에도 굳이 하나를 찾아야 한다면 좋은 인력을 찾을 것, 그리고 그 외의 방법을 -이를테면 Case툴,4GL, 방법론 등등 - 선전하는 컨설던트 직함을 달고 있는 영업사원의 말은 적당히 흘려 들을 것..
.. 라는 거죠..
 
 
Chaos 이론에 긍정적인 견해를 가지고 있는 독자로서 저자의 의견에 상당부분 동의하지만 별다른 새로운 점이 없었습니다. (책이 나온 시기를 감안하면 당시에는 맨먼쓰의 신화와 같이 아주 독보적인 내용이었으리라 생각되지만 지금 시점에서 본다면... 입니다.)
 
 
이전의 수십년이 그러했기 때문에 앞으로의 수십년도 그러 할 것이다와..
이전의 수십년이 그러했기 때문에 앞으로의 수십년은 다를 것이다는
 
는 동일한 근거를 가지지만 결론이 전혀 다른 이야기를 하고 있습니다.
독자는 앞으로도 계속 프로그래밍질을 하며 그리고 로버트 보다 좀더 오래 살아남아-_- 시간이 이 둘 중 어느 손을 들어줄까를 흥미롭게 지켜볼 생각입니다.
 
이런 종류의 책은 눈에 잘 띄지는 않고 퍼센테이지도 그리 크지 않지만 인체를 구성하는데는 필수적인 무기질 영양분과 같은 책이므로 지하철이나 볕 좋은 오후에 가볍게 읽는 다면 도움이 되리라 생각합니다.
 
그러나 먹었다고 당장 에너지를 발휘하는 책이 아니므로 혹 이 세상의 모든 방법론 혹은 다른 어떤 새로운 것은 불필요해 라고 외치는건 너무 성급하다고 생각합니다. 최근에 이런 종류의 책이 많이 나오다 보니 오히려 이전과 반대인 걱정이 생겼다고나 할까요-_-. 대부분의 경우 적절을 뛰어넘은 광신은 위험합니다. 
 

아.. 박재호씨의 번역과 베타리더분들의 적절한 조합은 조엘의 책에서도 느꼈지만 아주 훌륭하다고 생각합니다.

 

'Book' 카테고리의 다른 글

리팩토링 데이타베이스 : 진화적 데이타베이스 디자인  (0) 2009.03.14
Ajax Design Patterns  (0) 2009.02.10
프로그래밍 심리학  (0) 2009.02.10
추천 도서  (0) 2009.01.16
Javascript: The Definitive Guide  (0) 2009.01.11
Posted by bleujin
Book2009. 2. 10. 11:56
프로그래밍 심리학
ㆍ번역서 | 2008-01-02
Insight (인사이트)
Gerald M. Weinberg I 조상민
많은 관리자들은 이해하지 못하거나 인정하지 않으려는 사실 중 하나는
프로그래머는 정해진 수치의 능력을 발휘하는 게임속 캐릭터가 아니라는 사실입니다.
 
삼국지에서 조운과 미방을 백번 일기토 시켜본들 조운이 질리가 없지만.
현실에서 프로그래머는 장비도 될수 있고 가끔은 제갈량이 될수도 있습니다.
 
아직도 많은 사람들은 단순히 포드식의 컨베이어 벨트의 기계적인 조립공으로 프로그래머를 다루고 있기에(이책은 무려 1971년에 초판이 나온 책입니다.)
이책의 "프로그래머는 기계를 조종하는 또 다른 기계로 취급되지 않는가"라는 의문은 아직 유효합니다.
 
저자의 말대로 프로그래밍은 사람이 하는 일이라는 당연하지만 현실에서는 인정받지 못하는 문제에 대하여 기술적인 문제로 해결하기 어려운 프로그래머의 고민이나 어려움에 대하여 -잘 쓰여진 고전이 흔히 그러하듯이- 문제를 제기하고 생각의 여지를 남겨두고 있습니다.
 
"개인의 성격이 프로그래밍에 끼치는 영향,
 프로그래머의 지능과 문제 해결 능력, 동기와 훈련, 경험이 프로그래밍에 끼치는 영향,
 프로그래밍 팀의 심리 등 프로젝트를 이끌어나가는 사람 사이의 관게뿐 아니라 코드와의 관계..."
 
어찌보면 IT와 어울리지 않을 심리학이라는 인문학 제목이 낯설지 모르지만
프로그래머 뿐 아니라 관리자, 아키텍트, 테스터 등의 다른 관점에서 읽더라도 좋은 책입니다.

Posted by bleujin
Framework/예외처리2009. 2. 9. 08:31

밑의 예외 처리에 이어지는 글.

자바의 정설 이론은 checked exception는 정상적인 것이며 runtime exception은 처리할 수 없는 프로그래밍 에러를 가리킨다. 그리고 아래의 글중 관례 2는 자바의 정설에 기반한 관례이다.

사실 checked exception의 간단한 사용 예를 설명하는 예제들을 보면 이는 분명 멋진 생각처럼 보인다. 문제는 간단한 사용 예제가 아닐때이다.
// example
public interface User {
    public boolean login(String userId, String pwd) throws SQLException ;
    .....
}
이를테면 위의 예제와 같이 사용자 정보를 가지고 허가 여부를 확인하는 매소드를 작성하였다고 하자. 그러나 위의 인터페이스는 아주  깨어지기 쉽다. 첫번째로 사용자 정보가 DB에 있다는 가정을 하였고 두번째로 DB라고 해서 SQLException만 리턴하는 것은 아니다.(IOException등도 throw 할 수 있다.) 세번째로 그러함에도 불구하고 SQLException은 충분히 추상적이지도 충분히 세세하지도 못한 예외라른 사실이다.

물론 그런 저런 책들에서 언급한대로
// example
public interface User {
    public boolean login(String userId, String pwd) throws NoUserIdException ;
    .....
}
와 같은 새로운 고수준 사용자 예외로 처리할 방법을 생각했을 수도 있다. 사실 책에서의 글대로 이 아이디어는 아주 멋져보인다. 다만 이생각은 무균의 연구실을 벗어난 순간 아래와 같은 사실들로 오염되어 버린다.


1. 너무 많은 코드

직접 login 메소드의 구현을 담당한다고 생각해 보자.

public boolean login(String userId, String pwd) throws NoUserIdException {
      try {
           // connection DB 
           // exectue sql 
          .........
          // disconnect DB
      } catch(IOException e) {
             throw new NoUserIdException(.....) ;
      } catch(SQLException e){
             throw new NoUserIdException(.....) ;
      }
}

............... 와 같은 식의 메소드를 작성하게 된다. 별 문제 없어 보인다? What Problem ?...

문제는 이와 비슷한 식의 커스텀 예외를 던지는 메소드를 앞으로 수천개는 더 만들어야 한다는 것이다. 그 말은 수천개의 메소드들을 모두 자바의 표준 exception을 잡아서 사용자 예외로 wrapping해서 던지는 구문들만 수만줄은 된다는 얘기다.

단지 코드가 길다는게 좋은 프로그래밍이 아니다라고 할수는 없겠지만 이는 그 효과에 비해서 노력은 지나치게 많이 소모된다. 먼 미래 코드 어딘가에서 위 메소드를 사용했을때 NOUserIdException이라는 그럴듯한 이름을 가진 예외 처리를 할수 있다는 장점에 비해 위 관례를 지키기 위해 소요되는 노력은 지나치게 많다.



2. 깨지기 쉬운 메소드 원형

다시 위의 코드를 보자. login 메소드는 과연 NoUserIdException 만으로 충분한가? 위의 인터페이스로 좀더 코드를 작성하다보면 NotPasswordMatchedException이나 NotPermittedException 등등이 필요해질 것이다.
그러다 보면
public boolean login(String userId, String pwd) throws NoUserIdException, NotPasswordMatchedException, NotPermittedException, etc....
....와 같이 인터페이스를 수정해야 한다.

문제는 아직 더 있다. DB가 연결이 되지않을때도 엉뚱하게 그런 사용자가 없다느니 패스워드가 일치하지 않는다는 둥의 엉뚱한 예외가 튀어나올 것이다.

구현 메소드를 수정해서 connect절에 SQLException이 발생하면 다시 coonect DB 구문에 SQL 예외가 발생하면 다시 NotConnecttedUserInfo같은 사용자 예외를 던져야 할까?

그러다 보면

public boolean login(String userId, String pwd) throws NoUserIdException, NotPasswordMatchedException, NotPermittedException, etc....
 {
          // 변수 선언
           try {
                // connection DB 
           } catch(SQLException e){
               throw new NotConnecttedUserInfo(...) ;
          }
          // exectue sql 
         try {
           if (rs.next()) {
               if (pwd.equals(rs.getString("pwd") {
                    // 권한을 확인한다
                    try {
                       if ( isPermitted(rs)) {
                          ...
                      } else {
                         .....
                      }
                  } catch (SQLException ex) {
                   }
               } else {
                   throw new NotMatchedException(....) ;
               }
           } else {
              throw new NoUserIdException(.......) ;
           }
         } catch(SQLException e){
              ....               // outer SQLException
         } catch(IOException e) {
              .....             // outer IOException
         }

}

.........
공공장소에서 쓰레기를 버릴때 드는 죄책감이 들게된다. 첫번째 문제인 원래의 본 코드보다 예외 처리하는 코드가 더 복잡해 보인다는 건 일단 넘어가더라도 구현 메소드를 작성하면서 인터페이스를 수정해야 되는 웃기는 상황이 자주 발생하게 된다. 왜냐하면 새로운 Exception 종류가 앞으로도 계속 생겨날 것이기 때문이다. 그리고 그만큼 코드는 예외처리가 더욱 복잡해질 것이다.



3. 예외들의 끝없는 wrapping

바로 위의 예제의 // OuterSQLException 에 있는 예외 처리구문을 보자. 여기다가는 어떤 사용자 예외를 넣어야 할까? 기본적을 RecordSet인 rs의 모든 메소드는 SQLException을 던지기 때문에 안 잡을 수도 없다. 그럼 UnknownedException 같은 웃기는 이름의 exception을 새로 만들어야 할까 ? 아니면 그냥 원래의 SQLException을 던질까?

이 상황을 타계하기 위해 NotLoginnedException이라는 상위 수준으로 추상화된 Exception으로 Wrapping  했다고 하자. 

즉 이와 같이 고쳤다고 해보자.
         } catch(SQLException e){
             throw new NotLoginnedException(.... ) ;               // outer SQLException
         } catch(IOException e) {
             throw new NotLoginnedException(.... ) ;           // outer IOException
         }


그럼 메소드 원형은 public boolean login(String userId, String pwd) throws NoUserIdException, NotPasswordMatchedException, NotPermittedException, NotLogginedUserException etc.... 와 같이 될것이고 이 지저분한 쓰레기들을 보다가 문득 깨닫게 된다.

다른 사용자 예외들의 부모클래스로 NotLogginedUserException를 지정하면
public boolean login(String userId, String pwd) throws NotLogginedUserException ;
와 같이 간편하게 바꿀 수 있다고 ....

그럼 코드는 아래와 같이 수정할 수 있다.
public boolean login(String userId, String pwd) throws NotLogginedUserException {
      try {
           // connection DB 
           // exectue sql 
          .........
          // disconnect DB
      } catch(IOException e) {
             throw new NotLogginedUserException (.....) ;
      } catch(SQLException e){
             throw new NotLogginedUserException (.....) ;
      }
}

사실 지저분한 코드를 잔뜩 썼다가 지웠지만 그 결과문은 맨 처음 예제에서 에외 이름만 바뀐거에 불과하다. 한걸음만 더 생각해보면 우리는 닭질을 하고 있다. 앞의 예에서 우리가 사용자 예외로 처리함으로서 얻을 수 있는 작은 이득은 NoUserIdException이라는 예외 이름 그 자체에 있다고 했다.

그런데 login이라는 메소드에 NotLogginedException이라는 예외 이름이 과연 직관적인가? 그럴바엔 애초에 SQLException이나 별 차이도 없지 않은가 말이다

이렇게 변명할 수도 있다. 물론 메소드 원형에서 던지는 NotLogginedException은 좀 그렇지만 아래와 같이 

void report(UserInfo userInfo) {
       try {
            boolean isPermitted = login(userInfo.getUser(), userInfo.getPwd()) ;
            .....
       } catch(NotPermittedException ex) {
           // print notPermitted message 
           ....
      } catch(NotLoggingedException ex ) {
      }
      ........
}

와 같이 쓸수 있을거라고 ......

라는 생각은 한번도 상업 프로그램을 짜보지 않은 학자들이나 교생들 혹은 공기가 통하지 않는 곳에서 연구를 하고 있는 연구생들이나 할만한 생각이다.

첫번째로 login이라는 원형 메소드에 있는 NotLoggingedException 도 신경쓰기 귀찮은 판에 그 하위 exception 까지 문서화된 정보를(그런게 있다면 말이다..) 보면서 신경쓰고 싶지 않고

두번째로 신경쓰고 싶더라도 report라는 메소드를 작성하고 있는 프로그래머는 login 메소드 말고도 그 안에서 호출하고 있는 수많은 메소들마다 던지는 사용자 Exception에 아주 질려버릴 것이기 때문이다.

그래서 report 함수의 프로그래머는
void report(UserInfo userInfo) throw Exception{
       boolean isPermitted = login(userInfo.getUser(), userInfo.getPwd()) ;
       .....
       // 기타 등등의 코드....

}

와 같이 최상위 Exception으로 처리해야 하는 귀찮음을 대충 보자기 Exception 같은걸로 둘둘 싸서 다른 프로그래머에게 던져 버린다.

물론 쓸데없이 부지런한 프로그래머는
void report(UserInfo userInfo) throw ReportException{
       try {
          boolean isPermitted = login(userInfo.getUser(), userInfo.getPwd()) ;
          .....
          // 기타 등등의 코드....
       } catch(Exception ex){
           throw new ReportException(....) ;
       }

}
와 같이 자신의 쓰레기도 쓸쩍 넣는 치밀함을 보이기도 한다 -ㅅ-;

이를 단순히 개발자의 게으름으로 치부할 수는 없다. 엔트로피는 상승하게 마련이고 사실 작은 코드에서는 멋져보이는 해결책이 실제로는 엄청난 엔트로피의 증가를 가져오는 씨앗이 됐기 때문이다.

작은 메소드에서는 합당해 보이지만 그 메소드들을 호출하여 만드는 다른 프로그래머는 checked exception에 드는 과도한 노력을 피하기 마련이고 이는 결국 속이 보이지 않는 검은색 봉투로 exception을 모두 담아서 wrapping을 해버린다. 물론 이러한 과정에서 유용한 정보를 더한다면 나름 그럴듯한 선택일수도 있다. 그러나 애초에 복구가 가능하지 않는 NotLogginedException같은 경우 그것을 감싸는 것은 아무것도 성취하지 못하고 새로운 쓰레기만 더하게 된다. 그리고 그 쓰레기 만큼이나 stack rewind 하는 비용이 더 들게 된다.


4. 위의 이유들로 checked Exception이 인터페이스에서 잘 동작하지 않는다. 

결국 인터페이스를 작성할때 UnKnownException같은 불분명한 중립적 사용자 예외를 작성하거나 최상위 Exception을 던지는 인터페이스들을 만들다 보면 상황은 더욱 더 심각해진다.

마치 늪처럼 발버둥을 칠수록 더욱 더 깊이 빠져들게 되는 것이다.
이 문제들은 처리할 수 없는 예외들을 잡고, 감싸진 예외들을 다시 던지도록 강요받는 checked Exception의 문제로 속성지어질 수 있다. 이것은 성가시고, 그 자체가 에러를 낳기 쉬우며, 어떤 유용한 다른 목적도 제공하지 않는다.


그럼 다음에는 계속....


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

GUI TEST  (0) 2009.06.08
예외 수집기  (0) 2009.03.26
exception framework  (0) 2009.03.10
checked vs runtime  (0) 2009.03.07
예외 처리 격언  (2) 2009.02.09
Posted by bleujin
Framework/예외처리2009. 2. 9. 05:15


exception란 말 그대로 exception이 필요한 상황은 예외적이라고 생각해서일까?
언어에 대한 기본 문법책은 아주 많이 있지만 exceptional 하게도 exception 분야는 그리 많이 다루지 않는다.

좋은 클래스와 좋은 메소드 디자인과 마찬가지로 좋은 예외처리 디자인은 중요하다. 


관례 1 예외는 예외 상황에만 써야 한다.

// Bad
try {
   int i = 0 ;
   while(true)
       a[i++].fn() ;
} catch(ArrayIndexOutOfBoundsException e) {
}


// Good
for (int i =0 ; i < a.length ; i++)
   a[i].fn() ;

예외 기반의 구현 패턴은 코드의 목적을 애매하게 만들고 성능도 떨어뜨린다. 게다가 제대로 동작하리란 보장조차 없다. 예외 기반의 구현패턴을 쓰면, 다른 버그가 있어도 프로그램은 이 버그를 감춘채 조용히 수행된다. 이런 버그는 정말 잡아내기 어렵다. 예외는 말 그대로 예외상황에서만 써야 한다.프로그램 흐름을 예외로 제어하려 하면 안된다. 


관례 2 checked exception과 runtime exception을 구분해서 던져라

처리해야 하는 예외(checked exception)는 호출자가 예외 상항을 복구 할수 있다가 기대할 수 있을때 던진다. 보통의 경우 런타임 예외는 프로그래밍 오류(precondition violation)가 발생했을때만 써야 한다. 에러는 JVM의 자원이 부족하거나, 불변규칙이 변하는 것과 같이 더 이상 프로그램을 진행할 수 없을때 JVMㅡ에서만 던지는 것이 관례이다.

그러나 관례란 관례일 뿐이다. 관례 2는 많은 예외상항이 있는데 그것에 관해서는 따로 다른 글로 포스팅하겠다.



관례 3 예외를 던질때는 신중해야 한다.

# Bad
} catch(TheCheckedException e) {
   throw new Error("Assertion error") ;
}


# BadBad
} catch(TheCheckedException e){
   e.printStackTrace() ;
   System.exit(1) ;
}

# Not Bad
if(obj.actionPermitted(args)) {
   obj.action(args) ;
} else {
   // 예외 상황을 처리한다.
}


처리해야 하는 예외를 던지는 메소드가 너무 많은 API는 아주 쓰기 번거롭다. 처리해야 하는 예외를 던지는 메소드를 호출하는 메소드는 catch 블록을 써서 이 예외를 잡거나, 같은 예외를 던진다고 선언하여 이 예외를 외부로 전파해야 한다. 사실 이런 작업은 프로그래머에게는 만만치 않은 부담을 준다. API를 정확히 쓰더라도 이런 예외가 발생할 수 있고, 프로그래머가 이 예외를 적절하게 처리할 수 있을때만 처리할 수 있는 예외를 던져야 한다. 위의 2조건을 모두 만족하지 못한다면 처리하지 않는 예외를 던지는 것이 좋다. 이 메소드를 사용하는 프로그래머들이 어떻게 처리할까 라는 질문을 한번 더 던져보자....

사실 관례 2의 예외는 바로 이 관례 3에 기인한다. 지나치기 많은 예외를 던지는것은 부작용을 너무 많이 가져온다. 



관례 4 표준 예외를 써라

클래스의 이름이 중요한만큼이나 예외의 이름도 중요하다. 따라서 가능하면 존재하는 예외라면 존재하는 표준 예외를 써주는 것이 좋다.

IllegalArgumentException : 인자값이 적절하지 못할때
IllegalStateExcetpion : 호출을 받은 객체 상태가 적절하지 못할때
NullPointerException : null을 금지한 인자값이 null일때
IndexOutOfBoundsException : 인덱스 값이 범위를 벗어났을때
ConcurrentModificationException : 동시 수정을 금지한 객체를 동시에 수정할때.
UnsupportedOperationException : 객체가 메소드를 지원하지 않을때.


관례 5 예외를 적절하게 추상화하라

// exception translation
try {

   ......
} catch(LowerLevelException e){
   throw new HigherLevelException(...) ;
}

낮은 계층의 세부 구현사항이 외부에 드러나게 되어 추상화 수준이 높은 계층의 API를 오염시킬수 있다. 인터페이스 디자인할때 어려운 점중 하나는 어느 수준의 예외를 던져야 하는가이다. 메소드 구현이 되지 않는 상태에서 어떤한 예외가 나올것이라고 추측하는 것은 미래를 예측하는 것 만큼이나 매우 매우 어렵기 때문이다. 그래서 인터페이스에서 아무 예외든 다 받아주겠어 식의 throw Exception은 다시 관례 2의 예외로 나타난다. 



관례 6 실패에 대한 자세한 정보를 상세 메시지 문자열에 담아라

예외의 문자열 표현과 최종 사용자가 쉽게 이해할 수 있어야 하는 "사용자에게 제공하는 오류 메시지"와 혼동하면 안된다. 사용자에게 제공하는 오류 메시지와 달리, 예외의 문자열 표현은 프로그래머나 유지보수 요원이 실패를 분석할때 쓰는 것이다. 따라서 예외ㅡ 문자열 표현은 이해하기 쉬운 정보를 담기보다는 자세한 정보를 담는 것이 훨씬 더 중요하다.


# Bad
try {
    ....
} catch(IOException ex) {
   throw new UserException("예외 발생.") ;
}


# Good
try {
    ....
} catch(IOException ex) {
   throw new UserException( ex.getMessage() + "예외와 관계있을수 있는 프로퍼티 정보 ") ;



관례 7 실퍠 원자성을 얻기 위해 노력하라

# Good
public Object pop(){
   if (size == 0) throw new EmptyStackException() ;

   Object result = element[--size] ;
   elements[size] = null ;
   return result ;
}



관례 8 예외를 잡아서 버리지 마라

예외를 잡아서 버리지 마라, 너무나 당연한 진리를 많은 프로그래머가 무시하고 있기 때문에 다시 한번 이야기한다. 어떤 메소드가 예외를 던질 수 있다는 것은, 이 메소드의 설계자가 여러분께 뭔가 알리고 싶어한다는 것이다.

catch 블럭 안에서 정말 아무것도 할 것이 없다면, 최소한 왜 예외를 잡어서 처리하지 않고 버리는지 그 이유라도 주석으로 달아 놓아야 한다.

그러나 이런 관례는 오히려 프로그래머의 게으름을 촉진시킬수 있다.




예외의 예외는 다음 글에서 =ㅅ=;




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

GUI TEST  (0) 2009.06.08
예외 수집기  (0) 2009.03.26
exception framework  (0) 2009.03.10
checked vs runtime  (0) 2009.03.07
checked exception의 문제  (0) 2009.02.09
Posted by bleujin
Database 일반2009. 2. 7. 08:04

문) SQL로 100 ! (100의 팩토리얼)을 구하라 (난이도 C)




물론
select 100 * 99 *98 * 97  ..... * 2
from dual

이런식의 방법은 우아하지 못함을 떠나서 아마도 수치연산 오류로 제대로 작동하지 않을테니 굳이 시험해 보지 않아도 된다. 정확히 기억나지 않지만 오라클의 경우 최대 연산 가능한 수는 10^128 보다 작다.

'Database 일반' 카테고리의 다른 글

Database - Plan 이해  (0) 2009.03.07
Database Quiz - count  (0) 2009.02.13
Database Quiz - 실행계획 유도  (0) 2009.02.07
Database Quiz - 연속성  (0) 2009.02.07
Database Quiz - 달력  (0) 2009.02.07
Posted by bleujin
Database 일반2009. 2. 7. 04:13


1. 사원의 수가 아주 많아서 NL조인으로는 충분한 전체범위 처리 속도를 얻기 어렵다. 아래 SQL을 Hash Join 실행계획을 사용하도록 유도하라. (난이도 C+)


select a.ename, a.sal, b.grade
from emp a, sal_grade b
where a.sal between b.minValue and b.maxValue



- 기대되는 실행계획 :

SELECT STATEMENT
HASH JOIN
  TABLE ACCESS FULL EMP
  TABLE ACCESS FULL SAL_GRADE


'Database 일반' 카테고리의 다른 글

Database - Plan 이해  (0) 2009.03.07
Database Quiz - count  (0) 2009.02.13
Database Quiz - 함수의 활용  (0) 2009.02.07
Database Quiz - 연속성  (0) 2009.02.07
Database Quiz - 달력  (0) 2009.02.07
Posted by bleujin
Database 일반2009. 2. 7. 03:57

row의 연속성을 구현하는 문제이다.

1. 아래와 같은 입력 테이블이 있다. 연속일로 매출이 발생한 정보를 출력하라. (난이도 C)

매출년일        수량
20090130         30
20090131         10
20090201         25
20090202         20
20090204         35
20090205         40
20090206         10
20090209         20
20090211         35


기대되는 출력
기간                           수량
20090130 - 20090202      85
20090204 - 20090206      85
20090209 - 20090209      20
20090211 - 20090211      30



2. 같은 입력으로 토요일과 일요일은 매출이 없어도 휴일이기 때문에(일반 국경일은 패스) 연속성을 가지는 걸로 가정하고 출력. 즉 금요일에 매출이 발생하고 다음 월요일에 매출이 발생하면 연속성을 가지는 걸로 간주한다. (난이도 C+)

기대되는 출력
기간                           수량
20090130 - 20090202      85
20090204 - 20090209      105
20090211 - 20090211      30



'Database 일반' 카테고리의 다른 글

Database - Plan 이해  (0) 2009.03.07
Database Quiz - count  (0) 2009.02.13
Database Quiz - 함수의 활용  (0) 2009.02.07
Database Quiz - 실행계획 유도  (0) 2009.02.07
Database Quiz - 달력  (0) 2009.02.07
Posted by bleujin
Database 일반2009. 2. 7. 03:41

열렬한 팬사이트 중의 하나였던 엔코아에서 작년에 SQL Quiz 게시판을 없애버렸다. 참여율이 저조해서인지 아니면 다른 이유가 있는지는 모르겠지만 개인적으로는 아쉽기 그지 없었다. 그래서 개인적으로 재미삼아 퀴즈문제를 만들어 보기로 했다 -ㅅ-  사실 이 블로그 자체가 남에게 보여주기 위함보다 그냥 개인적인 목적으로 만든 블로그지만 - 그동안 하도 글들을 날려먹어서 -ㅅ- 머 어쩌랴 싶기도 하다. 퀴즈는 아마도 이 블로그에서 유일하게 타인만을 위한(정말?) 글이 될 예정...

웬일인지 개인적으로 면접을 본 횟수보다 면접을 한 횟수가 10배정도 많은데 그 때마나 DB파트에서는 꼭 SQL 문제를 내곤 했다. 단순한 암기적 지식이 필요한 질문은 면접 질문중 최악이지만 SQL은 암기적 지식이 필요 없고 평소 RDMS를 제대로 관계형 패러다임으로 인식하고 있는지 알아볼 수 있기 때문이다. 문제별 난이도는 주관적이고 상대적이다.

1. 해당년원을 인풋으로 받아서 SQL을 사용하여 달력을 출력하기 (난이도 D)


ex)
입력 : 200801

출력 :

일 월 화 수 목  금  토
         1   2  3    4   5
6   7   8  9  10  11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31




1-1 입력은 같지만 이전달과 이후달의 날짜도 같이 출력하기. (난이도 C)


입력 : 200801

출력 :

일 월 화 수 목  금  토
30  31 1  2  3    4   5
6   7   8  9  10  11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31  1  2



'Database 일반' 카테고리의 다른 글

Database - Plan 이해  (0) 2009.03.07
Database Quiz - count  (0) 2009.02.13
Database Quiz - 함수의 활용  (0) 2009.02.07
Database Quiz - 실행계획 유도  (0) 2009.02.07
Database Quiz - 연속성  (0) 2009.02.07
Posted by bleujin
Framework/Database2009. 2. 7. 03:24

DB 아키텍처에 대해 깊히 이해하지 못하는 객체지향 개발자가 흔히 하는 실수중의 하나는 DB에 대한 블랙박스 증후군이다.

이들은 마치 데이타베이스를 라디오의 건전지처럼 교체할 수 있어야 한다고 생각하고 데이타베이스의 특정 기능을 사용하는 것을 마치 나쁜짓인양 무슨 수를 써서라도 피하려고 한다. 그래도 데이타베이스 독립이라는 명록으로 데이타베이스의 기능을 사용하고 데이타베이스 활용을 거부한다. (데이타베이스 종속이란 말 자체가 사실 우물에 독뿌리기 오류를 범하고 있다. 종속이란 그리 듣기 좋은 단어가 아니기 때문이다.) 사실 데이터베이스의 독립을 이루기란 극히 어려울뿐 아니라 반대의 경우보다 훨씬 더 많은 비용이 든다.

이 문제는 크게 경제성과 비경제성 문제로 나눌수 있는데

첫번째로 블랙박스 증후군에 걸린 개발자는 수학이 아니라 공학이 가져야 하는 경제성 즉 비싼 데이타베이스 비용을 낭비하거나 이미 존재하는 기능임에도 직접 작정하는 수고를 통해 많은 시간을 낭비하게 된다.

두번째로 앞에서도 말한바와 같이 실질적으로 매우 어렵다. Ansi SQL만을 사용해서 어떤 제품을 만든다는 것은 Hello World 프로그램 따위에서나 생각할 수 있다. DB 벤더마다 Length, substring 같은 기본 함수들의 사용법이나 명칭등이 다르기 때문에 고작 쓸 수 있는 SQL이란 select * from emp 같은 정도를 사용할 수 있을 뿐이다.

세번째로 어려울뿐 아니라 어떤 문제는 사실 불가능한 것들도 있다. 예컨데 트랜잭션 모델의 경우 Oracle과 MSSQL은 많은 차이가 있고 이는 설사 같은 SQL을 사용했다고 하더라도 다른 결과를 일으키는 경우가 있다.

이러한 등등의 문제로 10년이 넘는 개발자의 생활중 사실 단 한번도 DB 독립을 갖춘 제품을 보지 못했다는 경험적인 이유도 있다. 그 많은 제품들은 물론 데이타베이스의 종속을 피하고자~ 라는 말이 대부분 있었음에도 불구하고 말이다. 실질적으로 제품정도의 코드에서 데이타베이스의 종속을 제거한 코드를 만드는것은 이론적으로 불가능은 아닐지라도 매우매우 어렵다.

그래서 객체지향과 DB는 서로간에 한발 양보를 하고 타협을 하게 되는데.
하나는 객체지향쪽에서 DB쪽으로 한발 접근한 DB를 객체형식으로 다루는 등의 하이버네이트식의 접근이고
다른 하나는 DB쪽에서 아예 객체기반 DB를 만드려는 시도이다.

여기서 두번째는 이 글의 주제와 맞지 않고 사실 논리적으로도 문제가 있다. DB의 종속을 피하기 위해 객체지향 DB를 사용하라는것 자체가 모순이다.(그리고 사실 객체기반 DB는 단순히 종속성의 문제때문에 개발된게 아니다. )


첫번째 하이버네이트식의 접근은 그 열렬한 추종자가 많이 줄긴 했지만 지금도 충분히 지나치게 과대평가라고 생각한다. 몇년전 하이버네이트 소스를 며칠동안 뜯어본적이 있었는데 그 대부분이 케이스별 SQL을 만드는 string 연산이였다. 지금은 나아졌는지 모르겠지만 어쨌거나 이방식은 겉보기에는 종속을 피할 수 있을지라도 DB의 효율성을 심각하게 감소시킨다. 무료(?)인 오픈소스 디비를 사용하면 비용이 안든다고 주장하지만 그 만큼의 저 효율을 어딘가에서 메꿔야 하기 때문에 그닥 납득하지는 못하겠다.

IBatis의 방법은 조금 더 현실적이긴 하지만 이도 역시 다른 문제가 있다. 이건 머 차차 쓰기로 하고 잠이나 -ㅅ-;;;;

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

Framework (DBManager)  (0) 2009.03.04
Framework (구조적 중복 제거)  (0) 2009.02.21
Framework (실험실 코드)  (0) 2009.02.20
Framework (개요)  (0) 2009.02.20
Framework (커서)  (0) 2009.01.12
Posted by bleujin
IT 이야기2009. 2. 4. 19:39

이전 글에서 객체지향 프로그래밍 십계에 대해 언급한 적이 있는데
(물론 모세처럼 신약을 받은건 아니고-ㅅ- 그렇다고 새로운 이론을 창조하는 것도 아니다. 굳이 말하자면 요구사항을 캐내듯이 - 수집이 아니라 - 별다섯개짜리 책들에서 캐낸 것이다.)

1계는 당연히 재사용 성배를 뜻한 DRY(Dont Repeat, yourself)이다.
3계는 앞서 말한대로 더 이상 분해가 불가능한 원자단위까지 쪼개서 하나의 Aspect관점으로 묶어라 이다.

마음대로 정한 2계는 SOC 즉 변화의 속도이다. (SOC는 Service-Orinted Programming같은게 아니라 Speed Of Change로 맘대로 지어낸 용어다 -ㅅ-) 객제 지향은 "Object는 관련 있는 변수와 메소드의 모음" 이라는 정의로 출발하는 관계 있는것끼리 묶자라는 시도이다.

좋아~ 그럼 관련 있는 것이란 무엇인가 ?

관계(혹은 관련)에 대한 화두는 이화식씨에게 RDBMS를 배우던 시절로 올라간다. 관계형 DB 모델링 과정에서 엔티티란 '... 어쩌고 저쩌고....  관계 있는 개체의 집합' 라고 정의했을때

"관계란 무엇인가? 저기 창문밑의 길가는 사람은 나와 관계 있는 건가? 아닌가?" 라는 질문을 던졌을때 당시의 나는 매우 당황스러웠지만 그 후 몇 년이 지난후에야 나름대로의 답을 찾게되었다.  RDBMS에서 모든 개체는 관련을 가지고 있다. 따라서 창문밑의 길가는 사람과 나는 관계가 있는 것이다. 다만 RDBMS에서는 직접적 관계와 간접적 관계를 구분한다. 그래서 모델링시 사원과 부서가 일차적 직접 관계를 가지느냐 이차적 이상의 간접적 관계를 가지느냐에 대한 판단을 하게 된다.

이러한 RDBMS에서의 관계의 의미와는 달리 객체지향에서 관계의 의미는 조금 다르다. 설계시 A라는 클래스와 B라는 클래스는 관계가 있느냐? 혹은 a라는 메소드와 b라는 메소드는 관계가 있느냐를 판단할때의 기준은 공간적 시간적 변화의 속도이다. 즉 어떤 클래스를 수정할때 다른 클래스도 마찬가지로 수정해야 된다면 이 두개의 클래스는 관련이 있으므로 묶어두어야 한다. - 클래스 통합이 될수도 있고 같은 패키지에 둘수도 있고 inner 클래스를 사용할수도 있겠다. - 이러한 공간적 관련성 말고도 시간적으로 어떤 부분의 변동과 다른 부분의 변동이 같이 일어난다면 이도 시간적 관계가 있다고 할 수 있다.

쉽게 말하면 객체지향의 디자인은 관련있는 것들은 그 관련정도에 따라 거리를 조절하는 것을 뜻한다. SOC가 아주 비슷하다면 그 거리도 가까워야 하고 SOC가 서로 관련이 없다면 가능한 서로 의존하지 말아야 한다. 달리 말하면 소프트웨어 공학에서 말하는 커플링(Loose cupling)과 코헨션(Tight cohesion)에 대한 얘기이다. 언뜻보면 모순으로 보이는 이 두 개념은 SOC에 따라 커플링이나 코현션이냐를 판단하게 되는 것이다.



객체지향 프로그래밍 제 2계
관련있는 것은 가능한 묶고 관련없는 것들은 가능한 떨어뜨려 놓는데 여기서의 관련이란 이 두개의 시간적 공간적 변화의 속도이다.



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

소프트웨어의 변증법  (0) 2009.02.23
추상화  (0) 2009.02.22
금붕어 이야기  (0) 2009.02.04
형식적 민주주의와 형식적 방법론  (0) 2009.02.04
좋은 프로그램과 위대한 프로그램  (0) 2009.02.03
Posted by bleujin