國 K1


...

by silverbird | 2009/07/28 12:30 | 단상 | 트랙백 | 덧글(3)

사람을 먹으면 왜 안되는가?


<이미지 출처: 알라딘>

 철학은 생각하는 학문이다. 이 세상에 생각이 필요없는 학문이 어디 있겠냐만은 다른 것들이 생각을 수단으로 이용하는 반면 철학은 생각 자체를 목적으로 한다는 점에서 다른 학문과 차이가 있다. 그래서 사람들은 철학을 '메타 학문' 이라 부르기도 한다.
 그러나 아쉽게도 우리가 학교에서 배운 철학은 철저한 암기 과목이었다. 심지어 과목명도 '도덕' 혹은 '국민윤리' 였지만 물론 전혀 도덕적이지 못한 선생 밑에서 절대 윤리적인 방식이라 볼 수 없는 방법으로 배워야 했다. 
 그러다 보니 정작 철학은 온데간데 없이 단지 흄이니 키에르케고르니 보드리야르니 하는 발음하기도 힘든 철학자 이름을 달달 외워야 했고 성선설을 주장한게 맹자인지 순자인지 헷갈려 시험 때마다 연필을 굴려야 했으며 왜 에피쿠로스 학파는 에피쿠로스가 창시했는데 스토아 학파는 스토아가 창시하지 않았는지 중간 고사 채점 때마다 분을 삼켜야 했다. 

 요는 이렇다. 철학은 위에서 말한 그런 철학자나 그들의 이론을 들먹여야만 철학이 아니다. 철학은 생각의 학문이고 따라서 모든 것에 의심을 갖고 질문을 던지는 것이 철학의 본질이다. 그런 면에서 사실 우리는 매일 철학을 실천하고 있다. 오늘도 수많은 블로거들이 다른 이들의 글에서 별 시덥잖아 보이는 사항 하나 하나에 댓글로 딴지를 걸고 있다. 그저 그냥 아무 생각없이 넘어가줘도 별 상관없을 것 같은 이야기에 '님 그건 성급한 일반화의 오류인것 같네요...' 뭐 이렇게 이죽거리지 않는가? 그렇다! 철학은 쉽게 말하면 딴지를 학문적으로 승화한 것이다.

 이 책은 지금껏 많은 철학자들이 걸었던 유명한 딴지(이 책에서는 이것을 철학 퍼즐이라고 점잖게 표현하지만)들 중 일부를 소개한 책이다. 일단 구성이 독특하다. 어린 시절 즐겨 읽었던 스토리형 퍼즐책('A를 선택했다면 53 페이지, B를 선택했다면 72 페이지로 가시오' 라는 식의 지문이 달린 책) 과 유사한 방식을 취했다. 그래서 윤리, 논리, 형이상학 등의 다양한 주제를 연관된 챕터 별로 쫓아가며 읽는 재미가 있다.
 내용 면에서는 헌혈이나 장기 기증, 태반크림 등과 굶주림을 면하기 위한 식인 행위의 차이는 무엇인지, 1년 동안 호위호식하던 칠면조가 그 동안의 경험을 통해 크리스마스 이브날에도 주인이 주는 먹이를 기대했다가 먹음직스러운 구이로 재탄생하는 반전 동화에 나오는 귀납 추리의 오류라든지, 내가 보는 빨간색과 남이 보는 빨간색이 정말 같은 색깔이라는 것을 어떻게 증명할 것인지, 시간은 정말 흘러가는 것인지 등등의 많은 철학적 질문들을 예화와 함께 비교적 어렵지 않게 풀어나간다. 

 사실 이런 책 하나 읽는다고 사람이 철학적이 되는 것은 아닐게다. 아니 '철학적' 이라는 말도 좀 우습다. 다만 2시간 정도 읽고 나면 그만인 그저 그런 책들 보단 좀 더 긴 시간을 즐길 수 있는 재미있는 책임에는 분명하다. 게다가 가끔은 이런 책을 통해서 딴지의 내공을 쌓아놔야 극장에서 '대한 뉘우스'를 보며 낄낄거리는 단무지는 안되지 않겠나 싶다. 요컨데 똥인지 된장인지는 구별하고 쌈싸먹는 인간이 되자는 말이다.

 p.s. 책의 뒷 표지에 이 책을 읽고 나면 '저녁 식탁 위에 활기찬 논쟁이 불꽃처럼 피어날 것이다.' 라는 추천사가 있던데 글쎄... 저녁 식탁에서 '사람을 먹으면 왜 안되는가?' 에 대해서 토론 했다가는 앞으로 고기 반찬 볼 일이 별로 없을 듯 싶다.

by silverbird | 2009/06/28 21:35 | 내가 읽은 책들 | 트랙백 | 덧글(6)

가장 보통의 존재



그대에게 난 가장 보통의 존재...추억조차 남지 않았겠지
나에게 그댄 가장 고통의 존재...

by silverbird | 2009/06/06 19:04 | 단상 | 트랙백 | 덧글(0)

블로그 하나 더 개설했습니다.

워낙에 천성이 게으른 탓에 한동안 블로그에 글을 쓰지 못했습니다. 
근래들어 회사에서 하는 일도 그렇고 해서 병렬/분산 프로그래밍에 관심을 갖고 공부를 하고 있습니다. 그러다보니 공부하고 적용한 내용들을 정리하려고 따로 블로그를 하나 만들었습니다. 새로 만든 블로그는 http://parallel.textcube.com/ 입니다.
이글루는 워낙에 잡다하게 끄적이다 보니 차분히 내용을 정리하기에는 힘들것 같더군요. 앞으로도 여기는 특정 주제에 치우치지 않고 그저 한번씩 끄적이고 싶을 때마다 애용할 생각입니다.
암튼 뭐 그렇다구요...

by silverbird | 2009/06/05 23:35 | 기타등등 | 트랙백 | 덧글(2)

자바 병행 프로그래밍 시 실수하기 쉬운 문제들

http://stackoverflow.com/questions/461896/what-is-the-most-frequent-concurrency-problem-youve-encountered-in-java

 원문 제목 그대로 자바에서 병행 프로그래밍을 할 때 자주 발생하는 문제들을 나열해 놓았습니다. 제가 이 블로그에서 언급했던 내용도 있고 어처구니없는 실수도 있고 정확히 알고 있지 않으면 착각하기 쉬운 것도 있고 어쨌든 한번쯤 훝어보고 상기해 볼만한 내용입니다.
 참고로 제가 최근에 했던 실수는 이것...

final CountDownLatch latcher = new CountDownLatch(n);
for (int i = 0; i < n; ++i) {
    executorService.submit(new Runnable() {
        public void run() {
            ...
            latcher.countDown();
        }
    });
}
latcher.wait();

흑...ㅜㅡ

 p.s. 혹시 CountDownLatcher 에 대해 모르시는 분이 있을까봐 첨언하자면 이름처럼 객체 생성 시 카운트다운 갯수를 지정하고 특정 조건에 이를때마다 카운트다운을 해서 0 에 이르면 빗장(latch) 를 엽니다. java.util.concurrent 패키지에 있습니다. 역시 같은 패키지에 있는 CyclicBarrier 와 함께, 기존의 notify(), wait() 를 대체할 수 있는 조건 동기화 클래스입니다. 원래 빗장이 열릴 때까지 기다리는 함수는 await() 인데 이게 wait() 함수랑 헷갈려요...

by silverbird | 2009/03/30 21:40 | 프로그래밍 | 트랙백 | 덧글(0)

잘 모르면 제발 가만히 있어라

배열 접근 연산자 operator[] 를 사용하는 것이 성능을 저하 시킨다는 내용이 effective STL 에 나왔던걸로 기억하는데요. at 을 사용하시는 걸 고려하시는게 좋을것 같습니다. 2005년도부터 Visual Studio 의 STL 라이브러리에서 at 을 사용할때 범위 체크를 해서 예외도 던져 줬던걸로 기억합니다.

둘다 오래전 기억들이라 정확치 않군요... ^^;

 - 오래전 기억이라 정확하지 않으면 그냥 답글 달지 말아라. 정 아는체 하고 싶으면 다시 찾아보던가...그저 몇 분만 투자해서 STL 책을 찾아 보거나 vector 코드를 살펴보거나(STL 코드는 템플릿이라 구현 소스를 다 볼 수 있다.) 직접 테스트 프로그램을 만들어 보거나 그것도 싫으면 검색해보면 될 것을 왜 정확치 않은 기억을 토대로 시간 낭비해가면서 반대로 가르쳐주는지 모르겠다.


하지만 동적으로 생성하시는분들도 있다. 이경우 클래스가 자기 자신의 포인트 형을
캡슐화된 형태로 가지고 있다가 객체 접근용 함수에서 NULL을 검사하고 생성해주고
접근하는 형태를 띄게 되는데 이경우는 객체 접근용 함수외에도 객체의 소멸용 함수를
하나더 만들어 주어야 한다. 하지만 동적할당으로 생성된 객체를 delete로 소멸시키려 접근한다면
delete는 또다시 소멸자를 호출하게 되면서 무한 재귀 함수로 빠져들게된다.
소스코드가 여기서 최소 약 5줄가량 늘어나며 무책임한 에러를 뱉어내기 시작한다.
선택은 자유지만 간편하며 안전한게 좋지 않을까?

소스를 직접 올리는 행위는 하지 않겠다.

 - 무한 재귀 함수에 빠져드는지 그렇지 않은지 잠깐만 자기 컴퓨터로 확인해보고 저런 말을 하기 바란다. 소스를 직접 올리는 행위를 하지 않는건 프로그래밍을 못하기 때문은 아닌지 의심된다.


뭐니뭐니해도 최고는 이것...

 - 쓰레드에 관한 글인데 전체적으로 워낙 오류가 많고 개판이라 잘못된 부분만 따로 발췌하기도 불가능한 수준이다.

-> 한빛 미디어 관계자 분이 이 글을 봤는지 그 사이에 해당 글이 없어졌다(정말 다행스러운 일이다). 하지만 불행하게도 누군가 저 글을 퍼가는 바람에 잔재가 남았다는 거...http://blog.naver.com/ki3ki7/80056924730 이 링크 글도 하루 빨리 인터넷 세상에서 사라지길 바란다.  

사람은 누구나 실수도 하고 착각도 하고 그래서 어지간하면 저런 거 못본척 넘어가는데 오늘따라 유난히 눈에 거슬리더라...자신들이 올린 잘못된 내용을 지식으로 삼아 고생할 사람들 생각은 안하나? 이런 무책임한 사람들 같으니라고...

p.s. 그리고 프로그래밍 관련 글쓰면서 구구절절 글로만 설명하고 소스는 귀찮아서 생략한다는 사람들...글쓰는 것보다 프로그래밍이 귀찮으면 그냥 프로그래밍 하지마...

by silverbird | 2009/03/26 19:00 | 단상 | 트랙백(1) | 덧글(12)

대학 신입생을 위한 추천 도서

2009 대학 새내기 추천도서
블로거가 고른 2009 새내기 추천도서

 추천 도서라는 것은 무엇보다 추천 받은 사람이 실제 읽어야 그 가치가 있는 법이다. 그런데 한국 간행물 윤리 위원회에서 추천한 목록은 아무리 봐도 평균 수준의 대학 신입생이 읽기에는 무리가 있어 보인다. 그리고 특정 전공을 지칭한 것도 아니고 일반 대학 새내기를 대상으로 한다면 최소한 다양한 분야를 포괄적으로 다룰려는 노력을 보여야 하지 않을까? 무엇보다 추천 목록을 아무리 봐도 그저 '에헴...이 정도는 읽어줘야 자고로 지성인이라 불릴만 하지...' 정도의 지적 허영심 외에는 추천 이유를 찾기 힘들다.

 각설하고 비판이 있었으면 대안을 제시해야 하는 법이다. 그런 의미에서 아이추판다님이 블로거들의 추천 목록을 만들어 보자는 제안을 했다. 내 깜냥에 모든 분야를 어우르는 추천 목록을 만들기는 불가능하지만 적어도 내가 지금껏 읽은 책 중에 대학 신입생이 읽기에 괜찮아 보이는 책들은 다음과 같다.

1. '플라톤 향연' - 조안 스파르, 문학동네


 비록 플라톤의 향연은 많은 번역본이 있지만, 중간 중간 내용에 어울리면서도 위트넘치는 삽화가 다른 책과는 다른 특별함을 준다. 그 나이 또래면 가장 관심있는 주제일 '사랑' 에 대해서 그리스 철학자들의 재기넘치는 사유를 엿볼 수 있다. 이 책을 읽으면 '아, 철학적 사유를 이렇게 재밌게 할 수도 있구나.' 하는 생각이 든다.

2. 변경 - 렁청진, 더난 출판사


 이 책을 한마디로 표현하면 '현대판 사기 열전' 이라 할 수 있다. 비록 최근에 나온 책이기에 '사기 열전'만큼 높이 평가받지는 못하지만 내 생각엔 이 책이 '사기 열전'보다 더 낫다. 그 이유는 첫 째, 시대적 한계로 인해 '사기 열전'에서는 다루지 못하는 사마천 이후의 다양한 인물들의 이야기를 많이 다루고 있다(솔직히 '사기 열전' 이야기는 이미 다른 곳에서 지겹게 접해서 진부한 면이 없지 않아 있다). 둘 째, 보다 현대 상황에 맞게 인물들을 해석하고 있다. 셋 째, 주제별로 더 체계적으로 정리되어 있다.
 우리가 역사를 공부하는 것은 과거를 통해 현대를 살아가는 지혜를 배우기 위함일 것이다. 역시 같은 이유로 과거 인물들의 살아온 방식에 관심을 갖는 것은 그들의 삶과 인성을 통해서 내가 어떻게 살아가야 할 것인가 하는 처세를 익히기 위함일 것이다. 그런 의미에서 이제 어설프게나마 사회를 접하게 될 대학 신입생에게 이 책 만큼 적합한 추천 도서가 있을까?

3. 과학 철학 입문 - 루돌프 카르납, 서광사


 윤리 위원회 추천 목록 중에 토마스 쿤의 '과학 혁명의 구조'가 있더라. 물론 그 책이 훌륭한 책이라는 점엔 이견이 없지만 훌륭한 책이 반드시 초보자에게도 훌륭한 책은 아니다. '과학 혁명의 구조'는 내가 보기엔 전혀 대학 신입생에게 어울리는 책이 아닐 뿐더러 이 책의 번역본은 정말 최악의 번역을 자랑한다. '과학 철학'이란 용어 조차 생소할 이들에게 자칫 '역시 철학이란 말이 들어가면 어렵고 따분해' 라는 인식을 심어줄까 두렵다. 
 물론 카르납의 '과학철학입문'도 그다지 쉬운 책은 아니다. 그럼에도 불구하고 이 책을 추천하는 이유는 그만큼 이 책을 읽을 필요가 있다고 느끼기 때문이다. 첫머리에서부터 과학에 대해 명쾌한 정의를 내리면서 시작하고 있는 이 책은, 단순히 과학을 암기 과목처럼 접했던 신입생들에게 이보다 더 적합한 과학 철학 소개서는 없다 할만하다. 게다가 요즘처럼 사이비가 판치고 출처가 의심스러운 정보가 들끓는 세상엔 이 책처럼 좋은 지침서가 될 만한 '과학철학서'를 읽을 필요가 있다.

4. 설득의 논리학 - 김용규, 웅진 지식 하우스


 논리적 사고는 학교 공부를 함에 있어서도 필요하지만 졸업하고 회사에 나가면 더욱 절실해지는 능력이다. 개인적으론 고등학교 때 수학과 국어 수업 시간을 한 시간씩 줄이고 대신 논리학을 일주일에 두 시간 정도씩 따로 가르쳤으면 하는 생각을 한다(예전부터 그렇게 했었다면 아마도 '100분 토론'이 지금처럼 짜증나는 프로가 되지 않았을 것이다). 물론 그렇게 하면 수학과 국어를 가르치는데에도 큰 도움이 될 것이다. 
 이 책은 재미도 있고 쉽게 읽히면서 마냥 가볍지만은 않은 미덕을 갖고 있다.

5. 수, 과학의 언어 - 토비아스 단치히, 한승


 베르나르 베르베르의 단편 소설집 '나무'에는 17보다 큰 숫자가 무엇인지 알고자 평생을 정진하는 한 사제 기사의 이야기가 나온다. 그 소설 속 세상에서 사람들은 숫자에 대한 개념이 매우 원시적이어서 다 큰 어른도 10보다 큰 숫자를 아는 사람이 드물다. '이 무슨 바보같은 세상이 다있단 말인가' 하고 생각할 수 있겠지만, 그리고 단순히 작가의 상상력에서만 존재하는 세상이라고 치부할 수도 있겠지만 아마 이 책을 보면 그 생각이 달라질 것이다.
 이 책은 우리가 지금과 같은 높은 수준의 수학적 직관력을 갖기까지 얼마나 오랜 시간 어떤 과정을 거쳐 발전해 왔는지 흥미로운 내용을 담고 있다. 수학하면 '홍성대' 부터 떠올릴 대학 신입생들에게 색다른 시각을 선사할 좋은 책이다.

by silverbird | 2009/03/01 12:29 | 기타등등 | 트랙백 | 덧글(0)

자바 병행 프로그래밍 - 잘못된 락 객체 사용법

ConcurrentHashMap vs. HashTable 이란 글에서 아래와 같은 코드는 잘못된 방법일 뿐더러 위험한 방법이라고 했습니다.

class SharedData {
    private Integer intData = 0;
    private Boolean boolData = false;

    public int getInt() { synchronized (intData) { return intData; } }
    public void setInt(int n) { synchronized (intData) { intData = n; } }
    public boolean getBool() { synchronized (boolData) { return boolData; } }
    public void setBool(boolean b) { synchronized (boolData) { boolData = b; } }
}

 우선 잘못된 이유에 대해서 먼저 설명하자면 프로그래머의 의도와 달리 intData 나 boolData 객체는 동기화되지 않습니다. 그 이유는 setInt() 나 setBool() 함수가 호출될 때마다 락으로 사용되는 intData 나 boolData 객체가 변할 수 있는데 이런 경우 쓰레드들이 서로 다른 락에 접근하기 때문입니다. 예를 들어 다음과 같은 코드가 있다고 합시다.

public class SyncTest {
  static private Object lock = new Object();

  static class TestRunnable implements Runnable {
    @Override
    public void run() {
      try {
        synchronized (lock) {
          System.out.println("before sleep in thread");
          Thread.sleep(1000);
          System.out.println("after sleep in thread");
        }
      } catch (Interrupted Exception e) {
      }
    }
  }

  public static void main(String[] args) {
    ExecutorService threads = Executors.newFixedThreadPool(2);
    threads.submit(new TestRunnable());
    threads.submit(new TestRunnable());
    threads.shutdown();
    try {
      threads.awaitTermination(1, TimeUnit.MINUTES);
    } catch (InterruptedException e) {
    }
    System.exit(0);
  }
}

 위 코드를 실행시켜 보면 항상 아래처럼 출력됩니다.

before sleep in thread
after sleep in thread
before sleep in thread
after sleep in thread

그러나 위에 동기화 부분을 다음과 같이 고치면 문제가 발생합니다.

synchronized (lock) {
  lock = new Object(); // assigned another object to lock
  System.out.println("before sleep in thread");
  Thread.sleep(1000);
  System.out.println("after sleep in thread");
}

 lock 객체가 동기화 블럭내에서 다른 객체로 변경되었기 때문에 이후에 다른 쓰레드에서 lock 객체에 접근하면 더이상 쓰레드간 동기화 효과가 없습니다. 자바에서 모든 객체는 레퍼런스 객체입니다. 그런데 synchronized 블럭에서 동기화를 위해 참조하는 객체는 이 레퍼런스 객체가 아니라 레퍼런스 객체가 참조하고 있는 실제 객체입니다. 따라서 비록 같은 lock 객체라 하더라도 이 객체가 참조하는 실제 객체가 바뀌었기 때문에 쓰레드간 동기화는 깨지고 맙니다.

 이 글의 처음에 소개된 SharedData 클래스의 잘못된 점은 intData 나 boolData 가 setter 메소드에서 다른 값이 할당되는 순간 Auto boxing 에 의해 다른 객체를 참조하기 때문입니다. 그러므로 이 시점에 다른 쓰레드가 synchronized 블럭에 접근하게 되더라도 다른 객체에 접근하기 때문에 락이 해제될때까지 기다리지 않습니다. 따라서 어떤 경우라도 synchronized 블럭 내에서 락 객체의 참조값을 변경하지 말아야 합니다. 보통 이런 실수를 할 소지는 적습니다만 SharedData 클래스 예처럼 Auto boxing 이 발생하는 Integer, Boolean, Long 등과 같은 클래스를 사용할 때는 자칫 착각할 수 있습니다. 

 이제 SharedData 클래스의 동기화 방식이 위험한 이유에 대해서 설명하겠습니다. 우선 아래 코드를 보시기 바랍니다.

public class SyncTest {
  static private String lock = "This is a lock;

  static class TestRunnable implements Runnable {
    @Override
    public void run() {
      try {
        synchronized (lock) {
          System.out.println("before sleep in thread");
          Thread.sleep(1000);
          System.out.println("after sleep in thread");
        }
      } catch (Interrupted Exception e) {
      }
    }
  }

  public static void main(String[] args) {
    // 이전 코드와 동일...
  }
}

위 코드가 제대로 동작할까요? 
 - 예 그렇습니다.
그렇다면 좋은 방법일까요?
 - 아뇨 그렇지 않습니다(Joshua Bloch 말투 좀 흉내내 봤습니다).

그러면 왜 좋은 방법이 아닐까요? 왜냐하면 String 객체를 락으로 사용하는 것은 예기치 않은 dead lock 을 발생시키기 때문입니다. 예를 들어 아래 코드를 보시죠.

public class BadLockSample {
  static void main(String[] args) throws Exception {
    String lock = "This is a lock";
    synchronized (lock) {
      Future<String> future = Executors.newSingleThreadExecutor().submit(new Callable<String>() {
        @Override
        public String call() throws Exception {
          String anotherLock = "This is a lock";
          synchronized (anotherLock) {
            return "Result";
          }
        }
      });
      System.out.println(future.get());
    }
  }
}

 위 코드에서 메인 쓰레드와 Callable 클래스가 호출되는 쓰레드는 서로 다른 락 객체를 사용하고 있습니다만 실행시켜보면 데드락이 발생하여 프로그램이 종료하지 않습니다. 왜 그럴까요? 그 이유는 자바에서 문자열을 다른 객체와 달리 특별한 방식으로 관리 하기 때문입니다. 자바는 메모리를 절약하기 위해 컴파일 시점에 평가 가능한 문자열에 대해서 영구 메모리에 문자열을 저장하며 이 문자열을 참조하는 String 객체들은 명시적으로 new String() 을 사용해서 객체를 생성하지 않는한 같은 문자열일 경우 동일한 객체를 참조하게 됩니다(혹은 String.intern() 메소드를 호출하면 명시적으로 이런 처리가 가능합니다).
 결국 위에서 lock 과 anotherLock 은 다른 레퍼런스 객체이지만 동일한 상수 문자열을 참조하기 때문에 사실 동일한 객체나 마찬가지입니다. 따라서 위 프로그램의 메인 쓰레드와 Callable 쓰레드는 같은 락을 획득하려고 경쟁하기 때문에 데드락이 발생합니다. 
 그런데 이게 SharedData 클래스와 무슨 관계일까요? SharedData 에서는 String 이 아니라 Integer 와 Boolean 객체를 사용했고 이들 클래스는 Auto Boxing 에 의해 primitive type 값을 자동으로 해당 타입에 맞는 객체로 생성해줍니다. 따라서 String 에서처럼 같은 객체를 참조할 일은 없을 듯 싶습니다.
 하지만 실제로는 그렇지 않습니다. 왜냐하면 Integer 나 Boolean 같은 Wrapping type class 들은 성능 향상을 위해 몇몇 값들에 대해서는 매번 객체를 새로 생성하는 것이 아니라 미리 만들어 놓은 객체를 재 사용하기 때문입니다(이런 방식을 Flyweight pattern 이라고 합니다).
 따라서 SharedData 객체를 만약 아래와 같이 사용하게 되면 데드락이 발생합니다.

public static void main(String[] args) {
static void main(String[] args) throws Exception {
    Integer lock= 0;
    synchronized (lock) {
      Future<String> future = Executors.newSingleThreadExecutor().submit(new Callable<String>() {
        @Override
        public String call() throws Exception {
          return new SharedData().getInt();
        }
      });
      System.out.println(future.get());
    }
  }
}

 결론적으로 값 객체를 직접 락으로 사용하지 말아야 합니다. 꼭 값 객체를 별도의 락으로 동기화시키려면 java.util.concurrent.lock.ReentrantLock 같은 락 전용 클래스 객체를 사용하는 것이 좋습니다.

p.s. 노파심에서 언급하는 건데...혹여라도 ReentrantLock 을 아래처럼 사용하지는 마세요...

Lock lock = new ReentrantLock();
synchronized (lock) {
  ....
}

java.util.concurrent.lock.Lock 관련 클래스들의 올바른 사용법은 다음과 같습니다.

Lock lock = new ReentrantLock();
lock.lock();
try {
  ....
} finally {
  lock.unlock();
}

by silverbird | 2009/02/28 12:06 | 프로그래밍 | 트랙백 | 덧글(3)

경험이 우리에게 주는 것

 '지금까지 작성한 코드는 총 몇 줄?' 이란 글에서 글쓴이는 지금까지 몇 줄이나 프로그래밍을 해봤는지 혹은 경력이 얼마나 되는지는 큰 의미가 없다고 주장합니다. 이와 비슷한 주장은 여러 글에서 많이 봤습니다. 주변에서 소위 업계에 잔뼈가 굵은 선배 개발자가 있었는데 도대체 그 년차가 될 동안 뭐했나 싶을 정도로 실력이 형편 없더라는 그런 이야기들도 함께 하면서 말이죠.

 어쨌든 이글에는 다음과 같은 주장이 담겨 있습니다.
1. 사람마다 학습 능력의 차이가 있다. 따라서 사람을 뽑을 때는 그 사람의 경력보다는 학습 능력을 파악해야 한다.
2. 학습 곡선은 선형적이지 않다. 따라서 경력이 쌓일 수록 실력이 늘어나는 속도는 점점 줄어든다. 따라서 경력이 많다고 해서 적은 사람보다 실력이 그렇게 뛰어나진 않다.
3. 프로그래밍은 노력만으로 극복하기 힘든 즉, 재능이 필요한 전문적인 작업이다.

 일견 맞는 말입니다. 사람마다 학습 능력에 차이는 있고 따라서 10년차 경력자가 반드시 1년차 개발자보다 실력이 뛰어나지는 않을 것입니다. 그런데...  사람마다 다른 그 학습 능력이란 것은 대체 어떻게 구분하고 파악할 수 있을까요? 학습 능력을 파악하려면 그 사람을 가르쳐보는 것이 가장 확실한 방법입니다. 하지만 그렇다고 면접보러 온 사람에게 '당신의 학습 능력을 알아보고 싶으니 저희 회사에 한 1주일 정도만 나와서 우리 하는 일을 배워보시겠습니까?' 라고 말해야 할까요? 아니 사실 그 사람의 능력을 제대로 파악하려면 1주일 가지고는 어림도 없습니다. 적어도 몇 달 혹은 1년 정도는 같이 지내봐야 하겠죠. 즉, 현실적으로는 같이 일해보지 않는 이상 그 사람을 평가한다는 것은 거의 불가능한 일입니다. 대신 그 사람이 '코드 몇 줄이나 짜봤냐' 혹은 '이러이러한 기술 혹은 분야를 얼마나 경험해봤냐'를 아는 것은 적어도 '이 사람이 평균적인 학습 능력을 가졌다면 이 정도 실력은 되겠구나' 라는 것을 추정하는데 도움이 되는 정보입니다. 정리하자면 코딩 줄 수는 절대적인 가치는 될 수 없지만 적어도 편리한 보충 자료 역할은 할 수 있습니다.

 학습 곡선이 선형적이지 않다는 말 역시 맞습니다. 시험에서 50점 맞던 학생이 80점 맞는 것보다 90점 맞던 학생이 100점 맞는 것이 더 어렵습니다. 그런데 그렇다고 만약 누군가가 '5년 차 개발자나 10년 차 개발자나 또이또이다.' 란 주장을 한다면 그건 좀 난감합니다. 만약 그런 사람이 있다면 전 이렇게 물어보고 싶습니다. '그럼 당신은 회사에서 5년 차부터는 연봉을 인상해주지 않더라도 괜찮겠습니까?'

 회사는 학원이나 학교가 아닙니다. 사람을 학습 능력이나 실력이 향상되는 양에 비례해서 평가하지도 않고 심지어 실력만으로 평가하지도 않습니다. 연봉 협상 자리에서 '전 제 작년에 파이썬을 마스터했구요. 작년에는 루비를 공부해서 10분 만에 제 블로그 만들었어요. 그러니 연봉 인상해 주세요.' 라고 주장할 수는 없습니다(뭐 신입사원 면접이라면 어필이 될 수 있겠죠).

 '프로그래밍은 지적이며 창조적인 예술이다.' 란 말을 많이 합니다. 그래서 재능 이야기도 나오고 사회가 우릴 몰라준다는 항변도 하고 그러죠. 그런데 정말로 그런지는 좀 생각해봐야 할 문제입니다. 여러분이 개발자라면 자신이 지금 작성하고 있는 코드를 한 번 바라보십시오. 정말로 지금 만들어 놓은 프로그램이 자신의 모든 역량을 최대한 발휘해서 만들어 놓은 예술 작품이라고 생각하십니까? 평범한 사람은 감히 생각하지 못했을 자신만의 독창적인 알고리즘을 가지고 있습니까? 누가봐도 감탄을 금치못할 깔끔하고 세련된 구조를 가지고 있습니까? 더 이상 뺄것이 없는 완벽한 코드를 위해 방망이를 다듬고 있습니까? 아니면 그냥 예전에 배운대로 혹은 저번에 했던 방식으로 반복적인 코딩과 기계적인 리펙토링을 하고 있습니까?
 혹자는 '난 정말 예술적인 프로그래밍을 하고 싶은데 일정 상 어쩔 수 없이 이렇게 할 수 밖에 없다!' 라고 항변할지 모릅니다. 아닙니다! 어쩔 수 없다라고 생각하는 바로 그 일이 원래 지금 하고 있는 그 일의 본질입니다.
 
 '소프트웨어 아키텍처 문서화' 라는 책의 '역자의 말'에서 인상적인 문구를 보았습니다. 역자들이 들은 아키텍처 수업 시간에 교수가 학생들에게 다음과 같이 말했다고 합니다.

'자네들 모두 소프트웨어 아키텍트가 되고 싶은 거 아네. 그런데 그거 아는가? 아키텍트가 하는 일 중에 98%는 모두 따분하고 재미없는 문서화 작업이라는 거. 나머지 한 2% 정도만 자네들이 신나고 재미있어 하는, 뭔가를 설계하고 결정하는 일이지. 힘빠지는 얘기겠지만, 어쩌겠는가? 대부분의 전문분야가 다 이런 식으로 돌아가는걸.'

 프로그래밍 역시 마찬가지입니다. 우리가 지적이고 예술적인 재능을 뽐낼만한 기회는 극히 드뭅니다. 대부분의 작업은 지루한 반복작업이며 이것을 잘 처리하는 능력은 대개 우리의 재능에서 나오는 것이 아니라 경험에서 나옵니다.
 자신의 일에 대해 자부심을 가지고 있는 것은 높이 평가할만 하지만 그렇다고 과대포장해서는 안될 일입니다. 

 못푸는 문제는 계속 못풀고 한번 실수하면 똑같은 실수를 반복한다는 주장은 섣부릅니다. 비록 우리는 똑같은 실수를 반복하지만 그게 무의미하지는 않습니다. 더 많이 실수하면 결국 더 이상 그 실수를 하지 않게되는 순간이 올 수도 있고 전에는 실패했던 방법이 상황이 바뀌면서 더 이상 실수나 실패가 아닌 순간이 올 수도 있습니다.

 얼마전 raganworld 라는 블로그에서 Old 라는 글을 읽었습니다(좋은 글입니다. 일독을 권합니다). 이 글에서 글쓴이는 경험이 쌓일수록 얻게 되는 이득에 대해 이야기 합니다. 얼핏 생각하기에 경험이 많으면 예전에 했던 실패를 거울 삼아 그 때 했던 삽질을 반복하지 않는 장점이 있다라고 생각하기 쉽습니다. 그러나 글쓴이는 그 뿐만이 아니라 때로는 예전에 실패했던 방법 그 자체가 언젠가 상황이 바뀌어 미래에는 적합한 해결책이 될 수도 있기 때문에 경험이 중요하다고 말합니다. 포유류는 백악기 시대에는 낙오자였을지 모르지만 지금은 - 물론 바퀴벌레는 그렇게 생각하지 않겠지만 - 세계를 지배하고 있습니다. 그것은 포유류의 능력이 갑자기 향상되었기 때문이 아니라 기후가 바뀌었기 때문입니다.

 이처럼 과거의 경험은 현재의 문제를 해결하는데 필요한 매우 중요한 정보가 됩니다.그 경험이 똑같은 실수를 반복하는 것을 피하는데 사용될 수도 있고 반대로 좋은 해결책 자체가 될 수도 있습니다. - 진부한 표현이지만 - 경험의 힘입니다.

 '사람을 평가하는데 있어 그 사람의 미래 가능성을 보는 것이 중요하다.' 라는 주장에는 이론의 여지가 없습니다. 좋은 말입니다. 하지만 그렇다고 해서 과거 그 사람이 쌓아온 경험을 무시해서는 안됩니다. 미래 가능성과 과거 경험은 둘다 그 사람의 현재를 평가하는 주요 속성입니다.
 '너 지금까지 코드 몇 줄이나 짜봤어?' 라는 질문은 가볍게 보자면 한없이 가볍게 볼 수 있는 유치한 질문일 수도 있겠지만 그 내면에는 무시할 수 없는 무게를 가지고 있습니다. 마찬가지로 누군가가 '나 지금까지 한 백 만줄 짜봤어' 라고 말한다면 '치 코드 양이 중요한가 뭘 어떻게 짜봤는가가 중요하지...' 라고 코웃음치기 전에 그가 지금까지 백 만줄의 프로그래밍을 하기까지 겪었던 수많은 경험의 무게를 느껴볼 필요가 있습니다. 삽질도 백만번 하면 왠만한 포크레인 수준입니다.

by silverbird | 2009/02/22 20:25 | 단상 | 트랙백(2) | 핑백(3) | 덧글(5)

몇 가지 링크들

by silverbird | 2009/02/18 19:43 | 기타등등 | 트랙백 | 덧글(0)

<< 이전 페이지     다음 페이지 >>