Joinc 팀블로그 리눅스 메뉴얼 정리 Joinc 위키
댓글

Recent Comments

Powered by Disqus
팀블로그 카테고리
  전체 (1105)
   공지사항 (1)
   검색엔진 (21)
   기술동향 (58)
   게임 (2)
   독서 (6)
   리눅스 (12)
   보안 (1)
   사회문제 (22)
   어셈블리 (43)
   영화 (3)
   오픈소스 (10)
   음악 (9)
   인물 (1)
   포인터 (4)
   프로그래머 (23)
   팀블로그 (20)
   테터툴즈 (29)
   C/C++ (152)
   FireFox (11)
   Gimp (2)
   Google (98)
   Java (13)
   Perl (2)
   Pthread (11)
   STL (13)
   TCP/IP (8)
   Tools (31)
   Web2.0 (42)
   Wiki (1)
«   2010/07   »
        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
2009/07/23 00:18

disqus 에서 euckr 대응 문제

Recent Comments 가져오기

요즘사이트들은 거의 utf8을 기준으로 만들어져있겠지만 joinc 사이트가 만들어진 2000년에는 euckr이 대세였고, 시대조류? 맞지 않게 euckr을 유지하고 있다. utf-8로 바꿀걸 생각해봤지만 워낙에 귀찮아서..

문제는 disuqs가 euckr을 전혀 지원하지 않는데 있다. 그러다보니 브라우저에 따라서 컨텐츠가 깨지는 문제가 발생한다. Firefox 에서는 잘되는데.. IE에서는 깨진다. 암튼 언제나 IE가 문제다. 그래도 (아마도)80%이상의 방문자가 IE를 사용하니 IE에서도 보이게 해줘야지..

해서 다음과 같은 간단한 함수를 만들어서 disuqs의 recent comment 컨텐츠 자체를 euckr 로 변경해 버렸다. phpiconv함수를 사용했다.
function get_recent_comment() 
{
$contents = array();
$handler = fopen('http://disqus.com/forums/joinc/combination_widget.js?num_items=5&color=blue&default_tab=recent','r');
if(!$handler) return 0;
while(!feof($handler))
{
$line = fgets($handler,1024);
$line = iconv('utf-8', 'euckr', $line);
if(ereg("^\t +<h3>", $line))
$line = str_replace('Recent Comments', '최근댓글', $line);
if(ereg('combo-tab-recent', $line))
{
$line = str_replace('Recent','최근댓글', $line);
}
if(ereg('combo-tab-people', $line))
{
$line = str_replace('People','댓글러', $line);
}
if(ereg('combo-tab-popular', $line))
{
$line = str_replace('Popular','높은인기', $line);
}
if(ereg("dsq-widget-meta", $line))
{
$line = str_replace('hours ago','시간 전', $line);
$line = str_replace('minutes ago','분 전', $line);
$line = str_replace('Some thread attached to test page','FrontPage', $line);
}
$contents[] = $line;
}
$text = join($contents);
return <<<FOOT
<script type="text/javascript">
$text
</script>
FOOT;
}
이왕 이렇게 된게 Recent Comments같 은 문자열까지 한글로 바꿔 버렸다. str_replace에 비용이 좀들어갈 것 같은데, 나중에 시간이 되면 static 페이지를 생성하는 스크립트를 만들어 봐야 겠다. 우선은 이것으로 만족. 사이트 옆에 붙여놓은 위젯을 보면 (눈속임)한글화가 된 것을 확인할 수 있다. 아직 blog에는 적용하지 못했고 joinc wiki 에만 적용했다. 시간이 남으면 blog에도 적용시켜야지.
:::
2009/06/23 22:40

논어를 읽고 프로젝트 관리에 대해 생각해 보다.

논어ISBN : 9788970650340를 읽고..

서점에 가면 프로젝트 관리와 관련된 책들이 널려있다. 특히 애자일 열풍?이 불어닥치면서 애자일 관련된 책들만해도 수십권은 되어보인다. 그런책들은 언제 시간나면 한번 읽어보기로 하고, 논어에 나오는 격언들을 프로젝트관리에 적용시켜보면 어떨까라는 생각이 느닷없이 든김에 생각을 정리해 보기로 했다.

공자왈 백성들을 정치로 인도하고 형벌로 다스리면 백성들은 형벌을 면하고도 부끄러워함이 없다. 그러나 덕으로 인도하고 예로써 다스리면, 백성들은 부끄러워할 줄도 알고 또한 잘못을 바로잡게 된다.
일정으로 프로젝트와 팀원을 제어하려고 하면, 팀원은 일정을 어기게 되더라도 부끄러워함이 없어진다. 많은 경우 이러한 일정은 (마음으로)동의하지 않은 일정이기 때문이다. 사람은 동의하지않은 권위에는 복종하지 않으려고 한다. 일정에 차질이 생기면 쉽게 핑계를 댈 수 있다. 마음으로 받아들이지 않게 된다. 일정에 사람을 맞추는 것보다 사람에 일정을 맞추어야 하는게 아닐까란 생각을 해본다. 애자일관리 기법에서 일정보다 사람을 우선시 하는 이유도 여기에 있을 것이다. 일정은 따라오는 것이지 따라가는 것이 아니다.

공자왈 군자는 천하에서, 반드시 그래야만 한다는 것도 없고, 절대로 안된다는 것도 없으며, 오직 의로움만을 따를 뿐이다
반드시 내가 생각한데로 이렇게 이렇게 해야만된다라고 결정하고 그것을 지킬것을 명하는 경우가 있다. 특히 그 프로젝트를 내가 잘 알고 있다고 생각하는 리더의 경우에는 더욱 그러할 수 있다. 아무리 뛰어난 리더라도 프로젝트를 제대로 이해하는건 거의 불가능하게 되었다. 정형화된 제조업이라면 어떠할지 모르겠지만, 소프트웨어 관련 프로젝트 특히 인터넷 관련 프로젝트에서는 더욱 그러한것 같다. 자신의 생각을 고집하지 말고 융통성있게 남의 의견을 받아들여야 하지 않을까. ? 물론 그러하기 위해선 수평적 관계형성이 중요할 것이다. 소프트웨어 개발관련 조직에서 수평적 관계형성이 주목받는 이유일 것이다.

공자왈 군자는 말에 대해서는 모자라는 듯이 하려하고, 행동에 대해서는 민첩하려고 한다
리더가 너무 똑똑하고 그걸 내세우면 프로젝트가 산으로 가는 경우가 많은 것 같다. 한사람이 모든것을 파악할 수 있는 시대가 아니다. 모든걸 이해하고 있다고 생각하는 순간 프로젝트는 산으로 향하신다.

자유왈 임금을 섬김에 번거롭게 자주 간언을 하면 곤욕을 치루고 치욕을 당하게 되고, 친구에게 번거롭게 자주 충고하면 곧 소원해진다.
시시콜콜한거 까지 일일이 참견하고 간섭하는 걸 좋아하는 사람 없을 거다. 충고나 간섭은 필요한 때에 필요한 만큼만 하는게 좋을 것 같다. 상대방이 감당할 수 없는 충고는 충고가 아니다. scrum같은 개발방법론에서는 일단 개발사이클이 결정되면, 외부에서는 절대 참견하지 못하도록 하고 있다. 굳이 보고싶다면 참관만 허용하는 정도이다. 참견은 개발주기가 끝난 다음에 이루어진다. 시시콜콜한 충고와 간섭을 없애기 위함이다.

공자왈 군자는 절박한 것은 도와주지만 부유한자가 더 부자가 되게 도와주지 않는다
2MB옹은 지금 하고 있는 짓이다. 절박한 사람의 것을 빼앗아서 부유한자가 더 부자가 되게 하고 계시다. 잘하는 사람은 잘하는데로 되었으니 그냥 두어도 괜찮다. 뒤쳐지는 사람에게 더 많은 배려가 필요하다. 이렇게 행동하면 되지 않을까 ? 그렇지만 실제는 이 반대인 경우가 많은 것 같다. 예컨데 심복을 키우겠다 라든지 뭐 그런 이유로 말이다.

자로가 여쭈었다. 선생님께서 삼군을 통솔하신다면 누구와 함께 하시겠습니까 ? 공자께서 말씀하시길 맨손으로 범을 잡고 맨몸으로 황하를 건너려다 죽어도 후회가 없는 사람과는, 나는 함께하지 않겠다. 반드시 일을 대담에 신중하게 하고, 계획을 잘 세워 일을 이루는 사람과 함께 하겠다.
욕심이 앞서면 프로젝트를 망친다. 예컨데, 열정과 감정은 다르다.!? 알수 없는 내일을 위해서 오늘 하루, 이한몸 불사른다는 마음가짐을 버리자. 몸과 시간으로 떼우면 일정같은거 맞출 수 있을 것이란 것은 그나마 굴뚝산업에나 통해먹는 행동양식이다.

공자왈 부가 만약 추구해서 얻을 수 있는 것이라면, 비록 채찍을 드는 천한 일이라도 하는 하겠다. 그러나 추구해서 얻을 수 없는 것이라면 내가 좋아하는 일을 하겠다
어떤 결과를 얻기 위해서 일을 진행하기 보다는 그 자체를 좋아할 수 있어야 하지 않을까 ? 혹은 좋아할 수 있는 환경을 만들어야 하지 않을까라는 생각이 든다.

군자는 평온하고 너그럽지만, 소인은 늘 근심에 쌓여있다.
근심에 쌓이는 프로젝트가 있고, 그렇지 않은 프로젝트가 있다. 근심이 쌓이는 프로젝트라면, 프로젝트가 제대로 진행되고 있는 것인지 되짚어볼 필요가 있다.

마굿간에 불이 났었는데, 공자께서 퇴근하시어 사람이 다쳤느냐라고 물으시고는 말에 대해서는 묻지 않으셨다.
자본을 신으로 모시는 자본주의 사회이다 보니 크게는 회사이익, 작게는 프로젝트이익에 해를 끼치면 때때로 사람이 사람취급을 받지 못하는 경우가 생겨난다. 프로젝트에 불이 나지 않도록 하는게 우선이겠지만, 일단 불이 났다면 사람을 보듬는게 우선이 되어야 하겠다. 물론 쉽지 않은 일이겠지만.

공자께서 말씀하셨다. 지나친 것은 모자란 것과 마찬가지이네

중궁이 정치에 대해 여쭙다. 공자께서 말씀하시길 먼저 실무자들에게 일을 분담시키고, 작은 잘못은 용서해 주며, 현명한 인재를 등용하거라
정치와 관련된 공자의 격언들을 보면 윗사람은 사사로운 것까지 통제하려하면 안된다는 가르침이 자주 등장한다. 예컨데 리더는 큰 방향을 잡아주는 사람이지 사사로운 것까지를 전부 간섭해서는 안된다는 것이라 하겠다. 비슷한 맥락으로 사사로운 것에 연연하면, 큰걸 이루지 못한다고 하셨다. 큰 방향을 잡고, 그 방향안에서 수행해야할 일들은 실무자에게 맡기고 소소한 잘못은 용서한다. 이렇게 하려면 역시 어느정도의 대범함과 느긋함이 있어야 할듯 싶다. 사람을 믿을려면 대범함이 필요할테고, 대범하려면 멀리봐야 할테니 말이다.

섭공이 정치에 대해서 묻자, 공자님께서 말씀하시길 가까이 있는 사람들은 기뻐하고, 먼 데 있는 사람들은 찾아오도록 하는 것입니다라고 하셨다.
프로젝트를 하다보면 정치관련된 얘기가 많이 오간다. 이때 정치는 공자님이 말하는 정치와는 분명히 다르다. 정치라는게 무엇인지 생각해봐야 하지 싶다.

자하가 정치에 대해 여쭙자, 공자께서 말씀하시길 빨리 성과를 보려 하지 말고, 작은 이익을 추구하지 말라. 빨리 성과를 보려하면 제대로 성과를 달성하지 못하고, 작은 이익을 추구하면 큰일이 이루어지지 않는다
이루려고 하는 일을 바라보는 시각에 대한 핵심적인 사상이 담겨 있는 격언이라고 생각된다. 조급하면 일을 쉽게 망칠 수 있다는 것은 다들 알고 있는 사실이다. 단지 격언으로 뿐만 아니라 경험적으로도 알고 있는 사실이다. 그런데 조급해지지 않기가 쉽지 않은 것 같다.

공자께서 말씀하셨다. 가난하면서 원망하지 않기는 어렵지만, 부자 이면서 교만하지 않기는 쉽다
프로젝트가 제대로 수행이 안되면, 서로 원망하게 마련이다. 책임을 떠넘기기도 한다. 이때문에 서로 상처를 입히고, 팀이 와해되기도 한다. 큰 프로젝트는 제대로 수행되기가 매우 어렵다. 특히 최근의 프로젝트들은 아주 작은 프로젝트라고 하더라도 입력되는 정보와 출력되는 정보가 명확하지 않기 때문에 욕심을 부리다가는 망해먹기 십상이다. 이런 이유로 애자일에 서의 (대략 한달 주기의)짧은 주기의 개발방법론등이 대안으로 제시한다. 한번에 완성된 제품을 만드는 대신, 기능을 최소화하고 입력과 출력을 제한한 중간 제품들을 만드는 식이다. 기능을 줄이고 입력과 출력을 제한하면, (완성된 단계가 아니라고 하더라도) 그 단계에서의 성공적인 수행 확률은 높아진다. 팀원들은 자신감을 얻게 되고 사기는 올라간다.

공자께서는 네 가지를 절대로 하지 않으셨다. 사사로운 뜻을 갖는일이 없으셨고, 기필코 해야 한다는 일이 없으셨으며, 무리하게 고집부리는 일도 없으셨고, 자신만을 내세우려는 일도 없으셨다.
프로젝트를 진행할때는 사사로이 하고 싶어하는걸 해서는 안될 것이다. 혼자진행하는 거라면 모르지만 서도 말이다. 하고싶은 것이 있다면 공적인 장으로 끌어올려서 공유해야 할 것이다. 기필코 해야 한다는 일이 없다는 것은 일함에 있어서 융통성을 가져야 한다는 것을 의미할 것이다. 이 바닥은 하나의 문제를 해결하는데 있어서 하나의 해결책만 있는게 아니다. 다양한 해결책이 있다. 때때로 다른 사람의 해결책이 자신의 것보다 못하다고 생각되더라도, 그 방법이 크게 잘못된게 아니라면 시시콜콜하게 소숫점까지 따질 필요는 없다고 나는 생각한다.

현대 자본주의 사회에서 살아남기 위한 덕목은 스피드경쟁력, 효율성이다. 이를 달성하기 위해서 시간과 공간을 집적시키길 원한다. 때로 인간다운 삶을 포기해야 한다. 이러한 현실에 비추어 유교의 가르침은 고리타분하고 비현실적이라는 느낌을 줄 수 있다. 욕심 없이 유유자적하면서 살 것이라면 모르지만 치열한 경쟁 사회에서 살아가기위한 지침으로 삼기엔 적당하지 않다고 생각되어지기 때문이다. 아름답지만 현실적이지 않은 가르침이라고나 할까 ?

시간과 공간을 집적시켜서 효율을 극대화 시키고 그것으로 이윤을 창출했던 산업시대에는 확실히 유교의 느긋함, 길게 보기, 사람 중심으로 보기, 결과 보다는 과정이 런건 사치로 여겨졌을 지도 모르겠다. 정보화,인터넷 시대인 지금 이러한 인식이 변하고 있다. 소프트웨어 업계의 여러가지 새로운 개방방법론들은 산업시대의 것들과는 분명히 다르며, 동양적사상을 오히려 따르려 하고 있음을 느낄 수 있다.

공자님의 격언을 보면 일관되게 일을 함에 있어서 소소한 것에 크게 신경쓰지 말라라고 하신다. 그게 해야할 업무이건 실수이건 간에 말이다. 큰것을 해결하면, 작은 것은 알아서 해결되는 경우가 많기 때문이다. 작은 것들에 신경을 쓰는 가장 흔한 이유는 잠깐이면 끝낼 수 있는 것 아니냐. 내가하면 5분안에 끝낼 수 있는데..라는 생각 때문인 것 같다. 큰일을 해결하면 작은일들도 해결되지만 작은일들이 모이면 큰일이 된다. 네버엔딩 프로젝트가 될 수도 있다. 인내와 믿음이 있어야 가능한 일이다.
:::
2009/06/10 18:02

객체지향

음.. 완성된 문서가 아닙니다. 문서는 wiki 를 통해서 계속 수정/보완해나갈 생각입니다.

1 문서정보

1.1 작성자 정보

  • 최초 작성자: mwyun()
  • 이래저래 수정한 사람 : yundream

1.2 히스토리

  • 내용 대폭 수정/추가 - 2009/6/9
    1. 오탈자 수정
    2. 문맥에 맞지 않는 내용 수정/추가/삭제
  • http://jamesthornton.com/eckel/TIJ-3rd-edition4.0/TIJ3.htm <-- 이문서 어떤가요? 객체에 대한 개념설명으로 괜찮은것 같은데, 이거 정리하고 뺄거 빼고, 살좀 붙이면 스터디에 괜찮을 듯.. - yundream

2 객체지향

어디에선가 OO에 대응되어서 사용되는 객체지향자체가 잘못된 번역의 결과물이란걸 읽은 기억이 있다. 그러나 이게 번역이 잘못되든 되지 않았던간에 의미를 전달하는데 별 지장이 없고, 현재 표준적인 용어로 사용하고 있으므로 당분간은(혹은 매우 오랫동안) 객체지향이라는 단어를 사용하도록 하겠다.

최초의 근대적 기계의 개념을 담고 있는 기계의 제작은 아마도 고대 그리스시대로 올라갈듯 하다. 아리스토텔레스는 전쟁에서 사용될 수 있는 기계를 만들었으며, 실제 전차(현대적 개념의 탱크)도 설계했던 것으로 알려진다.

이후에 만들어진 기계는 뭐 사실은 고만고만한 기계였는데 이들 기계는 주로 물리력을 이용해서 "물건을" 옮기는 일을 하였다. 바퀴와 기어들로 이루어져 있으며 제어하기 위해서 인간이나 동물의 물리력을 필요로 했으며 얼마나 많은 일을 할 수 있는지를 나타내는 단위로 '마력을 사용했다.

그러다가 컴퓨터라 는 기존의 기계의 개념과는 매우 다른 기계가 만들어진다. 이 기계는 전자를 이용하는데, 특히 정보를 처리하는데 효과적으로 만들어진 기계였다. 얼마나 많은 정보를 처리할 수 있느냐로 성능을 나타내며 단위로 Hz(헤르쯔)를 사용한다.

컴퓨터라는 기계를를 제어하는 데에는 물리력 대신, 소프트웨어라고 불리우는 프로그램을 사용하게 된다. 우리 개발자는 컴퓨터 언어를 이용해서 컴퓨터를 제어하는 프로그램을 만드는 일을 한다.

컴퓨터는 정보를 처리함에 있어서 획기적인 기계이긴 했지만 아날로그 기계와는 달리 상태가 거짓으로 표현되는 한계를 가지고 있었다. 참과,거짓으로 정보분석이 진행되는 논리연산에는 효율적이였지만 아날로그 적인 실세계의 다른 정보들을 처리하기에는 그다지 효율적이지 못하다. 초기에는 컴퓨터의 사용용도가 한정적이였으므로 ,거짓을 잘 이용하는 정도로 대부분의 일을 처리할 수 있었다. 프로그래밍언어 역시 이러하였다. 기계어, 어셈블리어, C(이론이 있을 수 있겠다) 등이 그러한 부류에 속한다.

거짓에 기초를 둔 논리연산은 어떤 일련의 순서를 따르면서 정보를 처리하도록 되어 있다. 컨테이너 벨트를 이용해서 물건을 처리하는 것으로 보면 될 것이다. 컨테이너 벨트는 물건과 물건을 처리하는 프로세스가 분리되어 있는데, 컴퓨터 역시 데이터데이터를 처리하는 방법이 분리되어 있다. 이러한 방식은 복잡하지않은 정보를 처리할때는 효율적이지만 가계/기업경영/문서작성/음악재성/공장제어/게임에서와 같이 정보와 정보가 상호연관되어서 복잡하게 얽혀있는 경우에는 효율이 극히 떨어지게 된다. 수백개의 컨테이너 벨트가 만들어져 있는데, 필요에 따라서 이들 각 컨테이너를 서로 연결시켜서 데이터를 처리해야할 경우를 생각해보면 될것이다. 입력과 출력이 매우 명확한 제조업에서야 컨테이너벨트를 재배열해야 하는 일이 그다지 필요 없겠지만 소프트웨어 개발영역은 그렇지 않다. 따라서 소프트웨어를 개발하고 유지하고 보수하는데 많은 비용이 들게 된다.

그래서 만들어진게 "객체지향 프로그래밍"으로 컴퓨터가 데이터와 데이터의 처리과정을 분리시켜서 생각하는걸 하나의 객체로 보고 처리하도록 만들어진 방법론이다. 이 방법론을 이용해서 코드의 재사용성, 유지/보수성을 높이고자 하게 된다.


2.1 객체란

간단히 말하자면 객체는 주변에서 볼 수 있는 모든 (관찰되어지는)사물이다. 삽살개, 호랑이, 세포, 사람.. 전부다 객체다. 또한 눈에 보이는 구체적인 것 뿐만 아니라 경제, 국가, 시장 같은 눈에 보이지 않는 것도 객체라고 한다. 모든 것이 객체다!!! 단순명료하긴 하지만 너무 포괄적인 것 같으니 객체의 특징에 대해서 정리해볼 필요가 있을 것 같다.

객체는 내면과 내면을 감싸는 외피를 가진다. 세포라는 객체는 세포내용물질과 이들을 감싸는 외피로 구성이 된다. 관찰자에게 보이는 것은 외피가 된다. 내용물들과 내용물들이 상호작용하는 과정은 관찰자에게 감추어진다. 이렇게 내면을 감추는 외피를 가지는 것을 추상이라고 하는데, 이 추상은 객체가 가지는 대표적인 특징이다. 여기에 따르면 외피를 가지지 않는 것은 객체라고 할 수가 없다. 외피가 중요한 이유는 주변의 다른 사물과 구분되는 표면이 있어야 관찰자에게 독립적인 사물로 보여질 수 있기 때문이다. 표면은 경계라고 해도 좋을 것이다.

경제나 국가와 같은 것들도 인간은 객체라고 본다. 물리적인 외피를 가지지 않지만 인간의 인식하에서 경제는 경계를 가지고 있기 때문이다. 경계를 가지고 있으므로 관찰자인 인간은 경제를 관찰하고 분석할 수 있다. 여기에서 어떤 대상이 객체로 보이느냐 아니냐 하는 것은 상대적일 수 있음을 알 수 있다. 경제관념이 없는 지역의 사람들에게는 경제는 관찰할 수 있는 대상이 아니기 때문이다.

객체는 객체를 포함할 수 있다. 치아와셰퍼드는 객체다. 여기에서 더 나아가 이들 치아와나 셰퍼드를 통칭하는 도 객체가 될 수 있다. 는 치아와와 셰퍼드와 같은 객체의 공통적인 특징을 분석해서 인간의 지성이 만들어낸 가상의 개념이지만 고양이라는 다른 개념과 구분되는 외피를 가지고 있으므로 객체라고 할 수 있다. 라는 객체는 치아와, 셰퍼드 객체를 포함한다. 이러한 객체의 속성을 이용하면 객체의 계층적- Hierarchy - 구조를 만들 수 있다. 이것은 복잡한 자연현상을 단순화 시켜서 인식할 수 있도록 도와준다. 대표적인 예가 종,속,과,목,강,문,계일 것이다.

객체는 주변환경 혹은 다른 객체와 상호작용한다. 생물의 경우 상호작용은 감각기관을 통해서 내부로 정보를 받아들인 다음 이를 처리하고 운동기관을 통해서 다른 객체를 조작한는 형식으로 이루어진다. 개가 위협적으로 달려들면 눈으로 이 정보를 받아들여서 처리한다음 다리근육을 움직여서 달아나거나 혹은 온몸을 이용해서 싸우거나 하는 식이다. 이러한 상호작용은 경제와 같은 구체적인 형태를 가지지 않은 객체에도 적용된다. 경제의 경우에는 신문,뉴스, 주식매입,은행업무등을 통해서 상호작용할 것이다.

이상에서 객체의 다음과 같은 특징을 뽑아낼 수 있을 것 이다.
  1. 객체는 내면과 내면을 감싸는 외피를 가진다.
  2. 내면은 외피 내부로 숨겨지며 이를 추상이라고 한다.
  3. 객체는 외피를 가짐으로써 주변사물과 독립적으로 구분될 수 있다.
  4. 객체는 외피를 가짐으로써 관찰대상이 될 수 있다.
  5. 구체적인 형태를 가지지 않는 것들 - 경제, 국가 - 도 객체가 될 수 있다.
  6. 객체에 대한 정의는 상대적이다.
  7. 객체는 객체를 포함할 수 있다.

위의 객체에 대한 내용은 다분히 철학적, 다른말로 말장난으로 보일 수 있을 것 같다. 그러나 이러한 특징은 컴퓨터 영역에서의 Object-orinted Programming 에도 그대로 나타난다.

2.1.1 객체와 과학

모든 사물을 객체로 바라보는 주의는 실증주의경험주의에 바탕한 현대적인 과학의 바탕이 된다. 즉 인간의 오감과 상호작용해서 분석되어진 정보를 오랜시간 분석해서 - 즉 경험을 통하여 - 보편적인 지식으로 만드는 과학적사고 방식 만들어냈다.

2.1.2 과학과 종교

과학적 사고는 상호작용 가능한 객체를 대상으로 이루어진다. 이런 의미에서 종교는 과학과 다른 길을 가게 된다. 신과 상호작용할 수는 없는 노릇이기 때문이다. 상호작용할 수 없는 건 객체가 아니다. 언젠가 신과 제대로 상호작용할 수 있는 어떠한 방법을 찾아낸다면 종교도 과학이 될 수는 있겠지만 말이다. 아 물론 지금도 신도들은 기도를 통해서 신과 상호작용 한다고 하지만 상호작용의 결과를 보여주지 않으니, 분석불가가 된다. 입력은 있는데 출력은 없는 상태라고나 할까.

신을 직접 입증하는게 불가능하다고 생각이 되자, 그들의 성서에 적혀있는 신화적 내용이 신화가 아닌 사실임을 증명하는 것으로 신이 있음을 간접적으로 증명하고자 하는 시도가 있었다. 신화는 어떤 부족의 역사를 담고 있는 경우가 많고, 역사는 과학적 탐구가 가능한 영역이니 말이다. 이것을 창조과학이라고 한다.

그러나 창조과학이 의미가 있을지에 대해서는 회의적이다. 설사 역사적 사실이 입증되더라도 말이다. 신화속의 도시로만 알려졌던 트로이가 발견이 되고, 아킬레우스가 실제 존재하던 인물이였음이 증명되었다고 해서, 아킬레우스가 신의 아들이고 트로이 전쟁을 신들이 배후조정했다는 증거가 되는건 전혀 아니기 때문이다. 종교는 그냥 믿음의 영역으로 두면 되는 것이다.

때때로 기술이 발전함에 따라서 너무터무니 없어서 신화와 같은 것으로 생각되던게 상호작용 가능한 과학적 탐구가능한 객체가 되기도 한다. 4차원이네 10차원이네 하는 것들은 과거에는 터무니 없는 것이였으나 입자가속기의 등장으로 그 실체를 거의 규명할 수 있게 된게 그 예가 될 것이다. 그렇다고 해서 신과 대화가능한 기계를 만들어 낼 수 있을까 ?? 뭐, 이벤트호라이즌호는 강력한 중력발생기를 이용해서 뜬금없는 지옥도 다녀오긴 했지만 이건 어디까지나 영화의 이야기고.

2.2 추상(抽象)화 와 추상화 과정

위에서 객체는 내부를 숨기는 외피를 가진다고 했다. 이것을 추상이라고 하는데, 객체의 가장 큰 특징중 하나다. 이 추상에 대해서 알아보도록 하자.

현대적인 추상개념을 체계화 한것은 플라톤으로 생각된다. 플라톤은 이데아라는 것을 주창하였다. 세상은 이데아라는 완전한 세계에 있는 원본틀의 그림자로 생겨난 것이다라는게 이데아의 핵심이다. 원본의 그림자이니 세상은 언제나 불완전할 수 밖에 없다. 이데아는 완전한세계, 영혼으로 볼 수 있는 세계라는게 플라톤의 생각이었다.

를 예로 들어보자. 를 본적이 있는가 ? 뜬금없는 말 같지만 그 자체를 본적은 없을 것이다. 왜냐하면 는 물리적인 대상을 가리키는게 아니기 때문이다. 우리는 삽살개, 치아와, 셰퍼드를 볼 수 있지만 를 본적은 없다. 플라톤이 주장하는 바에 따르면 가 바로 치아와 삽살개 셰퍼드등 이 세계에 존재하는 여러가지 개의 성질을 가지는 것들의 유일한 원본이다. 이 유일한 의 그림자가 바로 우리가 볼수 있는 치아와 인 것이다. 이데아는 우리가 사는 세계보다 차원이 높은 세계이므로 우리는 단지 의 그림자만을 볼 수 있을 뿐이다.



이처럼 차원이 낮아지면 얻을 수 있는 장점이 있다. 그것은 수많은 개의 성질을 가지는 객체를 만들어 낼 수 있다는 점이다. 앞서 이 세상에 물리적으로 존재하는 개들은 이데아 의 그림자라고 했는데, 그림자는 그 모습이 완벽하지 못하다. 광원의 거리와 흔들림에 따라서 찌그러지기도 하고 커지거나 작아지거나 할 수 있다. 는 하나이지만 수많은 개들이 존재하는 이유이다.

플라톤이 이데아를 생각해 냈던 것을 반대로 하면 그게 추상화가 된다. 즉 멍멍 소리를 내고, 꼬리를 흔들며, 다리가 4개고, 코가 뾰족한 특징을 가지는동물들을 라고 정의 하는 것이다. 이렇게 해서 우리는 눈에 보이지 않는 라는 새로운 상위 차원의 개념을 만들어내게 되었다.

추상화 과정이란 어떤 구체적인 사물로 부터 공통적인 속성을 찾아내어서 그것들을 포괄할 수 있는 상위의 포괄적 개념을 만들어내는 과정이다.



2.3 컴퓨터에서의 추상화

컴퓨터 언어역시 이러한 추상화 과정을 거친다. 가장 간단한 어셈블리는 이를테면 생명체의 바이러스라고 할만한데, 가장 간단한 추상화 과정을 거친다. 기계어와 거의 일대일 대응을 하는데, 다만 좀더 이해하기 쉽게 만들도록 "한단계"의 추상화 과정을 거쳤을 뿐이다. 포트란, 베이직, C와 같은 언어들은 어셈블리어에 비해서 더욱 많은 추상화를 이루고 있으며, 여러가지 면에서 크게 발전되었다.

그러나 이들 언어는 컴퓨터 기계가 만들어 졌던때의 그철학을 그대로 따르고 있어서 실제 생활에서 발생할 수 있는 다양한 문제를 푸는데 있어서 절차지향적인 방법을 따른다. 이건 어셈블리어 뿐만아니라, 포트란, 베이직, C 모두에 포함된다. 절차지향적이란 컨테이너 벨트라고 생각하면 된다. 재료를 집어 넣고 컨테이너 벨트에 집어 넣으면 최종적으로 물건이 튀어 나오는 것이다. 풀어야할 문제가 복잡해 질 수록 이런 절차지향적 방법으로는 한계에 부딪히게 된다. 즉 개발모델이 문제다.
여기에서 한계란.. 문제를 풀 수 없다라는 것이 아니고, 효율적으로 풀수 없으며 단지 푸는 것 뿐만 아니라, 유지하고 보수하고 확장시키는데 기존 방법으로는 많은 시간과 비용이 소비될 확률이 많다는 것이다.
그래서 만들어진 개발 모델이 객체지향 모델이다. 컨테이너 벨트 모형을 따르는 절차지향 개발 모델에서는 데이터와 데이터를 가공하기 위한 메서드(함수)가 서로 분리 되어 있다. 데이터가 계속 흘러가고 중간에 함수가 있어서 가공하고 다시 다음 함수로 넘겨주는 방식이다.

반면 객체지향 개발 모델에서는 데이터와 메서드를 분리하지 않고 하나의 공간에 둔다.

객체지향을 목표로 제작된 최초의 (성공적인) 언어로 Smalltalk라는 언어가 있다. Java도 이 언어를 기초래 햇 만들어 졌는데, 객체지향을 위한 기본적인 노선이 정립된 언어다. 객제지향 언어라고 한다면 보통 아래의 5가지의 요소를 만족시키는 특성을 지원할 수 있어야 한다.

  1. 모든 것은 객체다 : 간단하게 생각해서 객체는 데이터와 데이터를 처리하기 위한 메서드를 함께 가지는 모든 것을 말한다. 이론적으로 객체를 이용하면 모든 사물을 완벽하게 구현할 수 있다. (자동차, 개, 건물, 은행 서비스 ..)
  2. 프로그램은 객체사이의 메시지 전달을 이용해서 통신한다 : 두명의 사람(객체)가 상호작용하기 위해서 대화를 하는 것과 마찬가지다. 프로그램의 경우 두개의 객체(보통 클래스, 패키지라고 한다)를 연결하기 위한 메시지 전달 클래스를 만들 수도 있을 것이다. 사람과 사람이 대화를 하는데 중간에 매질(공기)이라는 객체가 대화를 전송하는 것과 같은 이치다.
  3. 각각의 객체는 자신만의 메모리를 가진다 : 객체는 데이터와 메서드를 하나의 공간에서 다루며, 객체는 다른 객체와 독립적으로 행동한다. 고로 자신만의 데이터를 저장하기 위한 공간을 가질 수 있어야 한다.
  4. 모든 객체는 이름을 가진다 : 각 객체는 독립적으로 구분될 수 있어야 한다. 그러기 위해서 이름(type)을 부여한다. 각각의 사람을 구별하기 위해서 "이름"을 부여하는 것과 마찬가지다.
  5. 동일한 특성의 객체는 동일한 메시지를 사용한다 : A라는 사람과 B라는 사람은 독립적인 객체이지만, 또한 "사람"이라는 동일한 특성의 객체이기도 하다. 이들 객체간의 대화를 위해서는 당연하지만 같은 언어가 사용되어야 할 것이다. 사람과 개의 경우에는 대화가 되지 않을 것이다. 프로그램에서도 동일한 특성의 객체들은 동일한 메시지를 이용해야 한다.

2.4 추상화를 통해 얻는 이득

자동차를 생각해보자. 자동차는 인류가 개발한 육상이동 수단중 가장 고도로 추상화된 기계다. 자체에 발전,공급,저장,통신,제어 시설을 갖춘 소형 공장이라고 할만하다.

그러나 운전자가 이러한 모든내용을 알아야지만 자동차를 이용할 수 있는 건 아니다. 대부분의 기능들은 추상화(숨겨져)있으며, 사용자는 단지 핸들과, 브레이크, 악셀레이터와 몇개의 계기판을 볼수 있으면 운전이 가능하다.

복잡한 내부 구현을 숨김으로써 사용자는 이것 저것 신경쓸 필요 없이, 제공되는 몇개의 인터페이스만으로 사용이 가능하다. 이게 추상화가 가져다 주는 첫번째 이득이다.
자동차가 처음 나왔던게 19세기 말이였던 것 같다. 그러나 성능상의 차이는 있겠지만 100년이 지난 지금도 자동차의 기본적인 운전방법은 거의 변함이 없다. 그때나 지금이나 여전히 운전자는 핸들, 브레이크, 악셀레이터 이 3가지를 이용해서 자동차를 제어한다. 이러한것 자동차의 구현을 "추상화"함으로 가능하다.

즉 구현과 인터페이스를 분리시켜줌으로 (최초에 인터페이스만 잘 설계한다면)기능이 대폭업그레이드 되더라도 사용자는 이것에 신경쓸필요 없이 기존의 운전기술을 그대로 사용할 수 있게 된다.

프로그램개발에 있어서도 이러한 이득을 그대로 이용할 수 있다. 추상화를(잘) 시키게 되면 인터페이스와 구현을 구분시켜 줌으로써 일반 프로그램개발을 할적에 세부저인 복잡한 구조를 신경쓸 필요 없이 제공되는 몇개의 인터페이스만을 이용해서 필요한 일을 할 수 있다. 구현을 업그레이드 시켜야할 경우에도 개발자는 여기에 대해서 신경쓸 필요가 없게 된다.

간단하게 생각하자면 우리가 프로그래밍을 위해서 사용하는 open(2), write(2)같은 함수역시 추상화의 결과물이다. 우리는 open(2)의 내부구조가 어떻게 되어있는지 신경쓰지 않고도 잘 쓸 수 있다.

2.5 객체는 인터페이스를 가진다.

객체에 대해서 깊은 사고를 한 최초의 철학자는 (보통)아리스토 텔레스로 알려져 있다.그는 "the class of fishes and the class of birds"라고 실존하는 모든 것들을 객체로 분류했다. 객체는 일반적으로 유일하며, 각 객체는 고유의 특징과 행동특징을 가지는 것으로 정의할 수 있다. 클래스란 이러한 객체의 고유 특성과 행동특징을 함께 묶어놓은 개념이다. 하나의 클래스는 여러개의 객체를 포함할 수도 있다. 새라는 클래스에 참새 1, 참새 2, 제비, 할미새와 같은 객체가 포함될 수 있는 것과 마찬가지다.

클래스(class)를 처음 도입한 객체지향 언어는 Simula-67 이다.

Simula는 그 이름에서 느낄 수 있는것 처럼 어떤 상황을 "시뮬레이션"하기 위한 용도로 작성되었으며 bank teller problem과 같은 문제를 해결하기 위해서 사용되었다. 여기에 상담원, 고객, 트랜잭션, 계정, 등과 같은 많은 요소들이 있다. 이러한 요소들은 "은행업무"라는 작업을 달성하기 위해서 상호통신하면서 일종의 그룹처 럼 움직인다. 그렇다면 이들 요소를 하나의 클래스로 묶어서 처리하게 된다면 좀더 현실에 가깝게 상황을 시뮬레이션 할 수 있을 것이다. 즉 요소의 유기적인 모임인 클래스가 또하나의 데이터가 되는 것이다. 각 요소는 하나의 클래스 안에서 유지적으로 움직인다. 예를 들어 고객은 상담원과 상담을 하고 자신의 계정을 통해서 저금을 하거나 돈을 찾거나 또는 다른일을 할 수 있다. 만약 새로운 고객이 은행창구에 들어온다면 새로운 "은행업무-1" 객체가 생성될 것이다.

이처럼 클래스라는 개념은 어떤 상황을 시뮬레이션 하기에 적당한 개념이라는 것을 알 수 있다. 이론적으로 클래스를 이용하면 모든 상황에 대한 시뮬레이션이 가능하다. 클래스에 있는 각각의 요소들은 어떤 문제를 풀기 위해서 존재한다. 즉 객체지향 프로그래밍이라 함은 어떠한 동일 문제해결영역에 있는 여러 요소들을 제어함으로써 문제를 해결하기 위한 개발철학이라고 할 수 있다. 대부분의 객체지향 언어에서 문제해결영역은 보통 class라는 키워드로 표현된다.

지금까지 클래스에 대한 대략적인 내용을 살펴보았는데, 지극히 추상적이고 철학적이라서 어떻게 써먹을 수 있을지 감이 잡히지 않을 수 있을 것 같다. 구체적인 이해를 돕기 위해서 전구에 대한 제어를 시뮬레이션 해보기로 하겠다. 문제영역은 빛의 조절이며 이 문제를 해결하기 위해서 켜기, 끄기, 밝게하기, 어둡게 하기라는 인터페이스 들이 필요함을 알 수 있다. 이들 인터페이스를 통해서 다루는 요소(데이터)는 이 될 것이다.
위의 클래스를 보면 을 조절하기 위해서 4개의 인터페이스가 사용자(프로그래머)에게 제공되어짐을 알 수 있다. 프로그래머는 4개의 인터페이스를 이용해서 필요한 모든일을 할 수 있는데 인터페이스를 통해서 실제 내부적으로 어떠한 일이 일어나는 지와 내부의 데이터가 숨어(추상화)되어 있음을 알 수 있다. 사용자는 각 인터페이스를 조절해서 필요한 일을 수행하게 된다.

여기에서 클래스의 이름은 Light라고 했다. 자 이제 여러분이 전구를 하나 샀다고 하면 이로서 It이라는 새로운 객체를 생성된 것이다. 여러개의 전구가 필요할 수 있는데, 그럴 때마다 서로 다른 이름을 가지는 객체를 생성시키면 된다. It객체는 클래스 Light를 참조해서 생성된 객체이며 new라는 키워드를 통해서 생성된다(돈주고 전구하나 사는 것과 동일하다). 여기에서 우리는 클래스와 객체의 이름간에 연결이 있음을 알 수 있다.



위의 같이 클래스와 객체간 연관관계를 연결하는 다이어그램(diagram)형식의 구성도를 그릴 수 있을 것인데, UML(Unified Modeling Language)라는 도구를 이용해서 그릴 수 있다. 위의 경우는 클래스와 객체의 가장 단순한 예이지만 객체자체가 클래스가 될 수 있고, 상속등이 일어날 수 있으므로 실제로는 꽤나 복잡한 구성도가 만들어지게 된다. UML은 그 자체가 하나의 학습분야이므로 여기에서는 자세히 다루지 않을 것이다. 이런것이 있다는 정도만 이해하고 넘어가도록 하자.

2.6 객체는 서비스를 제공한다.

뻔한 얘기다. 은행업무-1객체는 고객에게 은행서비스를 제공하기 위해서, It객체는 밝게 비춰주는 서비스를 제공하기 위해서 존재한다.

3 OOP (Object-Oriented Programming) 개론

이 글은 제가 오래전 잡지에서 본 강좌를 타이핑하여 파일로 저장해둔 것을 올린 것입니다.

아쉽게도 잡지명이나 저자 이름은 오래된지라 기억이 나지 않지만 전문을 올렸으니 잘 읽어보시기 바랍니다.

3.1 Object-Oriented Programming의 등장

3.1.1 소프트웨어 위기 (Software Crisis)

컴퓨터가 출현하고 그 기능이 발달함에 따라 우리들은 그것을 사용하여 보다 편리하고 윤택한 생활 - 정말 윤택하게 되었는지 아닌지에 대한 언급은 하지 않도록 하겠다 - 을 하게 되었다. 그에 따라 소프트웨어의 수요가 기하급수적으로 증가하게된다. 결국 공급이 수요를 따라가지 못하는 상태에 이르게 된다. 하드웨어의 발전은 눈부시도록 놀라운데 그에 비하면 소프트웨어의 발전은 그 발치에도 미치지 못하고 있는 것이다. 이러한 위기상황 속에서 이를 극복하고자 하는 노력을 구체적인 방법론으로 표현한 것이 소프트웨어 공학 (SE : Software Engineering)인데, Object-Oriented Programming(Paradigm)도 바로 이 SE의 한 범주에 속한다고 할 수 있겠다. 집채만한 공룡이 메추리알 크기의 뇌를 가지고 있는 상태라고 볼 수 있을 것이다.

3.1.2 소프트웨어의 구성 방법의 변천

초창기에는 모든 소프트웨어를 단지 하나의 Procedure로 만들어 냈다. 그러나 많은 시간과 여러 사람의 노력이 필요한 큰 시스템을 구축하려고 할 때에 이런 방법은 적절하지 못하다. 그래서 큰 프로그램을 각 기능별로 여러개의 Subroutine으로 나누어(Functional Decomposition) 독립적인 부분으로 만들어(Modularization) 여러사람에게 할당하고, 각각의 모듈이 완성된 후에는 그것들을 서로 짜맞추어 하나의 시스템으로 완성하는 방법을 사용하게 된다. 이것을 Modular Programming이라고 한다. 이 Modular Programming과 함께 몇몇 규칙들을 적용하여 Structured Paradigm이라는 소프트웨어 구성방법이 생겨나게 되었으며, 지금까지도 널리 사용되고 있다.

3.1.3 Structured 방법의 문제점

기존의 Structured 방법은 처리(Process)를 중심으로 하고 있다. 바로 이점이 문제가 된다. 데이타(Data) 는 단지 강의실에서의 칠판처럼 필요할때마다 썼다 지웠다하는 보조 수단으로 여겨 그다지 중요시하지 않게 생각했다. 데이터를 독립된 단위로 보는 이러한 시각은 처리해야할 데이터의 절대적인 양자체가 적었을때는 크게 문제가 되지 않겠지만, 요즘처럼 다루어야 하는 데이터의 기본단위가 기가가 되는 경우에는 문제가 된다. 많은 데이타를 공유해야만하고, 원하는 데이타를 여기저기 마구 불러 사용하는 상황은 Modular Programming의 원리를 어기게 되었고 따라서 모듈의 재활용성(Reusablity)이 떨어지게 된 것이다. DBMS(DataBase Management System)를 사용하여 이런 문제를 다소 해결할 수는 있으나 이로서는 충분하지 않다.

3.1.4 Object-Oriented Paradigm의 등장

프로그램의 재활용성을 높이기 위해서는 Modular Programming, 이를 위해서는 Procedure뿐만이 아니라 데이타도 모듈화 되어야 한다는 방법론이 등장했으며 이것이 Object-Oriented Paradigm의 중요한 기본 요소가 되었다. 1960년대에 등장한 Simula는 현실세계를 Simulation하는 것을 주목적으로 하는 프로그래밍 언어였는데, 이 프로그램에 도입된 프로그래밍 개념이 바로 Object-Oriented Paradigm의 효시가 되었다.


3.2 OOP의 기본개념

3.2.1 Object

Object는 데이타와 이와 관련된 Procedure를 한데 묶어 표현한 소프트웨어 패키지이다. 이는현실세계가 처리중심이 아닌 사물(객체 : Object)중심으로 이루어졌다는데에 바탕을 둔 것이다. 세포(Cell) 를 예로 들어 생각해 보자. 세포는 핵, 미토콘드리아, 세포질, 세포막 등으로 이루어 졌는데, 이러한 세포의 구성 요소들에게는 각각의 역활이 주어져 있다. 그러나 기관의 입장에서 살펴면, 세포의 구성 요소들이 어떠한 일들을 하는지는 그다지 중요한 사실이 아니다. 단지 단백질이나 무기질을 세포내로 전달해 주면, 세포는 그것들을 가지고 자신의 임무만을 수행하면 되는 것이다. 세포내에 어떠한 구성원들이 있는지는 알 필요도 없고, 단지 세포 그 자체로서만 인식되면 충분한 것이다. Object도 이와 마찬가지로 생각하면 쉽게 이해가 갈 것이다.

3.2.2 Abstract Data Type & Data Abstraction

프로그래머가 기존의 Data Type을 이용 - 조합 - 하여 정의한 새로운 Data Type을 Abstract Data Type이라고 하며, 이것을 Data Abstraction(데이터 추상화)이라한다. 이때 일반적으로 새로운 데이터와 그 데이터에 대한 연산까지 함께 묶어서 - 즉 객체단위로 - 정의한다. 이렇게 함으로써 사람의 생각을 한단계 높여, 구체적인 Low-Level(Primary) Data와 연산이 아닌, 추상화된 Data와 연산을 다룰 수 있게 된다. 이 Data Abstration은 복잡한 데이타(Complex Data)를 다룰때에 효과적이다. 실제로 "Program = Level of Abstraction"이라는 관점도 있다. 가장 간단한 형태의 데이터 추상은 구조체일 것이다.

3.2.3 Encapsulation

Data Abstraction를 이용하면 Encapsulation을 달성할 수 있다. 필요한 데이타와 Procedure를 모아 캡슐에 담는 것에 착안하여이렇게 이름을 붙인 것이다. 실제로 이 Encapsulation으로 인해 생겨난 결과가 Object이다. 예를 들면, Nucleus(핵), Mitochondria(미토콘드리아), Membrane(세포막)등의 변수들과 그와 관계된 함수들을 Cell(세포)이란 object내에 정의해 놓은 것이다. 이렇게 함으로써 우리들은 자세한 부분까지 신경을 쓸 필요가 없고 단지 세포라는 Object와 Object로의 입출력 데이터만 생각하면 된다.

3.2.4 Infomation Hiding

Encapsulation으로 인해 내부의 데이타는 외부로 부터 고립되었다. 데이타는 필요한 때에 단지 외부로부터의 Message에 의해서만 접근되어질 수 있는데, 이러한 것을 Information Hiding(정보 은닉)이라 한다. 만약 Object내의일부분을 수정하였다고 해도 그 변화는 단지 Object내에서만 영향을 끼치고, 이로 인하여 완전히 모듈화가 이루어지는 것이다.

3.2.5 Composite Object

한 Object가 다른 Object를 포함할 수 있는데 이를 Composite Object라 한다. 이렇게 함으로써 포함된 Object를 새로운 Object의 한 부분으로 단순화시킬 수 있고, 그에 대한 자세한 내용을 알 필요도 없으며 많은 주의를 기울일 필요도 없이 사용할 수 있다. 미토콘드리아와 세포와의 관계를 생각하면 될 것이다.

3.2.6 Message

Message는 Object사이의 소통을 가능하게 하는 방법이다. Message는 Receiver, Method, Parameter의 세부분으로 구성되어 있는데, 예를 들어 "Car go: 20" (이것은 Smalltalk에서 사용되는 표현이다. C++에서는 Car.go(20)의 형태이며, Object-Oriented 방법을 지원하는 Programming Language에서 Message의 구성요소들의 순서는 일반적으로 같은 경우가 많다.)라는 Message에서 Car는 Receiver이고 go:는 Method, 20은 Parameter이다. 쉽게 알수 있듯이 이 Receiver는 대상이 되는(Message를 수신하는) object의 이름이고,go:는 Car Object내에 정의된 Procedure(또는 Function)인데 Object-Oriented방법에서는 Method라고 부른다. 20은 Method의 Parameter이다. Parameter는 경우에 따라 필요하지 않을 수도 있다. Object는 Message를 통해서만 접근될 수 있다.

3.2.7 Overloading

같은 Method이름에 하나 이상의 의미를 부여하는 것을 Overloading이라 한다. 예를 들어 Circle, Triangle, Rectangle 이라는 세 Object는 도형이라는 공통점을 가지고 있다. 이러한 도형을 그리기 위해 Method를 정의한다고 하자. 세 도형을 그리는 방법은 확연하게 다르다. 그러므로 각각 CircleDraw, TriangleDraw, RectangleDraw라는 별개의 이름으로 된 Method를 만들어야 하는데, 이러한 불편함을 없애기 위해서 Draw라는 한개의 공통된 Method이름을 사용한 세개의 method를 만들어 각각의 object에 정의한다. 단지 어떤 Receiver에게 Message가 수신되는가에 따라 세가지의 Method(Draw) 중 하나가 결정되어 사용되는 것이다. 그러므로 "Circle Draw:10"이라는 Message가 주어지면 반지름이 10인 원을 그릴 것이고, "Rectangle Draw: 30 20"인 Message로는 가로 30, 세로 20인 직사각형을 그 것이다.

3.2.8 Overloading의 장점

예를 들어 Shape라는 Object가 있다고 가정해 보자. 이 Object는 위에서 예로 든 세가지의 Object중 하나의 값을 가질 수 있다고 하면, Program내에서 이 Shpae를 그린다고 할 때 기존의 방법으로 하려면 세가지의 선택문으로 표현되어야 한다.
if      Shape = Circle   then CircleDraw 
else if Shape = Triangle then TriangleDraw
else RectangleDraw

이렇게 하게되면, Program내에서 Object에 대한 상세한 내용까지 Programmer가 알고 있어야 하므로 Programmer에게 부담이 된다. 나중에 Shape에 새로운 Object(예를 들면, Hexagon 같은)를 추가된면 역시 Program내에 수정이 가해진다. 그러나 Object-Oriented방법으로는 간단하게 "Shape Draw:라는 문장으로 충분하다. 새로운 object를 추가하더라도 Program을 수정할 필요 없으므로 확장성이 좋고, Program내에서 Object에 대한 자세한 내용을 알 필요가 없으므로 Information Hiding이 가능해 지며, 사용하기에도 편리하며, 이 모든 장점으로 인 Module화가 가능해진다.

3.2.9 Polymorphism

공통된 Interface를 사용하여 하나이상의 기능을 수행할 수 있는 것을 Polymorphism이라고 한다. 이것은 Overloading과 Overriding(특별한 형태의 Overlading)을 보다 일반적으로 일컫는 표현이다.

3.2.10 Class

Class는 Method와 Attribute(속성)들을 포함하는 특정한 형태의 Object를 정의하는 (Template) 이다. 따라서 Class는 금형과 같이 수많은 복제품을 만들어 낼수 있으며, 이 복제품을 Instance라고 한다. Instance는 단지 (Value)들 만을 포함하고 있으며, 따라서 이 Instance에 Method가 수신되면 Class에서 Method를 찾아 수행한다. 그러므로 'Object'는 Class의 Instance라 고 할 수 있다. 세포로 얘기하자면 어떠한 세포로도 분화 가능한 만능세포가 Class 쯤에 해당한다고 볼 수 있다. 만능세포는 자신이 위치하는 기관에 따라서 신경세포, 근육세포, 뉴런세포등 다양한 세포를 만들어 낸다.

3.2.11 SuperClass와 SubClass

한 Class가 다른 Class의 특정한 형태의 하나로 정의될 때 기존의 Class를 SuperClass, 새로운 Class를 SubClass라 한다.

oop-1.jpg

3.2.12 Inheritence(상속)

SubClass는 SuperClass의 모든 것들을 상속 받을 수 있다. 즉, SuperClass의 모든 Method와 Attribute들을 별도의 정의없이 사용할 수 있다.

3.2.13 Class Hierarchy

Class Hierarchy란 Class들의 Tree모양의 구조를 말한다. 이것은 -이론적으로- 제한없이 중첩(Nesting) 될 수 있으며, Inheritance는 축적되어 아래 단계로 내려간다. 즉, 한 Class에서는 그 상위 Level에 있는 조상 Class의 모든 성질을 계승받을 수 있다. 이 Class Hierarchy는 정보와 정보를 다루기 위한 방법들을 전승할 수 있다는 장점을 가진다.

oop-2.jpg

3.2.14 예외(exception)의 처리 : Overriding

앞의 예에서 Vehicle Class에 비행기를(Aircraft) 라는 SubClass를 첨가시킨다고 하자. Vehicle을 움직이게 하는 Method가 'go'라고 할때, go 신호를 보내면 일반적으로 시동을 걸고 Hand Break를 푼 후에 엑셀레이터를 밟아 앞으로 나아간다. 하지만 비행기는 자동차와 상당히 다르다. 스위치를 눌러 시동을 건 후, 여기저기 게기판을 만진 후에 하늘로 날아오른다. 그후에도 고도조절, 속도조절, 기류도 한번 살펴보고 건물이나 산과 부딕치지 않도록 조심하고...

실제 Class의 경우에 대해서 생각해보자. Method의 이름을 다른 것으로 바꿀 것인가? 그러면 일관성이 없어진다. 그렇다고 SuperClass인 Vehicls에서 'go'란 Method를 한단계 밑으로 끌어내려 정의한다면, 똑같은 내용을 Auto, Truck, Bus의 세 Class에 정의해야 하므로 중복이 되어 비효울적이다. 이때는 SuperClass(Vehicls)에 있는 Method는 그대로 두고 SubClass(Aircraft) 에 'go'라는 Method를 재정의하는 것이다. 그러면 Message를 수신하는 Object가 어떤지에 따라서 적합한 Method가 선택되어 실행된다. 이렇게 SuperClass에 있는 Method의 이름으로 새롭게 Method를 재정의 하는것을 Overrding이라 한다.

3.2.15 Virtual Class(Abstract Class)

단지 구조적인 목적으로만 사용되기 위하여 설계된 Class를 말한다. 앞으로 사용될 기능들(Attribute, Method)을 모아놓기만 하고 구체적인 구현은 나중으로 미루어, 다른 Class들의 Base Class로만 사용된다. 따라서 Virtual Class의 Instance는 존재할 수가 없다. Abstract Class라고도 하지만, Abstract Data Type과의 혼동을 방지하기 하여 일반적으로 Virtual Class라고 한다.

3.2.16 Multiple Inheritance(다중 상속)

한 Class가 여러개의 SuperClass를 가질 수 있도록 하는 것을 말한다. '철강회사의 노동조합장'의 경우를 예로 들어보자, 그는 유능한 용접공이며 또한 회사의 업무를 관장하는 간부이기 하다. 단지 Single Inheritanc만이 가능하다고 하면

oop-3.jpg

그림에서처럼 간부의 역활을 이중으로 정의해야 하므로 비효율적이다. 이때 Multiple Inheritance를 이용하면 효율적이다. 하지만 이때에 주의해야 할 사항이 있다. 같은 이름으로 정의된 Method가 각각의 SuperClass(용접공, 조합장)에 존재하면, 이때에는 어떤 SuperClass의 Method를 사용해야 할지 결정할 수가 없다. 즉, Conflict가 일어나게 되는 것이다.

Multiple Inheritance를 이용하면 이러한 문제를 해결할 수 있다. 그러나 함부러 마구 갖다붙이지 않도록 주의를 기울여야 한다. 중요하지 않은 곳에 오용되는 경우가 종종 있다. 위의 예에서 '조합장'의 경우를 생각해 보자. Multiple Inheritance를 올바르게 사용한 것인가? 이전에는 용접공이었지만 조합장이 된 후에는 실제로 용접을 하지않고 회사의 업무만을 관리하게 되었다면 그때부터는 사실상 용접공이라고 할 수가 없다. 이러한 경우에는 용접공의 계승을 없애버려야 한다. 계승되는 SuperClass의 성질을 온전히 포함하고 있는지 살펴보는 것이 올바르게 Multiple Inheritance를 사용하고 있는지 여부의 판단 기준이 된다.

3.2.17 Class Hierarchy의 구성

제대로 된 Class Hierarchy를 구성하기 위해서는, 우선 나중에 쉽게 재활용될수 있도록 일반적인 목적으로 설계되어야 한다. 또한 이 Class Hierarchy는 현실세계를 잘 반영할 수 있어야 하며, Method는 가능한한 가장 높은 최상의 단계에서 정의되어야 중복을 줄일 수 있다.

oop-1.jpg

3.3 Object-Oriented 방법을 이용한 Software의 구축

3.3.1 Reusability(재활용성)

Object-Oriented 방법의 가장 중요한 착안 사항이 바로 이 재활용성일 것이다. Reusable Module이 많이 마련되어 있다면 그것들을 이용하여 Software를 구축하면 보다 적은 노력만이 필요할 것이다. 실제로 Reusable Module을 설계하는 데에는 설계, 분석의 과정을 거쳐야 하므로 설계상의 자세한 내용은 줄이고 개념적인 것만 살펴보자.

Reusable Module을 설계하는 것은 대게의 경우 필요한 것을 그때 그때 만들어 쓰는 것보다 더 많은 계획과 노력을 필요로 한다.

OOP의 핵심은 추상화에 있는데, 이 추상이라는 것은 다루고자하는 객체들의 공통된 속성을 뽑아내어서 일반화된 계층을 만들어 내는 행위다. 그러므로 다루어야 할 객체들과 주변환경에 대한 폭넓은 이해가 우선적으로 필요하다. 삽살개, 진돗개, 치아와 등에 대한 공통적인 특징들을 제대로 알고 있어야 비로서 를 제대로 정의할 수 있는 것과 마찬가지다. 많은 시간이 필요할 수 밖에 없다.

이들 Reusable Module은 Class 를 중심으로 설계된다. 전에 언급한 Class의 장점들 - 현실세계를 잘 반영할 수 있으므로 인간의 생각을 표현하는데에 수월하고, 상속(Inheritance) 을 이용하여 확장이 쉬워지며, Polymophism을 적용하여 특별한 예외 경우를 잘 처리할 수 있는 점 등 - 이 Module을 설계하는데 꼭 맞게 적용되기 때문이다. Reusable Class는 필요한 것들을 직접 설계해서 얻을 수 있을 뿐만 아니라, Programming Language에서 제공되기도 하고, 때로는 상점에서 구입하는 것이 효율적일 때도 있다.

3.3.2 Object를 직접 사용한 Software의 구축

기존에 만들어진 Reusable Object를 모아 Software를 구축할 수 있다 하지만 이 방법은 필요로 하는 Object들을 모아 실제로 구동시키는 새로운 Object를 만들어야 하는데 불편함이 있다 (Program = Class Libraries + Solution Classes). 물론 기존의 방법에 비하면 이 정도로도 훌륭하지만, 더 나은 방법이 있다.

3.3.3 Simulation

그 방법은 Class Library들을 모아 Modeling을 하는 것이다. 즉, 기존의 Class들을 이용하는 High-Level Object 까지도 미래의 필요에 대비하여 설계하는 것이다. 은행의 전산처리 System을 구축하는 것을 예로 들어보자. 여기에는 입출금 계산, 신용카드 결재, 각종 공과금 자동납부 등 여러가지 작업들이 필요할 것이다. 이때에 Class Library들을 이용하여 입출금 계산 System, 신용카드 결재 System, 공과금 자동납부 System 등을 미리 설계해 놓으면, 나중에는 단지 이것들을 끼워 맞추기만 하면 되므로 Class Library들을 직접 이용하여 모든 것을 다시 설계하는 것보다 훨씬 수월할 것이다. 신용카드 결재 방법을 바꾸었다고 하자. 그러면 단지 신용카드 결재 System, 그 중에서도 특정한 Class들만을 고치면되므로 수정도 용이하게 할 수 있다.

3.3.4 Rapid Prototyping

Prototype이란 한마디로 '시험판(Trial Version)'이라고 할 수 있다. 실제로 기업에서의 간부들은 '그들이 정말로 원하는 것이 무엇인지'를 제대로 알지 못하고 있는 경우가 대부분이다. 그들에게는 프로그램이 동작하는지 아닌지만 중요할 뿐이다.

3.3.5 System의 구축

Reusable Class들의 Library를 구축한다. 이 Class들을 이용하여 Working Model을 구축한다. Rapid Prototyping을 이용하여 System을 구축한다. - 필요에 따라서는 이전의 단계로 되돌아갈 수 있다(Feedback).

3.4 Object-Oriented 방법의 장점과 단점

3.4.1 장점

우선 짚고 넘어가야 할 점은, 기존의 사고 방식을 가지고 단순히 Object-Oriented Language를 사용하여 Programming을 하는 것은 별로 도움이 되지 않는다는 것이다. 이제까지 가지고 있던, Programming 할 때의 기존의 사고방식을 과감히 탈피하여 새로운 개념을 가지고 이에 적합한 분석과 설계가 뒤따라야만 Object-Oriented 방법의 장점을 충분히 살릴 수 있을 것이다.

  • 설계 시간의 단축
    기존에 만들어진 Module을 이용하여 Rapid Prototyping의 방법으로 소프트웨어를 구축하므로 시간을 절약할 수 있다.

  • 질적인 향상
    이미 충분히 검토되고 시험된 모듈을 이용하여 모아서 프로그램을 만들기 때문에, 필요에 따라서 그때그때 만든 것들 보다 더 높은 질을 가진 프로그램을 만들 수 있다. 이점은 Object-Oriented 방법으로 만들어진 Reusable Module을 사용하기 때문에 이루어지는 것이지 Object-Oriented 방법 자체가 질적 향상을 가능하게하는 것은 아니다.
  • 유지 보수의 수월함
    Object-Oriented 방법은 현실 세계를 그대로 소프트웨어 시스템으로 반영할 수 있으므로 결점을 발견하기가 쉽다. 또한 모듈화 되었으므로 결점을 고쳐도 그 파급효과가 다른 모듈에 끼치는 영향이 거의 없으므로 시스템을 유지하기가 수월하다.
  • 제작 비용의 감소
    기존에 만들어진 프로그램을 이용할 수 있으므로 프로그래밍의 노력이 줄어들고, Rapid Prototyping을 통해 시스템 디자인의 노력을 줄일 수 있고, 필요로 하는 모든 Class Library를 일일이 제작할 필요가 없이 시중에 나와있는 것들을 구입하므로, 회사의 경영 차원에서도 제작 비용을 줄일 수 있다.
  • 대형 시스템구축의 수월함
    Modular Programming과 Polymorphism도 대형 시스템의 구축을 가능하게 한다. Object-Oriented 방법으로만 가능한 그러한 것은 아니다. 일반적으로 대형시스템이라고 하는 것은 많은 추상화 단계를 거치기 마련이다. 그러므로 추상화를 지원하는 OOP가 좀 더 수월하게 대형시스템을 구축하도록 도와주리라는 걸 예상할 수 있으며, 실제로 그렇다.
  • 더 나은 information 구조
    현대의 기업사회에서 요구하는 복잡한 정보를 효과적으로 표현할 수가 있다. 이것은 Data Abstraction으로 가능하다.
  • 적응성(adaptability)의 향상
    수정을 가해도 그 영향이 국소화 되므로 필요한 부분만을 고쳐 쉽게 새로운 스템에 적용시킬 수 있다.

3.4.2 단점

  • Object-Oriented 방법의 미 성숙
    어느 정도 기본적인 것은 갖추어 졌지만 Object-Oriented 방법은 아직 제대로 성숙되지 못했다. 이 방법을 믿고 사용하는데에 어려움이 따른다.
  • 표준의 필요성
    Programming Language에 대한 표준이 제대로 되어 있지 않기 때문에 프로그램을 이식하는데에 문제점이 있다. 이렇게 되면 소프트웨어를 같은 회사에서 구입해야 하고 다른 회사의 것은 섞어서 사용할 수 없게 된다. 이것은 큰 문제점을 야기할 수 있다. 만약 거래 회사가 망했다고 하자. 어떻게 할 것인가?
  • 더 나은 도구(tool)의 필요성
    Object-Oriented 방법을 바탕으로 시스템을 구축하는데 필요한 Tool 들은 몇가지가 있다. Object를 쉽게 설계할 수 있도록 해주는 것, Reusable Object들의 Library를 유지할 수 있도록 해주는 것, Data Input Form과 출력을 셜계하고 유지할 수 있도록 해주는 것들이 있다. 새로운 방법론에 비해 그것을 지원해 줄 수 있는 Tool 들은 늦게서야 만들어지기 마련이지만, Object-Oriented 방법은 기존의 것과 상이하게 다르기 때문에 그들을 이용하기 힘들다는데 문제가 있다. 예를 들면, 현재 Class Library Management Tool 들은 기껏해야 간단한 Browser 정도만 제공할 뿐이다. 그들의 체계적인 분류, 사용 목적, 사용 방법 등에 관한 것은 충분히 지원하지 못하고 있다.
  • 느린 개발 속도
    객체지향은 처리하고자 하는 일에 대한 명확한 이해를 필요로 한다. 전체에 대한 잘못된 이해 혹은 분석이 부족한 상태에서 일을 시작하게 되면 프로그램 구조자체에 문제가 생길 수 있다. 초기설계에 많은 시간이 소모된다.
  • 느린 실행 속도
    Object-Oriented Language로 만든 소프트웨어들은 대체적으로 실행속도가 느리다. 추상화에는 많은 컴퓨팅파워가 소모된다. 기능이 강력하고 많은 만큼 속도가 상대적으로 느린 것은 당연하다 할 것이다. 하지만 Object-Oriented 방법 자체가 실행 속도를 중심으로 설계된 것은 아니기 때문에 속도는 큰 문제가 아닐 수도 있다.
  • Conversion에 사용되는 비용
    기존의 방법론을 Object-Oriented 방법으로 바꾸는 간단한 문제가 아니다. 새로운 Programming Language, DBMS 뿐만 아니라 그에 해당하는 여러가지 Tool 들, Graphics가 지원되는 Hardware System 들이 OOP를 필요로 한다. 그러므로 기존의 패러다임을 OOP로 바꾸는 작업이 필요하게 되는데, Conversion에 소요되는 비용을 간과할 수는 없다. 또한 물리적인 비용 뿐만이 아니라, Programmer와 설계자, Manager에게 들어가는 교육비용또한 상당하다.

3.4.3 장단점의 적절한 조화

  • 성숙성
    Smalltalk이나 C++, 그외의 기존 Programming Language에도 Object-Oriented 방법이 추가되어 새롭게 등장하는 프로그래밍 언어들은 OOPL을 사용하는 데에는 큰 불편함이 없다. 또한 이 새로운 개념을 전문적으로 취급하는 연구단체나 기업이 점점 늘어나고 있으며 이러한 연구단체나 기업들의노력으로 단점을 충분히 파악할 수 있게 되었다.

    기존의 방법론과 비교해 보고 싶으면 동일한 Application을 기존의 방법을 이용하는 또다른 Team에게 맡겨보면 된다. 아마도 세가지 정도의 Application을 완성할 때 쯤 되면 Object-Oriented 방법의 장단점을 명확하게 파악할 수 있을 것이다. 이때 주의할 점은, Team 구성원 누구에게도 자신들이 시험의 대상이 되고 있다는 것을 알게해서는 안된다는 것이다. Heroic Effect(자신들이 시험의 대상이 되고 있다는 사실이 평소보다 더 열심히 한다든가 하는 등의 영향요소로 작용제로 Application을 개발할 때보다 수정하는 경우에 비용이 더 많이 소요되는 경우)가 종종 있기 때문이다.

  • 객체지향은 패러다임의 변화를 요구하게 된다. 이 패러다임의 이해도에 따라서 개발자간에 커뮤니케이션 하는데 어려움이 생길 수 있다. 이차이는 개발자의 코딩능력과는 별개다. 십수년의 경력을 가지고 있다고 하더라도 객체지향적으로 프로그램을 만들어오지 않았다면 커뮤니케이션에 어려움이 생길 수 있다. 이러한 개발자간 커뮤니케이션의 문제점은 패턴에 대한 학습을 선행함으로써 상당부분 해결 가능하다.


:::
2009/06/05 19:58

개발 및 배포 플랫폼으로써의 리눅스와 오픈소스 소프트웨어


1 Linux More Popular as Deployment Platform

많은 개발자들이 자신의 실력을 다른 개발자들에게 자랑하기 위해서 혹은 그들과 의견을 주고 받기 위한 목적으로 오픈소스 프로젝트를 수행한다. 많은 경우 프로젝트 리더들은 프로젝트를 함께 개발하는 개발자의 소프트웨어 개발 환경에 대한 정보를 알기를 원한다.

이클립스 프로젝트는 4월 일반적인 개발자들이 어떠한 환경에서 개발을 하는지에 대한 광범위한 조사를 실시 했다. 주목할만한 내용은 개발플렛폼으로 리눅스가 상당한 진보를 이루어냈으며, 특히 배포플랫폼으로써는 윈도우즈를 추월했다는 점이 될 것이다.

이클립스 제단의 마케팅 디렉터인 Ian skerrit 이클립스를 사용하는 개발자의 64%가 윈도우즈를 사용하고 27%가 리눅스를 사용하고 있다는 결과를 발표하였다. 참고로 2007년 조사결과에 따르면 윈도우즈 사용자는 74% 리눅스 사용자는 20% 였다. 상당한 개발자가 리눅스를 개발환경으로 이동되었음을 알 수 있다.

deployment 플랫폼으로 보자면 리눅스가 43%로 41%의 윈도우를 앞지르고 있다.

개발자 커뮤니티는 데스크탑 개발환경과 deployment 개발환경을 지속적으로 리눅스로 바꾸어나가기 때문인 것으로 보고 있다. Skerrit는 그의 블로그에서 우분투와 레드햇으로의 이동은 분명한 이득을 주지만 윈도우즈는 그러하지 못하기 때문이라고 그 이유를 설명한다.

이러한 결과가 발생한 또 다른 이유는 리눅스 친화적인 MysqlOracle과 같은 데이터베이스의 점유율 때문이다. 이들 두 데이터베이스의 점유율은 55%가 넘고 있다.

또한 이번 조사 결과는 기업들이 단지 오픈소스를 사용하기만 하는데에 머무르지 않고, 오픈소스에 공헌을 하는 정도로 오픈소스에 대한 인식이 성숙되었음을 보여주고 있다.

2007년에 46%의 기업들이 OSS의 사용을 허락했지만 OSS에 대한 공헌은 이루어지지 않았다. 즉 내부적으로 OSS를 사용하기만 했다. 지금은 이 비율이 27%로 줄었다. 이제 48.2% 의 응답자들이 그들의 기업이 OSS 커뮤니티로의 지원을 허락하고 있다고 응답을 하고 있다. 2007년의 37%에 비하면 10%나 증가한 수치다. - 국내의 경우에도 대략 2007년과 2008년을 기점으로 기업들의 오픈소스에 대한 직접적인 참여와 지원이 늘어나고 있다. -. OSS를 통한 비지니스 모델에 기대를 걸고 있다는 응답도 2007년 10%인 것에서 2008년 15.6%로 대폭 증가했다.

2 The Open Source Developer Report 2009

이 문서는 2009년 Eclipse Community 의 보고서인 The Open Source Developer Report를 보고 정리했다.

2.1 핵심 내용

이 보고서는 다음과 같은 핵심내용을 포함하고 있다.
  • 리눅스는 데스크탑과 서버 환경모드를 공유하고 있다. 개발자들이 개발을 위한 데스크탑운영체제로 Microsoft 윈도우즈에서 리눅스와 Mac OX로의 이동하는 모습이 분명히 감지되고 있다. 특히 depolyment 운영체제환경으로 리눅스는 가장 일반적인 플렛폼이 되었다.
  • Mysql 과 Oracle 데이터베이스는 55%이상의 지배적인 점유율을 보여주고 있다.
  • 형상관리도구로는 SVN(Subversion)이 57% 점유율을 보여주고 있다.
  • 기업은 성숙한 OSS 모델을 받아들이고 있다.
    1. 더 많은 기업들이 오픈소스 소프트웨어의 사용과 기여에 참여하고 있다. 보고서에 따르면 2008년 48.2%였다. 2007년에는 37%였다.
  • 15.6 %의 회사가 OSS에 연계한 비지니스 모델을 만들고 있다.

3 보고서 참여자 통계 자료

응답자의 반이상이 프로그래머였으며 기타 시스템 아키텍쳐, 매니저, 소프트웨어 품질관리 및 테스터, 마케팅 메니저 등이 참여하였다.

4 개발자 데스크탑 개발 환경

개발자가 사용하는 데스크탑 운영체제 통계정보를 보여주고 있다. 윈도우즈에서 Linux와 Mac OSX로 이동하는 것을 확인할 수 있다. 26.9%의 개발자가 주요 개발 데스크탑 환경으로 리눅스를 사용하고 있다고 응답했는데, 2007년에 비하면 7%가 증가한 수치다.

2007년에 비하면 10%가량 줄어들긴 했지만, 여전히 윈도우즈는 64%의 사용율을 가지는 지배적인 운영체제다. 가장 많이 사용되는 리눅스 배포판은 Unbuntu인 것으로 조사되었다. Mac OSX도 2007년 3.5%에서 6.9%로 증가했다.
  1. Windows Server or Client : 64.3%
  2. Linux : 26.9%
    1. Ubuntu 14.5%
    2. Fedora 3.4%
    3. SUSE 3.2%
    4. Debian 2.6%
    5. RHEL 1.3%
    6. 기타 배포판 1.8%
  3. Mac OSX : 6.9%
  4. Sun Solaris or OpenSolaris : 0.9%
  5. Other : 0.8%
desktop.png

4.1 IDE : 통합개발 환경

Eclipse IDE가 가장 인기있는 개발환경으로 지목되었다.
  1. Eclipse JDT : 60%
  2. Eclipse PHP 개발 툴 : 12.6%
  3. Eclipse C/C++ 개발 툴 - CDT - : 6.3%
develop.png

4.2 형상관리 툴

SCM(Source code management), CMS(changes management) 그리고 BM(Build management)에 대한 사용율을 조사한 자료다.

SCM : 가장 널리 사용되는 소스코드 관리 시스템은 Subversion으로 57.7%의 사용율을 보였다. 20%의 CVS가 그 뒤를 따랐다. SCM으로는 오픈소스가 절대적인 위치를 차지하고 있음이 확인되고 있다. 단 5,000 명이상의 고용인을 가진 대기업의 경우에는 Subversion의 점유율이 41.3 %로 상대적으로 적었다는 점이 특이할만 하다. 최근 몇 년사이에 Subversion의 사용이 증가했는데, 일반적으로 대기업은 이러한 변화에 느리게 반응하는게 이유인 것 같다.
scm.png
CMS : JIRA와 Bugzilla가 각각 17% 점유율을 기록했다. CMS는 아예 사용하지 않는다는 응답도 22.7%에 달했다. 예상과 달리 TRAC은 7.2%의 낮은 점유율을 보여주었다. Custom 즉 직접만들어서 사용한다는 응답이 8.4%에 달했는데, 이는 회사의 다른 정보들과 연동되어서 사용되어야 하는 CMS의 특성때문으로 생각된다.
cms.png
BE : 33.4%의 Ant가 가장 널리 사용되는 것으로 확인되었다. CMS와 마찬가지로 21.7%의 비교적 많은 응답자가 BE를 사용하지 않는다고 응답을 했다.

5 언어 및 응용프로그램

자바는 커뮤니티에 의해서 주도적으로 사용되는 언어였으며, 76.6%가 그들의 첫번째 언어로 자바를 사용한다고 응답했다. 개발용도는 Server-Centric 30.2%, 웹이 24.7%, 데스크탑 애플리케이션이 23.4%였다.

appstyle.png

이 보고서는 주요 3가지 개발용도에 대해서 각각 어떠한 툴 혹은 언어를 사용하는지에 대해서 조사했다.

5.1 Server-Centric 애플리케이션

server-centric 애플리케이션의 개발을 위해서 가장 널리 사용되는 되는 것은 servlet이였다. 그다음으로는 spring 프레임워크였으며, EJB도 38.3%로 널리 사용되는 것으로 조사되었다. 대표적인 server-centric 애플리케이션은 J2EE 애플리케이션, 데이터베이스 애플리케이션, ERP, CRM 등이 있다.

5.2 Web, Rich 인터넷 애플리케이션

웹과 rich Internet 애플리케이션 (RIAs)의 경우에는 주도적인 프레임워크나 툴이 없는 것으로 조사되었다. 오픈소스 Ajax 프레임워크, Flash/Flex 등이 많이 사용되었으며, 아예 사용하지 않는 다는 응답도 꽤 되었다. GWT가 많이 사용되고 있다는 점이 눈에 띈다.

5.3 Rich Desktop Applications

Eclipse RCP (47.6%)와 Swing (43.8%)로 양분되어 있는 모습을 보여주고 있다.

6 Deployment 환경

개발자들이 그들이 개발한 애플리케이션이 설치될 타겟 환경으로 어떠한 것을 이용하는지에 대한 조사내용을 포함하고 있다. 운영체제, 데이터베이스 그리고 애플리케이션 서버 환경에 대해서 조사를 했다.

리눅스는 주목할만한 Depolyment 타겟 운영체제로 성장을 했으며, 지금은 오히려 윈도우를 앞서고 있는 것으로 확인되었다. 2008년 기준 42.7%의 점유율을 보여주고 있는데 2007년의 37%에 비하면 5%가까이 증가한 수치다. Ubuntu(12%), Red Hat Enterprise Linux (10.2%) 배포판이 널리 사용되고 있었다. 결과를 보면 윈도우환경의 유저가 리눅스, Mac OSX 등으로 이동한 것으로 보인다.

deployment.png

6.1 주요 데이터 베이스

예상대로 MysqlOracle이 각각 27.7%와 27.3%로 주요하게 사용되고 있었다. Mysql과 Oracle은 선호대상이 갈리는 것이 확인 되었다. 기업규모로 보자면, 5000 명 이상을 고용하고 있는 거대 기업의 경우에는 Oracle이 33.5%, IBM DB2가 10.7%, Mysql 이 11.6% 였다.

Oracle은 다음과 같은 선호대상층을 가진다.
  • Java를 주요 개발언어로 사용하는 경우
  • server-centric 애플리케이션을 개발하는 경우
  • Application 서버를 이용하는 경우

Mysql은 다음과 같은 선호대상층을 가진다.
  • PHP 언어를 주요언어로 사용하는 개발자
  • RIA/Web 애플리케이션

database.png

6.2 주요 Application 서버

Apache Tomcat이 가장 널리 사용되고 있다. 그다음으로 JBoss, IBM WebSphere가 사용되고 있다. 아무 것도 사용하지 않는다는 응답도 25.3%나 되었다. 5000명이상 고용인을 가진 대기업의 경우에도 여전히 Apache Tomcat이 가장 널리 사용되었으나 IBM WebSphere가 6.9%에서 12.0%로 크게 오르고 Apache Tomcat 는 34.8%에서 26%로 떨어진걸 확인할 수 있었다.

appserver.png

7 평가

몇년전만 하더라도 오픈소스는 기업에서는 받아들이기 힘든 모델이라고 평가되기도 했었다. 혹은 많은 기업들이 단지 오픈소스의 단물만 빨아먹으려고 할뿐 결코 오픈소스 모델에 참여하지는 않을 것이라고 생각되던 때도 있었다.

그러나 이 보고서에 따르면, 오픈소스는 메이저한 개발/배포 환경은 물론이고 비지니스 환경까지 그 영역을 지속적으로 확장시켜가고 있음을 확인할 수 있다. 더불어 분명하게 더 많은 기업들이 적극적으로 오픈소스 모델에 직접적으로 참여하고 있는 것도 확인할 수 있다.

대세는 OSS

oss.png
:::
2009/05/20 22:38

저작권의 출현과 오픈소스

저작권의 출현

쓰여진 글에 대한 저작권이 언제 출현했을까? 거기에 대해서 왠지 알아보고 싶어졌다. 당연히 쓰여진 글의 저작권이니까. 글이 종이든지 어디에든지간에 씌여진 시점부터라고 생각할 수도 있겠지만, 실제 저작권은 쓰기가 발명되고 난 뒤에도 한참이나 지나서 만들어졌다. 정확히 말하자면 쓰기가 내면화 되는 시점 - 대게는 인쇄가 일반화된 시점부터 본격적인 내면화가 시작되었다고 보고 있다 - 부터 만들어졌다고 봐야 될 것이다.

쓰기가 내면화 되었는지가 왜 중요한지에 대해서 알아봐야 겠는데, 그럴려면 최초 등장한 쓰기와 쓰기가 내면화된 시점의 쓰기의 차이점에 대해서 먼저 이해를 해야 될것 같다.

쓰기가 내면화되지 않은 시절에 은 기억을 용이하도록 하기 위해서 예전부터 내려온 틀에박힌 정형구과 운율등을 이용했다. 영웅의 일대기를 그린 호머의 서사시가 대표적인 예가 될 것이다.

아킬레스가 분전을 했다. 라고 말하는 것보다 빠른발의 아킬레스는 영웅의 방패와 창을 들고 적진으로 돌진했다라는 식으로 표현하는게 훨씬 기억하기가 쉽기 때문이다. 오디세우스를 지모가 뛰어난 오디세우스라고 한다든지, 신과 같은 아가멤논이여라고 하는 것도 비슷한 이유에서다. 이러한 정형구적인 표현은 중세 작품에도 자주 등장한다. 잠자는 동안의 달콤한 꿈을 믿을 수 있다면 내 꿈은 필시 좋은 소식이 온다는 증거일 것이다. - 로미오와 줄리엣 중-. 정형구적인 표현은 사람의 감성을 강하게 자극하기 때문에 적절히 사용한다면 매우 숭고하게 보이기도 한다. 그래서 호머의 서사시가 그동안 그렇게 높은 평가를 받아왔는지도 모르는 일이다. 지금은 이러한 표현은 거의 사용하지 않지만 말이다. 환타지 소설에서나 간혹 볼 수 있을 뿐이고, 가능하면 정형구적인 표현을 사용하지 말도록 지도를 받는다.

아뭏든.. 이들 정형구와 운율은 개인의 것이 아닌 집단에 의해서 전승된 공중의 지혜와 같은 것이기 때문에, 이들로 이루어진 결과물 역시 개인의 것이 아닌 집단의 것이라는 인식이 강했다. 그러니 저작권을 주장한다는 것 자체가 있을 수 없는 일이었다.

쓰기가 출현한뒤에도 오랫동안 저작권이라는 개념이 모호했는데, 왜냐하면 초기 쓰기는 지금의 쓰기와는 달리 사람이 로 한것을 옮겨적는 작업이였기 때문이다. 공동의 재산이라고 생각되는 말을 종이에 고정시키는 작업이였다. 이당시 말로 된 작품이란 것은 과거의 지혜를 기억하기 좋게 운율이 가미되어서 전승된 정형구의 집합이였으니, 이들 과거의 지혜와 정형구들 운율들에 소유권을 주장할 수 없는 것이었다. 그것은 공동의 재산이였기 때문이다. 이경우 중요한 것은 저작권이 아니라 그 지혜를 말로써 나타낼 수 있는 능력을 가진자 즉 시인 혹은 나이를 먹은 지혜로운 노인들이였다.

노인이 천대받는다고 걱정들이 이만저만이 아니다. 슬프다고 생각할지 모르겠지만 이것은 당연한 현상이다. 지금 지혜는 구전되는 말로써 전달되는게 아니다. 시간과 공간에 독립된 문자에 의해서 전달되고 공유되어진다. 현대사회에서 노인의 지혜는 거의 쓸모가 없어졌다. 물론 노인이 가지고 있는 삶의 지혜는 중요한 자산이 될 수 있겠으나 자본주의 사회에서 돈으로 환산되지 않는 삶의 지혜는 쓸모가 없어진다. 대게는 할일 없는 노인의 쓸데없는 잔소리 취급받는다. 그러니 노인이 버려질 수 밖에.. 이건 덤으로 드는 생각인데, 노인이 되어서 버려지지 않기 위해서는 자기 스스로의 생산수단을 가지는 수 밖에 없다. 농사든지 뭐든지간에 말이다. 그렇지 않다면, 당신이 왠만큼의 돈과 지식과 정보를 가지지 않는 한은 폐기처분 될 걸 각오해야 할 것이다.

본론으로 되돌아와서 인쇄술이 발달해서 본격적인 쓰기가 정착되면서, 동시에 프라이버시 의식 역시 성숙하게 된다. 기존의 말하기가 집단과의 교류하는 행위라면 쓰기와 읽기는 개인의 내면과의 대화이기 때문이다. 혼자 짱박혀서 무엇인가를 할 수 있는 개인만의 공간이 라는 것이 이때부터 생겨나고 여기에서 프라이버시라는게 자라난다. 물론 그전에도 몇몇 작가들이 그러한 개인적인 행위를 해오긴 했지만 극히 예외적인 경우였다. 또한 창작의 행위가 가능했는데, 글로 적혀지면 기억할 필요가 없기 때문에 고리타분한 정형구적 표현을 벗어던지고 자신만의 생각을 글로 옮길 수 있게 되었기 때문이다.

이렇게 해서 씌여진 문서나 책은 공중과 집단의 것이 아닌, 개인이 창작해서 만들어낸 소유할 수 있는 물건의 성격을 띄게 된다. 이러한 과정을 거쳐서 자신의 물건에 대해서 소유권을 주장하듯이 자신이 만들어낸 글에 대해서 소유권을 주장하는 저작권의 개념이 만들어지게 된다.

이후에 글과 문서에 대한 저작권의 개념이 확고해지고 최근까지 안정적으로 유지된다. 이것은 인터넷시대에까지 계속 유지되게 된다.

왜 아시아는 저작권이 잘 지켜지지 않는가 ?

인터넷 컨텐츠에 대한 저작권이 특히 아시아지역에서 잘 지켜지지 않는 것에 대해서, 그들이 교육을 못받아서, 미개해서, 심지어 양심이 버려서라는 평가를 하기도 한다. 하지만 조금만더 돌이켜 생각해보면, 이것은 문화적차이 때문인거지 교육을 받지 못했거나 미개하기 때문인 것은 아니라는 걸 알 수 있다.

서양은 이른 시간에 쓰기를 내면화 시켰고 이에 기반해서 개인주의를 발전시켰다. 반면 동양은 여전히 개인적이라기 보다는 좀더 집단친화적이고 공동체의 가치를 중요시 하는 경향이 있다. 이러한 공동체의 가치를 중요시 하는 문화 즉 구술적문화에서는 컨텐츠를 개인의 것이 아닌 집단의 것으로 생각하는 경향이 강하게 남아 있다. 과거 쓰기가 내면화 되기 전의 사람들이 그랬던 것 처럼 말이다. 그래서 이들은 여전히 컨텐츠가 순전히 개인의 물건이라는 개념을 쉽게 받아들이지 못하는 것이다.

동양인들의 인식이 저급하기 때문이 아니라는 것이다. 물론 많은 사람들이 진보라는 것을 개인주의에 기반한 자본주의가 얼마나 제대로 뿌리를 내렸는가로 판단하려고 하기 때문에, 동양의 그러한 공동체적 마인드 자체를 저급하게 생각하는 경향이 있긴 하다. 그러나 동양적인 마인드와 서양적인 마인드는 서로 다른것이지 등급을 메길 수 있는 그런건 아니다. 유럽을 중심으로 하는 공동체생활방식의 등장, 자본주의에 대한 위기론 혹은 회의론들, 동양철학에 대한 재평가, 뿔뿌리 공동체라고 할 수 있는 오픈소스운동과 자유소프트웨어 운동 등에서 나타나듯이 말이다.

자유소프트웨어와 저작권

자유소프트웨어 공동체와와 오픈소스 공동체는 자본주의와 개인주의에 기반한 생각과 지혜의 물건화와 사유화에 반대한다. 이들은 생각, 아이디어는 함께 공유해야할 공동의 자산이라고 본다. 고대의 서사시처럼 말이다.

어떻게 보면, 자유소프트웨어오픈소스는 서양보다는 동양에 어울리는 운동이라고 볼 수 있다. 이러한 운동이 오히려 서양에서 먼저 시작되고 서양에서 뿌리를 내리고 있는 것은 모순이라고 볼 수 있을 것이다. 자본주의가 먼저 뿌리를 내렸고, 공동체정신이 거의 남아있지 않았기 때문에 오히려 그에 대한 반성으로 먼저 서양사회에서 생겨난게 아닐까 ?

이러한 반저작권 혹은 반자본주의적 운동이 소프트웨어영역에 쉽게 뿌리내린 이유는 인터넷이란 매체의 특징이 한 몫 한것으로 생각된다. internet은 애초에 관리주체나 중심이 없는 상태로 설계되었는데, 이는 자원과 노동력을 집중시키는 자본주의와는 많은 차이를 보인다. 예컨데 인터넷은 독점적인 권한을 가지는 개인 혹은 집단이 관리하는 사유재산이 아닌 인류공동의 재산이라는 인식이 초기에 생성이 되었다. 이러한 인식하에서 자유소프트웨어 재단이 있게한 해커문화가 생겨나게 되었고, 인터넷의 자본화에 맞서서 강력한 풀뿌리 공동체를 지켜내는 원동력이 되었다. 그 어떤 산업분야에서도 볼 수 없는 (독점적인 저작권에 기반하지 않은)자유로운 정보공유, 서로 연대하며 서로를 존중해주는 공동체 문화를 간직하고 있다.
:::
2009/05/08 01:38

지각 문화에 대해서

지각문화

다른 산업분야와는 달리 소프트웨어 업계는 지각문화가 안정적?으로 자리를 잡은 거 같다. 더불어 야근문화까지 안정적으로 자리잡았다는게 꺼림찍하긴 하지만 말이다. 이쪽 바닥에 계속 일했던 사람들이라면 뭐 9시반에서 10시사이에 출근을 하거나 혹은 10시가 넘어서 출근해도 뭐 그닥 느낌이 없을 수도 있을 것 같다. 내 출근 시간이 대략 9시반에서 10시 사이인데, 이제 막 출근해서 엘리베이터를 타려는 사람들로 북새통을 이룬다.

대충 청바지에 대략적인 흰면티, 가끔 슬리퍼에 간혹반바지와 더해서 아주 일상적으로 경험할 수 있다.

때때로 대신 10시까지 출근했다면 7시까지 일을 하게되니, 어차피 일하는 시간은 비스무레하다라고 주장할 수 있을 것 같지만 주위에서 주워들은바 다른 산업분야에서는 이해가 되지 않는 문화들이시다. 내 친구의 형은 8시반에 출근한다. 그렇다고 해서 5시반에 퇴근하느냐 하면 퇴근 시간은 7시다. 10시에 출근하고 대신 7시에 퇴근한다? 요런건 생각조차할 수 없는 곳들이 태반이다.

이러한 와중에 유독 소프트웨어 업계에 지각문화가 안정적으로 자리 잡은 이유에 대해 생각을 해보았다. 좀 뜬금없지만 말이다.

시간엄수 문화

시간은 금이 되었고 시간을 제대로 지키지 못하는 사람은 상종치 못할 사람이 되었다. 그러다 보니 좀 바쁘게 사는 사람은 좀 과장하자면 분단위로 시간을 관리를 해야 한다. 시간을 제대로 지키는 것은 의무이자 인간의 본성처럼 인식되는게 지금이다.

하지만 시간엄수문화는 그 역사가 그리 오래되지 못했다. 산업화시대를 거치면서 우여곡절 끝에 정착이되었으며, 고작해야 한 100년정도가 되었을 뿐이다. 비교적 산업화에 늦게 진입했던 우리나라의 경우 시간엄수문화가 정착한건 50년이 채 안된다. 지금은 잊혀진 얘기지만 코리안타임 이라고 해서, 약속시간에 30분정도 늦는것은 애교로 봐주던 때가 그리 오래전이 아니다.

그렇지 않은 대부분의 시간 즉 최근의 100년정도를 제외한 나머지 수십만년의 기간동안 인류는 시간을 인식하면서 살지 않았다. 아니 그렇게 살아갈 필요가 없었다. 자연은 분단위로 시간을 맞출 것을 인간에게 요구하지 않았기 때문이다. 게다가 시간의 표준은 어떻게 할 것인가 ? 그리스도가 태어난날로 ? 아니면 그리스도가 못박힌날 ? 석가모니가 태어난날 ? 공자생일 ? 왕이 바뀐날 ?? 대략 보름단위로 씨뿌리는 날 수확하는날, 비가올것 같은 날 정도를 예상할 수만 있으면 되었다.

시간엄수는 인간의 본성이 아니다. 인류가 살아왔던 전체시간 중에 고작 0.x% 정도인 최근에서야 시간개념이라는 것이 생겨났다. 사람은 천성적으로 (지금보다는 훨씬더) 게으른 존재다. 산업화를 거치면서 산업과 자본의 요구에 따라서 지금처럼 과도하게 부지런해지도록 길들여진 것이다. 천성을 거슬려고 하다보니 자기자신과 싸워야 하는게 아니겠는가 ?? 서점에 가보면 게으름을 다른 시각으로 바라보는 책이 늘어난 것을 볼 수 있는 것도 이러한 이유 때문아닐까 싶다. 자고로 천성을 거스르면 행복과도 그만큼 멀어질 확률이 높다.

소프트웨어 분야에 종사하는 사람들은 다른 산업분야와는 달리 자유소프트웨어 공동체, 오픈소프트웨어 공동체, 해커 공동체 등의 자유로운 풀뿌리 공동체 덕분에 자본화, 다른말로 산업역군화 또다른 말로 기계화가 덜 진행된 것이리라 생각된다. 그러다 보니 시간엄수가 비교적 덜 내면화 되고, 시간감각이 무뎌디게 된게 아닐까 생각해 본다. 지맘대로 출퇴근을 해대는 개념없는? 개발자나 디자이너 얘기를 어렵잖게 듣는 이유일 것이다.
:::
2009/04/09 22:55

리눅스 시스템 프로그래밍 7장 쓰레드

아오.. 일단 포스팅 하고 보자..

<!> 문서는 완성된게 아니며, 틀린 내용이 있을 수 있습니다. 수정해야 할 부분이 있음 알려주세요. 확인 후 반영하도록 하겠습니다.

1 Thread에 대해서

프로그램을 병렬로 실행시키는 방법으로 fork()에 대해서 알아보았다. fork()는 매우 이해하기 쉬운 프로그래밍 방법이긴 하지만 자원효율성에서 몇가지 문제점을 가지고 있다. 프로세스는 기본적으로 code, data, stack, file I/O, 그리고 signal table의 5가지 요소로 구성이 된다. fork() 를 이용해서 새로운 프로세스를 생성하게 되면, 이러한 5가지 구성요소가 모두 복사가 된다. 그러하다 보니 프로세스를 생성하는데 많은 비용이 소비될 것이다. 대게의 경우에는 프로세스를 새로 생성시킬때 발생하는 성능저하가 문제가 되지는 않겠지만 웹서비스처럼 대량의 접근이 발생하는 영역에서는 문제가 될 수 있다.

fork의 이러한 방식은 상당히 효율이 떨어지는 측면이 있다. 어떤 프로그램을 병렬로 실행시킨다고 했을 때, 실제 우리가 병렬로 실행되기를 원하는 영역은 코드의 일부분이지 프로그램 전체는 아니기 때문이다.
// ... 
pid = fork();
if (pid > 0)
{
// 실제는 이 부분의 코드만 병렬로 실행되면 된다.
// fork()는 다른 모든영역의 코드가 복사되어 버린다.
}

게다가 전혀다른 프로세스를 생성시킴으로써, 프로세스간 통신이라는 상당히 복잡한 문제까지를 해결해야 한다. 병렬로 작동하는 프로그램은 특성상 데이터를 공유하거나 서로 통신을 해야 하는 경우가 많다. 그런데 프로세스는 서로 독립된 객체이므로 일반적인 방법으로는 데이터를 공유할 수가 없다. 이러한 프로세스간 데이터 통신을 위해서 리눅스는 IPC라는 설비를 제공하는데, IPC라는게 사용하기가 여간 까다롭지가 않다. IPC에 대해서는 별도의 장을 할애해서 다룰 계획이다.

Thread를 이용하면 fork()를 이용한 프로세스 기반의 병렬처리의 문제점의 많은 부분을 해결할 수 있다. Thread는 새로운 프로세스를 생성시키지 않고, 특정 문맥(코드)만을 병렬로 실행할 수 있도록 허용한다. 새로운 프로세스를 생성시키지 않기 때문에 그만큼 자원을 아낄 수 있으며, 더 효율적으로 빠르게 움직일 수 있다. 또한 같은 프로세스이기 때문에, 데이터를 공유하기가 쉽다는 장점도 가진다.

1.1 Thread vs Process

Thread는 프로세스와 다음과 같은 차이점을 가진다.
  • 프로세스는 독립적이다. 쓰레드는 프로세스의 서브셋이다.
  • 프로세스는 각각 독립적인 자원을 가진다. 쓰레드는 stat, memory 기타 다른 자원들을 공유한다.
  • 프로세스는 자신만의 주소영역을 가진다. 쓰레드는 주소영역을 공유한다.
  • 프로세스는 IPC를 이용해서만 통신이 가능하다.
  • 일반적으로 쓰레드의 문맥교환(context switching)는 프로세스의 문맥교환보다 빠르다.

1.2 Multi Thread 프로그램의 단점

모든 도구가 그러하듯이 Multi Thread 프로그램이라고 해서 장점만 가진 것은 아니다. Multi Thread 프로그램은 Multi Process 프로그래밍 방식에 비해서 다음과 같은 단점을 가진다.
  • 하나의 쓰레드에서 발생된 문제가 전체 프로세스에 영향을 미친다.
    멀티 프로세스의 경우에는 프로세스하나가 문제가 생기더라도 단일 프로세스로 문제가 제한된다. 그러나 멀티쓰레드 프로그램의 경우 하나의 쓰레드에 생긴 문제가 다른 쓰레드에까지 영향을 줄 수 있다. 예를 들어 쓰레드 하나가 다른 프로세스의 메모리 영역을 침범할 경우 프로세스 자체가 죽어버림으로써, 프로세스에 생성된 다른 모든 쓰레드도 프로세스와 함께 죽어버리게 된다. - 이 문제는 해결 가능하지만 여기에서는 다루지 않도록 하겠다. 시그널을 잘 활용하면 된다. 관심있으면 한번 고민해 보기 바란다. -
  • 디버깅이 어렵다. 문맥이 서로 교환되므로 추적하기가 까다롭다.

이러한 단점이 있음에도 불구하고 멀티쓰레딩 프로그래밍 기법을 선호하고 있다.

1.3 PThread

Thread운영체제에서 제공하는 병렬처리 메커니즘으로, 실제 이 메커니즘을 이용하기 위해서는 Thread의 구현체가 필요하다.

리눅스에서는 pthread라는 thread 구현 라이브러리가 사용되고 있다. pthread는 POSIX thread 의 줄임말로 POSIX 표준을 따르고 있다. pthread는 리눅스 뿐만 아니라 다른 거의 대부분의 유닉스에서도 사용할 수 있다. 이외에도 BSD 계열에서 사용하는 'Light Weight Kernel Threads , Apple 에서 사용하는 Multiprocessing Services등의 구현체가 있다. 이 문서는 pthread구현만을 설명하도록 할 것이다.

pthread는 리눅스 운영체제에서 제공하는 thread 를 제어하기 위한 함수들을 모아 놓은 C 라이브러리로, 다음과 같은 기능의 함수군을 제공한다.
  • 쓰레드 생성과 종료 관련 함수들
  • 쓰레드 동기화 관련 함수들
    쓰레드는 많은 데이터를 공유한다. 그러므로 데이터에 대한 동기화 문제를 해결해야할 필요가 있다.
  • 쓰레드 시그널 제어 함수들
    signal은 프로세스단위로 작동한다. 그러나 쓰레드 프로그램의 경우, 각 쓰레드 마다 다른 시그널 정책이 필요하므로, 쓰레드 전용의 시그널 제어 함수가 필요하다.

1.4 Multi Thread 프로그램

병렬로 작동하지 않는 하나의 문맥흐름만을 가지는 프로그램을 단일 쓰레드 프로그램이라고 한다. 반대로 아래와 같이 문맥이 나뉘어서, 동시에 두개 이상의 쓰레드가 실행되면, 이를 멀티 쓰레드 프로그램'''이라고 한다.


1.5 Process, Kernel Thread, User Thread

프로세스는 가장 무거운 커널의 스케쥴링 단위이다. 프로세스는 운영체제에게 할당받은 자원들 - 파일 핸들러,소켓,장치 핸들러 - 을 할당받게 된다. 프로세스는 독립된 단위로써 파일이나 주소영역 등을 공유하지 않는다.

kernel thread는 가장 가벼운 커널 스케쥴링 단위다. 하나의 프로세스는 적어도 하나의 커널 쓰레드를 가지게 된다. 만약에 프로세스가 하나이상의 쓰레드를 가지고 있다면, 이들 쓰레드는 같은 메모리와 파일자원등을 공유하게 된다. 만약 커널의 프로세스 스케쥴러가 선점형이라면 쓰레드의 스케쥴러도 선점형인 경우가 많다. 참고삼아서 선점형과 비선점형에 대해서 간략하게 설명하도록 하겠다.
  • 비선점형 : 특정 프로세스가 CPU를 독점하는 것이 가능하다.
  • 선점형 : 특정 프로세스가 CPU를 독점하는게 불가능하다.
특정 프로세스가 CPU를 독점하는게 불가능하게 하는 것은 프로세스가 인터럽트를 무시하기 못하게 하는 것으로 구현한다. 선점형은 어떤 프로세스가 시스템콜을 수행중이더라도 커널이 인터럽트를 보내면, 즉시 빠져 나와야 한다. 즉 운영체제가 CPU를 선점한다는 얘기가 된다. 시스템콜이 수행중이더라도 인터럽트를 걸고 다른 일을 수행하도록 할 수 있으므로 보다 빠른 반응성을 보여준다.

때때로 쓰레드가 유저영역 라이브러리로 구현되는 경우가 있는데, 이를 user Thread 라고 부른다.

1.6 쓰레드의 생성과 종료

멀티 쓰레드 프로그램이라고 하더라도, 처음 시작되었을 때는 main()에서 시작되는 단일 쓰레드 상태로 작동이 된다. 이 상태에서 pthread_create(3) 함수를 호출함으로써, 새로운 쓰레드를 생성할 수 있다. pthread_create를 이용해서 생성된 새로운 쓰레드를 worker 쓰레드라고 하자.

멀티 쓰레드 프로그램은 다음과 같은 흐름을 가진다.



생성된 worker thread는 언젠가 종료가 될 것이다. Master Thread (이하 부모 쓰레드)는 pthread_join()을 이용해서 worker thread들의 종료를 기다린다. pthread_join()는 종료된 worker thread의 자원을 정리하는 일을 한다. fork()를 이용한 멀티 프로세스 프로그램에서, 부모 프로세스가 wait()를 이용해서 자식 프로세스를 기다리는 것과 같은 이유라고 보면 된다.

1.6.1 pthread_create : 쓰레드 생성

pthread_create(3)함수를 이용하면 새로운 쓰레드를 생성할 수 있다. 이 함수는 다음과 같이 사용할 수 있다.
#include <pthread.h> 

int pthread_create(pthread_t * thread, pthread_attr_t *attr,
void * (*start_routine)(void *), void * arg);
  1. thread : 쓰레드가 성공적으로 생성되었을 때, 넘겨주는 쓰레드 식별 번호.
  2. attr : 쓰레드의 특성을 설정하기 위해서 사용한다. NULL일 경우 기본 특성
  3. start_routine : 쓰레드가 수행할 함수로 함수포인터를 넘겨준다.
  4. arg : 쓰레드 함수 start_routine를 실행시킬 때, 넘겨줄 인자
이 함수는 성공적으로 수행되었다면, 0을 리턴한다. 그렇지 않을 경우 1을 리턴한다.

1.6.2 pthread_join : 쓰레드 정리

쓰레드가 실행시키는 것은 함수 이다. 그러므로 return이나 exit(0)등을 이용해서 쓰레드를 종료시킬 수 있게 된다. 그러나 쓰레드 함수가 종료되었다고 해서 곧바로 쓰레드의 모든자원이 종료되지 않는다. fork()기반의 멀티프로세스 프로그램에서 종료된 자식프로세스를 정리하기 위해서 wait()로 기다리듯이, 종료된 쓰레드를 기다려서 정리를 해주어아만 한다. 그렇지 않을 경우 쓰레드의 자원이 되돌려지지 않아서 메모리 누수현상이 발생하게 된다.

pthread_create()로 생성시킨 쓰레드는 pthread_join()을 통해서 기다리면 된다. pthread_join 함수는 다음과 같이 사용할 수 있다.
#include <pthread.h> 

int pthread_join(pthread_t th, void **thread_return);
  1. th : pthread_create에 의해서 생성된, 식별번호 th를 가진 쓰레드를 기다리겠다는 얘기다.
  2. thread_return : 식별번호 th인 쓰레드의 종료시 리턴값이다.

pthread_join이 하는 일은 명확하다. 다만 주의 할것은 pthread_join은 반드시 joinable 한 상태로 생성된 쓰레드만을 기다릴 수 있다는 점이다. pthread_create로 쓰레드를 생성시킬 때, 나중에 join되지 않을 것으로 생각하고 생성시킬 수 있는데, 이렇게 되면 이 쓰레드는 종료하자마자 모든 자원을 해제하며, pthread_join으로 기다릴 수가 없다. 부모쓰레드와 떨어져서 완전히 독립적으로 작용한다고 하여, 이를 detach 한다고 한다. 쓰레드를 detach하는 방법은 아래에서 다룰 것이다.

1.6.3 쓰레드 생성 예제

pthread_create와 pthread_join을 알고 있다면, 이제 thread를 생성시킬 수 있다.
#include <pthread.h> 
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

// 쓰레드 함수
void *t_function(void *data)
{
int id;
int i = 0;
id = *((int *)data);

while(1)
{
printf("%d : %d\n", id, i);
i++;
sleep(1);
}
}

int main()
{
pthread_t p_thread[2];
int thr_id;
int status;
int a = 1;
int b = 2;

// 쓰레드 생성 아규먼트로 1 을 넘긴다.
thr_id = pthread_create(&p_thread[0], NULL, t_function, (void *)&a);
if (thr_id < 0)
{
perror("thread create error : ");
exit(0);
}

// 쓰레드 생성 아규먼트로 2 를 넘긴다.
thr_id = pthread_create(&p_thread[1], NULL, t_function, (void *)&b);
if (thr_id < 0)
{
perror("thread create error : ");
exit(0);
}

// 쓰레드 종료를 기다린다.
pthread_join(p_thread[0], (void **)&status);
pthread_join(p_thread[1], (void **)&status);

return 0;
}
아주 전형적인 프로그램이긴 하지만 pthread_join부분에 문제가 있다. pthread_join은 쓰레드가 종료될 때까지 블럭되기 때문이다. 이래서는 쓰레드를 두개이상 생성시키지 못할 것이다. 그렇다고 pthread_join을 이용하지 않는다면, 메모리 누수가 생기게 되니, 생략할 수도 없는 노릇이다.

1.6.4 자식쓰레드를 부모쓰레드로 부터 분리하기

pthread_join의 사용으로 발생할 수 있는 문제점을 해결하기 위한, 가장 좋은 방법중의 하나는 pthread_detach 를 이용해서, 자식 쓰레드를 부모쓰레드와 완전히 분리해 버리는 방법이다. 이 경우 자식 쓰레드가 종료되면, 모든 자원이 즉시 반환된다. 반면, 자식 쓰레드의 종료상태를 알 수 없다는 문제가 발생한다. 대게의 경우 자식 쓰레드의 종료상태가 중요한 문제가 되지는 않을 것이다.

만약 자식 쓰레드의 종료상태를 알아내는게 중요하다면, 종료상태를 저장할 전역변수를 두고, 여기에 종료상태를 기록하는 방식을 사용할 수 있을 것이다. 자식 쓰레드가 종료할때, 변수의 값을 바꾸고, 부모쓰레드에 시그널을 전송하는 방법이다. 이 방법은 이 문서의 뒤에서 따로 다루도록 하겠다.
#include <pthread.h> 
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

// 쓰레드 함수
// 1초를 기다린후 아규먼트^2 을 리턴한다.
void *t_function(void *data)
{
char a[100000];
int num = *((int *)data);
printf("Thread Start\n");
sleep(5);
printf("Thread end\n");
}

int main()
{
pthread_t p_thread;
int thr_id;
int status;
int a = 100;

printf("Before Thread\n");
thr_id = pthread_create(&p_thread, NULL, t_function, (void *)&a);
if (thr_id < 0)
{
perror("thread create error : ");
exit(0);
}

// 식별번호 p_thread 를 가지는 쓰레드를 detach
// 시켜준다.
pthread_detach(p_thread);
pause();
return 0;
}

1.7 쓰레드 동기화

이제 우리는 간단한 다중쓰레드 프로그램을 만들 수 있게 되었다. 그러나 이들 쓰레드 생성 함수만 가지고는 복잡한 쓰레드 프로그램을 만들 수가 없다. 쓰레드간 동기화라고 하는 문제가 놓여있기 때문이다. 아주 간단한 프로그램이 아닌한은 반드시 동기화문제를 고민해야만한다.

동기화란 여러가지 의미로 사용될 수 있는데, 이 경우에 있어서 동기화서로의 시간을 맞춘다를 의미한다. 멀티쓰레드 프로그램은 하나의 시간에 여러개의 프로세스가 돌아가는 형태를 취한다. 또한 멀티쓰레드 프로그램은 자원의 상당부분을 서로 공유하는 경우가 많다. 만약 단지 자원을 읽어들이는 거라면 상관없지만 읽고/쓰는 것이라면 동기화와 관련된 문제가 발생할 수 있다.

예컨데 다음과 같은 경우다.
  1. A와 B 두개의 프로세스가 있다. 이 프로세스는 int count=1 이라는 자원을 공유한다.
  2. A가 count를 읽어들이고 1을 더한다.
  3. B가 count를 읽어들인다. 아직 A가 count에 쓰지 않았기 때문에, B도 1을 읽어들인다.
  4. A가 count에 2를 쓴다.
  5. B도 count에 2를 쓴다.
  6. count에는 2가 저장되었다.
우리가 원하는 값은 2가 아닌 3이다. 그러나 쓰레드가 동기화 되지 않음으로써, 원치않은 잘못된 연산을 하게 되었다. 우리는 이 문제를 해결해야 한다.

1.8 접근제어

동기화 문제는 현실세계에서도 자주 발생한다. 화장실을 생각하면 된다. 화장실은 공유자원이며, 여러명이 사용한다. 누군가 화장실을 사용하고 있다면, 다른 사람은 화장실을 사용하면 안된다. 이 문제를 우리는 접근을 제어하는 방식으로 해결한다. 문을 걸어 잠궈서 한번에 한사람만 화장실에 들어가도록 하는 방법이다. 매우 이해하기 쉬운 방식이다.

다중쓰레드 프로그램에서도 마찬가지로 접근제어를 이용해서 이 문제를 해결한다. 이를 위해서 pthread는 mutex라는 잠금 메커니즘을 제공한다.

1.8.1 mutex 잠금

동시에 여러개의 쓰레드가 하나의 자원에 접근하려고 할때 발생하는 문제를 pthread는 임계영역을 두는 것으로 해결하고 있다. 임계영역안에는 접근하고자 하는 자원이 놓여있고, 오직 하나의 쓰레드만 임계영역안으로 진입할 수 있도록 제한한다. pthread는 이를 위해서 mutex를 제공한다. mutex는 그 자체가 가지는 잠금의 특성 때문에 mutex 잠금이라고 불리워지기도 한다.



위 그림은 mutex가 작동하는 방식을 보여준다. thread 1이 자원에 접근하면 mutex 잠금을 얻게 된다. 이 잠금은 단지 하나만 존재하기 때문에 thread 2는 잠금을 얻지 못하고 임계영역 밖에서 대기하게 된다. thread 1이 자원을 모두 사용하고 임계영역을 벗어나면 thread 2는 잠금을 얻게 되고 임계영역에 진입해서 자원을 사용할 수 있게 된다.

1.8.2 mutex의 사용

mutex를 사용하기 위해서는 다음의 4가지 함수가 필요하다.
  • mutex 잠금객체을 만드는 함수
  • mutex 잠금을 얻는 함수
  • mutex 잠금을 되돌려주는 함수
  • mutex 잠금객체를 제거하는 함수

1.8.3 pthread_mutex_init

mutex를 사용하기 위해서는 먼저 pthread_mutex_init() 함수를 이용해서, mutex 잠금 객체를 만들어줘야 한다.
pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr *attr); 
이 함수는 두개의 인자를 필요로 한다.
  1. mutex : mutex 잠금객체
  2. mutex_attr : mutex는 fast, 'recursive, error checking의 3종류가 있다. 이 값을 이용해서 mutex 타입을 결정할 수 있다. NULL 일경우 기본값이 fast가 설정된다.
    • fast : 하나의 쓰레드가 하나의 잠금만을 얻을 수 있는 일반적인 형태
    • recursive : 잠금을 얻은 쓰레드가 다시 잠금을 얻을 수 있다. 이 경우 잠금에 대한 카운드가 증가하게 된다.
mutex_attr을 위해서 다음의 상수값이 예약되어 있다.
  • fast : PTHREAD_MUTEX_INITIALIZER
  • recursive : PTHREAD_RECURSIVE_MUTEX_INITIALIZER
  • error checking : PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP

1.8.4 pthread_mutex_lock

mutex 잠금을 얻기 위한 함수다.
int pthread_mutex_lock(pthread_mutex_t *mutex); 
mutex 잠금을 얻는다라는 표현보다는 mutex 잠금을 요청한다라는 표현이 더 정확할 것 같다. 만약 mutex 잠금을 선점한 쓰레드가 있다면, 선점한 쓰레드가 mutex 잠금을 되돌려주기 전까지 이 코드에서 대기하게 된다.

때때로 잠금을 얻을 수 있는지만 체크하고 대기(블럭)되지 않은 상태로 다음 코드로 넘어가야할 필요가 있을 수 있을 것이다. 이 경우에는 아래의 함수를 사용하면 된다.
int pthread_mutex_trylock(pthread_mutex_t *mutex); 

1.8.5 pthread_mutex_unlock

mutex 잠금을 되돌려주는 함수다.
int pthread_mutex_unlock(pthread_mutex_t *mutex); 

1.8.6 mutex 잠금 예제

count 프로그램을 예제로 할 것이다. 임계영역안에서 보호되어야할 자원은 count이고, 여러개의 쓰레드가 count에 접근해서 +1을 시도하려고 한다. 이때 제대로된 count를 위해서는 한번에 하나의 쓰레드만이 counting을 하도록 해야할 것이다. mutex를 이용해서 임계영역을 보호하도록 할 것이다.

임계영역을 보호하지 않을 경우 다음과 같은 문제가 발생할 수도 있을 것을 예상할 수 있다.
int a = 1;  
Thread A 에서 a를 읽어들인다.
Thread B 에서 a를 읽어들인다.
Thread A 에서 a = a+1를 한다.
{
a = a+1;
결과는 2;
}
Thread B 에서 a++를 한다.
{
a = a + 1; // 읽어들인 값이 1이기 때문에
역시 결과는 2가 된다.
}
두번의 count가 발생했기 때문에 3이되어야 하겠지만 임계영역이 보호되지 않음으로써 2가 되어 버렸다.

mutex는 임계영역을 잠금으로서 이러한 문제를 해결한다. 이러한 문제를 해결하기 위해서는 임계영역에 단지 하나의 쓰레드만 접근하는걸 보장해줘야 할 것이다. mutex는 아래의 요소들을 보장함으로써 이를 보장한다.
  • Atomicity - mutex 잠금은 최소단위 연적 - atomic operation - 을 보장한다. atomic operation에 대해서 간단히 설명하고 넘어간다. 자세한 내용은 [http]Atomic Operation을 참고하기 바란다.
    1. aotomic operation은 일련의 연산 즉 mutex 잠금 연산이 끝날때 까지 다른 프로세스가 그 연산의 변화를 알 수 없는 상태가 되는 연산을 의미한다. (일반적으로 연산은 이전의 연산의 결과를 관찰한 후에서야 이루어질 수 있게다)
    2. 전체연산중 하나라도 실패할 경우 모든 연산이 실패하며 시스템은 전체 연산이 시작하기 전의 상태로 복구된다.
  • Singularity : 한 쓰레드가 뮤택스 잠금을 얻었다면, 이 쓰레드가 뮤택스 잠금을 내어놓기 전까지는 다른 쓰레드가 뮤택스 잠금을 얻을 수 없도록 한다.
  • None Busy Wait : 이것은 성능과 관련된 것이다. 바쁜대기상태에 놓이지 않는다는 뜻이다. 뮤택스 잠금을 얻을 수 있는지를 확인하기 위한 연산이 필요하지 않는 다는 의미로 받아들이면 될 것이다.

이상 mutex는 위의 3가지를 지원하는 것으로 공유되는 자원을 충돌없이 그리고 효율적으로 사용할 수 있도록 보장해준다.

다음은 mutex를 사용한 count 예제프로그램이다.
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <stdio.h>  
#include <unistd.h>
#include <pthread.h>

int ncount; // 쓰레드간 공유되는 자원
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 쓰레드 초기화

// 쓰레드 함 수 1
void* do_loop(void *data)
{
int i;

pthread_mutex_lock(&mutex); // 잠금을 생성한다.
for (i = 0; i < 10; i++)
{
printf("loop1 : %d", ncount);
ncount ++;
sleep(1);
}
pthread_mutex_unlock(&mutex); // 잠금을 해제한다.
}

// 쓰레드 함수 2
void* do_loop2(void *data)
{
int i;

// 잠금을 얻으려고 하지만 do_loop 에서 이미 잠금을
// 얻었음으로 잠금이 해제될때까지 기다린다.
pthread_mutex_lock(&mutex); // 잠금을 생성한다.
for (i = 0; i < 10; i++)
{
printf("loop2 : %d", ncount);
ncount ++;
sleep(1);
}
pthread_mutex_unlock(&mutex); // 잠금을 해제한다.
}

int main()
{
int thr_id;
pthread_t p_thread[2];
int status;
int a = 1;

ncount = 0;
thr_id = pthread_create(&p_thread[0], NULL, do_loop, (void *)&a);
sleep(1);
thr_id = pthread_create(&p_thread[1], NULL, do_loop2, (void *)&a);

pthread_join(p_thread[0], (void *) &status);
pthread_join(p_thread[1], (void *) &status);

status = pthread_mutex_destroy(&mutex);
printf("code = %d", status);
printf("programing is end");
return 0;
}

1.9 앞으로 할 것

쓰레드는 매우 광범위한 주제로 여기에서는 쓰레드를 사용하기 위한 가장 기본적인 내용만 다루었다. 쓰레드에 대한 좀더 자세한 내용은 별도의 장을 할애해서 다룰 생각이다.

:::
2009/03/27 23:42

리차드 스톨만과 자유소프트웨어 그리고 오픈소스에 대해서


59-1.jpg

많은 개발자들이 회사일과는 별도로 오픈소스 프로젝트에 참가하려고 한다. 그리고 가능한 이름있는 프로젝트로까지 성장시키기를 원한다. 왜 일까 ? 돈을 벌 기회를 얻을 수 있다라거나 혹은 이름을 알릴 수 있는 기회를 엿볼 수 있다라는 등등의 이유가 있을 수도 있을 것이다. 그러나 그렇게 단정짓기에는 왠지 뒷통수가 근질근질 하다. 단지 그 이유 때문일까 ? 그렇다면 다른 산업분야에 비해서 왜 유독 소프트웨어 분야에서 그런 현상이 발생하는 것일까 ? 이렇게 말하면 오픈소스 공동체 혹은 자유소프트웨어 공동체가 잘 유지되고 있어서라고 대답할 수 있을 것이다. 그럴듯하다. 그렇다면 이렇게 되물어볼 수 있을 것이다. 왜 소프트웨어쪽은 그러한 풀뿌리 공동체 공동체가 살아있는 것일까. 다시 말하자면 왜 유독 놀만한 멍석이 잘 깔려져 있을까 라는 물음이다.

소프트웨어 산업에는 장인정신예술인의 중간의 의미를 가지고 있는 해커문화라 는게 남아 있다. 자신의 이름을 걸고 물건을 만드는 장인처럼 자신의 이름이 새겨진 소프트웨어를 만들어내기를 원한다. 혹은 자신의 이름이 아로새겨진 예술작품이 전시되는 것처럼 자신의 이름이 아로새겨진 소프트웨어가 전시 되기를 원한다. 다른 어떠한 산업분야에서도 이러한 모습을 발견할 수 없다. 아마 예술분야에서나 겨우 발견할 수 있을 것이다.

이렇게 멍석을 만들어 놓은 사람이 리차드 스톨만이다. 시대의 반항아. 똘아이?. 소프트웨어 계의 아방가르드, 공산주의자, 사회주의자, 근본주의자, 원리주의자, 순종주의자, 천재 프로그래머, 마지막 해커, 고집쟁이, 피리부는 아저씨, 사이비 교주 요러한 수식어가 따라다니는 사람이다.

이 사람이 어떻게해서 우리가 몸담고 있는 소프트웨어 바닥에 예술계에나 있을 법한 이러한 잘다듬어진 공동체, 해커 마인드를 만들게 되었는지, 소프트웨어 개발은 예술의 그것과 비슷하다라는 생각을 가지도록 했는지 즉 일종의 자존심을 가질 수 있는 문화의 기반을 닦았는지 생각해볼 필요가 있다. 이러한 현상은 예술계에서나 볼 수 있는 것이기 때문에 특이하며 때문에 생각해볼 가치가 있다.

우선 순수예술이라는 것에 대해서 좀 생각을 해봐야 겠다. 비록 소프트웨어 영역에서 처럼 성공적이진 못했지만 소프트웨어처럼 자본과 시장에 대항해서 그들 자신의 공동체를 지키고자 하는 운동들이 있어왔으며, 소프트웨어 보다는 더 오랜 역사를 가지고 있기 때문이다.

기실 예술이라는 것이 지금처럼 대접을 받게 된것은 그리 오래되지 않았다. 근대이전의 예술가는 독립적인 예술가가 아닌 교회궁중의 후원을 받는 고용인에 지나지 않았다. 그러므로 자기가 만들고 싶은 것을 만들어낸다라는 지금의 예술가의 이미지와는 전혀달랐다. 후원을 받는 궁중과 교회에 봉사하는 고용인으로써 그들의 의뢰를 받아서 작품을 만들 따름이었으니 예술가라고 하기에는 부족함이 있었다. 실제 당시의 많은 작품들에 작가가 명시되어있지 않았던데에는 이러한 이유가 있었다. 레오나르도 다빈치, 바흐, 베토벤 정도되는 유명인 정도가 되어야 그나마 이름을 남길 수 있었으며, 이들 당대의 유명인 조차도 종속된 상태에서 벗어날 수가 없었다.

예술가가 예술가로써의 독립적인 지위와 명성 자존심을 회복 한것은 개인의 주체의 중요성이 부각된 르네상스 이후에서 부터이며, 이때부터 일반 대중은 예술에 대한 동경을 가지게 되고 그들을 존경하고 그들과 같이 되고자 하였다. 누구에게도 얽매이지 않고 자신이 만들고 싶어하는 것을 만들며 명성과 부를 누릴 수 있으며, 개인이 인간으로써 가져야할 자존감을 지켜나갈 수 있다!! 얼마나 매력적인가. 물론 이때의 예술가는 태어나면서 부터 자질을 타고난 천재라는 이미지가 강하긴 했지만 말이다.

자본이 지배하는 지금에서도 마찬가지일 것이다. 사람은 자본이나 회사 사회의 굴레에서 자본이나 혹은 고객을 위해서 무엇인가를 만들어내는 것보다는 자신이 자기를 위해서 무언가를 만들어내기를 원한다. 왜 예술가에 대한 동경을 가지고 있을까. 왜 자기 스스로가 자본가가 되길 원하는 것일까. 자기 자신을 위해서 무엇인가를 할 수 있기 때문이다. 자기가 자신을 위해서 무엇인가를 할 수 있다는 것은 자신의 삶을 자신이 책임질 수 있는 상태임을 얘기하는 것이다.

많은 노동자, 기술자들이 장신 혹은 예술가 처럼 그렇게 살기를 원한다. 정확히 말하자면 실용적 예술가라고 할 수 있는 장인이 되길 원한다. 그러나 실패했다. 소프트웨어 분야를 제외하고는... 다른 거의 모든 분야가 산업화되고 자본에 완전 종속되어 버렸다. 소프트웨어분야 처럼 해커문화, 장인문화, 풀뿌리 공동체 문화가 명백하게 남아 있는 분야는 없다.

소프트웨어를 완전히 산업에 종속시키지 않도록 만든데에는 역시 리차드 스톨만과 자유소프트웨어재단 그들의 이상에 따라주었던 도전적이고 열정적인 개발자들의 힘이 무엇보다 컸다고 할 수 있을 것이다. 적당히 자본과 타협하면서 적당히 우리의 자존심을 유지시켜줄 공동체를 지켜나가자라 고 안이하게 타협했던 다른 산업의 노동자와는 다른, 어찌 보면 정줄을 반쯤 놓은 사이비교주처럼 모든 상업, 독점, 자본, 시장, 상품에 일말의 타협도 없이 자신의 철학을 관철시킬려고 하는 이들이 있었기 때문에 어느 산업에서도 볼 수 없는 강력한 공동체를 만들 수 있었을 것이다.

많은 젊은이들이 소프트웨어영역에 대한 막연한 동경을 가지고 있는데에는 자유스러우며 반사회적이며 공동체지향적인 해커문화가 큰 역할을 하고 있다.

자유소프트웨어 재단과 오픈소스 진영의 껄끄러운 관계

많은 사람들이 자유소프트웨어운동과 오픈소스운동이 같은 것이라고 혼동한다. 때때로 오픈소스진영의 대부가 리처드 스톨만인 것으로 소개하는 문서들도 있다. 하지만 자유소프트웨어 재단과 오픈소스진영은 그닥 좋은 관계는 아니다.

2006년 리처드 스톨만이 한국을 방문해서 강연을 하는 와중에 자유소프트웨어가 아닌 오픈소스에 대한 질문을 하자 바로 차단신공을 발휘했다는 에피소드에서 보듯이, 일체의 어떠한 타협을 거부하는 자유소프트웨어 재단과 완고함은 비교적 자본과 시장과 유연한 관계를 보여주는 오픈소스진영은 (언뜻 이해되지 않기도 하겠지만)꽤나 껄끄러운 관계를 유지하고 있다.

아방가르드라고 할 수 있는 리처드 스톨만의 눈에 자본과 시장과 적당히 타협하는 모습을 보이는 오픈소스진영은 적과 손잡은 위험한 불순분자 정도로 보일지도 모르는 일이다. 아마도 분명히 그렇게 생각하고 있으리라고 생각한다. 그의 생각이 지나치게 완고하든지 간에 그의 그러한 행동은 오픈소스진영이 자본과 사회적 공동체 가운데에서 균형을 지킬 수 있도록 긴장감을 주는 것은 분명한 것 같다. 자본과 시장이라는 거대한 세력에 맞서서 자신들의 공동체를 지키려면 이러한 사람도 반드시 필요한 것이라는 생각이 든다.

산업화와 자본화의 거대한 물결속에서도 예술계와 소프트웨어계가 나름 이러한 공동체문화를 지켜나갈 수 있었던건 역량있는 이단아들이 활약해주었기 때문 아닐까.
:::
2009/03/05 23:53

command pattern

Command Pattern

패턴과 패턴에 대한 (UML을 포함한)설명글을 보면 역시 사용하는 것보다 설명하는게 더 어렵군이라는 느낌이다. 내 생각을 잘 이해하기 쉽게 잘 전달해보자라는 마음가짐으로 가능한 평이하게 글을 만들어 봐야겠다.

Command Pattern은 행동자체를 객체로 본다. 행동을 객체로 봄으로써 좀더 쉽게 명령을 내리기 전의 상태로 복귀할 수 있다. 문제가 생길때 마다 그때 그때 쪽지로 일거리를 만들어서 주는 경우를 생각해 보자. 나중에 그 결과를 정리하는 것도 매우 복잡한 일이 될 확률이 높을 것이다. 이렇게 하지 않고 문제자체를 객체로 만들어서, 그러니까 문제를 분류하고 묶어서 서류철을 만들어서 넘기고 결과를 포함한 서류철을 다시 받게 된다면 문제에 대한 처리가 훨씬 간결해 질 것이다. 일반적인 업무처리에서도 흔히볼 수 있는 방식이기도 하다. Command Pattern이란 즉 수행해야할 문제 혹은 명령을 객체로 처리하는 방식이라고 정의내릴 수 있을 것이다.

이러한 특징은 다음과 같은 응용에 유용하다.
  1. Multi-level undo
    유저의 명령을 객체로 만든다. 만들어진 명령객체은 stack에 유지시키면,가장 최근에 실행된 명령이 가장 위에 놓이게 될 것이다. undo를 원한다면 undo() 메서드를 실행시켜서 pop을 하면 된다.
  2. Progress bar
    프로그램에게 주어진일의 명령의 연속으로 이루어진다고 가정한다. 이때 각각의 명령객체는 getEstimatedDuration메서드를 가진다. 프로그램은 이 메서드를 이용해서 명령이 어느정도 수행되었는지를 쉽게 판단할 수 있다.
  3. thread pool
  4. parallel processing
  5. networking

Command_pattern.png

Command
이 패턴에서 가장 중요한 클래스는 명령을 수행하는데 필요한 인터페이스를 가지고 있는 Command객체다. 일상업무에서의 작업요청서라고 볼 수 있을 것이다. 우리가 이 패턴을 사용하는 이유는 명서세에 적혀있는 명령을 실행하는 것이므로 명령을 수행하기 위한 execute메서드를 포함한다.
ConcreteCommand
Receiver객체가 어떤 Action을 취할지를 정의한다.
Receiver
주어진 요청에 대해서 어떤일을 수행해야 하는지를 알고 있는 객체.
Invoker
명령의 수행을 요청한다.
Client
ConcreteCommand 객체를 생성한다.

예제

C++

간단한 요리 프로그램이다. 재료를 준비를 위한 준비명령객체, 준비된 재료를 가지고 프라이팬에 볶는등의 작업을 하는 행동명령객체가 준비된다. 요리는 사람이 하는 거라서 때때로 실수가 있을 수 있기 때문에 Undo기능을 가진다. Undo 기능은 명령객체를 stack에 쌓아두고 pop하는 것으로 구현할 수 있다. 빠른 구현을 위해서 STLvector를 사용했다.

#include <iostream> 
#include <vector>
#include <string>

using namespace std;

// 가상메서드를 포함한 인터페이스 슈퍼 클래스
class Command{
public:
virtual void execute(void) =0;
virtual ~Command(void){};
};

class Ingredient : public Command {
public:
Ingredient(string amount, string ingredient){
_ingredient = ingredient;
_amount = amount;
}
void execute(void){
cout << " *Add " << _amount << " of " << _ingredient << endl;
}
private:
string _ingredient;
string _amount;
};

class Step : public Command {
public:
Step(string action, string time){
_action= action;
_time= time;
}
void execute(void){
cout << " *" << _action << " for " << _time << endl;
}
private:
string _time;
string _action;
};

// command를 저장하고 꺼내기 위한 stack 클래스
class CmdStack{
public:
void add(Command *c) {
commands.push_back(c);
}
void createRecipe(void){
for(vector<Command*>::size_type x=0;x<commands.size();x++){
commands[x]->execute();
}
}
void undo(void){
if(commands.size() > 0) {
commands.pop_back();
}
else {
cout << "Can't undo" << endl;
}
}
private:
vector<Command*> commands;
};

int main(void) {
CmdStack list;

//Create ingredients
Ingredient first("두스푼", "식용유");
Ingredient second("세컵", "쌀");
Ingredient third("한스푼","케찹");
Ingredient fourth("네홉", "콩");
Ingredient fifth("한스푼", "간장");

//Create Step
Step step("후라이팬에 볶기","3-4분 정도");

//Create Recipe
cout << "볶음밥을 만들어봅시다." << endl;
list.add(&first);
list.add(&second);
list.add(&step);
list.add(&third);
list.undo();
list.add(&fourth);
list.add(&fifth);
list.createRecipe();
cout << "요리시작!" << endl;
return 0;
}

C

음.. 그닥 객체지향적이지 않다고 생각되는 C를 이용해서도 구현해 봐야 겠다. 다음과 같은 요소들이 필요하지 않을까 싶다.구조체에 함수포인터 다발을 두는 것으로 클래스 비슷하게 만들어낼 수 있긴 하겠다.

PHP

애초에 전혀 객체지향적이지 않게 만들어졌던 php는 php4가 되어서야 class 키워드를 제공하기 시작했고 php5에 이르러서 그럭저럭 객체지향적이다라는 얘기를 듣게 되었다. 이제는 객제지향 패턴을 사용해서 만들어진 PHP 프로그램도 어렵지 않게 찾아볼 수 있다.
:::
2009/03/04 00:53

욕먹어 가면서 배워야 빨리배운다.

욕해가면서 가르쳐줘야 하고 필요하다면 때리면서 갈켜야 빨리 배울 뿐더러 한번 배운것 까먹지 않는 다는 얘기들이 있다.

여전히 사랑의 매라는 이름으로 체벌이 정당화 되고 가정내에서의 폭력역시 여러가지 이유를 들어서 눈감아 주거나 긍정해주는 현실이다. 가정과 학교가 이러하니 사회는 더 말할필요도 없다. 더 빨리, 더 잘 가르키기 위해서는 적당한 욕과 적당한 인격모욕적 행위가 필요한 것으로 인식이 되어지고 있고, 오히려 이렇게 하지 못하는 사람을 무책임하거나 제대로된 사회생활을 못하는 사람 취급을 받기도 한다.
 
나는 이 방식과 생각을 대단히 싫어한다.

이 방식은 대단히 나쁜 방식이다. 다만 결과가 빨리눈에 보인다는 점과 경쟁을 통해서 한명의 수제자만을 키워내기로 마음먹었을 경우 쓸만하다는 이유때문에 널리 사용되어지는 것으로 생각된다.

친구가 이런말을 하더라. 촬영을 가르킬 때 욕하면서 가르키는 거랑 그렇지 않은 거랑 습득속도에 있어서 상당히 큰 차이가 생긴다고.

욕을 하거나 맞거나 인격적으로 무시당하면서 배우면 정말로 잘 배운다. 우린 이걸 경험적으로 알고 있다. 한번 배운거 안까먹는다. 좋은 말로 해서는 안된다라는 말이 괜히 나온게 아니다. 게다가 성과와 결과와 효율이 최고의 가치가 되는 자본주의 사회에서야 더 말할필요도 없을 것이다.

욕을 먹거나 인격적으로 무시당하기를 원하는 사람은 없을 것이다. 그러하니 기를 쓰고 주어진 일을 주어진 방식대로 까먹지 않고 하려고 애를 쓴다. 때때로 자존심을 내세우는 사람들도 있지만 아주 소수만이 자신의 자존심을 내세울수 있을 뿐이다. 그러하니 대부분의 경우 일단 결과는 잘나온다. 그러나 인격적으로 무시를 당하게 되면, 사람의 몸과 마음이 위축이 되기 마련이다. 장점이 있으면 단점이 있는 법. 외연의 속도와 효율을 장점으로 하는 것들은 대게가 그 내연에 감추어진 눈에 보이지 않는 것들을 파괴시킨다. 결국 시키는 것만 잘하는 사람이 만들어지게 된다는 것이다. 복지부동형 인간이라고 한다. 새로운걸 하려고 하지 않는다. 왜 ? 실수하면 욕먹으니까. 인격적인 모독을 당하니까.

개중에는 욕을 먹어도 걸러낼 것은 걸러내고 흘려들을 건 흘려들여서 자신의 방향대로 밀고 배워나가는 소수의 사람들이 있다. 이런 사람들이 흔히 말하는 수제자가 되는 것이다. 몇명의 수제자를 키워내는 도제방식에서 폭력적인 수단이 꽤 잘 들어 맞는 것처럼 보인다는 얘기가 여기에서 나온다. 나머지는 낙오하거나 그냥 저냥 시키는 것만 해내는 주변인이 된다.

수공업이나 사람이 부속품 취급당하는 노동집약적인 산업이 아니면 그나마도 써먹기가 힘든방법이다. 특히 사고의 유연함이 중요한 소프트웨어 산업분야에서는 더 말할 나위가 없을 것이다. 그런데 여전히 도제방식의 반강압적인 학습방식이 사용되는 것 같다. 군대에서 그러했던 것처럼 욕하면서 갈궈야 제대로 배울 수 있다고 생각하는 경우가 많은 것 같다. 사수쯤 되는 위치에 있다면 한번 생각해 봐야할 것이다. 제대로 가르키는 것인지 아니면 제대로 가르키는 것처럼 보이는 것인지.
:::