기초적인 내용이지만, 되짚어보는 의미에서 작성한 자료입니다. 실은 팀원교육때 쓰려고 정리한 자료. 몇몇 빠진 내용이 있는데 나중에 보충하기로 하지요. (과연?!)
비동기적 고찰
회사에서 이번주까지 작업한 건 poller라는 간단한 클래스 템플릿이었다. (따지고보면 그리 간단치도 않다)
request-complete모델을 기반으로 비동기적 IO를 처리하는 프레임워크인데 request메소드를 통해 여러타입의 io작업을 요청하고 poll메소드를 통해 요청했던 io의 인스턴스를 되돌려 받음으로써 완료를 통지받는 형태의 작업으로 network io + C10K문제(1만의 동시접속자를 처리하는 문제)를 해결하기 위해 kqueue/iocp/epoll등의 OS지원을 단일 인터페이스로 사용하기 위한 코드다.
1.
이 코드를 작업하다 보니, 기존에 만들어 쓰던 Socket Wrapper가 전혀 의미가 없다는 사실을 깨달았다. 어차피 Socket에서 사용하는 작업들은 connect/listen/bind/send/recv/close 정도 인데다 굳이 복잡하게 소켓 API를 만들 필요가 없는거다. 그냥 Request & Forget형태로 상황에 맞는 코드, event-driven형식을 강요하면 문제가 해결된다.
게다가, 어차피 iocp지원을 위해서는 표준적인 send/recv가 아닌 Winsock에만 존재하는 WSASend/Recv를 써야하고 결국은 각 시스템에 맞는 별도의 코드를 구현해야 한다. 이건 DriverT라는 템플릿 매개변수로 빼두었기 때문에 그다지 큰 문제가 될 것 같지는 않다.
2.
io작업이 아닌 XML Pull Parser나 asynchronous task같은 서비스도 이런 형태로 구현이 가능하다.
3.
생각해보니 결국은 event-driven programming. 하지만 해볼 가치는 있는듯. 그나저나 철학이든 뭐든 죄다 난 늦게 깨닫는단 말이야. 쳇.
4.
자 이제 취미로 놀면 되는거다.
XML에 대한… 고찰?!!
XML을 처음 접하고 사용하기 시작한게 2000년 경이었을테니, 얼추 7년정도 사용한듯 하다. 2000년에는 XML문서버젼관리 시스템 프로젝트를 했었고, 그 뒤에는 PlayAction이란 사이트 겸 CMS를 만드는데도 사용했었고, 회사다니면서는 각종 설정파일, 유틸리티, 메타정보등을 생성/관리하는데 사용해왔다. 그리고, C++로 xml pulling parser방식의 인터페이스를 가진 라이브러리도 고민했었다. (libxml을 이용한 DOM라이브러리로 전환하긴 했지만..) 이렇듯 프로그래머로서의 삶에 깊숙하게 침투하신 이 분을 어떻게 요리할까라는 생각이 재개된건, 졸업프로젝트로 고려중인 Simulation Engine제작 때문인게 크긴 하다.
각설하고, XML을 분석하는 관점은 크게 Well-formed Document와 Valid Document라고 볼 수 있다. Well-formed는 XML의 기본 문법에 맞는지의 여부이고, Vaild는 문서정의 (DTD나 XML Schema)에 맞는지의 여부다. 이 두가지 관점을 항상 같이 고민하다보니 문제가 어려워졌던 것 같다. 오랜만에 다가온 Eureka!!는 실로 반갑다. 자 그럼 그 Eureka!!가 무엇이냐 하면.. (사실 별거 아니다)
XML을 가장 간단하게 분석하는 방법은 <와 >로 묶인 태그라는 점이다. XML의 가장 기본적인 요소인 Element외에도 DocType(<!DOCTYPE >)이나 Processing Instruction(<? ?>), Comment(<!– –>), CDATA(<![CDATA[ ]]>)등도 결국은 <와 >로 묶인 태그였다. 이렇게 관점을 바꿔놓고 보니 몇가지 재미있는 속성들이 발견되었다.
- <![ 로 시작되는 태그들은 ]]>로 닫힌다.
- <! 로 시작되는 태그들은 >로 닫힌다.
- <? 로 시작되는 태그들은 ?>로 닫힌다.
- <로 시작되는 태그들은 >로 닫힌다.
이런걸 왜 이제야 생각했는지 모르겠다. -_-
XML의 전체 스펙을 생각하고 파서를 작성하려고 들면, 일이 복잡해진다. 하지만, 위의 4가지 속성만 고려하고 작성한다면, 규모가 작아지고 작성이 간단해질 것 같다. – 기존에 사용하던 state_machine클래스를 사용하면 더욱더 간단히 🙂 –
또한, 각 태그들을 Event로 간주한다면, 트리기반의 DOM이나 콜백기반의 SAX와는 달리, XML문서를 Event의 리스트로 관리할 수 있게 된다. SAX의 단점이라면, 역시 수정이 불가능하다는 것이고, DOM의 문제라면 메모리를 많이 차지한다는 점일텐데, 이 두 문제점 사이에서 적절히 타협할 수 있는 안이 되지 않을까 라는 생각이 들었다. 그리고, Event의 리스트로 관리하게 되면 복잡하긴 하겠지만, 트리형태의 Access도 불가능한 것은 아닐거라 생각한다.
남은 일은, 구현하는 일이지만… 회사일과 졸업논문, 각종 시험과 과제가 발목을 잡고 있는 현실이 안타까울 따름….. 응??
내신과 특목고. 그 허상에 대해.
이리 저리 유유자적하며 웹서핑을 하던 중간에, 최근 내신과 특목고에 관련된 포스팅이나 기사들이 눈에 띄게 늘었다는 사실을 체감했다. 그리고 뉴스를 보며 이야기하던 내용을 나름 정리해본다.
C++ Native AOP의 가능성.
Aspected Oriented Programming(AOP)을 가장 잘 지원하고 있는 언어를 꼽으라면, 숨도 쉬지않고 Java를 선택할 수 있겠다. Java의 경우에는 주로, VM코드를 직접 수정하는 방식으로 구현하는 모양인데, C++에서 기계어를 고치고 있을 수는 없는 것 아닌가.. 상상만 해도 우울하다.
더 보기 “C++ Native AOP의 가능성.”
표준의 규모. 작은 것이 맞는가? 큰 것이 맞는가?
한국MS의 어줍잖은 변증법 via Channy’s blog
당신은 무엇 때문에 기술표준을 따르나 via 서명덕기자의 人터넷세상
이 두가지 포스팅을 읽던 중, 눈에 들어온 것이 하나 있었다. 한국MS의 ODF(Open Document Format)에 한 반론중, OpenXML은 “크지만 안정적” 이고, ODF는 “간결하지만 지속적으로 규모가 증가” 한다는 이야기인데, 표준의 규모에 대한 생각이 문득 들었다.
물론, 무엇에 관한 표준인지, 무엇을 담고 있는 표준인지가 중요하겠지만, 내 생각에 표준은 작고 간결해야한다. 표준이 크고 복잡하면 복잡할 수록 구현은 힘들어지고, 고려할 사항이 복잡해지기 때문이다. 그리고, 복잡할 수록 재사용이 난감해지는 경향이 있다. 작고 간결한 여러 종류의 (다른 기능적인) 표준이 존재하고 서로 의존적인 관계를 갖고 있다고 하면, 원하는 결과물을 얻기 위해 표준을 섞는 일이 가능해진다. 다른 표준에 의존할 수 있는 것은 의존하는 것이 맞다. 예를 들어, XHTML에 벡터그래픽에 대한 요구사항이 커졌다고 해서, XHTML 3.0에 벡터그래픽요소를 정의할 필요는 없다. XHTML 1.0문서와 SVG문서를 섞어서 사용하는 것만으로 충분히 구현이 가능하기 때문이다.
작고 간결한 표준은, 해당 표준을 준수하는 처리기processor 나 구현체implementation를 만드는데 필요한 리소스를 줄이는 데에도 큰 역할을 할 수 있다. 그리고, 리소스가 줄어든다고 하는 것은, 해당 표준에 대한 오픈소스 처리기/구현체의 증가를 의미하기도 하며, 좋은 참조구현reference implementation의 등장을 의미한다. XML이 지금보다 훨씬 복잡하고 잡다한 내용을 전부 담고있는 표준이었다고 생각해보자. 지금처럼 히트칠 수 는 없었을 것이다.
OOP(객체 지향 프로그래밍: Object Oriented Programming)적인 관점에서 바라본다면, 표준은 일종의 클래스class라고 할 수 있다. 생각해보자, 거대하면서 모든 일을 혼자 다 해치우는 클래스 하나가 좋은지, 자기 할일만 제대로 해내는 (그리고 변경하기 쉬운) 작은 클래스 여럿으로 구성되는 것이 좋은지. 답은 명확하다. 할 수 있는 한, 클래스는 작아야한다. 표준도 마찬가지다. 가능한 작아야한다. 원하는 기능이 다른 표준에 정의되어 있다면, 가져다 쓰는 것이 맞다. 굳이 여러번 정의할 필요는 없는거다.
표준. 작고 간결해야 표준으로서 가치를 갖게 되리라 믿는다. 정의가 존재한다면…
ps. 무려 1달하고도 9일만의 포스팅.. 덜덜.
표준안을 지키잣!
이전까지 쓰던 STLPort는 5.0.1이었습니다. 뭐 큰 문제도 없고 해서 그냥그냥 쓰고 있었는데, 5.1.0이 나온걸 보고 업그레이드를 결심. 다운로드후 컴파일하고 프로젝트의 세팅을 전부 변경한 뒤에, 빌드를 시작했지요. (시켜놓고 회식갔다가 오늘 아침에 봤습니다.)
빌드에 오류가 났습니다. 흐음. 5.0.1에서는 오류가 없었는데, 5.1.0에서는 오류가 발생하는군요. 이럴땐, STLPort가 문제일 가능성이 크다고 판단, 오류로그를 뒤지기 시작했습니다.
stlport/stl/_algo.c(130) 에서 오류가 발생하는군요. 에러내역은 다음과 같습니다.
error C2512: ‘SCT::stdex::view_iterator
‘ : 사용할 수 있는 적절한 기본 생성자가 없습니다.
SCT::stdex::view_iterator
STLPort 5.0.1의 소스코드
template <class _ForwardIter1, class _ForwardIter2> _ForwardIter1 search(_ForwardIter1 __first1, _ForwardIter1 __last1, _ForwardIter2 __first2, _ForwardIter2 __last2) { (.... 생략 ....) // 다른 부분!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! _ForwardIter1 __current = __first1; while (__first1 != __last1) { __first1 = find(__first1, __last1, *__first2); if (__first1 == __last1) return __last1; _ForwardIter2 __p = __p1; __current = __first1; if (++__current == __last1) return __last1; (.... 생략 ....) }
STLPort 5.1.0의 소스코드
template <class _ForwardIter1, class _ForwardIter2> _ForwardIter1 search(_ForwardIter1 __first1, _ForwardIter1 __last1, _ForwardIter2 __first2, _ForwardIter2 __last2) { (.... 생략 ....) // 다른 부분!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! _ForwardIter1 __current;// = __first1; while (__first1 != __last1) { __first1 = find(__first1, __last1, *__first2); if (__first1 == __last1) return __last1; _ForwardIter2 __p = __p1; __current = __first1; if (++__current == __last1) return __last1; (.... 생략 ....) }
STLPort 5.1.0
거의 같고 딱 1부분이 다른거 같습니다. 5.0.1은 __current에 __first1을 대입 하고있고, 5.1.0은 대입 하고있지 않습니다. (그것도 주석처리 되어있지요.)
이유는 28번 라인에서 언제나 __current는 __first1으로 업데이트가 되기때문에, 굳이 처음 생성시 __current에 __first1을 대입시켜줄 필요가 없지요. 이런 이유로 불필요한 작동을 줄이고자 주석처리를 해둔 것이라고 생각됩니다.
view_iterator에는 기본 생성자에 만들어줘야하는지, STLPort 코드를 수정해야할지를 고민하다가, C++표준안(정확히는 97년에 나온 드래프트)을 뒤적거려보니 Forward Iterator는 예측 불가능한 값을 갖는 Iterator를 생성하는 기본 생성자를 갖고 있어야 한답니다. view_iterator는 Random Access Iterator이고, Forward Iterator의 특성을 물려받으므로, 기본 생성자가 있어야 하는군요. 그래서 추가해줬습니다. (그리고, 배를 쨌습니다. 이상한 값을 갖는게 맞다잖아요. 무슨 결과가 나오든 전 모름 @_@)
당황해서 시간을 좀 낭비했는데… 역시 표준안을 숙지하고 미리미리 지켜주는게 인생 편하게 코딩하는 방법인가 봅니다. 에헤.
ps. view_iterator는 별 코드에 다 집어넣고 요상한 알고리즘과도 빙빙 돌려제끼는 반복자인데… 이번이 처음이었습니다.. 이럴줄은.. ;ㅁ;
어머나. 소스코드를 복사하다니! 다음 vs. 네이버
뒷북을 울려라~ 이히~ 둥둥둥~
하드코어모드로 끝간데 없이 달리는 회사일정에 때맞추어 열린 World of warcraft: Burning Crusade의 흥미진진한 새로운 세상에다가 활동을 재개한 밴드일정으로 정신이 하나도 없는 까막군에게 심심함을 덜어주는 포스팅거리가 생겼으니 뒷북을 울려라~!
사건의 요지는 다음에서 만든 자바스크립트 소스를 네이버에서 홀랑 베껴다 써먹었다는 훈훈한 이야기입니다. 출처는 스마트플레이스. 덕분에 읽을만한 블로그를 찾았군요. (처음에 어디서 봤는지는 기억이 -_- ZDNet이었나..)
여하튼, C++을 이용해 패키지를 만드는 업체에 근무하는 저로서는 상상하기 힘든 일입니다. 저희팀에선 External Copy & Paste가 드물거든요. (회사 내부코드에선 간간히 있지만..)
일단은 스펙(프로토콜 문서 혹은 인코딩 문서)이 공개되어있는 경우에는 스펙보고 코드를 만들면 그만이고, 스펙이 안나와있으면, 코드도 없기 마련인지라.. 하핫. 외부 코드를 가져와서 사용할때는 라이센스를 면밀히 살피죠. 나중에 문제될까봐. (그래서 남은건 boost, ACE, STLPort 정도이군요..)
심지어는 C++ 개발자들이 많이 보는 Code Guru같은 사이트에 올라온 코드들도 무용지물인 경우가 많습니다. MFC를 배제하는게 기본 원칙인데 MFC코드가 많거든요. MFC코드를 배제하더라도 네이밍규칙같은 것에 위배되는게 많아서 고쳐쓰려면 결국 코드를 다시 작성하는거나 다름 없답니다. (고쳐쓰느니 그냥 짜고 말죠.) 그리고, 이해하지 못하면 유지보수가 불가능한데 이해를 하다보면 그냥 짜는게 깔끔한 코드를 만드는 지름길인지라..
서비스를 만드는 환경과 패키지를 만드는 환경의 차이일까요?
어느쪽이나 시간압박은 비슷하고, 주어지는 외부 압력도 유사합니다. (큰 차이는 모르겠군요.) 아마 개발자 자신의 자세가 문제였을거란 생각이 드네요. 소프트웨어 프로그래밍을 예술로 생각하고, 장인정신이 없는 코딩은 스스로 만족하지 못해 몸을 빌빌 꼬는 제 입장에서 볼 때 말입니다. (모로가도 돌아가기만 하면 된다. 오픈만 빨리하면 된다. 라고 생각하시는 일부 혹은 대다수의 어떤분들과는 매우 사이가 안좋아질 가능성이 농후한거죠.)
자신의 코드에 애착을 갖고, 자신의 작업 결과물에 자부심을 느끼며, 그 성과물로 인정을 받는 정직한 소프트웨어 엔지니어가 많아지기를 기도하며, 뒷북울리기를 그만 할랍니다. (5분 쉬었으니 이제 다시 일하러.. ;ㅁ;)
ps2. 아 편집하다 날아간 내용이 있어서.. Daum과 Naver양사 모두 CCL을 위반한 케이스가 됩니다만(문제의 라이브러리), 문제가 되는 flexInput은 Naver가 Daum코드를 가져다 쓴게 맞는듯 합니다. 냐앙.
BabelFish놀이.
알타비스타의 번역 서비스인 바벨피쉬 를 이용해 문장을 돌려 번역해보면 재밌는 문구가 나옵니다. 한국어 -> 영어 -> 네덜란드어 -> 영어 -> 독일어 -> 프랑스어 -> 영어 -> 일본어 -> 한국어.. 대충 이런식으로 돌려서 번역해 보는 거지요.
원래 언어로 돌아와보면 참 재밌는 결과가 나옵니다. 간만에 생각나서 해봤습니다. ㅋ
x-like
- generic programming
- In computer science, generics is a technique that allows one value to take different datatypes (so-called polymorphism) as long as certain contracts such as subtypes and signature are kept. The programming style emphasizing use of this technique is called generic programming. – via wikipedia
사실, Generic Programming(이하 GP)은 C++이나 Java, C#등의 타입이 중요한 언어에서 로직의 타입에 대한 종속성을 줄이기 위해 유용하게 사용될 법한 기법이다. 그래서 저 말이 유용하게 들린다. 하지만, 막상 문서를 작성하다보면 머리가 좀 아플때가 있다.
C++을 주로 사용하기 때문에, C++을 예로 들면, process_event라는 메소드를 정의한 객체를 매개형식으로 받아야 오류가 발생하지 않습니다. 라는 말을 하고 싶은데 저 말을 딱히 줄여서 간단하게 쓸 방법이 도무지 떠오르질 않았었다. GP가 아니라 Object-Oriented Programming(이하 OOP)였다면 저런 경우 상위클래스를 뽑아놓고, 상위클래스의 포인터를 받는다고 써주면 되기 때문에 큰 문제가 발생하지 않지만, 다형성(polymorphism)을 GP를 이용해 구현하기로 했다면, 적절한 용어가 없어서 고민하게 된다.
이런 일로, 어떻게 써줘야하나 고민하고 있었는데, 불현듯 전에 잠깐 공부하던 pygame의 문서가 생각났다. 가장 인상적이었던 표현은 바로 rect-like object였는데, (top, left, width, height)의 튜플형태로 evaluate되는 모든 객체를 의미하는 거였다. 즉, 진짜로 저런 튜플을 넘겨주거나, 저런 튜플로 할 수 있는 연산을 미리 정의한 클래스라면 상관없다는 이야기. 즉, X-like 였던거다. X이거나 X와 동일하게 컴파일/실행 될 수 있는 타입!
iterator-like, int-like, short-like, stream-like등 활용예가 많아졌다. 🙂 – 위에서 예로 들었던 process_event를 정의한 객체같은 경우는 state machine-like가 되시겠다. –
여기까지 생각하다가 좀 더 생각이 나갔는데, GP는 말이 좀 어렵지 않나라는 생각이 들었다. 타입을 중시하는 언어에서나 적용될 법한 개념이기도 하니 말이다. x-like programming. 뭔가 좀 명확해보이긴 하나 역시 모호하긴 매한가지라는 생각도 들었다.
이젠 x-like라는 말로 간단하게 문서를 정리할 수 있을 것 같다.
ps1. STL같은 경우는 매개변수의 이름을 통해서 정리를 해주는 경향이 있다. iterator 혹은 그와 동일하게 evaluate되는 타입일 경우는 IteratorT와 같은 형태로 많이 쓴다. InputIteratorT, OutputIteratorT.
ps2. Boost MPL에서는 Concept이란 용어도 사용한다. 하지만, 그 컨셉에 맞는 객체를 표현하는 용어는 딱히 정해진게 없는 듯 하다.