Framework/Another Lore2009. 7. 5. 20:31
앞서 소개한적이 있지만 

"전산학의 모든 문제는 또 다른 수준의 간접층으로 해결할 수 있다" 
라고 말한 휠러는 

"그러나 그러면 또 다른 문제가 생기는 것이 일반적이다" 라고 덧붙인 적이 있다. 

"또다른 문제"의 대표적인 예로는 공간과 시간적 부담과 코드의 가독성 등을 들 수 있다. 

이 포스팅에서는 이중에서 시간적 부담 즉 속도에 관해서이다. 


일반적으로 대부분의 프레임워크는 하나의 간접층(Layer)이며 위의 명제를 피할 수는 없다. 그러나 프레임워크를 쓴다고 항상 느려진다고 할 수 없는 이유가 있다. 

만약 A -> B 과정이 1초가 걸렸다면
A -> A' -> B 과정은 1초보다 작게 걸린다는 것은 논리적으로 불가능하다. 

그러나 시간은 연속성의 특징을 가지고 있다. 무슨말이냐면 프로그램에서의 시간 혹은 속도의 개념은 하나의 event개념이 아니다. 프로그램을 작성하면 무수히 많은 A -> B 과정을 작성하게 된다. 

이를테면 A가 Client Call이라고 하고 B를 Engine라고 가정했을때 (Engine에는 DB나 NS등의 여러가지를 대입할 수 있다.)

1. Client Call(Engine Library) -> Engine과
2. Client Call(Framework Call) -> Framework(Inner Use Engine Library) -> Engine 라는 경우를 상상해 보자. 

하나의 원자 동작을 보았을때 1은 2보다 항상 속도가 빠르다. 그러나 실제 프로그래밍에서는 2가 종종 더 빠른 이유는(잘 만들었을 경우를 가정했을때...) 연속성의 이유때문이다. 함수 하나 혹은 command 하나는 말 그대로의 원자 event로 이루어지지 않는다. 

그리고 이것때문에 이를테면 1의 동작에 0.1초가 걸린다고 하고 10번 반복한다고 했을때 1은 1초가 걸리지만 2는 1초 이하로 떨어뜨릴수 있다. 

좀더 IT적인 용어로 말하자면 Context Switching 비용 때문이다. 

예를 들어
Row row = Engine.executeCommand() ;
if(row.exist()) Engine.updateCommand() ;
else Engine.insertCommand();

와 같은 코드의 경우 Engine의 row의 exist 여부를 체크하여 2번의 Engine Call을 실행한다. 이 과정에서의 속도는 (0.1 + a(context switching cost)) * 2 + b(Caller cost) 가 소모하게 된다. 

만약 위의 과정을 
Framework.mergeCommand() 라고 바꿀수 있다면 0.1 * 2 + a(context switching cost) + b'(Maybe Lower Caller Cost) + c (framework inner handling cost) 로 수식이 바뀐다. 만약 여기서 a + b> b' + c라면 프레임워크를 사용함으로서 속도가 향상되었다고 말할 수 있다. 추가적으로 좀더 간결하게 프로그램을 작성할 수 있다. 여기서 간결함이란 문제는 이전글을 참조하자. 

3번의 동작이 연속으로 이루어진다면 2a + b> b' + c 정도만 해도 향상될 수 있다. 


두번째 속도가 빨라질 수 있는 이유로 
앞서 원자 event라고 가정했던 1의 과정조차 실제로는 바깥에서는 보이지 않는 내부적으로는 연계된 다른 과정을 거치게 된다.

앞서 원자 action event라고 했던 1이 사실은 
Client Call -> Inner Action 1 -> Inner Action 2 -> Engine Inner으로 이루어져 있다가 가정하자. 
각각의 비용은 a + b + c + d  라고 가정하자. 

만약 
Client Call -> Inner Action 1 -> NewFramework -> Inner Action 2 -> Engine Inner로 작성하였다면..
a + b + @(framework cost) + c + d 의 비용이기 때문에 역시 단순 논리로 봤을때는 빨라지지 않는다. 

그러나 프로그래밍이 다중 사용자 환경(One User 프로그램의 경우에도 Multi Thread로 작성된다면 마찬가지이다. )이고 Action 2가 공유될수 있는 Action이라고 한다면 얘기가 달라진다

Inner Action2을 사용자 혹은 여러 Thread가 공유할 수 있다면

N번의 Call이 발생했을때. 
N(a + b + c + d)의 비용이 N(a + b + @ + d) + c의 비용 수식으로 바꿀수 있다. 
이는 c의 cosr가 total cost에서 얼마의 비중인가에 따라 그 가치가 달라진다. 잘 알려진 예제로 Connection Pooling 같은 과정을 생각한다면 이해하기 쉽다. 

# 컨텍스트 스위치 context switch
멀티테스킹 OS는 서로 다른 처리를 수행하는 처리 단위로 프로세스/쓰레드를 짧은 시간에 전환함으로써 병렬처리를 실현하고 있다. 이때의 프로세스/쓰레드 전환처리를 컨텍스트 스위치라고 한다. 이렇게 컨텍스트 스위치할때 멀티쓰레드는 메모리 공간을 공유하기 때문에 메모리 공간의 전환 처리는 생략할 수 있다. 

메모리 공간을 전환하지 않게 되면 CPU 상의 메모리 캐시(정확히는 TLB Translation Lookaside Buffer : 메모리의 가상 주소를 물리 주소로 변환하는 처리를 고속화하기 위한 캐시로 CPU 내부의 구조다. 컨텍스트 스위치가 일어나면 TLB가 초기화되는데 이 영향에 의한 TBL 캐시 미스는 상대적으로 비용이 많이 든다.)를 그대로 유지할 수 있는 등의 큰 이점이 있으므로 멀티 프로세스에 비해 성능에 미치는 영향은 현저하다. 

이러한 이유로 위의 경우 자바와 예로 든 엔진(예컨데 DB)의 변환은 멀티 프로세스 관계일때 더 차이가 두드러진다. 





원래 주제와 좀 떨어지지만 휠러 얘기가 나왔으니 "발생하는 또다른 문제"중 가독성의 얘기를 해보자. 

여기서의 가독성은 동전의 양면과 같다. 사실 맨 처음 웹 프로그래밍을 한다고 했을때 스프링을 사용하는 것은 그다지 좋지 못하다.(라고 생각한다.) 스프링의 스펙은 그리 만만치 않다. 오히려 기본적인 서블릿 프로그래밍보다 더 많은 걸 알아야 한다. 스프링 프레임아웤의 유용성을 떠나 아이러니한것은 중급개발자의 반복작업을 줄여주기 위한 프레임워크가 오히려 초보개발자용 프레임워크로 둔갑한다는 것이다. 

어쨌거나 휠러가 지적한 것은 프레임워크의 겉핧기 사용등의 프레임워크의 내부에 대한 이해 없이 접근하면 작성하는 프로그래머도 또 그걸 읽는 프로그래머(그 사람이 해당 프레임워크에 대해 알고 있는지와 상관없이)도 고통이 된다는 사실을 말한 것이다. 

앞서 동전의 양면이라고 한것은 프레임워크에 대한 많은 학습없이 직관적으로 사용이 가능하고 기대대로 프레임워크가 작동한다면 오히려 가독성에 도움이 될 수 있다는 의미이다. 

그런면에서 프레임워크의 직관적 사용은 좋은 프레임워크를 결정하는데 핵심이 된다. 스프링 프레임워크가 직관적이지 못한것은 어찌보면 프레임워크가 커버하는 범위와 관계가 있을지 모른다. 스프링 프레임워크는 너무 많은 일을 하는 프레임워크이고 또 유연성을 위해 XML 형식의 configuration이 지나치게 많고 복잡해서 휠러의 또다른 문제를 벗어나지 못했다. 











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

언젠가...  (0) 2009.08.14
XUL 단상  (0) 2009.07.15
read & write  (0) 2009.06.25
최근에 책을 읽다가..  (0) 2009.06.11
AL : Permission  (1) 2009.04.30
Posted by bleujin
Framework/Another Lore2009. 6. 25. 10:47

습관은 관습을 낳고 관습은 편견을 낳는다. 

우리는 bean 객체를 많이 봐왔기 때문에 getMethod가 있으면 setMethod도 있어야 할 것이라고 생각한다. 물론 이것이 틀렸다고는 할수 없지만 가끔은 생각을 바꿔보는게 도움이 될 수 있다. 

예컨데 다음 상황을 보자. 

Node rootNode = session.getRootNode() ;
NodeType empType = getNodeType("employee") ;

Node newNode = rootNode.createChild(empType, "abcd") ;


이 상태에서 newNode를 repository에 저장하는게 좋을까? 아니다. 그러기엔 너무 일러보인다. 왜냐하면 아직 실제 값을 설정하지 않았기 때문이다. 

그 보다는 
newNode.setProperty("ename", "bleujin") ;
newNode.setProperty("empNo", 20) ;
와 같이 값을 설정하고 

newNode.save() 를 호출했을때 repository에 저장하는게 보다 효율적일 것이다. Transaction Handling이 가능하고 setProperty를 호출할때마다 DBCall을 하는것보단 훨씬 효율적이다. 


다만 위의 경우 문제가 있다. 

다음 상황을 상상해 보자. 

Node parent = rootNode.createChild(empType, "parent") ;
Node child = parent.createChild(empType, "bleujin") ;
child.setProperty("ename", "bleujin") ;
child.setProperty("empNo", 20) ;
child.save() ;

별문제가 없어보인다. 
그러나 위와 같이 현재 Session의 모든 PendingEvent를 저장하는 session.save() 를 호출하지 않고 child.save() ;를 호출했을 경우에 (물론 API 상으로는 아무런 문제가 없다.) parent가 저장되지 않은 상태에서 child가 먼저 저장될 수 있는가? 에 대한 의문이 든다. 더군다다 child만 save()하고 parent는 일부러 혹은 실수로 save를 하지 않거나 혹은 parent.save()를 호출했을 경우에 에러가 발생했을 경우를 상정해 보면 문제가 더욱 복잡해진다. 

API상으로는 문제가 없지만 child만 save가 되고 parent는 save 되지 않았을 경우는 정상적인 상태가 아니다. 그렇다고 맨 처음의 방식으로 돌아가는 것도 Transaction이 보장되는 것은 아니다. 각각의 호출마다 repository Call을 했을 경우 첫번째와 두번째 사이에 에러가 발생할 수 있다는 것은 마찬가지 이다. 

물론 사용자 실수야 라고 탓이라고 문제를 회피할 수도 있겠지만 이는 올바른 방법이 아니다. 순서에 의존하는 API는 (예컨데 a를 호출하고 난 다음에 b를 호출하고 그 다음에 c를 호출하고..) 사용하기 복잡하고 실수를 가져오는게 당연하다. 

이 문제를 해결하기 위해 AL은 존재와 무존재를 구분한다. 
예컨데 


interface INode {
    .......
    getterMethod() ;
    setterMethod() ;
    Node retrieve(...) ;
    Node save() ;
}

interface NodeTemplate extends INode {
     ....
}

interface Node extends INode {
    NodeTempalte createChild(NodeType nodeType, String name) ;
}

와 같이 인터페이스를 분리하면 문제는 명확해진다. 
ISP(Interface Segregation Principle)의 의미는 어렵지 않지만 책임의 한정이 어렵다. 여기서는 책임을 read책임과 write책임으로 분리한 것이다. 


NodeTemplate parent = rootNode.createChild(empType, "parent") ;
위 상태에서 NodeTemplate는 createChild Method를 호출할 수 없기때문에 

Node savedParent = parent.save() ; 를 호출한 이후 child를 만들거나 아니면 session.save()를 호출하여 pendingEvent를 같이 처리해야 한다. 


위 예제에서 좀더 나아가서 getMothod용 Node와 setMethod용 Node를 구분한다면 개선의 소지가 더 있다. 이를테면 Setter가 없는 Node를 통해 더 가벼운 Node를 만들 수 있게 된다. 그리고 Getter가 필요없는 Node를 통해 더 빨리 Node를 얻어올 수 있다. 




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

XUL 단상  (0) 2009.07.15
레이어의 속도  (0) 2009.07.05
최근에 책을 읽다가..  (0) 2009.06.11
AL : Permission  (1) 2009.04.30
AL : 현재의 난제들  (0) 2009.04.30
Posted by bleujin
IT 이야기/유니코드2009. 6. 12. 16:14

UTF 얘기는 이미 충분히 글을 적었음에도 다시 포스팅을 하는 이유는 사람들이 자주 헛갈리는 캐릭터셋(charset)과 인코딩(enecoding)의 차이를 이야기 하기 위해서이다. 

"A"라는 글자가 컴퓨터에 이진수로 표현되어 저장된다는 것은 누구나 알고 있을 것이다. 중요한건 2단계를 거치는 것이 중요하다. 첫번째는 "해석"이고 두번째가 "저장"이다. 

첫번째 "해석"이란 컴퓨터가 아닌 사람을 위해 존재한다. "A" 글자를 저장해야 한다고 할때 글자 "A"라는 의미를 어떻게 전달해야 할까가 문제의 시발점이다. 다른 사람에게 "A"가 어떻게 저장되지? 라고 묻는건 올바르지 않다. 좀더 정확하게 말하자면 "2009년 현재 미국에서 사용하고 있는 알파벳의 대문자 A"라고 전달해야 한다. 번거롭기 그지 없다. 게다가 그 다른 사람이 사는 문화권에서는 "에이" 라고 불리는 다른 문자가 있을지도 있을지도 모른다. 원래 말이라는건 오해하기 쉬운 법이다. 

그래서 좀더 쉬운 전달을 위해 모든 문자에 숫자를 할당했다.(숫자은 전세계 모든 사람의 공용어 역할을 한다.) 이제 다른 사람에게 (십진수로) 65(16진수로 표현하면 0x41)번 문자는 어떻게 저장하지? 라고 물으면 된다. 이렇게 해석단계에서 사용하는, 문자에 번호를 매겨놓은게 charset (캐릭터 셋)이다. 컴퓨터가 발명된 초기부터 이렇게 별도의 해석 단계가 있었던건 아니었다. 컴퓨터가 처음 발명된 초기에는 해석 == 저장이었기 때문에 65번 글자인 'A'는 65번으로 저장한다 였다. 초기에는 128개(2^7)에만 번호를 할당했고 저장하였는데 구미지역에서는 이정도면 충분하였다. 

다시 말해서 캐릭터 셋은 해당 캐릭터 셋이 표현가능한 문자의 일종의 단순한 매핑 테이블이다. 이를테면 한글 "가"라는 글자는 KSC5601에서 "0116" 번으로 할당되어 있다. 이제 "0116" 에 해당하는 글자(즉 한글 "가")를 어떻게 컴퓨터의 이진 코드화 시키는가가 인코딩이다. 앞서 해석 - 캐릭터셋에 매핑된 숫자를 읽기 -는 논리적이며 저장 - 인코딩 -은 물리적 과정이기 때문에 서로 같지 않고 당연히 "0116" 글자가 0116 라고 저장되리라는 것을 기대하거나 보장할 수 없다. 

왜냐하면 캐릭터 셋은 논리적 과정이라 얼마든지 새로운 캐릭터 셋을 만들어도 상관이 없지만(물론 이 경우 다양한 단체의 알력싸움에 의해 정해진다.) 인코딩은 물리적 단계이며 이경우 가장 중요한 것은 호환성이다. 예컨데 "A"라는 글자는 KSC5601에서 "3305"번에 할당되어 있는데 디코딩은 인코딩의 역함수이기 때문에 기존에 ASCII로 "0x40"으로 저장된 코드를 "A"라고 읽을 수 없다. 따라서 캐릭터 셋의 번호대로 인코딩이 되지는 않고 실제로는 캐릭터셋의 해쉬 함수 인코딩을 하게 된다. 

KSC5601의 해쉬 함수를 통해 (KSC5601은 일반적으로 캐릭터셋의 의미를 가지지만 때로는 인코딩을 의미하기도 한다. 그래서 이전의 책이나 글에서는 문맥을 통해 구별하는 수밖에 없으며 이는 많은 혼란의 요인이 되었다.) "0116"글자는 "0xAC00"로 인코딩(즉 computer에는 AC00로 저장이 된다.) "3305" 글자는 "0x40"으로 바뀌어서 저장이된다. 문제는 디코딩을 할때 "0xAC00"  코드를 읽어서 화면에 "가"라고 보여줄 수 있느냐이다. 왜냐하면 파일에는 해당 파일의 캐릭터 셋에 대한 정보를 저장하기 않기때문에 이 파일을 읽을때 "0xAC00" 가 정말 "가"인지를 확인할 수 없기 때문이다. 어쩌면 다른 캐릭터 셋의 인코딩으로 "0xAC00"는 다른 글자일지도 모르기 때문이다. (어쩌면 초기에 구미에서 컴퓨터를 발명하면서 파일에 캐릭터 셋을 저장하지 않는 것이 문제의 시발점인지 모른다. )

파일을 인코딩한 해쉬 함수의 역함수는 당연히 캐릭터 셋에 종속이 되기 때문에 해당 파일의 캐릭터 셋을 모르고서는 해당 파일이 제대로 읽을 수 없다. 앞문장의 "제대로" 라는 뜻은 "0xAC00" 라는 코드를 읽어도 해당 파일의 캐릭터 셋을 알지못하면 이를 "가"로 제대로 화면에 보여주지 못한다는 이야기 이다. 

만약 자신의 컴퓨터에서 혼자만 쓰는 파일이라면 상관이 없다. 각 컴퓨터에는 기본 캐릭터셋이 지정되어 있기 때문에 아무런 추가 작업을 하지 않는 이상 기본 캐릭터 셋으로 쓰고 기본 캐릭터 셋으로 읽으면 된다. 그러나 A 컴퓨터에서 작성한 파일을 B 컴퓨터로 전달하는 경우(이메일을 쓰거나 웹에 글을 올리거나 하는 경우도 마찬가지이다. )에 해당 파일이 어떤 캐릭터 셋인지 전달해 주지 않으면 상대편의 컴퓨터에서는 제대로 읽을수가 없다. 설사 말로 알려준다고 하더라도 상대편의 컴퓨터에 해당 캐릭터셋에 대한 정보가 없으면 역함수가 없고 디코딩도 당연히 할수 없다. 

그럼 이쯤에서 나올만한 생각이 있다. 지구의 모든 컴퓨터가 공용으로 사용할 수 있는 캐릭터 셋을 만들면 되지 않을까? 정답이다. 그래서 나온게 유니코드이다. 문제는 유니코드의 발상이 나오기 전에 이미 많은 캐릭터 셋이 많은 컴퓨터에서 사용이 되고 있다는 점과 모든 글자를 담기 위해서는 글자당 할당되는 번호가 길어지고 이는 당연히 저장 공간이 길어지는 2가지 문제가 추가적으로 야기된다. 

둘을 묶어 보면 기존에 호환성을 유지하면서도(여기서 호환성이란 보통 ASCII만을 의미한다.) 수많은 글자를 가능한 작은 저장공간에 인코딩을 할 수 있어야 한다는 얘기이다. 


ASCII
당시의 컴퓨터는 유닉스 기반의 컴퓨터로 7비트가 1바이트인 메모리를 사용하였고 따라서 자연스럽게 하나의 문자를 표현하는데 7비트를 사용하였다. null로 시작하는 32개의 제어문자,공백문자, 94개의 프린트문자, 지움문자로 128개의 비트조합을 배정하였다. 이에 따라 1963년 최초의 ASCII 표준이 제정되었는데 이때까지만 해도 많은 비트 조합이 94개의 프린트 문자 번호로 배정되지 않은 상태였으며 1968년에 오늘날과 같은 ASCII 코드가 만들어져 표준으로 지정되었다. 


ISO 8859
같은 라틴계열의 문자이긴 하지만 별도의 강세문자를 가지는 프랑스나 그리스의 문자는 구미의 알파벳과 조금 달랐고 이런 언어의 표현을 포함하는 캐릭터 셋을 만들려는 국제적인 노력은 ISO8859 시리즈에서 나타났다. ISO 8859-1은 서유럽 언어를 다루기에 충분했으며, ISO 8859-7은 기본적인 그리스 문자, 알파에서 오메가, 발음기호 등 현대의 그리스 문자와 영어를 모두 지원했다. ISO 8859에서는 하나의 문자를 표현하는데 8비트를 사용하며 ASCII 외의 각 나라마다 자신이 사용할 문자는 128 이후에 배치하였다. 즉 ISO 8859는 128개의 세계 공통 문자(주로 알파벳과 숫자, 제어코드)와 128개의 지역 문자(지역별로 다른 문자 할당)의 조합이다. 

ISO 2022
상식적으로 공통으로 사용하는 128개의 문자말고 추가적인 128개의 문자는 지역마다 다르게 정의되었기 때문에 제대로된 문서 교환이 이루어질리 없다. 파일에는 그 파일이 어떤 캐릭터 셋을 사용했는지에 대한 정보가 저장되어 있지 않기 때문에 wrirte할때는 불어 지역문자를 사용하면 러시아에서 read 할때는 제대로 읽혀지지 않는다. 초기에는 네트워크가 활발하지 않았고 대부분 컴퓨터에는 혼자 사용하는 것이라는 인식이 강했지만 이게 문제가 되는 대표적인 예는 이메일(Email)이다. 

프랑스 사람이 러시아 사람에게 프랑스어로 이메일을 작성했을때 러시아인 컴퓨터에서 프랑스어가 제대로 보이기 위해서 이메일은 이스케이프 시퀀스(escape sequence)로 글자별로 캐릭터 셋을 설정하도록 하였다. 즉 프랑스 이메일 클라이언트는 프랑스어 코드가 나올때마다 ISO 2022 문자 인코딩들은 이어서 나오는 문자들에 대한 문자세트를 지시하는 escape sequence를 포함하고 있다. 그럼 저장단계에서 escape를 보고 해당 캐릭터셋의 번호로 저장 하였다. 즉 아직까지는 해석과 저장의 명확한 분리를 하지 않았기 때문에 기본 ASCII가 아닌 문서를 교환하는 것은 이렇게 비효율적인 면이 존재한다. (escape 문자로 인해 data 길이가 늘어나고 여전히 read하는 곳에서 해당 charset을 인식하지 못한다면 읽을 수 없었다.)

ISO 2022 문자세트들은 여전히 많이 사용되고 있으나, 최근에는 최신 이메일 소프트웨어 등 에서 UTF-8과 같은 유니코드 문자 인코딩들을 사용하는 것으로 차츰 변환되고 있다.


KSC 5601

KSC 5601은 94x94의 각 위치(행열)에 한글 문자를 일정한 순서에 따라 배열해 놓은 charset이다. 앞서 말했듯이 한글은 표의문자와 표음 문자 2가지 성격을 모두 가지고 있는 독특한 특성때문에 여러가지 다양한 방법중에서 한글 코드의 KS 제정에서 완성형이 채택된 것은 내부적으로 한글의 출력이 모아쓰기 형태로 이루어지면서 동시에 한자를 섞어서 쓸 수 있어야 한다는 사회적 요구로 조합형을 수용 하기가 어려웠기 때문이다.(물론 정치적인 이유가 없던것은 아니다.)

또 다른 배경은 국가간의 정보교환을 위한 코드 표준화 과정에서 앞의 ISO 2022에서 제정한 코드 체계에 따라 세계 각국의 문자를 처리하는데 기인한다. 이는 1바이트 코드로 한 문자 표현이 불가능한 CJK(Chinese, Japanese, Korean) 문자를 2바이트 코드 영역의 첫 번째 영역에 넣을 수 있도록 영역을 확보해야 했기 때문이다.


KSC 5601은 완성형 한글 2,350자, 한자 4,888자, 기술/학술기호 등 특수문자 432자, 숫자 30자, 한글 낱자 94자, 로마문자 52자, 그리스 문자 48자, 괘선 조각 68자, 라틴 문자 27자, 일본 문자 169자, 러시아 문자 66자 등 총 8,224자와 기타 사용자 정의 영역으로 한글 96자, 한자 95자 정도를 사용하도록 배정하고 있다.(이후 KSX 등의 명칭이 변동된 역사는 이전글을 참조)

를 보면 94*94(8836) 의 매트릭스에 위 문자들이 지정되어 있다. 'A'가 03 * 33에 'a'가 03*65에 지정되어 있고 '가'는 16*01에 할당되어 있다. 위 PDF를 보면 캐릭터 셋과 인코딩의 차이에 대해 좀더 이해할 수 있다. KSC 5601 캐릭터 셋이란 "한국"이라는 지역에서 최소한 지원해야 하는 문자들에게 각각의 번호를 지정해놓은 것이고 인코딩이란 그 번호들을 컴퓨터 이진수로 어떻게 저장할 것인가에 대한 문제이다. 

일반적으로 KSC 5601을 지원하는 인코딩은(이를테면 euc-kr)은 1byte의 첫번째 비트가 0이면 이후 7bit를 ASCII문자에 대응시키고 첫번째 bit가 1이면 다음 바이트까지 묶어서 KSC 5601의 문자번호를 지정된 해쉬함수 계산을 통해 저장된 문자로 인식한다. 

네트워크가 발전하고 CJK에 컴퓨터가 많이 보급되면서 위와같이 지역적인 문사셋을 사용하는 것은 글자깨짐의 문제(파일의 메타정보에는 문자셋을 지정할 수 없다는 것을 기억하자. 대표적으로 HTML안에도 HTML의 문자셋을 HTML 문자 안에 지정해야 한다. 이러한 - 파일 해석을 위한 방법이 파일안에 있는 - 방법이 먹혀드는 이유는 HTML은 규약상 charetSet을 지정하는 부분까지 ASCII를 제외한 다른 문자가 나오지 않아야 한다는 가정때문이다.)때문에 UniCode가 나왔다. 


UNICODE

유니코드(Unicode)는, 컴퓨터에 저장하려는 모든 문서의 글자에 대해 캐릭터 셋을 제공하기 위한 국제 표준이다. 유니코드는 오늘날 실제 사용되는 모든 문자들과, 학자들만 사용하는 문자들, 또 수학기호, 언어학기호, 프로그래밍 언어 기호 등까지 포함하고 있다. 보통 유니코드는 말하거나 문서에 적을때 캐릭터 셋과 인코딩의 두가지 의미를 동시에 가지기 때문에 다소 헛갈리지만 

보통의 경우 
유니코드라고 말하면 캐릭터 셋을, 
USC-2, UCS-4는 캐릭터 셋 혹은 인코딩 2가지 의미를
UTF-8, UTF-16, UTF-32라고 말할때는 인코딩 방법을 의미한다. 

UCS-2는 2byte 숫자로 전세계에서 자주사용하는 문자를 지정해놓은 캐릭터 셋이고(여기에는 기본 ASCII 와 서유럽언어, CJK 언어 일본어 등이 할당되어 있다. 단 65536의 제약이 있기 때문에 모든 글자가 할당되어 있지는 않다.) 이 캐릭터 셋의 번호로 컴퓨터에 저장하면 UCS-2 인코딩을 사용한 경우가 된다. 

USC-4는 4byte의 숫자로 전세계의 모든 문자와 학자들만 사용하는 문자들, 수학기호, 언어학기호, 프로그래밍 언어등까지 포함하고 이후에 새로이 나타나게 될지도 모를 문자들를 위해 많은 여유공간이 있다. 실제로는 0번부터 256^4 까지 순차적으로 번호를 부여하는게 아니라 32bit를 영역별로 쪼개서 언어판(Plane)과 Group를 지정한다. ( Group 1byte + Plane 1byte + CodePoint 2byte를 사용한다. UCS-4가 인코딩의 의미로 사용될때에는 0x00000000 ~ 0x0010FFFF 범위만을 합법적인 코드값으로 갖는다. 00그룹 + (00 - 10 까지의 17개 Plane) + codepoint 2byte)


인터넷에서는 카더라 통신이 많아서 혼란의 소지가 많지만. 위 문서는 유니코드에 대해 가장 잘 설명한 그리고 정확한 문서이다. 

'IT 이야기 > 유니코드' 카테고리의 다른 글

Unicode와 Database  (0) 2009.03.01
Global Software - Unicode와 Programming  (0) 2009.02.26
Global Software - Unicode  (0) 2009.02.25
Global Software  (0) 2009.02.22
Posted by bleujin