한글 글꼴 처리 기술의 변천사

※ 0세대

0이라는 숫자는 뒤에 나올 1~3세대와 비교했을 때 '상대적인' 관점에서 붙여졌다. 1~3에 비해 0은 기계/아날로그적인 성격이 짙다.
한글을 모아쓰기+네모꼴 형태로 표현할 여건이 도저히 안 되는 환경을 말한다. 한 낱자를 상황에 따라 여러 벌로 분간해서 처리할 수가 없고, 최소 수천 자에 달하는 한글을 글자 단위로 부호화할 수도 없다.

옛날에 전보가 한글을 풀어쓰기 형태로 찍었다고 그러고, 김 정수 교수가 고안한 한글 두벌식 기울여 풀어쓰기도 0세대 기술이다. 굳이 풀어쓰기가 아니라도, 쓰이는 한글 몇 글자만 그림처럼 다루는 것도 딱히 기술이란 게 쓰인 게 아니므로 넓게는 0세대 기술로 간주한다.

그나마 0세대 기술 중에서 한글의 원리를 가장 잘 반영한 바람직한 기술은 공 병우 한글 세벌식 타자기, 그리고 그 이념을 물려받은 직결식 글꼴이다.

※ 1세대

제한된 벌수의 자모를 조합하여 한글 글자를 정사각형에다 모아쓰기 형태로 찍을 수 있다. 16*16 크기의 화면용 조합형 한글 글꼴이 바로 1세대의 상징이다.

옛날에 자체 한글을 지원하던 국내 도스용 프로그램들은 전부 이 수준의 기술을 사용하였으며, 도스용 아래아한글 1.x는 더 나아가서 간단한 수준의 옛한글과 자체 조합 로직까지 구현했다. 1세대 기술은 작고 간결하면서도 한글의 조합 원리와 무척 잘 부합한다는 큰 장점이 있기 때문에, <날개셋> 편집기 역시 최소주의를 추구하는 차원에서 딱 이 수준의 기술만을 의도적으로 고수하고 있다.

철도역 승강장의 전광판이 0세대인 롤지나 플랩에서 LED로 바뀌면서 1세대 기술로 한글을 표현한 것들이 많다.

※ 2세대

1세대보다 많이 발전했다. 8*16, 16*16의 한계를 벗어나 글자 크기를 자유롭게 조절할 수 있고 심지어 윤곽선 글꼴을 지원한다. 영문의 경우 W와 I의 폭이 다른 가변폭 글꼴을 지원한다. Windows의 경우 트루타입 글꼴이 도입되면서 글꼴의 기술 수준이 1.x세대에서 2세대 수준으로 껑충 뛰었으며, 아래아한글도 2.x 버전으로 넘어가면서 이 수준에 도달했다.

디스플레이 소자의 기술이 발달하면서 요즘은 전광판이 청색이나 흰색을 포함한 원색도 잘 표현하고 해상도도 더욱 높아졌다. 그래서 종전의 16*16만으로는 글자의 크기가 너무 작기 때문에 2세대로의 전환은 필수이다.
그러나 2세대 기술은 구현체마다 차이는 있지만, 1세대에 비해 한글 자체만의 조합 가능성이나 옛한글 표현 능력은 오히려 퇴보한 경우가 많다. 1코드 포인트당 반드시 한 글자가 대응한다는 한계에 여전히 매여 있기 때문이다.

※ 3세대

글꼴 처리 기술의 만렙으로, PC에는 21세기 무렵부터 도입되었다. 한글까지 가변폭 글꼴의 처리가 완벽하게 지원되며, 가변폭으로도 모자라서 커닝까지 처리된다. OpenType 기술을 이용하여 아랍· 태국어 문자까지도 꼼수 없이 잘 처리할 수 있을 정도인데 하물며 옛한글쯤이야 모아쓰기 형태로 표시를 못 할 이유가 전혀 없다.

유니코드라는 건 이런 글꼴 처리 기술과 결부되지 않을 수가 없는 규격이다. 그렇기 때문에 문자의 서식을 전혀 고려하지 않는 텍스트 에디터를 만든다 해도, 이제는 유니코드를 완벽하게 지원하려면 워드 프로세서를 만들 때나 필요할 것 같은 이런 기술을 어느 정도 사용하지 않을 수 없게 되었다.

3세대에서는 글꼴의 화면 렌더링도 단순한 grayscale 수준을 넘어서서 LCD 화면의 픽셀 구조에 특화된 subpixl 방식을 지원한다.

Posted by 사무엘

2013/08/31 19:47 2013/08/31 19:47
, ,
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/872

한자어로 '원'이라고 부르는 동그라미라는 도형은 시각적으로나 수학적으로나 아주 신기한 도형이다.
둥글다는 게 무슨 의미인지 기계가 계산으로 표현할 수 있을 정도로 엄밀하게 정의하자면 결국 '어떤 점에서 거리가 같은 점들의 집합'이라는 정의가 등장하게 되고, n차원 직교 좌표에서 거리라는 건 결국 차원을 구성하는 각 축의 거리들의 제곱의 합의 제곱근이라고 정의된다.

원의 지름과 원의 둘레의 비율은 그 이름도 유명한 '파이'이며, 3.141592... 로 시작하는 이 값은 무리수인 동시에 초월수라는 것도 상식이다.

그런데 이 원을 정사각형 격자 모양의 래스터 그래픽 장치에서 어떻게 하면 효율적으로 그릴 수 있을까? 그런 물건의 내부엔 컴퍼스 같은 직관적인 도구가 없는데 말이다.
중심이 x, y이고 반지름이 r인 원을 구성하는 좌표들을 어떤 계산을 통해 얻어 올 수 있을까?
원점이 중심인 원의 방정식은 x^2+y^2=r^2. 따라서 y=sqrt(r^2-x^2) 방정식을 이용하면 사분원 내지 반원을 구성하는 점을 구할 수 있다. 그리고 이 값을 바탕으로 나머지 방향의 점을 그리면 될 것이다.

#include <math.h>
template<typename T>
void Draw_Circle(int x, int y, int r, T f)
{
    double R_2 = r*r;
    for(int i=0;i<r;i++) {
        int v = (int)(sqrt( R_2 - i*i )+0.5);
        f(x-i, y-v); f(x-i, y+v);
        f(x+i, y-v); f(x+i, y+v);
    }
}

for문 자체는 0부터 r까지 사분원의 x좌표만 돌고, 이를 바탕으로 점을 찍는 함수 f를 4개 방향으로 모두 호출한다.
r의 제곱 값은 한 번만 계산하면 되므로 for문 밖에서 별도로 선언해 주는 센스도.
소숫점은 버림이 아니라 반올림이 되도록 0.5를 더한 뒤에 int로 캐스팅하는 게 좋다. 그래야 당장 그려지는 원도 90*n도 부근이 더 탱탱하고 보기 좋아진다.

함수의 사용은 MFC 기준으로 이런 식으로 하면 된다. 함수 안에서 또 다른 함수를 내부적으로 호출할 때 함수 포인터보다 람다가 참 깔끔하긴 하다. (너무 남발한 게 꼬이면 code bloat은 피할 수 없겠지만)

CPaintDC dc(this);
auto x = [&](int x,int y) { dc.SetPixel(x,y,0); };
Draw_Circle(220,220, 200,  x);
Draw_Circle(420,330, 160,  x);

사용자 삽입 이미지

그런데 아뿔싸, 역시 기울기가 1보다 더 커지는 곳에는 점이 듬성듬성 떨어져 있게 된다.
이 틈을 점 찍기가 아니라 선 그리기 같은 다른 함수로 메운다는 건 있을 수 없는 일이고..
결국, 우리의 원 그리기 알고리즘은 언제나 기울기가 1보다 작은 구간에서만 동작하게 loop 구조를 바꿀 필요가 있다.
우리는 원을 4등분했는데, 그렇게 4등분된 조각도 한쪽 끝과 맞은편 끝이 완벽하게 대칭으로 이들을 동시에 그려 보자.

가령, 1사분면에서는 x좌표를 1씩 증가시키면서 r로 근접하고(위의 코드에서 i) y좌표는 r이다가 점점 0으로 작아지는데(위의 코드에서 v),
이와 동시에 반대편에서는 y좌표를 1씩 증가시키면서 r로 근접하고, x좌표는 r에서 0으로 근접시키도록 점을 같이 그리는 것이다.
이제 loop는 변수 i의 값이 r에 도달한 지점에서 끝나는 게 아니라 v와 값이 같아지는 지점에서 끝나면 된다. (정확히는 sqrt(2)*r/2 지점이 됨)

{
    double R_2 = r*r;
    for(int i=0; ;i++) {
        int v = (int)(sqrt( R_2 - i*i )+0.5);
        f(x-i, y-v); f(x-v, y-i);
        f(x-i, y+v); f(x-v, y+i);

        f(x+i, y-v); f(x+v, y-i);
        f(x+i, y+v); f(x+v, y+i);
        if(i>v) break;
    }
}

사용자 삽입 이미지
와, 이로써 굉장히 찰진 모양의 원이 그려졌다. 한 번 루프를 돌 때마다 점이 8개가 그려지는 것이다.
그러나 이런 원 하나 그리는데 부동소숫점에, 곱셈에, 심지어 제곱근까지 꽤 부담스러운 연산이 많이 들어갔다.
이걸 좀 줄일 수는 없을까?

...
    int R_2 = r*r;
    int v = r;
    for(int i=0; ;i++) {
        if(i*i + v*v > R_2) --v;
...

loop의 앞부분을 이렇게 고쳐 보자.
x축에 속하는 i의 값이 1증가할 때마다 y축에 속하는 v의 값은 그대로 유지되거나 1 감소하거나 둘 중 한 변화만을 겪을 것이다.
i가 증가함에 따라 원점에서 i, v까지의 거리가 R보다 확 커지게 됐다면, 이 궤적은 원의 범위를 벗어나는 것이므로 y축에 속하는 v를 1 줄여 준다.

실질적으로 행해지는 연산을 이렇게 최적화해 주면 최소한 부동소숫점과 제곱근 연산은 없어진다.
그러나 최적화의 여지는 그래도 여전히 남아 있다. 저 꼴도 보기 싫은 곱셈을 없애려면 어떡하면 좋을까?

방법이 있다.
결국, i*i는 0, 1, 4, 9, 16 ...의 순열을 생성해 낼 텐데, 얘는 덧셈을 두 번 하는 걸로 대체할 수 있다. 한 번 덧셈을 한 뒤엔 증가치가 2씩 늘어나니까 말이다(1과 4의 차는 3, 4와 9의 차는 5, 9와 16의 차는 7). x^2의 도함수가 괜히 2*x가 아니다.

그리고 v는 초기값이 아예 R_2와 같으니 약분이 가능하다. 그 뒤에 v의 값이 줄어들면서 차이만이 발생할 뿐이다. 그런데 얼마를 빼 줘야 할까?
x^2가 (x-1)^2로 바뀌었을 때 감소하는 값은 잘 알다시피 2*x-1이다. 따라서 이 값만 초기에 계산해 놓은 뒤, v가 1 감소하게 됐을 때 가상의 v_square은 그만치 빼 주고, 그 델타값 자체도 2 감소시키면 된다.

...
    int v = r, i_square = 0, i_delta = 1;
    int v_delta=2*r-1, v_square_delta = 0;
    for(int i=0; ;i++) {
        if(i_square + v_square_delta > 0) {
            --v; v_square_delta-=v_delta, v_delta-=2;
        }

... //점 여덟 군데를 찍어 준 뒤

        if(i>v) break;
        else i_square+=i_delta, i_delta+=2;
    }

이로써 그 부드러운 원을 오로지 정수의 덧셈만으로, 그리고 곱셈이라고는 loop 돌기 전에 *2 단 한 번밖에 안 하는 깔끔한 원 그리기 알고리즘이 완성되었다. 놀랍지 않은가? 게다가 고정적인 두 배 연산은 잘 알다시피 bit shift로도 수행 가능한 아주 가벼운 연산이기도 하고 말이다.

GWBASIC, Windows GDI API, 옛날 볼랜드 BGI 등 모든 그래픽 라이브러리에 들어있는 원 그리기 함수는 기본적으로 이 알고리즘을 이용하여 원을 그린다. 각종 알고리즘 서적에 예제로 실려 있는 소스들도 세부적인 변수 활용이나 계수 계산에 차이가 있을지언정 기본적인 아이디어는 동일하다.

사실, 이건 거의 대학교 학부 수준이고 정보 올림피아드 공부라도 했다면 중· 고등학교 시절에라도 접했을 기초적인 내용이다. 진짜 어려운 건 이걸 응용하여 안티앨리어싱을 적용한다거나 타원을 그리거나, 아예 부채꼴 내지 회전된 원을 그리는 알고리즘이다.

단, Windows GDI가 그리는 원은 왠지 좀 엉성하고 덜 예쁜 것 같다. 비교를 할 때 반올림 보정을 안 하는지 경계가 아주 약간 덜 통통하며, 특히 기울기가 1(45도)에 가까워지는 지점에 점의 배치가 지저분하다.
차이를 보이기 위해 움짤을 만들어 보았다. 파란색 원은 GDI 함수로 그린 것이고, 빨간색 원은 우리가 작성한 함수로 그린 것이다.

사용자 삽입 이미지

Posted by 사무엘

2013/07/28 08:27 2013/07/28 08:27
, , ,
Response
No Trackback , 6 Comments
RSS :
http://moogi.new21.org/tc/rss/response/860

IOCCC라고, 사람이 가장 알아 보기 힘들고 충공깽스러운 형태로 작성된 C 프로그램 코드를 접수받는 공모 대회가 있다.
단순 코더가 아니라 전산학 내공과 해커 기질이 충만한 레알 베테랑 프로그래머라면 이미 들어서 알 것이다.

입상작들은 내가 보기에 크게 (1) 아스키 아트형, 아니면 (2) 크기 줄이기 암호형이라는 두 갈래로 나뉜다. 대회에 공식적으로 이런 식으로 참가 부문이 나뉘어 있는 건 아니지만, 여기 참가자들이 추구하는 오덕질의 목표가 대체로 이 둘 중 한 갈래로 나뉘기 때문이다.

전자는 영락없이 아스키 문자로 사람 얼굴이나 문자 같은 그림을 그려 놨는데 그건 컴파일 되는 올바른 C 코드이다. 그뿐만이 아니라 그걸 실행하면 기가 막힌 유의미한 결과물이 나온다. 간단한 게임이라든가 원주율값 계산 같은 것부터 시작해 심지어 CPU 에뮬레이터나 간단한 컴파일러, 운영체제까지 들어있는 경우도 있다.

후자는 수단과 방법을 가리지 않고 길이를 줄이기 위해 들여쓰기, 주석, 헝가리언 표기법 따위는 다 쌈싸먹고 진짜 정체를 알 수 없는 이상한 숫자와 기호와 문자로 범벅이 된 코드인데, 빌드해 보면 역시 소스 코드의 길이에 비해 믿을 수 없는 퀄리티의 동작이 나온다. 자바스크립트 같은 코드를 난독화 처리한 것과 비슷한 형태가 된다.

어떤 언어에서 소스 코드 자신을 출력하는 프로그램을 콰인(Quine)이라고 부른다. GWBASIC이라면 언어에 LIST라는 명령이 있으니 쉽겠지만, 일반적인 컴파일 기반 언어에서는 그걸 만드는 게 보통일이 아니다. 그런데 이 IOCCC 대회 입상작 중에는 A라는 코드가 있는데 그걸 실행하면 B라는 소스 코드가 출력되고, B를 빌드하여 실행하면 C라는 소스 코드가 나오고, 다음으로 C를 빌드하면 다시 A가 나오는... 중첩 콰인을 실현한 충격과 공포의 프로그램도 있었다. 그것도 A, B, C는 다 형태가 완전히 다르고 인간이 인식 가능한 아스키 아트! Don Yang이라는 사람이 만든 2000년도 입상작이다.

역대 수상작들을 보면 프로그래머로서 인간의 창의력과 잉여력, 변태스러움이 어느 정도까지 뻗칠 수 있는지를 알 수 있다. 그리고 이런 대회는 한 프로그래밍 언어의 극악의 면모를 시험한다는 점에서 전산학적으로도 나름 의미가 있다. 들여쓰기와 긴 변수명과 풍부한 주석이 갖춰진 깔끔한 코드든, 저런 미친 수준의 난독화 코드든 컴파일러의 입장에서는 어차피 아무 차이 없는 똑같은 코드라는 게 아주 신기하지 않은가?

다른 언어가 아니라 C는 시스템 레벨에서 프로그래머의 권한이 강력하다. 그리고 전처리기를 제외하면 특정 공백 문자에(탭, 줄바꿈 등) 의존하지 않는 free-form 언어이며, 언어 디자인 자체가 온갖 복잡한 기호를 좋아하는 오덕스러운 형태인 등, 태생적으로 난독화에 유리하다. 게다가 도저히 C 코드라고 볼 수 없을 정도로 코드의 형태와 의미를 완전히 엉뚱하게 뒤바꿔 버리는 게 가능한 매크로라는 비장의 무기까지 있다!

심지어는 C++보다도 C가 유리하다. 함수를 선언할 때 리턴 타입을 생략하고 함수 정의에서는 리턴 문을 생략할 수 있다. 가리키는 대상 타입이 다른 포인터를 형변환 없이 바로 대입할 수 있으며, 또한 인클루드를 생략하고 표준 함수를 바로 사용할 수도 있다. C++이었다면 바로 에러크리이지만, C에서는 그냥 경고만 먹고 끝이니 말이다. C의 지저분한 면모가 결국 더 짧고 알아보기 힘든 코드를 만드는 데 유리하다는 뜻 되겠다.

현업에서는 거의 언제나 C++만 써 와서 잘 실감을 못 했을 뿐이지, C는 우리가 생각하는 것보다 저 정도로 꽤 유연(?)한 언어이긴 하다. IOCCC 참가자의 입장에서 C++이 C보다 언어 구조적으로 더 유리한 건, 아무데서나 변수 선언을 자유롭게 할 수 있다는 것 정도일 것이다.

그러나 겨우 그 정도로는 불리한 점이 여전히 유리한 점보다 더 많은 것 같다. 생성자와 소멸자, 오버로딩, 템플릿 등으로 더 알아보기 힘든 함축적인 코드를 만드는 건 상당한 규모가 있는 큰 프로그램에서나 위력을 발할 것이고, 긴 선언부의 노출이 불가피하여 무리일 듯.

옛날에는 대회 규정의 허를 찌른 엽기적인 꼼수 작품도 좀 있었다.
이 대회는 1984년에 처음 시작되었는데, 그때 입상작 중에는 main 함수를 함수가 아니라 기계어 명령이 들어있는 배열로 선언해 놓은 프로그램이 있었다(1984/mullender). 이건 기계 종류에 종속적일 뿐만 아니라 요즘 컴파일러에서는 링크 에러이기 때문에, 그 뒤부터는 대회 규정이 바뀌어 이식성 있는 코드만 제출 가능하게 되었다.

그리고 1994년에는 콰인이랍시고 0바이트 소스 코드가 출품되었다(1994/smr). 소스가 0바이트이니, 아무것도 출력하지 않아도 콰인 인증..;; 이건 충분히 참신한 덕분에 입상은 했지만 그 뒤부터는 역시 소스 코드는 1바이트 이상이어야 한다는 규정이 추가되었다. 빈 소스 파일을 빌드하려면 빌드 옵션도 좀 미묘하게 변경을 해야 했다고 한다.

이런 코드를 작성하기 위해서는 모든 변수와 함수를 한 글자로 표현하는 것부터 시작해서 평범한 계산식을 온갖 포인터와 비트 연산자로 배배 틀기, 숫자 테이블 대신 문자열 리터럴을 배열로 참고하기(가령, "abcd"[n]) 같은 건 기본 중의 기본 테크닉이다. 그리고 그걸 아스키 아트로 바꾸는 능력이라든가, 원래 오리지널 프로그램을 기가 막히게 짜는 기술은 별개이다. 이런 코드를 만드는 사람은 정말 코딩의 달인 중의 달인이 아닐 수 없다.

이 대회는 전통적으로 외국 해커 덕후들의 각축장이었다. 그러나 지난 2012년도 대회에서는 자랑스럽게도 한국인 입상자가 한 명 배출되었는데, 본인의 모 지인이다. 그가 출품한 프로그램은 영어로 풀어 쓴 숫자를 입력하면(가령, a hundred and four thousand and three hundred and fifty-seven) 그걸 아라비아 숫자로 바꿔 주는 프로그램(104357). 코드를 보면 저게 어딜 봐서 숫자 처리 프로그램처럼 생겼는가. -_-

코드를 대충 살펴보면, long long이 바로 등장하는 데서 알 수 있듯, 나름 32비트 범위를 벗어나는 큰 자리수까지 지원한다. 문자열 리터럴을 배열로 참고하는 것도 곧바로 쓰였음을 알 수 있다.
그리고 옛날의 C 시절에 허용되었던 관행이었다고 하는데, 함수의 인자들을 아래와 같은 꼴로 선언하는 게 이 대회 출품작에서는 종종 쓰인다고 한다.

int func(a,b) int a, char *b; { ... }

하긴, C/C++이 기괴한 면모가 자꾸 발견되는 건 어제오늘 일이 아니다.
a[2]뿐만이 아니라 2[a]도 가능하다든가,
#include 대상으로 매크로 상수도 지정 가능하다든가,
C++의 default argument로 0이나 -1 같은 것뿐만 아니라 사실은 아예 함수 호출과 변수 지정도 가능하다는 것..
switch문의 내부에 for 같은 다른 반복문이 나온 뒤에 그 안에 case가 있다던가..;;

정말 약 빨고 만든 언어에다 약 빨고 코딩한 개발자라고밖에 볼 수 없다.
나로서는 범접할 수조차 없는 이상한 프로그래밍 대회에 한동안 엄청 관심을 갖더니 결국 입상해 버린 그의 오덕력에 경의를 표한다. 그저 놀라울 뿐이다. 이 정도로 소개하고 띄워 줬으니, 그분이 이 자리에 댓글로 소환되는 걸 기대해 보겠다. 아무래도 한국인 다윈 상 수상자가 배출된 것보다는 훨씬 더 자랑스러운 일을 해낸 친구이지 않은가. ㄲㄲㄲㄲㄲㄲㄲ

뭐, 입상했다고 당장 크게 부와 명예가 뒤따르는 건 아니겠지만, 팀장이나 임원이 IOCCC에 대해서 아는 개발자 출신인 회사에 지원할 때 “나 이 대회 입상자요!”라고 이력서에다 써 넣으면 그 이력서의 메리트는 크게 올라갈 수밖에 없을 것이다. 실제로 IOCCC 같은 잉여로운 대회에 참가하는 geek 중에는 구글, MS급 회사 직원도 있고, 사실 이런 대회에 입상할 정도의 guru급 프로그래머가 일자리를 못 구해 걱정할 일은 절대 없을 테고 말이다.

이런 대회에 더 관심 있으신 분은, IOCCC의 국내 저변 확대를 위해 애쓰고 있는 저 친구의 소개 페이지를 참고하시기 바란다.

Posted by 사무엘

2013/04/10 19:20 2013/04/10 19:20
, , , ,
Response
No Trackback , 6 Comments
RSS :
http://moogi.new21.org/tc/rss/response/816

※ 들어가는 말

정렬은 검색과 더불어 컴퓨터가 인간에게 유용한 결과물을 내놓기 위해 내부적으로 가장 빈번히 수행하는 계산 동작에 속한다. 다른 알고리즘의 내부 과정으로 즐겨 쓰이기도 하고 말이다. 전산학 내지 컴퓨터 과학에서 정렬 문제가 얼마나 중요한지에 대해서는 더 말이 필요하지 않다.

정렬은 문제의 목표가 너무나 명확하고 실용적이며, 다양한 관점에서 문제의 접근이 가능하고 좋은 알고리즘과 나쁜 알고리즘의 차이도 아주 드라마틱하게 알 수 있기 때문에... 예로부터 그 특성과 해법이 연구될 대로 연구되어 왔다. 시간 복잡도 관념이 없던 초짜 프로그래머가 O(n^2)와 O(n log n)의 어마어마한 차이를 깨우치는 계기도 대체로 정렬 알고리즘을 공부하고부터이다.

n개의 원소에 대한 정렬 작업은 n개의 원소를 임의의 방식으로 늘어놓는 n!가지의 순열 중에, 원소들의 값 순서가 오름차순이나 내림차순이 유지되는 순열을 선택하는 작업이라고 볼 수 있다. 그리고 일반적인 정렬 알고리즘은 임의의 두 원소와의 비교를 통해 거기서 가능한 선택의 범위를 좁혀 나간다.

이런 원론적인 분석을 통해, 비교 연산 기반 정렬 알고리즘의 시간 복잡도는 아무리 기가 막힌 알고리즘을 고안하더라도 O(n log n)보다는 결코 더 좋을 수가 없다는 것이 증명되어 있다. 그리고 정렬 알고리즘 중, 제자리(in-place)라는 특성을 지닌 알고리즘은 교환(swap)이라는 동작도 공통적으로 사용하게 된다.

정렬 문제는 NP 완전 문제라고 알려져 있는 외판원 문제(TSP)에서 정점(vertex)들이 일렬로 쭉 나열되어 있는 특수한 경우라고 볼 수도 있다. 가까운 순서대로 순서대로 방문하는 게 정답일 테니 결국 정점들이 정렬된 것이나 마찬가지이다. 비록 domain이 1차원이 아닌 2차원 이상으로 가면 난이도가 곧바로 안드로메다 급으로 치솟지만 말이다.

※ O(n^2) 또는 O(n log n)인 비교 기반 알고리즘

역사적으로 굉장히 많은 수의 정렬 알고리즘이 고안되었으며 이들은 제각기 장단점과 특성이 있다. 알고리즘을 평가하는 주 잣대로는 자료 개수 n에 대한 시간 복잡도와 공간 복잡도가 있으며, 이들도 평균적일 때와 최악의 상황일 때를 따로 평가한다. 이 외에도 자료의 상태에 성능이 민감하게 달라지는지, 그리고 값이 같은 원소의 상대적인 순서가 보존되는지를 나타내는 순서 안정성(stability)을 따지기도 한다.

시간 복잡도가 O(n^2)에 속하는 정렬 알고리즘은 일명 '발로 짠 알고리즘'에 속한다. 직관적이고 구현하기 매우 쉬우나 성능이 쥐약이라는 뜻.
거품 정렬, 선택 정렬, 삽입 정렬이 대표적인데, 거품의 경우 배열이 아니라 아예 random access가 불가능한 연결 리스트 같은 컨테이너에다가 적용해도 좋을 정도로 바로 옆 원소와의 비교와 교환밖에 하지 않는다. 그 때문에 성능이 대단히 나쁘다.

선택 정렬은 비교에 비해 대입 연산이 적고 자료의 상태에 그리 민감하지 않은 게 특징이다. 그에 반해 삽입 정렬은 자료 상태에 따른 성능 편차가 크고 O(n^2) 알고리즘 중에서는 성능이 나은 편이기 때문에, 작은 범위의 입력에 한해서 종종 쓰이는 경우가 있다. 실제로 비주얼 C++의 qsort 함수 구현을 보면, 퀵 정렬을 쓰다가 구간이 8개 이하의 원소로 감소하면 거기는 삽입 정렬로 때운다.

O(n^2) 알고리즘들은 원리가 간단하기 때문에 공간 복잡도는 대체로 O(1)인 in-place이다. 한 쌍의 원소를 그때 그때 교환하기 위한 고정된 크기의 메모리밖에 쓰지 않는다는 뜻 되겠다. 시간이 비효율이면 공간 오버헤드라도 없어야 하지 않겠는가.

이론적인 시간 복잡도에 부합하는 O(n log n)급 알고리즘으로는 힙, 병합, 퀵 등이 있다. 이들은 시간 복잡도만 동일할 뿐 내부적인 특징은 정말 제각각이다.

일단 힙 정렬은 위의 세 알고리즘 중에서 유일하게 메모리 복잡도가 O(1)인 검소한 녀석이다. 그 대신 한 배열 안에서 왔다 갔다 하는 작업이 많아서 그런지 속도는 미세하게 다른 알고리즘보다 더 느린 편. 한 배열 안에서 heap 자료구조를 만든 뒤, 이것으로부터 정렬된 형태의 배열을 역순으로 만드는 두 단계의 과정이 무척 기발하며, 인간의 머리로 어째 이런 걸 생각해 낼 수 있는지 놀라움을 느낀다.

병합 정렬은 동급 시간 복잡도 알고리즘 중에서는 꽤 직관적인 편이고 또 유일하게 안정성도 있어서 좋다. 그러나 FM대로 구현한 녀석은 배열 복사본이 하나 더 필요하기 때문에 메모리 복잡도가 O(n)이나 되며, 대입에 대한 비용이 큰 자료구조에 대해서는 성능 하락의 폭이 큰 게 흠이다.

※ 퀵 정렬

한편, Tony Hoare이라는 영국의 전산학자가 1960년대에 20대 중반의 나이에 고안한 퀵 정렬은 정렬 알고리즘계의 종결자, 야생마, 이단아 같은 존재이다. pivot이라 불리는 중간값을 설정하여, 주어진 구간을 “pivot보다 작은 값, pivot, pivot보다 큰 값” 조건을 만족하게 swap 연산을 통해 바꾼다. 그 뒤, pivot을 기준으로 구간을 양분하여 양 구간도 재귀적으로 똑같은 작업을 한다. 알고리즘도 너무 명쾌하고 깔끔하지 않은가?

이 알고리즘은 대충 부분적으로 정렬되었거나 아예 완전히 무작위인 데이터에 대해서 매우 대단히 좋은 성능을 자랑한다. 그러나 pivot을 어떻게 정하느냐에 따라서 알고리즘의 성능이 크게 좌지우지되며, 자료의 상태에도 매우 민감해진다는 점이 간과될 수 없는 특성이다.

pivot이 데이터의 적당한 중간값으로 설정되지 못하고 하필이면 최소값이나 최대값으로 설정된 경우, 알고리즘 수행 후에도 구간은 깔끔하게 양분되지 못하고 하나씩만 줄어들게 된다. 이 경우 알고리즘의 수행 시간은 O(n log n)이 아니라 O(n^2)에 가까워진다! 역순으로 정렬된 데이터를 정렬하는데 구간의 맨 앞이나 맨 뒤의 값을 pivot으로 쓴다고 생각해 보자.

문제는 이때 시간 복잡도만 늘어나는 게 아니라는 것이다. 분할 정복법을 쓴다는 특성상 퀵 정렬은 재귀호출을 써서 구현되는데, 구간이 반씩 시원하게 안 쪼개지고 하나씩만 쪼개지면 재귀호출의 깊이도 자칫 n회가 될 수 있다는 뜻이다. 이 경우 프로그램은 stack overflow 오류가 발생하며, 이는 프로그램의 보안에도 악영향을 끼치게 된다.

다만, 쪼개진 구간 중에 원소 수가 많은 구간이 아니라 의도적으로 적은 구간부터 골라서 재귀적으로 처리하는 경우, 메모리 복잡도는 O(log n)으로 원천적으로 줄일 수 있다. 퀵 정렬 함수의 구현체 자체에 딱히 동적 배열 같은 게 없더라도 재귀호출 때문에 메모리 복잡도가 올라가며, 원소들이 정확하게 반씩 분할될 경우에 log n에 해당하는 깊이까지 간다는 뜻이다.

일반적으로 퀵 정렬의 구현체는 그냥 구간의 정중앙에 있는 원소만 pivot으로 지정하는 게 보통이다. 이렇게만 하더라도 O(n^2)의 최악 시간 복잡도를 만드는 입력 데이터를 일부러 만들기란 대단히 어려우며, 수학적으로 발생하기도 불가능에 가까운 건 사실이다.

하지만 공격자가 퀵 정렬 구현체의 알고리즘을 알고 있는 경우, 의도적으로 해당 알고리즘이 pivot을 요청할 만한 위치에 일부러 구간의 최대값이나 최소값을 집어넣어서 매 단계별로 퀵 정렬을 엿먹이는 게 불가능하지는 않다! 세상엔 그것만 전문적으로 연구한 사람도 있다. anti quick sort라고 검색해 보셈.. 이것이 퀵 정렬의 진정 오묘하고 이상한 면모라 하겠다.

이걸 이용하여 비주얼 C++의 qsort 함수로 테스트하면, 평소 같으면 인텔 i5 기준 눈 깜짝할 사이에 끝나는 정수 10만 개의 정렬이 수 초 대로 떡실신하는 기현상이 벌어지는 걸 볼 수 있다. 그런데 xcode의 C 라이브러리가 제공하는 qsort는 퀵 정렬을 쓰지 않는지 그런 것의 영향을 받지 않더라..

※ C/C++ 언어에서의 지원

C 라이브러리에 있는 qsort 함수는 콜백 함수에 전달해 줄 사용자 데이터--가령, 비교 옵션 같은 것--를 받는 부분이 없어서 무척 불편하다. 그래서 별도의 사용자 데이터는 전역 변수나 TLS(thread local storage)를 통해 얻어 와야 하는 번거로움이 있다. 이것이 비주얼 C++ 2005부터 도입된 qsort_s에서는 개선되었다.

한편, C++ 라이브러리에도 잘 알다시피 std::sort라는 함수가 있다. C 함수보다 type-safe할뿐만 아니라 iterator를 통해 포인터보다 더 추상적인 자료형도 정렬할 수 있으며, 비교도 직관적인 비교 연산자 아니면 functor로 편리하게 지정할 수 있어서 좋다. 또한 이건 템플릿 형태이기 때문에 정렬 코드가 해당 프로그램의 번역 단위에 최적화된 형태로 embed된다는 것도 더욱 좋다.

C의 경우 비교 연산 함수의 리턴값은 뺄셈 연산을 모델로 삼아서 '음수, 0, 양수' 중 하나를 되돌리게 되어 있다. 그러나 C++ 버전은 < 연산을 모델로 삼아서 그냥 true/false boolean값만 되돌리면 된다는 차이가 있다. 사실, 그것만 있어도 정렬이 되니까 말이다.

C++ 라이브러리에는 sort뿐만이 아니라 stable_sort도 있다. 하지만 실생활에서 꼭 stable_sort를 써야만 할 상황이 있는지는 모르겠다. 실제로 정렬 성능은 굳이 안정성이 지켜지지 않아도 되는 sort가 더욱 뛰어나다.

※ 기타 정렬 알고리즘

정렬 알고리즘의 시간 복잡도는 굳이 O(n^2) 아니면 O(n log n) 중 하나로만 떨어지는 게 아니다. 그 범주에 속하지 않는 대표적인 알고리즘은 셸 정렬이다. 고안자의 이름을 따서 명명된 이 알고리즘은 삽입 정렬이 대충 정렬된 자료에 대한 성능이 뛰어나다는 점을 응용하여, 삽입 정렬을 일정 구간별로 띄엄띄엄 반복해서 적용해 준 뒤 최종적으로 삽입 정렬을 full scale로 한번 돌려서 정렬을 끝낸다.

퀵 정렬이 pivot을 정하는 것이 판타지라면, 셸 정렬은 그 구간을 정하는 방식이 판타지이다. 셸은 분명 O(n^2)보다는 훨씬 더 뛰어난 성능을 보이지만 그렇다고 O(n log n)급은 아니다. 사실, 셸은 구간을 어떻게 설정하느냐에 따라서 시간 복잡도를 계산하기가 대단히 chaotic하고 어렵다.

구간을 두 배씩 좁히는 게 제일 나쁜 방법이이기 때문에 최악의 경우 도로 O(n^2)까지 떨어져 버리나, 약간 머리를 쓰면 O(n^1.5) 정도는 된다. 구간을 가장 잘 잡았을 때 최대 O(n (log n)^2)까지는 갈 수 있다는 것이 알려져 있다. 그래도 셸은 메모리 복잡도가 깔끔한 O(1)이고, 코딩이 상당히 짧고 간결하면서도 O(n^2)보다는 성능이 확실히 낫다는 데 의의가 있다.

앞서 말했듯이 정렬 알고리즘의 시간 복잡도의 한계가 O(n log n)이라는 것은 비교 연산을 사용하는 일반적인 알고리즘이 그렇다는 소리이다. 그런 방식으로 정렬을 하지 않는 알고리즘의 경우, O(n)짜리 알고리즘도 충분히 존재할 수 있다.

가령, 데이터의 도메인이 메달이어서 '금, 은, 동'이라는 세 종류밖에 없는 경우, 자료를 일일이 뒤져 볼 필요 없이, 각 메달의 개수를 세어서 금 a개, 은 b개, 동 c개라고 써 주기만 하면 될 것이다. 부동소숫점이나 문자열처럼 도메인이 굉장히 넓은 자료형은 그런 식으로 정렬할 수 없겠지만, 좁은 범위의 정수 정도면 그런 식으로 발상을 전환하여 비교 연산을 요청하지 않는 정렬 알고리즘을 쓸 수도 있다.

여기에 속하는 대표적인 알고리즘은 기수(radix) 정렬이며, 이 외에도 유사한 전략을 사용하는 알고리즘이 더 있다.

정렬 알고리즘에 대해서는 메아리 풉에도 수학적으로 더 엄밀한 개념 기술이 있으므로 참고하시고, 또 이 홈페이지에는 이미 아시는 분도 있겠지만 본인이 학부 시절에 정렬 알고리즘 모음집이라는 간단한 프로그램을 짜서 올려 놓은 게 있다. 일부 검색엔진에서는 '사이트'로도 등록되어 있다. ㅎㅎ 관심 있으신 분은 거기 소스도 참고하시기 바란다.

* 여담이지만, 전산학 덕후와 해커들의 머리 싸움 덕질에는 끝이 없는지라, 퀵 정렬뿐만 아니라 hash 알고리즘을 엿먹이는 연구도 이미 될 대로 돼 있다.. 특정 해싱 알고리즘에 대해서 충돌만 골라서 일으키는 입력을 생성하는 것 말이다.

Posted by 사무엘

2012/10/04 08:24 2012/10/04 08:24
, , ,
Response
No Trackback , 5 Comments
RSS :
http://moogi.new21.org/tc/rss/response/740

옛날에 나의 기억 속에 남아 있는 매킨토시는 가히 꿈의 컴퓨터였다. 여기서 옛날이라 함은 대략 1990년대를 말한다.

그때 우리의 IBM 호환 PC는 아키텍처가 다 공개되어 있기도 했으니 ‘행정 전산망용’ 내지 ‘교육용’이라는 타이틀을 달고 국내 대기업이 로컬라이즈까지 해서(일본의 로컬라이즈 방식을 따라한 것이겠지만) 보급되고 있었다. 그러니 맥에 비해 희귀하다는 느낌이 덜했다. 그리고 이 기계는 그래픽 성능이 맥보다 훨씬 시원찮았다.

그에 비해 매킨토시는 희귀함과 화려함 그 자체였다. IBM PC가 겨우 도스 명령 프롬프트에서 16색, 256색 VGA를 논하는 동안 매킨토시 화면에서는 화려한 GUI 운영체제에다 천연색 사진 그래픽과 각종 전자 출판물 편집 장면이 나오고 있었다. 듣자 하니 매킨토시 컴퓨터에는 텍스트 모드라는 게 아예 없다는데? (물론, PC에서도 텍스트 모드는 컴퓨터 켠 직후에나 잠깐 보이는 과거 유물 잉여가 된 지 오래이지만.)

사용자 삽입 이미지
이미지 출처는 모 블로그.

기계의 모양을 봐도 모니터와 본체 일체형에, 하드웨어와 소프트웨어도 다 무조건 자기네 순정만 쓰이는 게 고급스러움과 간지 그 자체였고, 웬지 지구인이 만든 물건 같지가 않은 티가 역력했다. 엘렉스 컴퓨터가 총판을 맡던 시절에, 매킨토시는 가격도 억소리 나게 크고 아름다웠기 때문에 딱히 전자출판· 그래픽 분야 종사자나 유학파 얼리어답터들이 아니면 쓸 엄두를 내기 어려웠다.

(물론, 그때 컴퓨터 덕질을 안 하고 그 돈 더 모아서 서울 강남에다 집을 사 놨으면, 지금쯤 떼부자가 됐을 거라고 자조 섞인 말투로 회상하는 얼리어답터도 있다고 카더라)

매킨토시 진영은 서비스 구리고 하위 호환성에 자비심 없는 것으로도 잘 알려져 있다. ‘윈텔’ 진영과는 성향이 달라도 너무 다르다. MS 윈도우야 API의 하위 호환성은 정말 경악스러울 정도이고, x86 아키텍처 자체도 호환성에 목숨 거느라 그 지저분함이 말도 못 할 수준이지 않던가.

그런데, 그 간지 최강 귀족 컴퓨터에서 돌아가는 맥 OS도, X 이전의 클래식 버전은 사실 선점형 멀티스레딩도 없이 기술적으로는 윈도우 95보다도 뒤쳐진 물건이었다고 한다.
하긴, 어렸을 땐 난 시커먼 도스 프롬프트에서 그 허접한 윈도우 3.1이 시동되는 모습만 보고도, 화려한 그래픽에 동심이 매료되고 가슴이 두근거렸는데 하물며 매킨토시는 어땠을까?

그로부터 세월이 흘러 매킨토시 진영의 역사상 있었던 대단히 큰 사건들을 요약해 보자면 다음과 같다. 200x년대에 굵직한 일들이 많았다.

1. 엘렉스 대신 애플 코리아가 직접 한국으로 진출 (1999)
2. 맥 OS X 출시 (2001)
3. 인텔 아키텍처 기반으로 전향 (2005-2006)
4. 아이폰의 흥행 대성공(과 국내에 드디어 시판) (2007, 2009)
(5. 그리고 아마, 잡느님의 사망. 2011)

매킨토시가 옛날에 비해서는 정말 가격도 많이 떨어지고 보급도 많이 된 건 사실이지만, 서비스의 품질은 오히려 엘렉스 시절보다도 못한 면모도 있다는 성토가 여전히 나돈다.
또한 최강의 장사꾼 기질로 한글화를 꼬박꼬박 친절하게 하는 MS 윈도우 진영과는 달리, 맥 진영은 소프트웨어의 한글화도 좀 투박한 구석이 있다. 기본 제공되는 한글 서체의 품질이 저질이라고 폭풍처럼 까여 온 것 역시 그런 맥락일 테고.

맥은 하드웨어 배경이 완전히 다르다 보니 640KB 메모리 제한이라든가 16비트/32비트 썽킹 같은 흑역사는 없다.
다만, PowerPC에서 x86으로 갈아탄 것은 워낙 여파가 너무 큰 변화이기 때문에 제작사인 애플에서도 어떤 형태로든 호환 레이어를 제공하지 않을 수가 없었다. 그래서 CPU 에뮬레이터인 '로제타'를 만들고, 그리고 한 프로그램 바이너리에 아예 x86 코드와 PowerPC 기계어가 같이 들어있는 Universal binary라는 포맷도 제정했다.

물론 지금은 시간이 충분히 지났기 때문에 Snow Leopard던가 Lion이던가 버전부터는 PowerPC 지원은 완전히 끊겼다. 그리고 Universal binary는 PowerPC/x86이 아니라 같은 x86 계열 안에서 32비트와 64비트 코드를 동시에 내장하기 위한 용도로 쓰이고 있다. 앞으로는 ARM과 x86(-64) 사이의 동시 지원이 필요해질 듯.

가만히 생각해 보면 이게 옛날에 MS가 윈도우 NT 시절에 제정한 Portable Executable과 일맥상통하는 개념이 아닌가 여겨진다. 당시에 윈도우 NT는 x86, PowerPC 등 다양한 CPU를 target으로 개발되고 있었기 때문에, 비록 기계어 코드는 공유를 못 하더라도 동일한 헤더로 실행 파일 바이너리들을 식별하고 관리 가능하게 할 필요는 있었다. 하지만 정작 PE는 한 바이너리에 다양한 아키텍처의 기계어 코드를 한꺼번에 담는 건 지원하지 않는다.

세월이 흘러 지금이야 PC의 역량도 충분히 매우 발전하여, 매킨토시를 사실상 다 따라잡은 지가 오래이다. (그런 비주얼 쪽의 발전을 주도한 건 다 게임이라 해도 과언이 아닐 듯.) 기계어까지 가상 바이트코드로 대체하려는 발칙한 시도가 가능해졌을 정도이니 컴퓨터가 얼마나 성능이 좋아진 셈인가?

그랬는데, 지금 나는 그 시절의 매킨토시보다 훨씬 더 성능이 좋은 매킨토시 노트북 PC를 아무렇지도 않게 갖고 다니며 쓰고 있고, 사실 그 기계로 맥OS보다 윈도우를 여전히 훨씬 더 많이 쓰고 지낸다. 격세지감이 아닐 수 없다!

사용자 삽입 이미지
(폭풍간지 사과 무늬...ㅋㅋ)

Posted by 사무엘

2012/08/24 19:37 2012/08/24 19:37
, , , ,
Response
No Trackback , 7 Comments
RSS :
http://moogi.new21.org/tc/rss/response/724

오늘날 PC에서 명맥을 유지하며 살아있는 데스크톱용 운영체제는 역시나 윈도우, 맥, 리눅스 3관왕이다. 다만 이들이 대등한 점유율이 절대 아니며, 셋의 점유율은 공비가 무려 10에 육박하는 등비수열을 이룬다.

맥이야 x86 계열 CPU로 갈아타고 기계의 가격도 내리면서, 옛날에 비해서야 정말 많이 대중화가 되었다. 또한 아이폰/아이패드가 모바일에서 워낙 큰 성공을 거둔 덕분에 맥북/아이맥까지 반사 이익을 보고 있기도 하다. 아이폰/아이패드에서 돌아가는 소프트웨어를 만들려면 결국 그 계열의 PC가 필요하니까 말이다.

그래도 윈도우에 비하면야 맥 사용자는 정말 10% 이내의 소수이다. 맥OS를 작정하고 써 볼 의향이 있는 게 아니라면, 맥 계열 기계는 비슷한 사양의 일반 컴퓨터보다 여전히 비싸며 구입 후에 서비스도 구리고 키보드· 마우스의 일부 동작 방식이 이질적이기 때문에 덥석 권할 게 못 된다. 솔직히 나도 지금의 맥북 살 돈으로 일반 노트북을 샀다면 아마 화면이 두 배 정도 더 큰 걸 살 수 있었지 싶다. 그러나 ‘스잡빠’, ‘앱등이’로 대표되는 굳건한 추종자도 있는 마당에, 이쪽 진영은 결코 없어지지는 않을 것이다.

맥은 소수이지만 인지도라도 있지 리눅스는 그조차도 없다. 리눅스를 서버도 아닌 데스크톱 로컬 환경의 주 운영체제로 쓰는 사람은 가히 소수 중의 소수이다. 작정하고 MS 진영을 반대하고 철저한 copyleft 정신으로 무장한 컴덕후 해커이거나, 잡스를 숭배하는 것처럼 리처드 스톨먼을 숭배하는(최소한 그의 인격이 아니면 그의 이념을) 사람 정도만이 리눅스를 쓰지 않을까 싶다.

물론, 맥이 예전보다 접근성이 개선된 것만큼이나 리눅스도 옛날에 비해서는 초보자가 쓰기 정말 편해지긴 했다. 하지만 그래도 초보자가 쓰기엔 리눅스는 인지도 있는 응용 프로그램이 부족하고, 뭘 세팅하고 바꾸려면 유닉스 명령줄을 다뤄야 하는 등 생소한 면모가 적지 않다.

사용자 삽입 이미지
(연구 목적으로 2010년 무렵에 VM을 만들어서 돌려 본 우분투 리눅스 9.x의 화면이다. 한때 리눅스의 그래픽 셸은 GNOME이냐 KDE냐로 갈라져 혼란스러운 편이었으나, 요즘은 결국 둘 다 지원하는 쪽으로 가는 추세라 한다.)

20년이 넘게 도스와 윈도우에만 길들여지고 10년이 넘게 윈도우 프로그래밍만 해 본 본인의 입장에서 맥 OS에 존재하는 주목할 만한 특징을 간추려 보면 다음과 같다.

가장 먼저, 운영체제의 시스템 메뉴와 응용 프로그램의 메뉴가 한데 완전히 통합되어 있다는 점이 매우 인상적이다.
Windows는 운영체제의 시스템 메뉴에 해당하는 시작 메뉴가 task bar에 있다. 이것은 응용 프로그램의 창에 소속된 메뉴하고는 당연히 완전히 별개이다. CreateWindowEx 함수는 창을 생성할 때 메뉴 핸들도 별개로 받는다.

그러나 맥은 화면 상단에 항상 고정되어 있는 시스템 메뉴에 응용 프로그램의 메뉴가 얹힌 형태로 나타난다. 이런 건 윈도우에서는 OLE 개체 embedding 상태에서나 어렴풋이 볼 수 있는 모습이다.

사용자 삽입 이미지
(제목은 워드패드인데 도움말에 나와 있는 건 그림판. 어?)

응용 프로그램 메뉴는 파일이나 도움말 같은 기본적인 것만 남고, 그 사이엔 개체를 제공하는 프로그램의 메뉴가 뜨는 것 말이다. 요즘은 이런 디자인도 과거 유물로 치부되어 별도의 프로그램 창이 따로 뜨는 형태로 바뀌고 있지만. (MS부터가 자기네들이 만든 표준 메뉴 인터페이스를 구닥다리로 치부하고 안 쓰려 하니 말이다)

맥에서는 시스템 전체를 통틀어 pull-down 메뉴는 하나만 있으며, 한 순간에 현재 활성화되어 있는 프로그램의 메뉴 하나만 볼 수 있다. 문서 창에 메뉴가 따로 달려 있지 않다. 그리고 맥에서 돌아가는 GUI 응용 프로그램이라면 반드시 이런 디자인을 따라야만 한다.

윈도우에서는 대화상자 하나만 달랑 띄우고 따로 메뉴를 만들기는 곤란한 프로그램의 경우, 대화상자의 시스템 메뉴를 customize해서 보통 ‘이동 / 닫기’만 있는 그 메뉴에다가 About이라든가 Always on top 같은 추가 명령을 넣는 경우가 있다. 그러나 맥은 어떤 프로그램에게라도 무조건 기본 메뉴가 주어지니 그런 식의 테크닉이 존재하지 않는다.

맥은 그런 기본적인 인터페이스가 모든 응용 프로그램에서 무조건 동일하기 때문에 윈도우처럼 무슨 오피스 200x 스타일 메뉴나 도구모음줄을 만들어 주는 GUI 툴킷이라는 게 존재하지 않는다. 윈도우에서야 보급 메뉴 대신에 그 자리에다 싸제 메뉴 창을 얹어서 보급 메뉴처럼 동작하게만 만들면 custom UI를 손쉽게 만들 수 있지만, 맥은 그렇게 할 수 없으니 말이다.

비주얼 C++의 MFC 프로젝트 마법사를 보면, GUI 응용 프로그램을 전통적으로 MDI, SDI, 대화상자라는 세 형태로 분류한다. 그런데 맥에서는 어떤 형태의 프로그램도 일단은 가장 범용적인 MDI에서 시작한다고 볼 수 있다. 실제로 문서 창은 하나밖에 생성하지 않는 프로그램이라 할지라도 말이다. ‘<날개셋> 타자연습’을 맥용으로 만든다면, 프로퍼티 페이지의 밖에 존재하는 ‘사용자 로그인’이나 ‘종합 환경설정’ 같은 명령은 응당 메뉴에서 내리는 명령으로 바뀌어야 할 것이다.

또한 맥은 동일 프로그램의 중복 실행에 대한 개념이 Windows와는 다르다. 같은 프로그램은 한 번만 실행되고 그 동일한 프로그램이 여러 문서를 담당한다는 MDI 사고방식이 맥은 더욱 엄격하다. 그래서 맥 OS의 task bar에 해당하는 dock은 프로그램이 실행됐냐 안 됐냐의 여부만 표시되어 있지만, 이 아이디어를 차용한 윈도우 7의 task bar는 프로그램의 중복 실행 개수도 살짝 표시하고 있는 것이다.

이런 디자인 때문에, 맥에서 프로젝트 단위로 문서를 다루는 프로그램은 내부 구조가 많이 복잡해진다. 개발툴이 그런 예 중 하나이다. 비주얼 C++이야 여러 개를 실행해서 제각기 프로젝트를 열면 되지만, xcode는 프로젝트별로 각각의 문서창을 차지하고 있으면서 그 내부에서 또 파일을 편집하는 창을 관리해야 한다.

맥 응용 프로그램은 마지막 문서 창이 닫혀서 문서가 하나도 없는 상태에서 키보드 포커스가 다른 프로그램으로 넘어갈 때 자동으로 종료되는 편이다. 이런 동작 방식은 Windows에서는 볼 수 없던 모습이다.
물론 모든 프로그램이 그러는 건 아니다. 대표적으로 Finder도 파일 표시(윈도우로 치면 탐색기 창 같은) 창이 하나도 없이 포커스가 바뀌더라도 종료되지 않고 언제나 실행되어 있는다. 내장 웹브라우저인 사파리도 마찬가지이다.

키보드로는 Alt+F4에 해당하는 Cmd+Q를 누르면 언제나 프로그램이 종료된다. 단, 윈도우의 Alt+F4는 그냥 창을 닫는다는 보편적인 용도도 포함하는 단축키인 반면, Cmd+Q는 언제 어디서나 해당 응용 프로그램을 완전히 종료시킨다는 의미 차이가 있다.

윈도우 프로그래머라면, 맥에서는 저런 것뿐만이 아니라 응용 프로그램의 파일 구성까지 상상도 못 할 정도로 다르다는 사실에 더욱 놀라게 될 것이다. 단순 실행 파일 말고 GUI 응용 프로그램은 아이콘, 리소스, 구성 파일이 한데 담긴 패키지 형태로 배포된다. 파일 시스템상으로는 디렉터리 구조이지만 운영체제 내부에서는 가상적인 단일 패키지 파일로 취급된다.

맥에서는 그럼 레지스트리가 없으면 응용 프로그램의 설정 저장을 위해 어떤 기법을 쓰는지? 프로그램 추가/제거는 어떻게 하는지? 동일 개발자가 만든 여러 프로그램이 동일 코드를 공유하려면 DLL 같은 건 어느 디렉터리에다 집어넣으면 되는지? 맥은 윈도우 같은 32/64비트 코드 혼용 문제는 없는지?

알고 싶은 게 한두 가지가 아닌데 그런 걸 윈도우 프로그래머의 입장에서 잘 설명해 놓은 인터넷 사이트나 책은 아직까지는 난 못 봤다. 아무래도 둘은 서로 달라도 너무 달라서 두 플랫폼의 사고방식에 모두 완전히 통달한 개발자는 거의 없으리라 예상된다.;;

이렇듯, 그토록 쉽게 다가설 수 없는 이질감에도 불구하고, 맥 OS는 좀 써 보면 윈도우에서는 느낄 수 없는 참을 수 없는 고급스러움, 미적 감각이 느껴지는 건 부인할 수 없다. 맥 같은 녀석이 존재함으로써 IT 세계가 좀 더 다양해지고 MS의 독점을 약간이나마 견제하는 효과가 난 건 인류 전체의 관점에서는 그래도 이익이긴 한 것 같다.

Posted by 사무엘

2012/07/10 08:11 2012/07/10 08:11
, , ,
Response
No Trackback , 10 Comments
RSS :
http://moogi.new21.org/tc/rss/response/705

1.

옛날에 폰 노이만(폰 노이만 구조라는 컴퓨터 근간을 닦은 사람)이라는 사람은 기계어로 직접 컴퓨터에다 코딩을 하는 기계어 매니아였다. 기계어가 너무 불편하다고 어느 제자가 어셈블리 비슷한 상위 계층 언어를 만들려 하자 “귀한 컴퓨터 자원으로 쓸데없는 짓이나 한다”고 그를 나무랐다.;;
이거 마치 희대의 저격수인 시모 하이하가 조준경 그딴 걸 왜 쓰냐고 나무란 것과 비슷한 맥락 같다.;;
 
그 반면, 데이크스트라(다익스트라. 그래프 탐색 알고리즘을 고안한 그 사람)는 어셈블리/기계어 같은 언어를 비생산적이고 삽질스럽다고 아주 강하게 디스한 것으로 잘 알려져 있다. 그도 그럴 것이, 구조화 프로그래밍을 주장하면서 GOTO문을 배격한 사람이 기계스러운 BRANCH 따위가 난무하는 저급 언어를 좋아할 리가 없겠다.
 
둘 다 우주괴수급의 천재 수학자 및 전산학자이다만, 이런 식의 관점의 차이가 존재하는가 보다. 재미있는 일이다.
 
2.

밸브 코퍼레이션의 창립자 게이브 뉴웰 (카운터 스트라이크, 하프 라이프, 포탈 등의 게임 개발사)
페이스북의 창립자인 마크 주커버그 (나보다 더 어림..)
마이크로소프트의 창립자인 빌 게이츠 (설명 불필요)
 
억만장자 IT 기업인인 이들은 모두 하버드 대학 중퇴자라는 공통점이 있다. 다 미국인이기도 하고.

3.

개발자가 소프트웨어를 팔아서 먹고 살려면

(1) 관공서나 기업에서 구입하지 않을 수 없는 핵심적인 프로그램을 개발 (교육이나 업무 분야)
(2) 하드웨어에 같이 들어가는 프로그램을 개발해서 하드웨어와 함께 판매
(3) 온라인 게임 개발 (늘 서버 접속을 하기 때문에 이용료 징수 가능)
(4) 아니면 개인을 대상으로도 유료 판매가 가능한 유통 경로(앱스토어, 스마트폰 등)를 거치는 프로그램 개발

중 하나로는 가야 할 것 같다. 저 네 가지 말고 혹시 다른 방법이 있을까?

4.

내가 맥 OS에 매력을 느끼는 큰 이유 중 하나는.. 폰트 래스터라이저가 정말 짱이라는 점.
똑같은 글꼴을 화면에 찍어 내는 퀄리티가 서로 게임이 안 되는 수준이니...

사용자 삽입 이미지
위는 Windows, 아래는 맥이다.
Windows는 ClearType을 시키면 맑은 고딕처럼 전용 힌팅이 들어간 글꼴이 아니면 그냥 안티알리어싱이 없는 것보다 약간 나은 정도로만 찍히는 반면.
Mac은 힌팅이 없다시피한 글꼴도 Adobe Reader 이상의 퀄리티로 찍어 준다!

5.

그나저나 맥 OS는 Finder (윈도우로 치면 탐색기)에서 파일이나 디렉터리의 이름을 바꾸는 게 엔터이고, 실행하거나 여는 게 Cmd+아래라니 참 희한하다. 윈도우라면 이름 바꾸는 건 F2이고, 여는 게 응당 엔터인데 말이다.

6.

과거에 MS 오피스가 2003에서 2007로 버전업되었을 때 비주얼이 화려해지고 좋아진 기능이 분명 적지 않았지만, 내게는 굉장히 마음에 안 드는 변화도 있었다. 그것 중 하나는 파워포인트에서 '컬러 타자기' 애니메이션 효과가 굉장히 느려져서 랙이 심해지고 프레임 수가 감소한 것이었다. 글자가 말 그대로 타자기로 찍듯이 한 글자씩 천천히 나타나는 것 말이다. 그렇게 현란하거나 CPU의 부하가 심한 효과도 아니다.

그랬는데 2010을 나중에 써 보니, 마치 2003처럼 애니메이션이 다시 매끄러워져 있었다.
혹시 컴퓨터가 빨라지고 화면 해상도가 낮아져서 그런 게 아닌가 싶어서 컴퓨터를 바꿔서 확인해 보았다.
그랬더니 같은 1280*1024 화면이라도 역시 2010에서는 Core2 duo급 컴에서도 매끄럽게 나오는 반면, 2007에서는 쿼드코어 i5급 컴에서도 버벅거렸다.

그래서 이것은 소프트웨어적인 알고리즘 개선 덕분이라는 결론을 내리게 됐다. 2007과 2010 사이엔 이런 차이도 존재하는가 보다.

7.

근래엔 <날개셋> 한글 입력기의 구성 파일들에 대해서 바이러스 및 악성 코드 진단 문의가 부쩍 늘었다. 그래서 그에 대한 개발자의 공식 입장을 내 홈페이지에다가도 게시할 필요를 느끼게 됐다.

결론부터 말하자면 당연히 “바이러스 아님”이다. 모든 프로그램들은 바이러스도, 안티바이러스(일명 백신)도 알지 못하는 100% 청정 컴퓨터에서 개발되며, 개발 환경에서 갓 빌드된 직후의 실행 파일들이 곧바로 설치 패키지로 포장된다. 바이러스 같은 게 들어갈 일이란 없다. 이 일 때문에 본인에게 문의하면 언제나 동일한 대답밖에 돌아올 게 없으며, 그 외에 더 할 말이 없음을 이 자리에서 밝히는 바이다.

더 근본적으로는 실행 파일과 MSI 패키지가 디지털 서명을 받지 못한 관계로, 웹브라우저부터가 빨간 경고와 함께 <날개셋> 프로그램의 다운로드를 저지(discourage)하는 것도 좀 아쉬운 점이다. 이건 훗날 프로그램이 더 나은 수익원과 배포 통로를 확보했을 때에나 해결 가능할 것 같다.

그래서 이 참에 아예 프로그램 다운로드 페이지에다가 설명을 써 놨다. “10년이 넘게 인생을 걸며 이 프로그램을 개발하고 개선해 온 저를 믿으신다면, 그런 보안 경고들은 모두 무시하고 안심하고 사용하시기 바랍니다.

문득 생각해 볼 문제: 비주얼 C++이나 그에 상응하는 개발툴이 설치된 컴퓨터를 자동으로 감지하여 프로그램이 링크될 때 쓰이는 C 라이브러리 같은 lib, obj 파일을 감염시키는 컴퓨터 바이러스 프로그램이 존재할까? 처음부터 바이러스에 감염된 프로그램이 생성되도록? -_-;;

Posted by 사무엘

2012/05/19 08:22 2012/05/19 08:22
, ,
Response
No Trackback , 9 Comments
RSS :
http://moogi.new21.org/tc/rss/response/684

굳이 전산학이나 컴퓨터과학· 공학의 전공자가 아니어도, 그리고 현업 프로그래머가 아니더라도 조금만 기계 다루는 것에 조예가 있는 컴덕후라면 요즘 컴퓨터의 발전 추세가 어떤지는 다들 알 것이다. 사실은 <날개셋> 한글 입력기의 개발자인 본인보다도 더 잘 알 것이다.

튜링 완전하며 메모리로부터 프로그램을 읽어 와서 구동하는(프로그램 내장 방식) 범용 컴퓨터가 발명된 지가 아직 100년은커녕 반세기 남짓밖에 지나지 않았다. 그러나 컴퓨터의 속도와 메모리 용량은 가히 넘사벽급으로 발달했다. 컴퓨터는 지난 수십 년 동안 자연이 아니라 인간의 발명한 물건의 내부에서, 시간에 따른 지수함수 스케일의 발전을 볼 수 있던 얼마 안 되는 엄청난 분야였다.

그러나 그것도 한계는 있어서 컴퓨터 성능의 대표적인 지표이던 클럭 속도가 2003년 즈음에 놀랍게도 지수함수적인 성장이 멈췄다. 10년까지는 아닌 거 같다만 8, 9년 전의 PC나 지금의 PC나 다 3GHz대이다. 오늘날과 같은 반도체 회로라는 근본적인 패러다임이 바뀌지 않는 한, 전력 소모와 발열 때문에 컴퓨터의 기본 동작 자체만의 속도가 더 빨라질 수는 없다.

우리가 다루는 컴퓨터는 생각보다 굉장히 정밀하고 빡세게 만들어져 있다. 예전부터 파이프라인, pre-fetching 등 온갖 있는 테크닉, 없는 꼼수를 다 동원해서, 어떻게든 낭비되는 자원이 없이 모든 자원이 계산에 동원되고, 1ms라도 속도를 더 올리려고 공돌이들의 온갖 공밀레 연구가 동원되었다. 이런 수직적인 성장이 한계에 달하니 요즘 컴퓨터는 코어 수를 늘려서 분업이라는 수평적인 성장을 추구하고 있다.

100이라는 일이 있어서 이게 2GHz짜리 컴으로 다 처리하는 데 10이라는 시간이 걸린다면, 1GHz짜리 컴으로는 20만큼의 시간이 걸릴 것이다. 그러나 1GHz 짜리 컴이 2개 있어서 그 일을 정확히 50씩 분담할 수 있다면, 각각의 컴퓨터의 최대 속도는 비록 1GHz밖에 안 되더라도 10에 가까운 시간 만에 일을 끝마칠 수 있어서 2GHz에 준하는 효과를 낼 수 있다. 이것이 기본적인 아이디어이다.

물론, 딱 10으로 줄이지는 못한다. 일을 분할하고 두 대의 컴퓨터를 세팅하고 굴린 후, 두 컴퓨터(코어)가 내놓은 결과를 취합하는 오버헤드가 역시 결코 작지 않기 때문이다. 그리고 세상에 상호 의존성이 없이 역할을 저렇게 딱 분담할 수 있는 작업이란 흔치 않다.

방대한 계산이 필요한 작업을 다수의 컴퓨터 기계들을 여러 대 동원해서 수행하는 건, 분산 컴퓨팅이라 하여 예전부터 그리 생소한 개념이 아니었다. 3D 그래픽으로 영화를 만드는 업계에서는 rendering farm이라 하여 수많은 컴퓨터들을 농장에다 비유할 정도로 열나게 굴려서 영상을 만들어 낸다. 빌드 속도가 느린 걸로 악명 높은 C++ 언어를 위해서 Incredibuild라는 이스라엘산 분산 빌드 시스템도 있다.

그런 것처럼 개개의 컴퓨터도 이제 코어가 여러 개 돌아가고 멀티스레딩 능력이 충분히 뛰어나니, 이제는 프로그램 차원에서 멀티코어-aware한 개발이 필요해졌다. 왜냐하면 분산 처리 시스템을 설계하는 건 정말 머리가 뽀개질 정도로 복잡하기 때문에 컴퓨터나 컴파일러가 자동화를 해 줄 수 없다. 예전 계산 결과에 의존적인 다음 계산을 병렬로 동시 수행시킬 수는 없는 노릇이니까 말이다.

그렇기 때문에 멀티코어-aware하지 않은 옛날 프로그램은 컴퓨터가 언제나 최악의 case로 가정하고 보수적으로 돌려서 코어를 하나만 할당하여 돌아가게 된다. 한 프로그램이 while(1); 만 하고 가만히 있다 해도 CPU 사용률이 100%로 치솟지 않는다.

특히 C/C++의 포인터는 그야말로 아무 메모리 주소나 가리킬 수 있고, *a, *b가 있으면 둘이 가리키는 주소가 같을지 아닐지 등 최적화나 병렬화를 할 여지가 없을 정도로 너무 generic하기 때문에 오히려 처리가 어렵다고 한다. 파스칼이나 포트란처럼 언어 표현력이 C/C++보다 부족한 대신에 컴파일러가 소스 코드만 보고서 그 복잡도를 어느 정도 파악할 수 있는 언어가 병렬화에는 오히려 더 유리하다고.

그래서 소스 코드의 특정 구간에 대해서 컴파일러나 CPU가 안심하고 병렬화를 할 수 있게 중간 중간에 부가정보를 인위적으로 넣어 줄 필요가 생겼는데, 이런 부가정보를 기술하는 표준 규격 중 하나가 그 이름도 유명한 OpenMP이다. #pragma omp 같은 컴파일러 지시자도 있고, OpenMP 라이브러리보부터 호출해서 쓰는 함수도 있다.

옛날에 C언어가 처음 발명되던 시절엔 최적화를 위해서 변수를 가능한 한 레지스터에 올려라고 지시하던 register라는 카워드가 있었는데, 앞으로 C/C++ 같은 네이티브 코드 언어는 멀티코어를 언어 차원에서 수용하는 규격이 덩달아 생겨야 할 것이다.

물론, CreateThread 같은 함수를 써서 코드의 로직 차원에서 대놓고 여러 작업 스레드를 만들었다면, 단일 프로세스가 여러 개의 코어를 자연스럽게 점유하는 게 응당 가능하다. 그러나 디자인의 성격상, 멀티스레딩은 보통 일하는 스레드, 사용자 UI 스레드, 입출력 신호를 기다리는 스레드처럼 용도별로 달리 배당하는 게 바람직하지, 동일한 일을 하는 코드 내부에서 굳이 다중 코어 활용을 위해 스레드를 분할하기에는 동기화를 비롯해 일이 너무 복잡해진다. 서버 같은 게 아니라면, 제각기 CPU를 full로 사용하는 여러 작업 스레드를 만들 일 자체가 매우 드물다.

이때 멀티코어 프로그래밍을 잘 하면 이런 단일 코드가 명시적인 스레드 생성을 하지 않고도 CPU의 자원을 골고루 전부 활용해서 고성능으로 돌아가게 된다. 다만 앞서 말했듯이 이렇게 작업을 분할하는 오버헤드부터가 큰 편이기 때문에, 소규모 작업보다는 동영상 인코딩이나 대용량 파일 압축이나 컴파일 같은 진짜 방대한 작업에서 멀티코어의 진가는 더욱 두드러질 것이다.
일례로, 비주얼 C++은 2005부터 빌드할 때 병렬 컴파일이 수행된 경우, 빌드 로그에 해당 빌드를 수행한 코어의 번호가 뜬다.

O(n^3)짜리 행렬 곱셈은 워낙 단순 무식하고 복잡한 의존도 따위도 없는 순수 노가다이다 보니, “나 병렬화 해 주세요”라고 온몸으로 외치는 문제라고 볼 수 있다. 퀵 정렬이나 병합 정렬처럼 구간이 딱딱 나뉘는 알고리즘이 병렬화에도 적합한 구조일 것 같긴 하다만, 요즘 컴퓨터의 성능이라면 겨우 internal sort 규모의 정렬 작업은 굳이 멀티코어를 쓸 필요도 없을 정도로 금방 끝날 듯.

요컨대 이제는 고성능 컴퓨터를 쓰는 것만으로 프로그램의 수행 속도가 저절로 올라가는 시대는 끝났다. 그 다음으로 레지스터 배당이라든가 캐시나 파이프라인 적중률 같은 건 CPU 설계에 맞춰 컴파일러가 더 똑똑해야 하는 영역인데, 이 역시 튜닝의 수준은 예술의 경지에 도달해 있다. 그리고 그 다음으로 필요해진 것이 코드에 등재되어 있는 병렬화 가능성 정보라고 생각하면 되겠다. 멀티코어는 프로그래머가 잘 숙지하고 있어야 하는 프로그래밍 패러다임이 되었음이 틀림없다.

Posted by 사무엘

2012/04/13 08:24 2012/04/13 08:24
Response
No Trackback , 7 Comments
RSS :
http://moogi.new21.org/tc/rss/response/668

요즘 학교나 관공서의 전산망에서는 인터넷 접속을 위해서 특정 보안 솔루션 ActiveX들과 그것도 모자라서 바이러스 백신까지 무조건 설치하라고 강요하는 걸 볼 수 있다. 그걸 안 하면 사이트 접속이 되질 않게 해 놓았다.  허나 본인은 그런 보안 솔루션들에 대해 정서적으로 굉장한 반감을 갖고 있으며, 그것들을 몸서리치게 싫어한다.

여러 보안 솔루션 중 키보드 보안 프로그램이 하는 역할은 아마도 사용자의 키 입력(비밀번호 같은)을 메시지 훅킹으로 가로챌 수 없게 하고, 반대로 없는 키 입력을 소프트웨어적으로 생성할 수 없게 하는 일일 것이다(온라인 게임에서 오토의 실행 차단). 또한, 은행 돈거래 관련 정보가 담긴 패킷은 정보가 유출되더라도 의미 파악이나 변조가 거의 불가능하게 아주 복잡한 계산을 동원한 암호화/해독이 클라이언트에서 행해져야 할 필요가 있을 것이다. 그런 기술적인 필요를 본인은 모르는 건 아니다.

다만, 웹 표준만으로 도저히 구현할 수 없는 운영체제 커널 기술 수준의 보안이 불가피하게 필요하다면, 차라리 무리해서 웹 애플리케이션을 만드는 걸 포기하고 깨끗하게 로컬 환경에서 돌아가는 exe 형태의 프로그램과 배포 패키지를 만들었으면 좋겠다.

nProtect 부류의 이상한 프로그램들은 웹브라우저를 끈 뒤에도 계속 메모리 차지하면서 남아 있는 것 정도나 보기 싫은 수준이고 그나마 ‘낫다’. 하지만 이놈의 빌어먹을 백신은 답이 없다. 바이러스나 악성 코드에 걸리지 말라고 설치하는 솔루션들이, 깔고 나면 악성 코드나 그 이상 수준으로 민폐 끼치면서 컴퓨터 성능을 쪽쪽 갉아먹기 때문이다. 좀 심하게 표현하면 컴을 완전히 병신으로 만들어 놓는다.

마치 치안과 국방을 담당해야 할 자국의 정규군이나 경찰이 하라는 일은 안 하고 자기네들부터 민폐 끼치고 민간인들을 등쳐 먹는다거나, 반공을 빌미로 공권력이 심심하면 멀쩡한 생사람을 빨갱이로 몰아서 잡아 죽인다거나 하는 상황을 생각하면 되겠다.

맥북 이전 4대 노트북을 쓰던 시절의 일이다. 본인이 다니는 학교는 내부에서 와이파이로 인터넷에 접속할 때 NetCare인지 뭔지 하는 보안 ActiveX와 바이로봇 백신을 반드시 설치하도록 강요를 하고 있다. 둘 중 하나라도 설치를 안 하면, 몇몇 사이트는 아예 접속이 되지 않거나 쿠키가 저장되지 않아서 로그인을 할 수가 없으며, 되는 사이트도 보안 솔루션들을 설치하라고 협박하는 문구가 든 프레임이 웹사이트에 제멋대로 추가되어 나오곤 했다.

그래서 본인은 어쩔 수 없이, 울며 겨자 먹기로 마지못해 깔라는 것들을 다 설치해 줬다. 그러자 저런 성가신 현상이 모두 없어지고 인터넷은 잘 되기 시작했다. 그러나 그 뒤부터 내 컴에서는 끔찍한 헬게이트가 시작되었다.

부팅 직후에 시스템이 시작 메뉴 구동 같은 각종 조작에 응답하는 속도가 눈에 띄게 느려졌고, 웹브라우저가 페이지를 여는 속도, 전반적인 파일 액세스 속도도 인내심의 한계를 느끼는 수준이 되었다. 최대 절전 모드에서 복귀하는 시간까지 예전보다 훨씬 더 길어졌다. 멀쩡하던 컴퓨터가 진짜 만신창이 장애인이 된 느낌이었다. 평상시에 운영체제의 메모리 사용량도 예전보다 수십 MB가량 늘었다.

나는 운영체제의 업데이트들은 목록만 자동으로 받게 한 뒤, 다운로드와 설치는 내가 지정한 것만 수동으로 하게 해 놓고 있었다. 그랬는데 그 보안 솔루션은 나의 설정을 씹고, 인터넷만 됐다 하면 마구잡이로 온갖 업데이트들을 제멋대로 받아서 설치했다.

언제부턴가 MS 오피스가 SP2이던 게 느닷없이 SP3으로 바뀌어 있었다. 프로그램이 버전업되어서 좋은 게 아니라 도리어 부아가 치밀었다. “이 자식, 지금까지 왜 이리 느리고 쓸데없이 디스크 액세스를 하는가 했더니, 그 수백 MB짜리 업데이트를 내 동의도 없이 제멋대로 설치하느라 그랬군.” 하는 생각에 말이다.

참다못해 하루는 넷케어고 백신이고 전부 다 모조리 지워 버렸다. 요즘은 백신도 용량이 몇백 MB 수준으로 뭘 하느라 그리도 커졌는지 모르겠다. 이것들을 다 지우고 나자 내 컴퓨터는 거짓말처럼 평화가 찾아왔다. 모든 성능이 예전 상태로 돌아갔다. 보안 솔루션들이 그들의 퇴치 대상인 악성 코드가 하는 짓을 동일하게 하고 있음이 입증된 순간이었다.

이제 맥북을 사용하면서 뜻하지 않게 얻은 큰 수확이 있다. 보안 솔루션 제약은 Windows 운영체제에만 적용되며, 맥에서는 그런 게 전혀 없이도 인터넷을 곧바로 자유롭게 이용할 수 있다는 것. 야호! 빌어먹을 넷케어니 바이로봇 따위를 설치하지 않아도 된다. 맥OS가 날 구했다. 스잡빠니 애플빠니 난 그딴 건 모르지만, 어쨌든 이거 덕분에 맥OS 호감도가 급상승했다.

한편, 고향에서도 비슷한 일을 최근에 겪었다. 고향집 컴퓨터가 언제부턴가 병신 중의 상병신이 돼 있었다. 부팅 후에 시작 메뉴를 눌러도 한참 동안 반응이 없고, 웹브라우저를 띄운 뒤에 창이 나타나기까지 몇 분이 족히 걸리고 있었다. 레지스트리나 파일 디렉터리를 살펴봐도 딱히 악성 코드에 걸린 것 같지는 않은데 영문을 모를 노릇이었다.

이 현상의 주범은 바로 V3 Lite였다. 이놈을 당장 지우자 컴퓨터는 운영체제를 갓 설치한 직후처럼 아주 쌩쌩해졌다! 그러니 난 도대체 진짜 악성 코드란 어떤 놈인지 가치관의 혼란을 겪을 수밖에 없었다.

바이러스가 묻은 메일 첨부 파일을 클릭한 것도 아니고, 이상한 사이트를 돌아다니다가 ActiveX 설치에 ‘예’를 누른 것도 아니었다. 이 V3은 어머니께서 집에서 인터넷으로 업무를 보시기 위해 어쩔 수 없이 설치한 것이었다. 이거랑 무슨 희한한 듣보잡 ActiveX들을 설치하지 않으면 직장의 업무 자동화 시스템에 접속이 되질 않기 때문이었다.

이런 일련의 사건을 겪은 뒤, 나는 더욱 더 백신 따위는 죽어도 절대로 쓰지 말아야겠다는 생각을 굳게 하게 되었다. 옛날처럼 백신이 그냥 사용자가 요청할 때만 파일이나 메모리를 스캔하면서 바이러스 검사를 해 주던 시절이 그립다. 저런 거지 같은 잉여 쓰레기 프로그램을 얹고도 작업을 원활하게 하려면, 가히 정말 최신식 최고급 컴퓨터를 써야겠다. 아니, 내 컴퓨터가 아무리 빠르고 메모리가 썩어 넘친다 해도 저런 프로그램에게 컴퓨터 자원을 내어 주기는 싫다.

보안을 빌미로 원치 않는 프로그램의 설치를 강요하는 이런 못돼먹은 풍조가 좀 없어졌으면 하는 바람이 있다. 이런 일이 계속될수록 이에 대한 반발 심리로 나의 컴퓨터 보안 위협 불감증은 더욱 커질 것이다.

Posted by 사무엘

2012/04/02 19:23 2012/04/02 19:23
, , ,
Response
No Trackback , 8 Comments
RSS :
http://moogi.new21.org/tc/rss/response/663

맥북 프로 지름

지난 3월 24일, 맥북 프로 13인치형 모델이 본인의 제 5대 개인용 노트북 PC로 취임했다.
본인이 고등학교 시절부터 노트북 PC를 사용한 이래로 14년 만에 애플 계열 컴퓨터를 개인용 컴퓨터로 장만하게 되었다.

지금까지 사용하던 제4대 노트북은 2008년 5월에 도입되었고 윈도우 비스타 + 코어2 Duo 기종이었다. 오늘날의 PC 기준으로는 완전히 구닥다리로 전락한 셈.
좀 나중에 석사 졸업 기념으로 컴을 바꿀 생각이었지만, 마침 고향에서 부모님께서 새 컴퓨터가 필요하다고 하여 지금 내가 쓰던 걸 고향으로 보내고 나는 새 컴을 예정보다 더 일찍 장만하게 됐다.

초대 노트북은 분실, 2~3대 노트북은 고장 폐기였던 것에 비해, 4대 노트북은 약 4년에 가까운 임기를 마친 후 비교적 명예롭게, 그리고 예상보다 살짝 더 일찍 은퇴했다. 빠진 키캡 정리와 하드디스크 정리, 사소한 접촉 불량 수리 같은 정비를 받은 후, 고향으로 갔다.

지금까지 정말 유용하게 잘 사용해 왔고 키보드와 터치패드의 모든 감도가 손에 착 익은 정든 놈이긴 하지만, 이제 성능이 너무 뒤쳐졌고 액정 화면도 슬슬 누렇게 뜨는 등 노후화의 기미는 피해 갈 수 없었다. 물론 이것도 고향에 있는 컴퓨터보다는 훨씬 더 좋은 기종이다. 지금까지 부모님께서 쓰시던 컴은 이제 정말로 갖다 버릴 때가 됐고.. ㅜㅜ

구입한 새 노트북에 대해 스펙 차원에서 좀 아쉬움을 감수한 것은,
운영체제를 두 개나(윈도우와 맥 모두) 쓰는 것치고는 좀 부족한 감이 있는 하드디스크 용량.
그리고 지금 노트북보다 화면 해상도 픽셀수가 가로와 세로 모두 떨어진다는 점이다.
게다가 4:3이 아닌 요즘 대세인 와이드 화면을 쓰는 만큼, 이제 task bar를 가로가 아닌 세로로 배열해야겠다.
이질적인 키보드· 마우스 사용법은 덤.

Windows 운영체제는 내가 알아서 장만이라도 해서 깔아야 하는지 우려됐는데(OS 자체의 설치는 그렇다 치더라도 각종 드라이버들은 어떻게 잡으라고!!), 다행히 웃돈만 주면 판매처에서 아예 알아서 설치까지 한 채로 제품을 준다고 해서 안심을 했다.

Windows에다가는 단골 18번지 프로그램들을 설치해서 내가 늘 하던 일만 쭉 하고, 오픈소스 크로스 플랫폼 형태로 존재하는 프로그램들은 가능한 한 맥용으로 설치하는 방법으로 맥OS에 차츰 적응을 해 나갈 생각이다. 물론, 단골 18번지 프로그램들이 다들 단순 취향을 넘어서 내 생업과 관련된 일들을 하기 때문에, 나는 Windows를 아주 떠나서 살 수는 없다.

당장 개발툴만 예로 들어 보면, Windows에다가는 비주얼 스튜디오를, 맥에다가는 xcode와 Eclipse를 설치했다. 이클립스를 굳이 윈도우에다가 설치할 필요는 없으니까. 나도 드디어 윈도우 7 + 비주얼 스튜디오 2010으로 완전히 갈아탔다. 거기에다 호환성 차원에서 2003도 여전히 설치.

나는 <날개셋> 한글 입력기를 혼자서 만들었을 정도로 Windows 환경 개발에 정통한 것에 '비해서'는 여타 운영체제를 너무 안 다뤄 봤고 너무 모른다. 가령, 그 정도 기술 수준의 프로그램을 만들 줄 알면서 유닉스 명령을 나 정도로 모르는 사람은 별로 없지 싶다. 지금까지 쓸 일이 없었으니까. 오로지 Windows 독식이었다.

그런 와중에 이번 맥북 장만은 약간 risk도 감안하면서 내린 결정이긴 하다만, 15년에 가까운 나의 Windows 독점 풍토에 뭔가 새로운 바람을 수혈해 넣을 거라는 기대를 해 본다.
비록 나는 이제 예전에 맨대가리 헤딩으로 프로그래밍에만 매달려서 윈도우 API를 공부했듯이 맥OS API를 새로 처음부터 공부할 수 있을 것 같지는 않지만... 그래도 사람 미래라는 건 알 수 없으니까 말이다.

같은 데스크톱급 PC로도 모자라서 스마트폰은...;; 글쎄다. 이것도 언젠가는 안드로이드든 아이폰이든 써 보면 좋을 것 같지만, 딱히 길 안내 기능 말고는 그 돈까지 주면서 일부러 앞장서서 사서 쓸 매력을 느끼지는 않는다. PC에서 벌여 놓은 일이 너무 많아서 이것저것 다 쫓아가다간 다 놓친다. pruning이 필요함.

컴퓨터를 새로 세팅하다 보니, 이제 운영체제와 각종 소프트웨어들을 온통 업데이트해 줘야 하고, 맥 기반 개발툴들도 다 인터넷을 통해서 구해야 한다. 고로 수백~수 GB에 달하는 트래픽이 예상되는데, 언제 날잡아서 안정적인 유선 네퉉으로 해치워야겠다는 생각이 든다.

Posted by 사무엘

2012/03/31 08:22 2012/03/31 08:22
, ,
Response
No Trackback , 5 Comments
RSS :
http://moogi.new21.org/tc/rss/response/662

« Previous : 1 : ... 4 : 5 : 6 : 7 : 8 : 9 : 10 : 11 : Next »

블로그 이미지

그런즉 이제 애호박, 단호박, 늙은호박 이 셋은 항상 있으나, 그 중에 제일은 늙은호박이니라.

- 사무엘

Archives

Authors

  1. 사무엘

Calendar

«   2024/04   »
  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        

Site Stats

Total hits:
2678953
Today:
1037
Yesterday:
2484