수요일, 10월 30, 2013

[일상다반사] 호프스태터와 인공지능

평상시에 늘 좋은 글을 소개해주시는 R님(@rhea813)께서 '<괴델, 에셔, 바흐>의 더글러스 호프스태터가 생각하는 AI'라는 트윗을 올려주셨기에 (거짓말 조금 보태) 숨도 쉬지 않고 The Man Who Would Teach Machines to Think를 읽어봤다. 오늘은 여기에 대한 감상문을 정리해보겠다.

아마 이 블로그 애독자라면 더글러스 호프스태터라는 이름은 한번 쯤 들어봤을테다. 1979견에 출간되어 퓰리처상을 수상한 Gödel, Escher, Bach: An Eternal Golden Braid는 '생각'과 '인지'에 대한 관점을 완전히 바꿔버린 명서이며, 유명한 과학저술가인 마틴 가드너는 이 책을 다음과 같이 평가하기도 했다.

Every few decades, an unknown author brings out a book of such depth, clarity, range, wit, beauty and originality that it is recognized at once as a major literary event.

퓰리처상이 언론, 문학, 음악과 관련해 수여되는 상임에도 불구하고, 호프스태터는 GEB를 수학, 미술, 음악에 대한 책이 아니라 신경과 두뇌, 사고와 인지에 대한 책으로 강조한다. 하지만 GEB에서 아주 살짝(!) 드러난 호프스태터의 문학, 수학, 예술, 언어, 철학에 대한 뛰어난 식견과 안목을 놓고 생각해보면... 인문학이 뭔지도 모르면서 인문학이라는 주제로 신나게 약파는 일부 몰지각한 사람들은(공학도들이 인문적인 소양이 부족하다는 둥... 좋은 제품을 만들려면 인문학적 특성을 가미해야 한다는 둥, 공자왈 맹자왈 ... 말은 청산유수다...) 호프스태터 앞에 일렬로 무릎꿇고 반성해도 시원치 않다. 빅 마우스 10명 아니 20명이 합세해도 엄청나게 무서운(진짜 말 걸기조차 무섭다고 한다) 호프스태터 앞에서는 특급 프로 체스 선수 앞의 동네 아마추어 모양으로 떡실신하리라 확신한다(지금 이 대목에서 웃으면 GEB의 '바흐' 부분을 읽은 사람이다. ㅋㅋㅋ).

자 그러면 도대체 GEB와 같은 역작을 내고 많은 사람들을 인공지능 연구로 끌어들인 호프스태터는 그 이후 무엇을 하고 있을까? 대학교 학창시절 인공지능 과목을 들을 때도 호프스태터의 이름은 수업시간에 언급되지 않았고, 요즘 엄청나게 쏟아지는 각종 연구 결과와 제품에도 그림자조차 비치지 않고 있다. 35살의 나이에 GEB로 당대 최고의 지식인이 될만큼 대단했던 호프스태터는 요즘 어디서 무엇을 하고 있을까? 일상에 찌들려 호프스태터라는 이름(다행스럽게 책장에 GEB와 The Mind's I가 꽃혀 있어 앞을 지날 때마다 종종 기억을 되살려주곤 하지만...)도 흐릿해질 시점에서 더 아틀랜틱에 실린 기사는 가뭄에 단비와도 같았다.

잠시 숨을 돌리기 위해 요즘 인공지능 추세를 살펴보자. 과거 '전문가 시스템'과 '기계 학습'으로 불렸던 이론을 토대로 IBM이 체스 기계를 만들고 구글이 번역 기계를 만들면서 내새운 구호는 간단하다. "더 많은 자료를!" 손에 들고 다니는 스마트폰의 성능이 초창기 슈퍼 컴퓨터(응?)에 맞먹을 수준에 이르렀고, 클러스터나 초병렬 컴퓨터 개념을 넘어 클라우드/가상화에 저렴한 컴퓨팅 파워와 스토리지를 갖추게 됨으로써 방대한 정보(심지어 '빅 데이터'라는 약 파는 용어도 등장했다!)를 잘 처리하면 저절로 컴퓨터에 지능이 생길 것으로 희망하고 있다(뉴턴 시절의 낙관주의를 떠올리게 만든다). 엄청나게 긁어모은 문서를 토대로 구글 번역기 수준은 초창기에 비해 일취월장했으며(특히 과거부터 번역에 목숨을 건 일본어를 중심으로 하는 번역 품질은 기절초풍할 수준이다), 체스에서 모든 사람을 놀라게 만든 IBM의 슈퍼 컴퓨팅 기술은 일반적인 산업 분야에도 기계 학습과 인공지능(?)을 전파하고 있으며, 대중의 사랑을 받는 애플의 시리 역시 사용자들의 질문과 대응을 누적하며 점점 더 강력해지고 있다. 하지만 이렇게 수 많은 자료를 긁어모아 처리한다고 해서 과연 컴퓨터가 '생각'을 하고 '인지'를 갖추게 될 것인가? 태풍에 휩쓸린 자동차 폐차장의 부품들이 이리저리 결합되어 신형 스포츠카가 탄생할 확률보다는 높지만 여전히 갈길은 멀어 보인다.

일흔이 다 된 호프스태터는 아직도 미련을 버리지 못하고 '무지막지한 자료'를 토대로 무지막지하게(brute force) 인공지능을 달성하는 방법 대신 사람이 생각하는 방식 그대로를 컴퓨터에게 가르치려 시도하고 있다. 여러 대학과 연구소에서 인공지능 관련 프로젝트를 제안했을테지만 (상업적으로 컴퓨터를 길들이는(응?) 주제로는) 성이 안 찼을테니, 외부(특히 인공지능 학회나 관계자)와 인연을 끊고 인디애나 대학교에서 자신의 꿈을 이루기 위해 소규모 팀을 운영하면서, 자신의 내면에서 일어나는 사고와 사고로 인한 행동을 직접 탐험하는 방식('현상학'이라고도 한다)으로 사실상 '컴퓨터'와는 무관하게 보이는 연구를 진행하고 있었다. 강직한 호프스태터는 잘 알면서도 실제 '지능'과 무관한 '인공지능'을 '지능'으로 포장해 파는 사기꾼 대열에 합류하기 싫었기 때문이었다. 다음 호프스태터의 말이 이를 뒷받침한다.

To me, as a fledgling AI person, it was self-evident that I did not want to get involved in that trickery. It was obvious: I don't want to be involved in passing off some fancy program’s behavior for intelligence when I know that it has nothing to do with intelligence. And I don't know why more people aren't that way.”

해커스에도 나오지만 ARPA가 DARPA로 변하면서 군과 무관한 기초적인 학술 연구에 투자를 끊으면서부터 MIT에서 싹을 틔운 1세대 해커들이 사분오열되며 급격히 상업적인 영역으로 넘어갔듯이, 순수한 '인공지능' 연구도 자금줄이 말라갔다. 호프스태터가 주장한 '인간의 지능을 이해하는 방법'에 대한 기초 연구가 결실을 맺지 못했기에 '인간 문제를 지능적으로 해결하는 방법'에 대한 응용 연구가 주도권을 잡으며 이미지 인식(군사 목표에 대한)과 전문가 시스템(복잡한 의사 결정을 도와주는) 분야가 급격하게 부상했다. 그리고 호프스태터는 사람들의 기억에서 급속히 잊혀지기 시작했다.

호프스태터는 마치 자신의 운명을 예언하기라도 한 듯, 인공지능 분야의 상황을 다음과 같이 요약했었다. "인공지능 분야의 모든 활동은 근본적으로 컴퓨터의 경직성을 타파하기 위한 전투다." 개인적인 생각(B급 프로그래머가 주절주절 늘어놓는 말은 너무 심각하게 받아들이지 말기 바란다. B급인데...)을 피력해보자면, 인공지능(한 걸음 더 나가 컴퓨터 분야)에서 최근 20년 동안 부분적인 전투에서 상당한 승리를 거두었고 일부는 훌륭한 해법을 찾기도 했지만 여전히 큰 그림(즉 전쟁)을 놓고 보면 획기적이고 판도를 완전히 뒤집을만한 성과를 거두지 못한 것으로 보인다. 사람들은 근본을 파고들 생각은 잘 하지 않기에 컴퓨터의 경직성도 문제였지만 사람들의 경직성이 풀어야할 더 큰 문제가 아닐까 싶다. 이런 상황에서 인간의 사고라는 본질을 놓고 벌이는 호프스태터의 고군분투는 놀랍고 대단하고 존경스럽기까지 하다. 아무쪼록 호프스태터의 건투를 빈다!

EOB

토요일, 10월 26, 2013

[독서광] 자바 병렬 프로그래밍

일단 프로그래밍 문제 하나 풀어보자. 다음 예제에서 숨겨진 Iteration을 찾을 수 있겠는가?

package net.jcip.examples;

import java.util.*;

import net.jcip.annotations.*;

/**
 * HiddenIterator
 * 
 * Iteration hidden within string concatenation
 *
 * @author Brian Goetz and Tim Peierls
 */
public class HiddenIterator {
    @GuardedBy("this") private final Set set = new HashSet();

    public synchronized void add(Integer i) {
        set.add(i);
    }

    public synchronized void remove(Integer i) {
        set.remove(i);
    }

    public void addTenThings() {
        Random r = new Random();
        for (int i = 0; i < 10; i++)
            add(r.nextInt());
        System.out.println("DEBUG: added ten elements to " + set);
    }
}

안 그래도 머리 아픈 독자 여러분들께 처음부터 코드를 불쑥 내밀어 대단히 죄송하다. 정답은 가장 마지막에 보여주기로 약속드리며 본론으로 들어가보자. 자바 프로그래머에게 권장할 책 세 권을 뽑으라면 두 번 생각하지 않고, 밥 아저씨의 'Clean Code(번역서: 클린 코드)', 조슈아 블로치의 'Effective Java(번역서: 이펙티브 자바)', 그리고 브라이언 게츠, 더그 리, 조슈아 블로치 등 막강한 저자들이 연합한 'Java Concurrency in Practice(번역서: 자바 병렬 프로그래밍)'을 고르겠다. 세 책 모두 깊이와 재미와 정확성을 모두 갖춘 보기 드문 특성을 제공하며 자바 뿐만 아니라 다른 프로그래밍 언어를 배우는 사람들에게도 많은 도움을 주는 내용을 담고 있다. 색인 작업까지 완료되었기에 조만간 복간판이 나올 '클린 코드'는 이미 이 블로그에서 몇 번 소개했므로 오늘은 넘어가고, '이펙티브 자바'는 조만간 소개해드리기로 하고, 오늘은 처음부터 끝까지 병렬에 목숨을 거는 '자바 병렬 프로그래밍'을 소개하겠다. '클린 코드'와 '이펙티브 자바'에서도 병렬 프로그램에 대한 내용이 일부 나오기는 하지만 병렬 프로그래밍 자체가 방대하고 복잡하다 보니 아무래도 다루지 않는 부분이 더 많기 마련이다.

자 그렇다면 오늘 소개할 '자바 병렬 프로그래밍'의 특징은 무엇일까? 이 책의 최대 장점은 바로 단순 API 설명을 넘어 병렬 프로그래밍의 기본 이론(_기본_이라 얕보면 절대 안 된다. 원래 기본이 제일 어려운 법이니...), API의 설계 사상과 동작 방식, 나쁜 프로그래밍 방법과 좋은 프로그래밍 방법, 아키텍처와 설계 방법, 성능과 확장성을 위한 프로그래밍 방법, 병렬 프로그래밍 테스트 방법, JVM의 내부 동작 방식과 메모리 모델 등을 빠짐없이 다룬다는 데 있다. 처음 이 책을 접하고 500페이지가 넘어가는 두꺼운 분량에 압도될 수도 있겠지만, 좋은 영화는 상영시간도 짧다고 느끼듯 다 읽고 나서 되돌아보면 엄청난 내용을 다루는 이 책이 결코 두껍지 않다는 사실을 느끼게 될 것이다. 자바는 처음부터 스레드와 동기화가 프로그래밍 언어에 속한 1등급 시민이므로 많은 내부/외부 라이브러리가 스레드에 안전하게(또는 특정 상황에서만 스레드에 안전하게) 작성되어 있으므로 API만 적당히 잘 사용하면 되지 않겠느냐는 생각이 들지 모르겠지만, 이 책을 읽다보면 지금까지 저지른 악행(응?)에 등골이 오싹해지고 소름이 끼치는 순간이 몇 번 온다고 장담해드리겠다.

개인적으로 이 책에서 가장 마음에 들었던 부분은 '3부 활동성, 성능, 테스트'다. 물론 다른 부분도 좋지만 특히 3부는 '락'을 중심으로 활동성, 성능, 확장성을 설명하고 있으므로, 단순히 동기화 모델로서 '락'을 넘어 새로운 시각으로 '락'을 바라보게 도와준다. 이 책을 읽고 나면 소스 코드에서 암시적인 락을 잡는 synchronized나 명시적인 락을 잡는 각종 키워드/API 함수를 볼 때마다 다양한 각도에서 이리 뜯고 저리 뜯어보는 좋은 습관이 들지도 모르겠다. 3부 후반에 설명하는 테스트 방법 역시 실전에 도움을 주는 구체적이고도 좋은 내용으로 채워져 있으므로 성능 문제로 고민하는 개발자분들께 많은 도움이 될 것이다.

마지막으로 번역 상태를 살펴보자. 인터넷 서평을 보니 번역이 나쁘다고 말하시는 분이 많았는데... 까칠한 B급 프로그래머 입장에서 보면 특별한 문제 없이 잘 읽혔다. 십중팔구 번역서가 어려우면 원서를 읽어도 어려울테니 굳이 진땀 흘려가며 두꺼운 원서를 독파하려 애쓸 필요는 없어 보인다.

보너스: 신형 홈페이지는 아직 작업을 진행하고 있지만, 옛날 홈페이지는 살아있으므로 소스 코드 등을 살펴보기 바란다. 참고로 에이콘 출판사 번역서 페이지에서도 전체 소스 코드를 내려받을 수 있다.

결론: 중급 이상 자바 프로그래머에게 강력하게 추천한다!

뱀다리: 처음 제시한 문제의 정답은 'System.out.println("DEBUG: added ten elements to " + set);'에 숨어 있으며, set을 출력하기 위해 Iterator를 돌린다. 아무리 간단한 프로그래밍이라 해도 병렬 특성이 들어가면 복잡해지므로 주의에 주의를 거듭해야 한다. T_T

EOB

화요일, 10월 22, 2013

[B급 프로그래머] SQL에서 UNIQUE와 NULL 제약 조건

NoSQL과 같은 최신(응?) 기술이 판을 치는 상황에서 갑자기 구닥다리 SQL을 꺼내 설명하려드니 독자 여러분들께서는 당황 아니 황당하다는 생각이 들지도 모르겠다. 하지만 프로그램을 작성하다보면 아주 기초적인 내용임에도 불구하고 알쏭 달쏭한 경우가 있기 마련이고, 궁금증이 생겼으면 뿌리부터 뽑아버려야 나중에 고생을 덜한다. 오늘 다룰 내용은 UNIQUE와 NULL이다. MySQL이라는 특정 데이터베이스를 기준으로 실험을 할 계획이니 혹시 진짜 여기 나오는 내용을 따라하고 싶은 독자라면 mysql 클라이언트를 하나 띄워놓기 바란다.

자 그러면 시작해보자. 가장 먼저 테이블을 생성하는 과정에서 PRIMARY 키에 대해 NULL 제약 조건을 허용하면 어떤 일이 벌어질까? PRIMARY인데 NULL이 가능한가? 원칙적으로는 모순되는 조건이다.

mysql> create table person (name varchar(64) null, age int, primary key(name)) ENGINE=InnoDB;

다음 명령 결과를 보면 알겠지만, MySQL은 내부적으로 (명시적인) null 지정을 가볍게 무시한다. PRIMARY 키로 지정한 name 필드의 Null을 보면 NO로 설정되어 있다.

mysql> desc person;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| name  | varchar(64) | NO   | PRI |         |       |
| age   | int(11)     | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+

자 그렇다면 난이도를 높여 약간 어려운 질문을 해보자. 위에서 정의한 person 테이블에 insert할 때 다음과 같이 name 값을 주지 않으면 어떤 일이 벌어질까? NOT NULL 조건이라는 사실을 염두에 두고 생각하면 오류가 발생할 것 같기도 하다.

mysql> insert into person (age) values (11);

하지만, 흥미롭게도 결과는 오류가 발생하지 않는다. select로 확인해보면 다음과 같다.

mysql> select * from person;
+------+------+
| name | age  |
+------+------+
|      |   11 |
+------+------+

이런! 화들짝 놀라는 분들도 분명히 계실 것이다. NOT NULL로 지정한 name 필드가 비어 있어! 물론 놀랄 필요가 전혀 없다. 다음 실행 예를 보면 이해가 갈테니까.

mysql> select * from person where name = NULL;
Empty set (0.00 sec)
mysql> select * from person where name = "";
+------+------+
| name | age  |
+------+------+
|      |   11 |
+------+------+
1 row in set (0.00 sec)

예전 수학 시험 문제 중 답이 없는 문제가 하나 있었는데, 답안을 쓰지 않은 학생이 선생님을 찾아가 "답이 없어 안 썼어요!"라 말했다가 혼난 기억이 새롭다. 선생님의 대답은 "답이 없으면 "답 없음"이라 써야지 안 그러면 자네가 모르는지 아니면 정말 답이 없는지 내가 어떻게 구분하나?"였다. NULL은 비어있는 상태를 의미하는 반면 ""는 빈값(즉 비어있는 문자열)을 의미한다(여기에 대해 나중에 블로그 글을 하나 더 올려드릴 계획이다). 여기서 Default가 NULL이 아니라(만일 NULL이라면 앞서 지정한 NOT NULL 조건에 위배된다) ""이라는 사실을 이해하면 이 모든 궁금증이 해소될 것이다.


NULL, NOT NULL로 충분히 장난을 쳤으니 이제 UNIQUE로 넘어가보자. 아까 테이블 그 상태 그대로 다시 다음과 같이 insert 문을 수행해보자. 어떤 결과가 나올까?

mysql> insert into person (age) values (12);

지금쯤이면 독자 여러분들도 속지 않으리라 믿는다. 다음 select 문 결과를 예측하고 있어야 한다.

mysql> insert into person (age) values (12);
ERROR 1062 (23000): Duplicate entry '' for key 'PRIMARY'

간단한 결론: PRIMARY는 NOT NULL이자 UNIQUE 속성이 자동으로 붙는다.


이제 UNIQUE에 집중해보자. 만일 PRIMARY가 아니라 다른 복합 색인을 생성하면 어떻게 될까? person 테이블을 조금 변경해보자.

mysql> drop table person;
mysql> create table person (name varchar(64), age int, money int, primary key(name), index myindex (age ASC, money ASC)) ENGINE=InnoDB;

myindex라는 age와 money를 포함하는 색인을 명시적으로 생성했다. 이제 다음과 같이 age, money 쌍이 동일한 값을 두번 insert 한다. scott/tiger를 보고 웃으면 당신은 옛날 사람이다. ㅋㅋㅋ

mysql> insert into person values ('scott', 100, 100);
mysql> insert into person values ('tiger', 100, 100);

앞서 PRIMARY와는 달리 중복되었다고 투덜거리지 않고 자료가 입력된다. 그러면 중복을 막으려면? myindex에 UNIQUE 조건을 걸어보자.

mysql> drop table person;
mysql> create table person (name varchar(64), age int, money int, primary key(name), unique index myindex (age ASC, money ASC)) ENGINE=InnoDB;

다시 한번 중복해 자료를 입력한다.

mysql> insert into person values ('scott', 100, 100);
mysql> insert into person values ('tiger', 100, 100);
ERROR 1062 (23000): Duplicate entry '100-100' for key 'myindex'

당연히 중복 오류가 발생한다. 자 그렇다면... age와 money를 둘 다 넣지 않으면 어떻게 될까?

mysql> delete from person;
mysql> insert into person (name) values ('scott');
mysql> insert into person (name) values ('tiger');

NULL-NULL이 중복될 경우 UNIQUE 조건을 위배하는지를 묻는 질문인데 주사위를 던져 정상/오류를 답하고 싶을지도 모르겠다. 중복되었다고 투덜거리지 않고 자료가 입력된다!

mysql> select * from person;
+-------+------+-------+
| name  | age  | money |
+-------+------+-------+
| scott | NULL |  NULL |
| tiger | NULL |  NULL |
+-------+------+-------+

앞서 설명했지만 NULL은 값이 아니라 비어있는 상태를 의미하므로 중복되었다고 볼 수 없다. 이미 예상하고 있겠지만, 단일 필드를 대상으로 unique를 지정해도 마찬가지로 NULL 중복(?)이 일어나지 않는다.


독자 여러분의 총정리를 위해 마지막으로 정말 쉬운 문제를 내며 이 글을 마무리하겠다. 만일 PRIMARY가 앞서 살펴본 단일키가 아니라 복합키로 구성되어 있을 경우 1) 중복을 허용하지 않게 하려면 UNIQUE를 붙여야 할까 붙이지 않아도 자동으로 될까? 2) 만일 PRIMARY 복합키는 중복되지 않더라도 복합키를 구성하는 개별 키가 중복되면(주의 기본값!) 어떤 일이 벌어질까? 다음 테이블로 직접 테스트해보시라!

mysql> drop table person;
mysql> create table person (name varchar(64), age int, money int, house int, primary key(name, house), unique index myindex (age ASC, money ASC)) ENGINE=InnoDB;
EOB

토요일, 10월 19, 2013

[독서광] 프로 Git : 그림으로 이해하는 Git의 작동 원리와 사용법

지난 번 [B급 프로그래머] hg/git 클라이언트인 SourceTree에서 git 책 한 권을 소개하겠다고 약속했는데, 까마귀 고기를 먹은게 아니라 책을 늦게 읽는 바람에 이제서야 독후감을 올려드릴 수 있게 되었다. 오늘 소개할 책은 git 책 중에 딱 한 권만 골라라고 요청이 들어올 경우 두 번 생각하지 않고 선택할 "프로 Git: 그림으로 이해하는 Git의 작동 원리와 사용법"이다.

오픈 소스의 활성화와 맞물려 국내에서도 이미 DVCS가 상당히 많이 보급되었기에 이미 git에 대한 이야기는 많이 들어봤을 것으로 생각한다. 깃허브는 이미 명실상부 오픈소스 저장소의 대명사로 자리잡고 있고, 한 때는 전문가의 전유물로 알려진 git는 이제 좋든싫든 기초 지식 정도는 알고 있어야 원활한 오픈소스 프로젝트 진행이 가능한 상황으로 가고 있다. 하지만 git의 진입 장벽은 높기로 악명이 자자하다. 이런 난국을 어떻게 돌파해야 할까? 정답은 바로 '프로 Git'다. 설명을 위한 다이어그램이 아주 다채롭고 풍부한 이 책은 깃허브에 근무하면서 git 전도사로 유명한 스캇 샤콘이 집필했기에 간결하면서도 쉬우면서도 정확하다는 특징이 있다(보통 이 모든 특징을 책 한 권에서 찾아보기가 쉽지 않다). git의 명령 체계는 고수준(Porcelain)과 저수준(Plumbing)으로 나뉘어져 있는데, 이 책은 둘을 절묘하게 잘 나눠 설명한다. 고수준 명령만 사용해도 대다수 작업에 어려움을 느끼지 않지만, 살다보면 저수준 명령을 사용해야 할 경우가 생기기 마련이다. 또한 git의 이해를 넓히려면 저수준 명령으로 눈을 돌려야 한다. 따라서 스캇 샤콘은 본문에서 꼭 필요한 경우에만 저수준 명령을 제시하고, 실제 저수준 명령의 동작 원리는 9장 'Git의 내부'에서 집중적으로 설명한다. 하드코어한 개발자라면 바로 9장부터 읽으며 "어라? git 코어는 일반적인 키-값 저장소에 포인터 개념을 결합해놓은 물건이잖아!"라고 외치며 낄낄거릴지도 모르겠다.

바쁜 독자를 위해 간략하게 이 책의 활용 방안을 소개하자면, 우선 2장 'Git의 기초'와 3장 'Git의 브랜치'를 읽는다. 그리고 나서 조금 써본 다음에 다시 5장 '분산환경에서의 Git'와 6장 'Git 도구'를 읽어본다. 그리고 실제 내부 동작 방식이 궁금한 독자라면 적절한 시점(응?)에서 9장 'Git의 내부'를 읽으면 git를 프로젝트에 적용할 준비가 완료되는 셈이다. 기존 cvs/svn과 같은 버전 관리 시스템에 익숙한 독자라면 아마 git의 파격적인 개념과 접근 방법을 접하면 거의 기절 초풍할지도 모르겠다는 생각을 해본다(이게 바로 git를 처음 접할 때 멍해지는 이유다). cvs/svn을 알고 있기 때문에 유리한 면도 있지만 불리한 면(특히 브랜치와 태그 관리 방법에 들어가면 완전 신세계가 펼쳐진다)도 있으므로 고정 관념을 버리도록 최선을 다하면 좋은 결과를 얻지 않을까 싶다.

독자 여러분을 위해 보너스 힌트를 드리려 한다. 이미 알고 계신분들도 있겠지만, 프로 Git는 원래 PDF 형태로 한국어 번역판이 공개되어 있었다. 자세한 내용은 '프로 Git', 이미 공개된 내용을 왜 책으로 만들었냐고요?를 살펴보기 바란다. 공개된 문서를 다듬어 정리된 번역서 품질이 아주 좋기 때문에 굳이 원서를 읽을 필요가 없다는 생각이다. 그리고 혹시 Hg(Mercurial)에서 git로 넘어갈 필요가 있다면 Mercurial for Git users를 읽어보기 바란다. 원래는 Git 사용자를 위해 만들었으나, Hg 사용자라면 반대 방향에서 접근하면 이해가 손쉬울 것이다.

결론: 고민할 필요없다! 'clone'만 간신히 할줄아는 초급 git 사용자는 물론이고 'branch를 따고 합칠줄도 아는' 중급 git 사용자 모두에게 강력하게 추천한다.

EOB

화요일, 10월 15, 2013

[B급 프로그래머] 10월 3주 소식 정리

시간이 참 빨리 가니 벌써 10월 3주가 되었다. 이번 주부터는 조금 형태를 바꿔 시간별이 아닌 분류별로 정리해 가독성을 높이겠다.

  1. 웹 개발
  2. 개발/관리 도구
  3. 고성능 서버/데이터베이스
  4. 기타 읽을 거리

그러면 기간이 조금 길긴 하지만... 11월 1주에 좋은 소식을 담아 독자 여러분을 찾아뵙도록 하겠다.

EOB

토요일, 10월 12, 2013

[B급 프로그래머] 블로거에 소스 코드 예쁘게 올리기

종종 블로그에 글을 쓰다 보면 소스 코드를 올려야 할 경우가 있다. 지금까지는 <pre> 태그를 사용해 밋밋하고 재미없는 소스 코드를 보여드렸는데, 앞으로는 Javascript code prettifier를 사용해 예쁜 소스 코드를 올려드리려 한다.

유명한 'hello, world'를 예로 들어보자. 지금까지 아래처럼 코드를 보여드렸다면...

/* hello, world! */
#include <stdio.h>

int main(int argc, char** argv) {
printf("hello, world!\n");
return 0;
}

앞으로는 다음과 같이 코드를 보여드릴 계획이다.

/* hello, world! */
#include <stdio.h>

int main(int argc, char** argv) {
printf("hello, world!\n");
return 0;
}

물론 C 코드 이외 다른 코드(HTML, 자바, 루비, 파이썬 등등)도 Javascript code prettifier에서 지원하므로 칙칙했던 B급 프로그래머 블로그가 조금 더 밝아지리라 기대한다.

# Ruby knows what you
# mean, even if you
# want to do math on
# an entire Array
cities  = %w[ London
              Oslo
              Paris
              Amsterdam
              Berlin ]
visited = %w[Berlin Oslo]

puts "I still need " +
     "to visit the " +
     "following cities:",
     cities - visited

그러면 어떻게 이런 마법을 부렸는지 독자 여러분을 위해 간단히 핵심만 설명드리겠다.

  1. 블로거 관리도구를 열어 좌측 메뉴에서 템플릿 항목을 선택하고 [HTML 편집] 버튼을 눌러 HTML 편집 화면으로 들어간다. 편집 화면에서 </head>를 찾아 바로 위에 다음과 같은 코드를 넣는다.
    <link href='http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.css' rel='stylesheet' type='text/css'/>
    <script src='http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js' type='text/javascript'/>
    
  2. 아직 편집이 덜 끝났다. 자바스크립트 코드를 구동하기 위해 <body>를 찾아 다음과 같이 가장 끝 부분에 onload 메소드를 추가한다.
    <body ... onload='prettyPrint()'>
    
  3. [템플릿 저장] 버튼을 눌러 변경 내용을 저장한다. 혹시 모르니 [템플릿 미리보기] 버튼을 눌러 화면이 깨지지는 않는지 확인한다.
  4. 이제 준비가 끝났으므로 블로거 관리도구에서 새 글을 작성해 다음과 같이 간단한 코드를 추가해본다. 알록달록 예쁘게 나와야 한다.
    <pre class=prettyprint>
    int x = foo(); /* foo */
    int y = bar(); /* bar */
    </pre>
    
  5. 코드에 행 번호를 보여주고 테마를 바꾸는 등 추가 정보는 Javascript code prettifier README를 참고하기 바란다.

한 가지 주의 사항을 덧붙이겠다. 이런 부류의 스크립트는 대부분 코드를 있는(!) 그대로 출력하므로 코드 내부에 <와 >등이 들어 있을 경우 웹 브라우저가 내부 문자열을 태그로 인식해 잡아 먹어버린다. 코드량이 적을 경우에는 문제가 되는 부분을 일일이 손으로 수정해도 되지만 그렇지 않은 경우 실수할 가능성이 높다. 다행히도 인터넷에 HTML 코드를 이스케이프하는 도구가 많이 올라와 있으므로(예: Replace special characters with HTML Entities - Online tool), 번거롭지만 이를 사용해 문제가 되는 문자를 치환하기 바란다.

EOB

화요일, 10월 08, 2013

[일상다반사] '해커스' 애독자분들을 위한 이벤트!

해님께서 올려주신 Peopleware 번역을 시작합니다를 이미 읽으신 분들은 알고 계시겠지만, Peopleware의 개정 3판의 번역을 한창 진행하고 있다. 피플웨어 : 정말로 일하고 싶어지는 직장 만들기라는 제목으로 국내에도 이미 2판 번역서가 나와있지만, 절판되었으므로 새로 구입하려는 독자분들께서는 중고책 대신 조금 기다리셨다 새로 번역된 책이 나오기를 기대하시면 좋겠다.

어쩌다보니 이야기가 옆으로 새버렸는데, 오늘 글을 쓴 목적은 피플웨어 소개가 아니라 여러분들께서 열렬히 성원해주신 해커스 애독자를 위한 이벤트 소개다. 이미 짐작하셨겠지만, 이벤트 상품으로 '피플웨어' 번역서를 골랐다. 그렇다면 이벤트 미션이 무엇일까? 2013년 10월 31일까지(시간은 아아주우 넉넉하게 드렸고 그 전에 응모하셔도 무방하다) 다음 중 하나를 골라 진행하시면 된다.

  • 오탈자와 이해 안 가는 곳 정리: (독자 여러분들께 무척 죄송하지만...) 해커스 책이 워낙 두껍다 보니 1쇄에 오탈자가 존재한다. 꼼꼼하신 분들이라면 책을 읽으시다 틈틈히 정리해 최종 결과물을 이메일(노파심에서 주소를 알려드리자면: jrogue 엣뜨 gmail.com)로 보내주시면 된다.
  • 독후감: 그냥 독후감이 아니라, 왜 하필 제목 옆에 '무삭제' 판이라 수식어를 붙였을까? 이를 중심으로 독자 여러분의 생각을 정리해 온라인 서점 서평이나 블로그에 올려주시고 이메일로 확인 편지를 보내주시면 된다.
  • 80년대 경험담: 한국의 개인용 컴퓨터 태동기인 1980년대에 직접 해킹한(좋은 의미로) 경험담을 재미있게 작성해 블로그에 올려주시고 이메일로 확인 편지를 보내주시면 된다. 만일 블로그를 운영하지 않을 경우에는 이메일로 사연을 보내주셔도 된다.

각 미션별로 가장 멋지게 목표를 달성하신 한두분을 뽑아 '피플웨어' 번역서 출간 직후 바로 보내드리기로 약속하겠다. 모든 '해커스' 독자 여러분들의 행운을 빈다!

EOB

토요일, 10월 05, 2013

[독서광] 어떻게 원하는 것을 얻는가

40대 직장인을 위한 조언: 과거 언급은 금물이라는 월스트리트 저널 기사를 읽다보니 다음과 같은 문구가 눈에 띄었다.

"사람들은 타인의 특정한 행동과 관련해 타협을 하거나 관대해야 한다고 생각하지만 그러기보다는 타인의 행동을 이해해야 한다. 타인의 행동 동기가 무엇인지를 인지하는 것이 더 중요하다. 사람들이 왜 어떤 행동을 하는지를 이해해야 한다”고 랑거 교수는 말한다."

그렇다면 타인의 행동을 이해하기 위해 우리는 어떤 노력을 해야할까? 오늘 소개한 '어떻게 원하는 것을 얻는가'라는 책을 읽다보니 다른 주제임에도 불구하고 동일한 해법을 사용한다는 사실에 깜짝 놀랐다. 이 책 저자인 스튜어트 다이아몬드 교수와 인터뷰를 한 기사('어떻게 원하는 것을 얻는가' 저자 스튜어트 다이아몬드 美와튼스쿨 교수)를 읽다보면 다음과 같은 문구가 나온다.

"협상의 가장 중요한 과제는 무엇보다 상대방 입장이 돼 그의 머릿속에 들어가봐야 한다는 것이다. 협상은 그들의 생각과 감성·니즈(needs·원하는 것들)를 파악하는 작업이다. 상대방이 예전에 했던 말도 찾아내 곱씹어야 상대방이 지금 원하는 걸 알 수 있다. 내가 볼 때는 별 의미 없는 것인데, 상대방이 이를 절실히 원한다면 비용 부담 없이 들어줄 수 있다. 그러면 내가 원하는 것을 상대방으로부터 얻을 수 있다."

표현은 다르지만 맥락은 비슷하다. 바로 '남의 입장이 되어 머리속을 그리고 무슨 생각을 하는지 파악하라'로 줄여 말할 수 있다. '어떻게 원하는 것을 얻는가'는 일반적인 자기 계발서나 대인 관계 테크닉 서적으로 읽힐 가능성도 있지만 의외로 우리가 너무나도 간과하는 기본적인 사실을 짚어주기 때문에 그냥 재미로 읽고 끝낼 책이 아니라는 생각이 들었다. 이 책에서 주장하는 가장 핵심적인 내용은 바로 '사람'이다. 다이아몬드 교수는 우리가 협상할 상대는 게임 이론에 나오는 이성적인 인간(스폭)이 아니라 감정적인 인간(커크)이며, 협상을 성공으로 이끌기 위해 전문 지식이나 협상 절차가 아니라 '사람'에 대한 이해가 가장 앞서야 한다고 강력하게 주장한다. 그리고 일상 생활에서 꾸준한 연습에 의해 이런 능력이 배양되므로 평상시에도 물건을 할인 받고 서비스를 추가로 받고 차별 대우를 받았을 때는 정당한 대우를 받도록 노력하라는 조언을 아끼지 않는다. 이 책의 대다수 내용이 (어떻게 보면) 정말 시시콜콜한 사례로 가득차 있는 이유는 이런 사례를 하나씩 따라하라는 것이 아니라 정말 다양한 상황에서 협상이 가능하다는 교훈을 줄 목적이 아닌가 싶은 생각도 들었다. 하긴 시시콜콜한 사소한 협상도 못하는 데 큰 협상이 가능할리 없지. T_T

이 책에서 주장하는 몇 가지 협상의 교훈을 정리해드리겠다.

  • 상대의 머리속을 파악하라: 항상 질문과 대답을 반복하며 상대방의 입장이 되어 구체적으로 상대가 진짜 무엇을 바라며 어떤 생각을 하고 있는지 지도를 그려야 한다. 그러면 협상의 폭이 자연스럽게 넓어진다.
  • 감정이 중요하다: 물리적인 지불을 하지 않고서 감정적인 지불만 하더라도 협상에 유리한 환경을 조성할 수 있다.
  • 동일한 상황은 없다: 전문적인 지식, 협상 절차를 갖추고 충분히 준비하더라도 그 때 그 때 상황은 바뀌기 마련이다. 사람이 동일하고 협상 건이 동일하더라도 매번 달라질 수 있다는 사실을 기억해야 한다.
  • 서로 중요하다고 생각하는 가치를 교환한다: 사람마다 원하는 가치가 다르므로, 돈의 관점이 아니라 요구의 관점에서 교환할 가치를 찾아야 한다. ((어른에 비해) '돈'이 없는 어린이들은 여기에 있어 거의 최고의 능력을 발휘한다)
  • 상대방이 따르는 표준을 활용한다: 사람들은 자신이 내건 표준과 모순되는 상태에 있기를 대단히 거북스러워한다. 협상 과정에서 혹시 상대편이 자신이 내세운 표준과 다른 형태로 계약을 맺으려 든다면 여기에 대해 짚고 넘어가자.
  • 위협과 비난은 해법이 아니다: 보통 목소리 큰 사람이 이긴다는 편견이 만연하다. 하지만, 이런 전략은 한 번은 통할지 몰라도 두 번은 힘들다.
  • 신뢰가 중요하다: 거짓말은 신뢰를 갉아먹는 적이다. 밝혀도 되는 안건에 대해서는 무슨 생각을 하고 무엇을 얻고 싶은지 미리 상대편에게 진실되게 알려주는 편이 협상의 성공 가능성을 높인다.
  • 제 3자를 활용하라: 상대편이 협상에 있어 실질적인 권력이 없는 경우가 있다. 이럴 때는 누구를 움직여야 하는지 이해 당사자를 찾아나서야 한다.
  • 걸림돌을 없애라: 협상 과정에서 나타나는 걸림돌을 차근차근 없애야 한다. 영화와는 달리 협상은 한 방에 화끈하게 끝나는 이벤트가 아니므로 상대방 입장에서 차근차근 문제점을 파악해 제거한다. 걸림돌 때문에 교착 상태에 빠지지 않으려면 처음에 손쉬운 안건부터 처리하는 방법이 유리하다.
  • 논리보다 공감: 단 '공감'이 진실되지 않으면 역풍을 맞을 것이다.

여기까지 읽고 와닿는 뭔가가 있으면 책에 나오는 다양한 교훈과 사례를 읽어보기 바란다. 매번 대인 관계에서 손해를 본다는 느낌이 드는 분들께 특히 추천한다.

뱀다리: 며칠 전 지방 출장이 있어 택시를 타서 기사분과 이런 저런 이야기를 나누던 도중 근무일에 평균 12시간 이상 운전하신다는 이야기를 듣고서 나도 모르게 '감정 지불'(응?)을 해버렸다. 결과는? 공사로 인해 길이 엄청 막혔음에도 불구하고 최대로 빠른 길로 우회해 평상시보다 더 빨리 도착했고 요금까지 할인 받았다. (평상시 에누리라고는 꿈도 못꾸던 상황에서 자신감이 조금 붙었기에) 앞으로도 계속 연습해볼 생각이다.

EOB

수요일, 10월 02, 2013

[B급 프로그래머] 2013년 10월 1주 소식 정리

10월 1주 소식을 정리해드린다.

그러면 따끈한 소식을 정리해 10월 3주에 찾아뵙도록 하겠다.

EOB