|
|
소개
음 패턴이야기 3번째네요. 아래 UML은 staruml을 이용해서 작성했습니다.
어떤 주어진일을 하는 프로그램을 만든다고 가정해보자. 일반적으로 하나의 함수를 이용하는 것보다는 가능한 분할을 해서 여러개의 서브함수를 만드는 방식을 선호한다. 이렇게 할경우 디버깅, 유지보수, 코드관리가 수월해지기 때문이다.
그러나 여러개의 서브함수를 두게 될 경우에는 이들을 다루기가 지나치게 복잡해지는 경우가 발생할 수 있다. socket프로그램을 예로 들어보자면, 하나의 endpoint 소켓을 만들기 위해서는 socket(2)-> bind(2)-> listen(2) 의 과정을 거쳐야 한다. 이때 이들 함수를 호출하는 개발자는 단순히 호출만 하는게 아니라 에러처리를 위해서 각각의 리턴값을 검사하는 코드도 신경써야 한다.
facade pattern을 이용하면, 이러한 과정을 숨기고 개발자에게는 단순한 Interface만을 제공할 수 있다. 제품을
만드는 공장으로 치자면, 여러개의 컨테이너 벨트로 나뉘어진 공정을 하나로 통일 시키는 거라고나 할 수 있겠다.
공정 1 : 3번의 입력, 즉 3개의 Interface가 필요하다. +--------+ -->| belt 1 |--+ +--------+ | | +--------+ | +--| belt 2 |<-+ | +--------+ | | +--------+ +->| belt 3 |--> +--------+ 공정 2 : 1번의 입력, 즉 1개의 Interface만을 가진다. +--------+ +--------+ +--------+ -->| belt 1 |-| belt 2 |-| belt 3 |--> +--------+ +--------+ +--------+
C++
아래는 컴퓨터를 가동하는 간단한 시뮬레이션 프로그램이다. 컴퓨터를 가동하기 위해서는 CPU, Memory, HardDisk를
순서에 맞게 제어를 해야 한다. facade 패턴을 이용하면, 이러한 과정을 숨길 수 있다. 프로그래머는 다른 것에 신경쓸
필요없이 startComputer메서드만 호출하면 된다.
#include <iostream> using namespace std; #define BOOT_ADDRESS 0x11 #define BOOT_SECTOR 0x18 #define SECTOR_SIZE 0x80 class CPU { public: void freeze() {cout <<"Freeze" << endl;} void jump(unsigned int pos){ cout << "Position " << pos << endl; } void execute(){cout << "EXECUTE" << endl;} }; class Memory { public: void load(unsigned int pos, char *data) { cout << "Memory Load" << pos << endl; } }; class HardDrive { public: char * read(long lba, int size) { } }; // Facade class Computer { public: void startComputer() { CPU cpu; Memory memory; HardDrive harddrive; cpu.freeze(); memory.load(BOOT_ADDRESS, harddrive.read(BOOT_SECTOR, SECTOR_SIZE)); cpu.jump(BOOT_ADDRESS); cpu.execute(); } }; int main() { Computer facade; facade.startComputer(); }
할일 :::

음 패턴쪽 공부겸해서 정리하고 있거든요. 대략 아래의 형식으로 정리해볼 생각이에요. 괜찮아 보이나요?
Factory Method Pattern
일반적인 상황
아시다 시피 factory는 공장을 의미한다. 공장패턴? 이 패턴은 공장의 작동방식을 생각해보면 어렵잖게 이해할 수 있는 패턴이다. 소프트웨어 개발이 아닌 영역에도 널리 쓰이는 패턴이다.
공장은 필요한 자원과 설비를 갖추고 있으며, 이들 자원과 설비를 이용해서 특정한 객체를
생산할 수 있는 시설이다. 만약에 오토바이를 만드는 공장이라고 하면, 이 공장은 단일 브랜드의 오토바이만 생산해내지는 않을
것이다. 그렇게 공장을 설계할리도 없을 것이다. 분명히 다양한 배기통 다양한 용도의 오토바이를 생산해낼 수 있게끔 설계가 되어
있다.
이렇게 해서 얻을 수 있는 잇점은 여러개의 비슷한 공정을 가지는 시설을 여러개 가지고 있을 필요가 없다는 점이 될 것이다. 스위치만을 이용해서 비교적 간단하게 다양한 제품을 생산할 수 있다. 이를 소프트웨어에 그대로 응용한게 factory pattern이다.
상황극
- 문 : 그래요. 알았으니 factory pattern의 현실적 예를 좀 들어주세요. 아무래도 이해가 좀.
- 답 : 어떤 제품을 만든다고 하면, 파생되는 제품이 있을거에요. 이 제품이 공장에서 만들어진다면, 파생되는 제품까지를 하나의 공장에서 생산해낼 수 있도록 해야 겠죠 ?
- 문 : 그런가요 ?
- 답 : 그렇죠. 파생 제품이라는게 동일한 자원과 설비를 필요로 할거잖아요. 공정만 약간 다른 식이죠. 그렇다면, 하나의
공장에서 여러개의 공정을 수행할 수 있도록 범용가능하게 만드는게 훨씬 이익이죠. 비슷한 공장을 2-3개씩 만들면 엄청난 낭비
아니겠어요 ?
- 문 : 음 그렇겠군요. 오토바이 공장이라면, 오토바이에서 파생되는게 제품이 스쿠터, 소형, 중형, 중대형 그리고 목적에
따라 여러가지가 만들어진다고 했을 때 스위치 조작정도로 여러개의 제품을 생산해낼 수 있도록 한다 뭐 그런거네요 ?
- 답 : 네 맞아요.
- 문 : 음. 객체지향 프로그래밍으로 보자면 class motocycle 가 만들어지고, 여기에서 상속되어서 cycle200cc, cycle300cc, batcar, roadrunner 클래스가 생성되는 형태겠군요.
- 답 : 네. 아주 좋은 예인거 같네요. 더불어 엔진,프레임,조립등의 메서드들을 가상함수로 만들어서 상속된 클래스에서 구현하도록 할 수 있겠죠. 또한 병렬처리하는데에도 유용하겠죠 ? 한라인에서는 cycle200cc를 만들고 다른 라인에서는 cycle300cc를 만드는 등으로 말이죠.
- 문 : (약간 우쭐해졌음) factory fattern 이라는 것도 그리 어려운건 아니군요.
- 답 : 네. 일상생활에서 흔히 경험할 수 있는 것들이에요. 이름을 붙이고 붙이지 않는게 그래서 중요하죠. 체계적으로 정리하고, 효율적으로 소통할 수 있도록 도와주니까요.
- 문 : 그렇겠네요. factory fattern을 위해서 구구절절하게 설명하는 것보다. 패턴의 의미를 알고 있다면, 훨씬 간단하게 의사소통이 가능하겠군요.
활용
- 팩토리 패턴은 툴킷이나 프레임워크의 라이브러리에서, 주어지는 인자에 따라서 다른 객체를 생성해서 넘겨주고자 할때 사용할 수 있다.
사용예
Image Reader를 위한 클래스를 만드는 경우를 생각해보자. 이 클래스는 여러가지 이미지를 읽을 수 있어야 할 것이다.
그렇다면, 이미지 타입을 인자로 받아들이고 해당 이미지를 처리할 수 있는 객체를 생성해서 리턴할 수 있을 것이다.
#include <iostream> #include <stdio.h> #define GIF 1 #define JPG 2 #define PNG 3 using namespace std; class ImageReader { public: virtual void decode() = 0; }; class GIFReader: public ImageReader { public : void decode() {cout << "GifReader RUN" << endl;} }; class JPGReader: public ImageReader { public : void decode() {cout << "JPGReader RUN" << endl;} }; class PNGReader: public ImageReader { public : void decode() {cout << "PNGReader RUN" << endl;} }; class ImageReaderFactory { private: int ImageType; public: void setImageType(int type) { ImageType = type; } ImageReader* getImageReader(int type) { setImageType(type); switch(type) { case GIF: return new GIFReader(); case JPG: return new JPGReader(); case PNG: return new JPGReader(); default: break; } } }; // 테스트용 Main 코드 int main(int argc, char **argv) { ImageReaderFactory * myReaderFactory; ImageReader *myReader; myReaderFactory = new ImageReaderFactory; myReader = myReaderFactory->getImageReader(PNG); myReader->decode(); }
:::

프로테스탄트 윤리와 자본주의 정신을 읽고
산업자본시대의 노동
노동생산성을 높이기 위해서 과학적 노동관리기법을 체계화 시킨분이 테일러라는 사람이야. 핵심은 성과급과 과업할당. 이 분은
1870년대쯤에 철강회사에서 일하던 엔지니어였는데, 당시만 하더라도 노동생산성을 높이기 위한 체계적인 업무관리 방법이라는게
없었다는군. 거기다가 필요에 따른 자유로운 노동을 하다가 올라온 시골청년들이 하루종일 의자에 앉아서 왜 필요한지도 모르는 일을
끊임없이 해낼리도 없을테고.
이를테면 인도나 중국시골출신 노동자를 고용한 업체사장들이 정말 쟤들은 게을러 터져서일을
도대체 시켜먹을 수가 없다고 투덜대는 그런 모양새지. 뭐 그때는 대부분의 노동자가 그러했던 시대라는 것이지. 이때까지만 해도
사람들이 덜 기계화 되었거든. 더 많은 소비를 위해서 더 많은 부를 축적해야 되겠다 요런 자본주의적 마인드도 아직 자리를 잡지
못했고. 얘들은 마인드가 생산을 위한 노동이였지, 소비를 위한 노동이 아니였어. 요새는 소비 - 사실 별 쓸데도 없는 - 를
위해서 노동을 하잖아 ? 카드인생이라는 것이 결국은 현재를 담보로 소비하는 행위고. 이거 여러모로 좀 위험하지.
 귀가하는 노동자들 - 몽크 그
러니, 태업이 일상다반사. 술이 진탕이 되어서 컨디션 안좋다고 출근 않기, 일하다 말고 기분 꿀꿀하다고 그냥 집에 들어가
버리기, 친구만나러 간다고 했다가 술집가기. 지금에서야 상상도 안될거 같지만, 근대이전의 농부들의 생활 방식을 곰곰히 생각해보면
이해가 된다. 일끝내고 동네 술집가서 술진탕되도록 마시고 다음날 컨디션이 대략 좋지 않다치면 안나가면 되는거잖아. 누가 뭐라고
그러겠어 ? 그냥 하루 뒹굴뒹굴 하면서 노는 거지. 농사일이라는게 그렇다보니 뭐 일년의 절반 이상이 노는 날이고, 툭하면
일주일씩 가는 축제고. 생각대로 하면되고라는 광고카피가 일상화된 정말 살기 좋은? 시대였다는 거지. 빈곤의 문제만 해결되는 수준에서 저러한 삶을 살 수 있다면 정말 좋은 세상 아니겠어 ?
여튼 이런 생활을 하던 얘들이 자본이 필요로 하는 생산력을 제공할 수 없을 거란건 당연하지.
그래서, 이걸 보다못한 테일러님이 노동생산성 향상을 위한 관리기법을 만들기로 하신거야. 그러니까 요즘말로 성실하게 일잘하며, 돈의 가치를 중요시하는 얘를 셈플로 골라내어서, 일정수준의 업무를 달성하면, 70%정도의 돈을 더 주겠다고 꼬득인거야. 여기에 일정수준의 업무가 어느정도인지 계산하기 위한 방법을 만들었고. 예컨데 삽질도 과학입니다 라는 카피가 만들어진거지. 하루에 몇시간을 일하고, 쉬는 시간을 몇시로하고 그에따라서 성과급을 얼마나 주고 승진에 어떤 이익을 주고 뭐 그런 관리방법의 체계화. 관리방법의 체계화라는 것은 자본가들 듣기 좋아라고 하는 소리고 예술적으로 부려먹는 방법을 체계화 시켰다라고 보면 되지.
이렇게 해서 나온게 노동 생산성 즉 단위 노동자당 뽑아낼 수 있는 돈의 양이라는 개념이 만들어진거지 머.
핵심은 task, differential piece rate 관리만을 위한 조직 즉 기획부의 운용 기능별 직장제 등등등.. 이고, 그냥 업무관리의 표준이 되잖아. 그냥 지금 다니고 있는 회사에서 업무가 어떻게 관리되고 있는지를 살펴보라고.
물론 얘도 단점이 없는게 아니지. 아무리 부려먹기 좋다고 해도 인간은 기계가 아니잖아. 근데, 인간을 기계처럼 부려먹을려고 하니
부작용이 발생할 수 밖에 없지. 이런저런 복잡한 심리적인 문제로 인한 생산성의 하락 같은 문제라던가. 생산성이 높아짐에 따른
역효과들 즉 잉여노동자과 그로인한 임금수준의 하락 이라든지 등등등.
전자의 문제를 해결하기 위해 인간의 심리도 고려하는 관리기법이 도입되었고, 후자의 문제는 잉여 생산을 소비를 통해서 해결하자라는 포드주의로 해결을 하고, 대충 그런식으로 땜빵을 했지.
특히 포드주의를 이용한 땜빵은 아주 악질적인 경우에 속하지. 컨터이너벨트를 만들고 여기에 노동자를 줄 세워놓고 - 그리고 막상 그다지 필요없는 - 소비의
장려를 통한 자본체제로의 자발적인 예속을 끌어냄으로써, 성장이 보장되는 세계를 만드신 거거든. 최신의 트랜드를 따라가는 미디어
플레이어를 사기 위해서, 최저임금 수준에도 미치지 못하는 임금을 받으면서도 자발적으로 노동을 감내하는 인류를 만들어내신거야.
지금에 와서 이러한 땜빵 처방에 따른 성장이 한계에 다다르니, 이에 위기를 느낀 자본이 만들어낸게 신자유주의라는 것이고. 자본에 있어서 국경을 없애서 저개발국가의 노동을 값싸게 착취해서 기존의 성장을 계속 이어나간다는게 신자유주의의 핵심이잖아. 뭐 걔들이야 온갖 미사어구로 치장을 하지만, 자본 만 자유롭게 이동가능하고 노동은 그렇지 않은 상황에서 결과는 뻔히 예상되지. 3세계 각국에서 벌어지고 있는 국제자본에 의한 어린이 노동 착취관련 정보들을 한번 찾아보길 바래. 나쁜 사마리아인들 이라든가 노암 촘스키의 책들을 권장하는 바이야.
신자유주의는 자본을 이용한 제국주의 건설 이라고나 할수 있을거야. 우석훈씨가 대한민국을 되먹지 못한 제국주의라고 말했던 것도
이런 이유 때문인거지. 19세기에서 20세기까지를 군사적 제국주의에 의해 수탈을 당했던 나라가, 이제 좀 아주 약간 살게되었다고
자본을 이용해서 수탈하는 대열에 참여하겠다는 발상. 바로 FTA를 이용해서. 아마 FTA에 찬성하는 사람들 중 상당수가 신자유주의는 필연이고, 그럴바에는 주도적입장 즉 착취자의 입장을 취하게 된다면 우리에게 이익이 될것이라는 생각때문일걸 ?
걔들 주장이 그렇잖아. FTA는 미국하고만 하는게 아니니까. 미국에서 손해를 보더라도 다른 더 많은 저개발 국가와의 FTA를
통해서 더 큰 이득을 볼 수 있을 것이다. 국익을 위해서라면 전쟁과 착취도 불사한다. 제국주의도 알고보면 별거 아니지 싶어.
안타깝게도 우리의 2MB정권은 그나마도 해내지 못할거 같긴해. 가만히 생각해보면 얘들은 아무래도 먹튀이지 라는 결론말고는 뭐
도출되는게 없어.
XP
테일러식 노동방식은 그 자체로의 한계도 가지고 있지만 비교적 최근 등장한 산업인 소프트웨어 분야에 있어서도 분명한 한계를 보여. task의 시간관리와 분업 이를 지원하기 위해서 만들어진 산물인 컨테이너벨트와 소비를 위한 노동을 통한 대량생산 대량소비의 포드주의가 적용되기는 힘든 산업이잖아.
소프트웨어에서 반자본주의적,좌파적 성향의 오픈소스운동, 자유소프트웨어 운동등이 생겨난 것도 이러한 산업의 특성 때문 아닐까 ?
이러한 기존의 노동관리 방식의 한계를 극복하기 위해서 만들어진게 e Xtreame Programming 일거라고 나는 생각해.
XP를 도입하려는 많은 기업이 XP의 개념은 그럴싸한데, 막상 적용시키려면 많은 어려움이 따르고 왠지 빛좋은 개살구처럼 보인다 라는 평가하잖아. 근데 가만히 살펴보면 실패한 많은 경우의 공통점은 대규모 프로젝트라는 거야. 근본적으로 XP는 대량의 에너지와 인력이 투입되는 대량생산 대량소비적 마인드를 지원하기 위한 조직에는 맞지를 않아. 그런맥락에서 대규모 프로젝트에 성공적인 XP사례가 없으니 XP는 병진이라 평가를 내리는 것은 맥을 한참이나 잘못 짚은 것이지 싶다.
XP는 대략 훑어보면 알겠지만 작은 사이클의 작지만 필요한 제품을 만들어내는 산업을 잘 지원하도록 되어있는데, 어찌보면 근대 이전의 수공업과 비슷하다고나 할까. 그런거야. 수공업의 특징은 장인에게 더 많은 권한이 주어지잖아.
고객과 상당히 대등한 관계로 만들어낼 것에 대해서 많은 얘기를 한다거나 중간중간 결과를 고객에게 보여주기도 하고, 수정해주기도
하고. 왕인 고객 앞에서는 노예만도 못한 짓을 강요당하는 노동자들이 꽤나 있는 거에 비하면, 그당시 고객은 그냥 고객일
뿐이였지. 예전에 호텔관리를 주제로하는 드라마를 본적이 있었는데, 종업원에 대해서 아주 명백히 고객이 잘못했는데도 불구하고
고객에게 용서를 구하라고 하는 거야. 인간의 자존심조차도 보장받을 생각을 하지 마라 이런거지 머. 언제부터 고객이 왕이 되었을까
? 이런생활이 좋을까 ? 자신도 다른 고객 앞에서 노예취급당할 수 있을 거란 생각은 못하는거 같어.
얘기가 셌는데 XP가 내세우는 가치 중에 개발자에게 많은 권한, 좀더 인간지향적인, 짧은 사이클, 대화
요런것들이 포함되어 있지. 수공업시대에 장인대우 해주는 거랑 좀 비슷해. 짧은 사이클내에서 자신이 직접 필요한 테스트를 하고,
함께 코드를 본다는 것은 즉 해당 팀에서 내가 단지 기계부품이 아닌 좀더 중요한 역할을 하고 있다라는 느낌을 가지게 만들어준다.
뭐, 그렇다고 해서 XP가 기존 수공업에서의 장인들과 같은 동일한 모델을 따르는 건 절대 아니지. 기존의 테일러식 방식보다는 분명히 인간지향적인 측면이 있기는 하지만, 소프트웨어 개발업체도 자본주의 체제에 편입되어 있는 이상 노동생산성을 올리는데 충실해야될 필요가 있기 때문이야. 일단 주주들이 뱁새눈을 뜨고 쳐다보고 있으니까.
수공업시대의 장인들과 같을 수 없는 이유는 장인이 자본의 입장에서는 있어서는 안되는
껄끄러운 존재이기 때문이야. 예를들어 자본을 들여서 식당을 차렸다고 가정해보자고. 그리고 엄청 요리를 잘하는 요리사를 고용했어.
이 요리사는 자신만의 요리 노하우를 가지고 있겠지 ? 이건 도제식으로 자신이 찜한 제자에게만 전승되는 거야. 이 요리사의 맛있는
요리 덕분에 장사가 잘 된다고 하면 이 요리사는 고용주와 동일한 권한을 가지게 될 게야. 대체할 수가 없잖아. 자기의 뜻대로
움직여주지 않을 뿐더러, 최악의 경우 "임금을 올려주지 않으면 나가겄소"할 수도 있는 문제가 생길 수도 있고. 돈주고 고용한
얘랑 동등한 입장에서 인간적인 대우를 해줘야 하다니, 얼마나 짜증이 나겠어.
숙련된 노동자가 생겨나면 어디에서든지 발생할 수 있는 문제들이야. 테일러는 이 문제를 메뉴얼을
이용해서 해결을 한거고. 그러니까 "삽질할때 지름과 깊이는 몇 cm로 할것인지, 각도는 어떻게하고, 각각의 단계에서 어떤 삽을
쓰고, 몇분 일하고 몇분쉴것인지, 협업의 방식, 관리및 평가 방법"을 몽땅 문서로 정리해버린거지. 비밀은 없다. 메뉴얼을 읽고
이해할 수 있을 정도의 사람이라면, 최소한의 교육으로 바로 현장에 투입될 수 있다. 이렇게 해서 노동자는 원래 자본가의 의도대로
언제든지 대체가능한 부속으로 전락되어 버렸어. T.T ? 이러한 상황을 타개하기 위해서 노동자는 노동조합이라는 집단을 만들어낸거고. 개인이 돈과 권력을 가진 자본과 싸우는건 한계가 있으니깐.
그러하니, XP가 아무리 개발자를 존중해준다고 해서 개발자가 장인의 역할을 하도록 내버려두진 않을건 당연하지. 그래서 오히려
XP시대에 개발자 메뉴얼, 문서화가 중요해지는 거고. 자본의 당연한 속성이라고 하면 너무 비정하게 들릴려나.
하지만 그렇다고 하더라도 XP와 같은 새로운 패러다임의 노동방식이 기존의 방식보다 (노동자의 관점)에서 진일보 한것은 분명한 사실이니, 여기에서 위안을 삼을 수 있을 것 같어. 주식회사 google이 개발자들에게 환영받는 이유는 이러한 새로운 좀더 인간적인 노동방식의 테스트와 도입에 적극적이기 때문이 아닐까 ? 난 그렇게 보거든. 빵이랑 밥 공짜로 주는것 때문에 구글만세를 외칠거라고 보는건 너무 단순한 생각인거지.
음.. 언제 구글의 개발자 문화에 대해서도 나중에 한번 생각을 정리해봐야 겠네.
관련문서
:::

이것저것 잡다한 생각들의 향연...
최근들어 애자일관련 글들을 보면, 초반의 열렬한 환호의 단계를 지나서 이론은 좋은데 뭔가가 좀 허전하다?라는 류의 다소 비판적인 글들이 많아 진것 같다. 그 이유에 대해서 다시한번 곰곰히 생각해볼까 하다가, 우선은 애자일이 나오기전의 조직관리가 어떠했는지 되짚어보는 것도 좋을것 같아서 간단히 정리해보기로 했다.
우리가 사회에서 가장 흔하게 볼 수 있는 조직관리체계는 맥컬럼이라는 사람이 만들었다. 그러니까 사장밑에 부사장 있고, 그 밑에 부서별 장이 있고, 과장있고 일반사원이 있는 하향식의 Hierarchical(위계적)한 조직구성이다. 이러한 조직구성을 도표로 나타낸 것을 조직도(Organization Chart)라고 한다. 맥컬럼은 이 조직도를 처음으로 만들어낸 사람으로 인정되고 있다.
이 조직은 예를들어서, 각 장급이 6명의 팀원을 관리한다고 했을적에, 1300명의 사원이 있다면 3단계의 계층적 높이를 가지는
조직으로 만들어낼 수 있다. 사장 > 부사장 > 부장 하는 식이다. 아래는 조직도의 일반적인 형태이다.
이러한 조직구성은 이른바 birthday paradox라
는 문제를 해결하기 위한 목적에서 만들어졌다. birthday paradox를 간단히 설명하자면, 어떤 조직의 구성원이 많아질
수록 복잡도가 기하급수적으로 늘어나는 현상을 말한다. 이러한 문제는 흔히 네트워크 효과로 설명되어지기도 한다. 구성원이 1명에서
10명으로 늘어나면 복잡도는 10배가 아닌 팩토리얼하게 늘어나게 된다. 이런 얘기다.
birthday paradox는 50명의 구성원이 있을적에 생일이 같은 구성원이 있을 확률은 얼마인가라
는 문제에서 나왔다. 이게 언뜻 생각해보면 50/365인데, 이건 개인만을 기준으로 했을 경우이고, 제대로는 각각의 구성원에
대한 경우의 수가 모두 더해져야 하므로 실제 계산을 해보면 (대략)95%이상이라는 답이 나오게 된다. 구성원이 23명일 경우
50%정도가 된다. 심심하면 계산해 보기바란다, 여하튼지간에 조직의 구성원이 많아지면 경우의 수가 급수적으로 늘어나고 그만큼
복잡해진다는 얘기를 함축하고 있다.
회사조직으로 얘기를 해보자면, 조직의 규모가 늘어나면 관리비용이 수익을 초과해버리는 상황이 발생하게 되고, 이는 선형적이 아닌 급수적이다 이런 얘기가 되겠다.
맥컬럼 조직관리체계가 만들어진건, 미국의 철도운송시스템의 복잡도를 해결하기 위함이였다. 이론은 간단하다. 각 철도레일을 구간별로 명확하게 나누고, 구간을 관리할 장을 둬서 책임소재를 명확하게 하겠다는 거다. 지금 생각해보면, 아주 당연히 상식적인 관리방식이겠지만 당시로서는 아주 획기적인 관리 방식이였던것 같다.
실제 구간별 (업무별)로 조직을 나누고, 각 구간별로 관리자를 두어서 책임을 명확히 지우고, 각 장으로 하여금 수집된 정보를 요약정리해서 상위 장에게 보고한다라는 원칙은 현재 대부분의 조직에서 상식적으로 적용하는 내용이기도 하다.
이 방식이 매우 성공적이였음은 말할필요가 없을 것이다. 정부조직,기업조직은 물론이고 동아리, 동창회, 조기축구회와 같은 사조직까지 쓰이지 않는 곳이 없을 정도이니까 말이다.
물론 이 방식도 당근 문제가 발견되었다. 일정 규모이상을 넘어가면 관리비용이 조직이 만들어내는 수익을 초과하는 때가 온다는 것. 공기업이든 사기업이던지 간에 규모가 커지게 되면, 수익이 떨어진다는 얘기가 나오는 이유일 것이다.
이러한 한계를 가장 명확하게 보여줬던게, IMF 이전의 대기업의 행태였을 것이다. 대기업들은 맥컬럼 조직관리체계를 잘만 제어할
수 있다면, 항상 관리비용을 조직이 만들어내는 수익이하로 할 수 있을 거라고 생각을 했다. 관리비용이 수익보다 더 낮은
수준에서만 유지된다면, 사업을 벌이면 벌일 수록 더 큰 수익을 얻을 수 있을 거라고 자신했다. 그래서 나온게 문어발식 사업확장이시다.
.. 결국은 IMF를 계기로 망하거나 매각되거나 정리되었다. 부당거래, 비리, 방만한 운영이 그 원인이었다. 조직이 커지면
처리해야될 정보의 양이 많아지는데, 정보가 많으면 판단이 힘들어지는게 정보공학의 원칙이다. 그러다보면 비리, 방만한 운영등이
크게 문제가 되지 않는 상황이 발생해버린다. 판단자체가 힘들어지기 때문이다. 결국은 이게 조직관행이 되어버리는데, 이래서야
조직이 제대로 운영될리가 없을 것이다. 이게 내부러 부터 곪아 오다가 터진게 IMF인 거고.
또다른 문제는 조직이 커지면서 경성화된다는 거다. 하향식 정보전달이 이루어지는 조직에서 볼 수 있는 문제다.
말단 사원이 알고 있는 정보는 매우 제한적이라는 것. 계층마다 정보의 양과 질에 있어서 분명한 차이를 보인다는 것. 같은 계층이라고 하더라도 카테고리 (부서)가 다르면 정보를 알 수가 없다는 것.
이렇게 정보의 양과 질이 달라지니, 이걸로 계급이 나누어지게 되고, 결국 조직의 최상위 권자는 막강한 지위와 권한을 가지게 된다. 대기업 총수가 막강한 권력을 유지할 수 있는 이유일 것이다.
막강한 권력에는 그에 비례하는 책임이 따라야 하겠지만 이게 또한 그렇지도 않다. 왜냐하면 밑바닥의 실무자는 가지고 있는
정보자체가 없기 때문에, 발을 뺄수가 없기 때문이다. 좋은 변호사만 고용할 수 있고 거기에 약간의 권력만 가지고 있다면 명백해
보이는 범죄도 무죄로 만들 수 있는 것처럼, 많은 정보를 가지고 있는 윗분들은 정보를 변호사 삼아서 명백해 보이는 실수도
피해가거나 밑에 얘들에게 떠넘길 수 있게된다. 왜 안 좋은일이 생기면 깃털만 무수히 날리는 것일까.
또한 위계질서는 경쟁을 만들고, 계층간 정보교류를 어렵게 만든다. CEO는 모든 정보를 알고 있을 거라고 생각하지만 실은
각계층의 이익과 필요에 따라서 요약,왜곡,때때로 조작된 정보가 CEO엑 올라가는 일이 비일비재하다. 막상 CEO와 사원간의
대화가 전혀 안되는 이유가 여기에 있다. 국가 CEO라는 2MB와 국민간의 소통이 전혀 이루어지지 않는 이유도 설명된다.
이러한 상황에서 발생되는 조직문제가 나와 우리 조직만 잘되면 된다라는 부서간 이기주의와 괜히 문제 만들지 말자. 시키는 일만 잘하면 땡큐하는 복지부동이
다. 괜히 일 만들었다가 문제 생기면, 갈굼당하는건 일을 만든 당사자이다. 오픈소스를 도입하려고 해도 도입하지 못하는 이유가
"나중에 문제생기면 갈굼당하니까"인 것만 봐도 복지부동이 생기는 이유를 알 수 있다. 사실 일의 추진여부는 위에서 결정하는
것인데 말이다. 그렇다고 모든 책임이 위엣 사람들에게 지워지는 건 아니겠지만, 추진을 결정하기 위해서 서로 협력하고 협업하고
그에 걸맞는 책임을 지는 분위기가 조성되어 있다면, 설사 일이 실패했다고 하더라도 그걸 진정한 실패 볼 수 없을 것이다.
이렇게 경성화된 조직은 정보불평등, 업무에 대한 불만, 평가와 조직에 대한 불신을 키우게 된다. 덤으로 현대 정보화사회에서 가장
중요한 경쟁력중 하나라고 하는 창의력을 말살시킨다. 컨테이너 벨트에서의 노동자가 그러하듯이, 주어진일만을 똑소리나게 처리하는
사람으로 만들어낸다. 그냥 주어진 일만을 해야 하는 상황에서 창의력이 발휘될 수 있겠는가.
요러한 표준적인 맥컬럼 조직이 가지는 문제를 해결하기 위해서, (아마도)여러가지 시도가 있었을 거라 생각된다. 아마도를 붙여서 어물쩡 넘어가려는 이유는, 이에 대한 정보를 가지고 있지 않기 때문이다. 그렇다고 공부하기도 더 귀찮고. 나중에 시간이 되면 한번 고민해볼까라고 생각만 하는 중이다.
하지만 국내의 대기업의 조직이 나쁜방향으로 기존의 조직이 가지는 문제를 해결하려고 했던 것은 분명해 보이니, 이에 대해서 좀 얘기해볼까 한다.
전체주의국가, 독재국가가 체제의 비효율성과 문제점을 감추기 위해서 매체를 이용해서 선전하듯이 전체주의적인 기업역시 사원을
교육시키고 세뇌시킨다. 이러한 상명하복의 조직형태가 당연히 받아들여야 하는 운명적인 것이고 진실한 것이라고, 이때문에 발전을
했왔으며 앞으로의 발전을 약속해줄 것이라고, 이러한 조직에 소속된걸 자랑스러워 하라고.
조직문화를 근본적으로 바꾸는 대신에, 선전을 해서 조직에 순응하는 인간을 만들고자한다. 그 이유는 간단하다. 조직문화가 바뀌게
되면, 기업총수의 막강한 지배력을 잃어버릴지 모르기 때문이다. 앞에서 말했듯이, 기업총수의 막강한 지배력이라고 하는 것은 분명한
위계질서와 여기에서 생겨나는 정보의 독점인데, 조직을 연성화켜서 더 평등한 조직이 만들어진다면 정보장악력이 그만큼 떨어질 수
밖에 없기 때문이다.
게다가 군대는 이러한 상명하복식 조직체제에 쉽게 순응할 수 있는 인간을 만들어내기 위한 인재양성소의 역할을 성실히
수행하기도하니, 그런 인재를 찾아내고 만들어내는 것도 그닥 어렵지 않다. 최근 국방부의 불온서적 목록에 삼성왕국의 게릴라들 ![Aladdin:ISBN-9788901078618 [ISBN-9788901078618]](http://www.aladdin.co.kr/Cover/9788901078618_1.gif) 류의 책이 자본주의 체제를 부정한다는 이유로 포함된걸 보면, 기업에 봉사하는 정부와 군대라는 말이 헛말이 아니라는걸 느끼게 해준다. - 근데, 기업비리야 말로 자본주의 체제를 무너트리는 불온한 행위 아니던가 ? -
하지만 선동과 선전을 통한 정보의 조작과 왜곡만으로는 잘못된 조직이 가지는 문제를 완전히 해결할 수 없다. 관리비용이 들어가는
건 분명한 사실이고, 눈덩이 처럼 불어날게 뻔하기 때문이다. 불법증여, 분식회계, 탈세, 각종 로비에 들어가는 비용과 이들
조직을 관리하기 위함 엄청난 비용들..
이 비용을 줄이기 위한 방법은 두가지가 있을 것이다. 첫째는 조직을 바꾸어나가는 것, 둘째는 다른 곳의 이익을 가져와서 메꾸는
것. 첫번째 방법은 포기하신것 같고, 선택한게 두번째 방법인 것 같다. 방만하고 비효율적인 조직의 유지에서 만들어지는 비용을
메꾸려면, 추가적인 이득을 만들어서 메꾸어야 할 것이다. 그래서 나오는게 임금 노동자에 대한 착취아니겠는가. 예컨데, 분식회계, 탈세, 불법증여 아뭏든 각종 다양한 비리에 동원된 돈다발은 사실은 노동자의 몫이다. 그러다가 기업에 문제가 생기면, 고통분담차원에서 임금노동자만 대량으로 길거리에 나앉아야 한다.
이러한 조직은 그 수장이 신격화 된다는 특징도 가진다. 잘못은 밑에 사람들이 못난 탓이고, 잘된 것은 수장이 똑똑하고
잘나서이다. 잘난 사람 한두명이 조직 전체를 먹여살릴 거라는 막연한 믿음을 가지는 것도 같은 맥락에서 이해할 수 있을 것이다.
우리나라 기업의 진정한 문제는 이러한 조직체제를 21C 정보화시대에도 그대로 끌고가려고 한다는 점이고, 대기업 프랜들리한 정부가
이를 물심양면으로 지원한다는 점이다.
음.. 원래는 애자일을 설명하기 전단계로 현재 기업들의 일반적인 조직관리에 대해서 알아보려고 했는데, 얘기가 좀 옆으로 세어버린 것 같다.
결론은 기존의 조직관리체제는 딱딱하며, 창의력을 필요로 하는 정보산업에는 적당하지가 않다. 새로운 관리체계가 필요하다라는 얘기가 되겠다. 다음에는 새로운 세대의 새로운 관리체계로써의 애자일에 대한 새을 정리해 볼까 한다.
:::

시스템 관제
인터넷 서비스를 위해서 수백~수천대의 컴퓨터 시스템과 네트워크 장비를 관리한다면, 시스템 관제가 필수 적일 것이다. 일반적으로는 snmp와 MRTG를
이용해서, 관제를 하지만 이것으로는 기본적인 정보만을 얻을 수 있다. 나는 MRTG와 SNMP를 뛰어넘는 IT자원관리의 틀에서,
시스템/네트워크 환경의 정보를 수집하고, 분석하고, 이벤트를 발생시키고 Report까지 제공하는 시스템을 만들기를 원했다. 이
Report에는 과거/현재에 발생한 사건들에 대한 정보와 미래에 일어날 사건을 어느정도 예측할 수 있는데 도움을 주는
통계정보까지를 포함되어야 한다.
구조
기본 구성은 wiki와 zenoss를 이용한 시스템 이벤트 이력관리 시스템 구축문서를 참고하기 바란다.
zenoss는 Event기반의 매우 훌륭한 관제툴이지만, 통합 모니터링 환경을 제공하지는 않는다. 그래서 zenoss와 wiki기반의 통합관제툴을 만들기로 했다. zenoss는 시스템의 정보를 RRD형태로 저장을 하기 때문에, wiki에서 RRD 파일을 제어하는 모듈과 인터페이스 관련 모듈을 만든다면 어렵지 않게 통합 모니터링 환경을 만들 수 있으리라 생각했기 때문이다.
+---------+ +------------------+ | Zenoss | | WIKI | | | | | | | | | +--| | | | | +---------+ | | | +---------+ | +------------+ | +->| RRD |----|->| RRD macro | | +---------+ | +------------+ | | | +------------------+
- Zenoss가 수집한 시스템 정보는 Device/성능별 RRD파일로 저장이 된다. 즉 Device의 이름만 알면, 해당 시스템의 성능을 저장한 RRD 파일을 찾을 수 있고, RRD 파일로 부터 그래프를 그려낼 수 있다.
perf -+-- Device1 ---+-- CPU.rrd | | | +-- Disk.rrd | | | +-- Interface.rrd +-- Device2 ---+-- CPU.rrd | +-- Disk.rrd | +-- Interface.rrd
- RRD wiki macro는 시스템 이름의 디렉토리 밑에 있는 rrd 파일을 모두 읽어서, 이것을 그래프로 변경시켜준다.
- perf 디렉토리를 scan 하면, rrd 정보를 포함하고 있는 모든 시스템의 이름을 얻어올 수 있다. 이것을 이용해서 관리중인 장비정보를 보여주는 인터페이스를 제작한다. scandir()류의 함수를 이용하면 어렵지 않게 제작할 수 있다.
- 시스템 목록에서, 보고 싶은 시스템을 클릭하면, 시스템의 상세정보를 보여주는 화면으로 넘어간다.
- RRD 파일과 SNMP를 제어할 수 있는 wiki macro를 만들어서 시스템의 상세정보를 얻어올 수 있다. SNMP와 RRD에 대해서 이해하고 있다면, 수백라인 수준에서 간단하게 제작할 수 있다.
운용 모습
다음은 실제 개발해서 운용하고 있는 화면들이다. 일부분만 보여주고 있다.
관리중인 전체 장비목록과 기본 정보들을 보여주고 있다. snmp와 rrd 정보를 이용해서 만들었다.
장비를 클릭했을 때 보여지는 상세화면이다. 시스템 가용율, CPU정보, 인터페이스, Memory, ICMP, Mysql 정보가 보인다.
위 그림에서 이어지는 화면으로 CPU, Interface, Memory, 파일시스템의 월간 통계정보를 보여주고 있다. 짤려서 보이지 않고 있지만, 아래에는 장비에서 발생한 이벤트들의 이력 정보가 있다.
평가
wiki의 활용도는 무궁무진하다. 위키를 사용하는 많은 사용자들이 단지 문서를 관리하기 위한 목적으로 사용하고 있는데,
wiki의 특징을 이용한다면 기업자원을 관리하기 위한 용도로까지 얼마든지 확장해서 사용할 수 있도록 되어 있다. 실제 이 기능은
내가 만들고 있는 ITMS중 일부분으로 장비관리, 업무지원시스템, 사용자관리, 분산 성능측정 시스템, 자동 배포 시스템을 포함한 포괄적인 시스템으로 만들어가고 있는 중이다. 분산성능 측정 시스템이 구현이 된다면, 이것을 확장해서 Master->Slave의 JOB 배포 구조를 가지는 분산 정보 처리시스템까지를 개발할 계획이다.
이런 것까지 가능할까? 라고 생각할 수 있겠지만. 가능하다. 필요한건 idea이다. 나머지는 위키가 알아서 해결해준다. :::

1 IT 모니터링
요즘엔 시스템, 네트워크 모니터링 이란 용어대신 IT 모니터링이란 말이 오르내린다. 예전과는 달리 모니터링 환경이 복잡해지고 서비스 모니터링 까지 외연이 확대됨으로써, 그 의미를 확대시킬 필요가 있기 때문으로 생각된다.
개인적으로 다른일 보다 이러한 모니터링 관련된 일을 해본경험이 좀더 많다. (ESM)통합 보안관제시스템도 만들어본적이 있고, IDC의 시스템/네트워크 관리 시스템도 만들어본 경험이 있다. 지금도 비슷한 일을 하고 있고..
이런일을 하면서 겪게되는 어려움이라는 것은 이러한 시스템을 위한 프로세스나 경험등이 정리된게 존재하지 않는다는 거다. Internet가 본격적으로 도입된게 1992년이고, 기업환경에서 컴퓨터가 주요하게 사용되었던것 까지 하면 20년 가까운 세월이 흘렀다고 생각되는데 여전히 주먹구구식으로 관리가 된다. 마땅한 툴도 없다.
사실 마땅한 문서나 툴이 없는건 아니긴 하다. 매우 훌륭한 문서와 IT 모니터링을 위한 철학들이 잘 구현되어 있는 툴들이 있긴
하다. 그러나 이런류의 일은 기업의 인프라를 관리하는 것으로, 오랜시간 고민을 하면서 구축해 나가야 하는데, 많은 회사들이 당장 돈이 안되며일에 자원을 투자하는 것을 안타까워 하는것 같다. 당장 돈이 안되며, 그 결과가 눈에 보이는 것도 아니니 빨리 빨리가 체질화된 우리나라 IT기업들에 있어서 필요성이 그다지 느껴지지 않아 보이는거 같기도 하고.
그러다보니, IT 모니터링 시스템 구축하는 것은 사이드 잡형태로 주어지는 경우가 많고 MRTG와 RRD, SNMP등을 가지고 간단하고 빠르게 만들어서 사용하는게 대부분이다.
2 최근의 분위기
다행히 분위기가 조금씩 바뀌고 있다. 아직은 초기단계이지만 플렛폼위에서 서비스를 계획하는 회사가 많아진게 이유인거 같다. 다수의
컴퓨터와 소프트웨어로 플렛폼이 구성되고, 그 위에서 서비스가 유기적으로 돌아가는 환경이기에, 그 필요성을 느끼고 있는것으로
보인다.
3 Zenoss
최근에 관심을 가지고 있는 툴이 zenoss이다. zabbix와 함께 조사해보던 툴인데, 결국 zenoss를 선택했다. 기능도 기능이지만 모니터링 프로세스, 이벤트 사이클, 이벤트 관리등 IT 모니터링을 위한 필요충분 요소들이 충실하게 녹아있다는게 선택의 이유가 되었다.
zenoss에 대한 소개는 Zenoss 위키페이지를 참고하기 바란다.
4 이벤트 이력관리 시스템
하지만 zenoss는 이력관리 시스템이 빠져있다. 있기는 있는데, 발생된 이벤트에 대해서 간단히 로그만 남길 수 있는 것으로, 활용하기에는 절대적으로 기능이 부족하다.
이벤트 이력을 관리하려면 적어도 다음의 기능은 만족시킬 수 있어야 할 것이다.
- 이벤트 이력을 남기는 건 기본
- 이벤트 분류,검색,레포트
5 Ticket 발행 시스템
어떤 이벤트를 추적하고, 이력을 나기기 위한 시스템은 여러개가 나와있다. 그중 가장 널리 사용되고 있는게 아마 trac일 거다. trac은 tciket을 발행하고 처리하는 이력을 남김으로써, 버그를 추적한다. ticket 방식은 예를들자면, 문제가 생기면, 티켓을 끊은 다음 담당자에게 티켓을 주고 나중에 티켓을 확인해서 일을 제대로 처리했는지를 검사하는 방식이다.
- 이벤트가 발생
- 레포터가 이벤트를 받는다.
- 이벤트의 내역을 적은 티켓을 생성한다.
- 티켓을 담당자에게 끊어준다.
- 티켓을 받은 담당자는 내용을 읽고 이벤트를 해결한다.
- 담당자는 이벤트 해결과정을 이력으로 남긴다.
- 처리가 끝났다면, 레포터에게 티켓과 이력서를 넘겨준다.
- 레포터는 처리내용을 확인하고, 이벤트처리건을 종료할지를 결정한다.
매우 직관적이고, 이해하기 쉽다는 장점으로 대부분의 이벤트 추적 시스템이 Ticket 발행/처리 방식을 사용하고 있다.
6 이벤트 이력관리와 wiki
남겨진 이벤트 이력은 쉽게 분류/검색 되며, 레포팅 될 수 있어야 한다. 시스템 관리를 예로 들어보자. 이벤트를 발생시킨 문제는
중복되거나 약간 형태를 달리해서 발생하는 경우가 대부분이다. 때문에 이벤트 이력은 지식베이스화 될 필요가 있다. 이렇게 될경우
많은 수의 중복된 문제에 대해서 쉽게 원인을 찾아서 대처할 수 있으며, IT 자원의 사용 품질을 높일 수 있을 것이다.
단언컨데, wiki는 지식베이스 구축을
위한 최적의 환경을 지원하고 있다. wiki는 효율적인 공동작업이 가능하게 도와주며, 이 모든 과정을 쉽게 문서로 남길 수
있다. 또한 다른 위키의 다른 문서들과 쉽게 링크될 수 있다. 검색환경도 비교적 쉽게 구현할 수 있으며, 쉽게 확장할 수 있다는
장점도 가진다.
trac이 ticket와 wiki기반으로 작성된건 우연이 아니다.
7 zenoss + Ticket + wiki
그래서 Ticket + wiki를 이용해서 이력관리 시스템을 구축하기로 했다. 대략적인 프로세스는 다음과 같다.
- zenoss 에서 이벤트가 발생한다.
- zenoss는 이벤트에 대한 처리 프로그램을 정의할 수 있는데, Ticket을 생성하는 wikipage를 호출하는
프로그램을 작성한다. 이 프로그램(이하 sendticket)은 HTTP/GET 방식으로 wikipage를 호출한다.
- 호출 받은 wikipage는 GET으로 넘어온 값을 이요해서 ticket를 생성한다.
- 이하 ticket은 일반적인 ticket 처리 프로세스를 따라서 처리하도록 한다.
ticket 처리 프로세스는 trac의 ticket 프로세스를 분석하면 어렵지 않게 구현할 수 있을 것이다.
zenoss 와 Ticket을 연결시키기 위한 키는 zenoss event의 event id로 하면 될 것이다. 각 ticket는 event id를 이름으로 가지는 wikipage 형태로 만들면 쉽게 연동할 수 있을 것이다.
DB에는 Event의 Meta 정보가 들어가고, File에 이벤트 처리에 대한 상세 내용이 들어간다.
TicketMake =========== exec HTTP/GET zenoss Event --> Event Command -------> sendticket ----------> wikipage --> DB
TicketView ========== DB | wikipage <-----> FireFox File | | |
8 wiki의 선택
wiki는 moniwiki를 선택하기로 했다. 이유는 다음과 같다.
- 순수 php로 구현되어 있다.
- plugin 제작을 통한 확장이 매우 쉽다.
- ticket 처리를 위한 plugin을 작성하면 된다.
- moniwiki의 매크로 시스템에 익숙하다. 역시 개인적인 이유다.
다음은 moniwiki 매크로를 통해서 Event Ticket를 처리하는 과정을 보여준다. 완성된 시스템이 아니기 때문에 스크린샷으로 대신한다.
9 지식기반 시스템을 위한 추가 요구사항들
위키와 Ticket을 이용하면, 위키 특유의 용이한 공동작업기능과 디렉토리 구성을 통해서 체계적으로 이벤트이력을 관리할 수 있을 것이다. 이제 생각해야 하는건 검색이다.
9.1 Tag의 활용
위의 스크린샷을 보면 TAG 부분이 있다. TAG를 이용하면, 현재 이슈가 되는 문제를 짐작할 수 있고, 관련된 정보를 신속하게
찾아낼 수 있을 것이다. 여러개의 서비스를 위해서 시스템이 분산되어 있을 경우 특히 도움이 될 것이다.
9.2 전용검색엔진 : TAG
검색엔진을 어떻게 구현할 것인가는 선택해야될 문제가 있다. 쉽게 구현하고자 한다면, TAG 클라우드에서의 검색이 있을 수 있을
것이다. 일반적으로 TAG는 카테고리에 비교해서 가볍게 사용할 수 있다는 장점을 가지지만, 체계적으로 정리하기가 매우 힘들다는
단점을 가진다. 병합, 분리도 수월하지 않다. 또한 TAG가 제대로 힘을 발휘할려면, 클라이언트가 똑똑하게 TAG를 사용해야
한다는 점도 부담으로 작용한다.
그러나 특수한 목적을 가지는 정보들만 수집된 영역이라면, 몇가지 사항을 제한함으로써, 이 문제를 해결할 수 있다.
일단 TAG 검색은 전형적인 rtree 자료구조를 가진다고 볼 수 있다. 그렇다면 Merg Sort를
이용하는 것으로 비교접 쉽게 문서를 검색해 낼 수 있을 것이다. 남은 문제는 문서에 사용할 Ranking 알고리즘의 설계다.
가장 손쉬운 방법은 Ticket을 처리하는 담당자가 직접 해당 문서의 중요도를 결정하게 하는 방식이다. 일반적인 인터넷 서비스에
이를 적용할경우 당장 SEO의 타겟이 되어서, 쓸모가 없어지게 되겠지만 내부데이터로 한정할 경우 어느정도 믿을 수 있는 수준에서 랭킹을 할당할 수 있을 것이다.
이 정도면 문서의 Score를 계산해내는건 큰 문제가 되지 않을 것이다.
9.3 전용검색엔진 : Full Text
우선 이러한 이력관리 시스템에, 상당히 무거운 검색엔진을 사용할 필요가 있는지에 대한 고민이 필요하다. TAG만으로 충분히 원하는 정보를 검색해 낼 수 있다면, 굳이 설치할 필요는 없을 것이기 때문이다.
이에 대한 결정은 뒤로 미루기로 하겠다. 우선 TAG를 이용한 검색시스템을 구현하고, 상황을 보아가면서 적용시킬 것인지를 생각해보도록 하겠다. :::

이 문서는 수정될 수 있습니다. 최신 문서는 Joinc Wiki에서 확인하세요.
책을 구입하기 까지
2007년 8월 18일 토요일 코엑스 반디엔 루인스에 들렀다. 딱히 책을 구입할 목적으로 간건아니다. 한 3년전 부터인가는
소프트웨어 관려된 책을 구입해본적이 없었기 때문이다. 그 전에는 책 수집하는 기분으로 이것 저것 사들이고는 했었다. 거기에는
정보를 늦게 얻게 되면, 뒤쳐질지도 모른다는 약간의 강박관념 비슷한 것도 자리잡고 있었으리라 생각된다.
그러다가 어차피 책을 읽지 않을 바에는 책을 사봤자 아무런 의미가 없다는 것과 모든 소개되는 기술들을 알아야 할필요도 없다는거,
어차피 95%의 기술은 버려진다는 것을 알게된 뒤로는 반드시 필요한 책만 사기로 마음을 먹게 되었다. 게다가 인터넷을 통해서
쉽게 원하는 정보를 얻을 수 있다는 것까지, 이런 저런 이유가 복합적으로 작용해서 책을 구입하지 않게된 이유가 된거 같다.
거기에 왠만해서는 잘 변하지 않는 (매우 보수적인) 유닉스 시스템/네트워크 프로그래밍 관련된 일을 하다보니, 더더욱 책을 살 필요성을 느끼지 못했던거 같다. 이들 기술은 10년전이나 지금이나 별로 달라진게 없다.
오히려 평소에 많은 관심을 가지고 있던, 자연과학 관련 책들을 주로 구입해서 보았다.
어쨋든 소프트웨어 관련 책을 살 생각은 전혀 없었지만, 간김에 이것 저것 둘러보다가 소프트웨어 아키텍처 이론과 실제라는 책이 눈에 들어오는 거였다. 예전같으면 그냥 지나쳤겠지만, 얼마전에 구입한 건축이 된 그림, 그림이된 건축이라는 책을 통해서 아키텍처(이 책에서 설명하는 아키텍처는 건물에 대한 아키텍처이다)에 관심을 가졌던 터라, 4만원의 거금을 주고 구입하게 되었다. 건축물에서의 아키텍처나 소프트웨어 아키텍처나 뭐 거기서 거기 아니겠는가 !?
이제 공부한 내용을 정리해 보려고 한다. 한장씩 읽고 그에 대한 요약과 그동안의 개발경험에 따라서 책의 내용을 재해석한 내용으로 채워보려고 한다.
아키텍처의 개요
아키텍처는 건축물에서 유래가 되었다. 16세기 르네상스 시대를 거치면서, 건축물에 대한 미적/수학적/산업적 가치에 대한 눈을 뜨면서 부터다. 그전에 건축관련 설계등을 하던 사람들은 길드에 소속되어서 일당을 받고 일을 처리하는 기능공으로써의 대우를 받았을 뿐이다. 16세기에 이르러서야 이들을 architecture라고 부르게 된다. architecture의 어원은 arkhitekon 이다. 아키텍처의 어원에 대한 자세한 내용은 아키텍처의 유래문서를 읽어보기 바란다.
소프트웨어 아키텍처
아키텍처는 기술,비지니스,문화,산업 환경을 아우르는 것으로 서로가 서로에게 영향을 끼친다.
아키텍처에는 넓은 범위를 포괄하므로 다양하며 충돌되는 이해관계자의 요구에서 최선의 해를 찾는 능력이 요구된다. 이해관계자에는 개발조직, 마케팅, 사용자, 유지보수, 고객등이 포진해 있으며, 몇몇 관계자는 전혀다른 요구사항을 내놓는다. 혹은 아키텍처 자신의 요구와 충돌 될 수도 있다.
개발조직과의 관계
여기 한명의 아키텍트가 있다. 이 아키텍트는 서버/클라이언트 환경보다는 RPC응용과 같은 묵시적인 호출을 이용한 아키텍처를
이용해서 프로젝트를 성공한 경험이 있다면, 다음 프로젝트에도 비슷한 아키텍처를 수립하려고 할 것이다. 만약 아키텍처가 유닉스환경을 선호한다면, 유닉스환경과 분산객체처리와 관련된 경험이 있는 개발원으로 개발조직을 꾸려나가길 원할 것이다.
만약 만들어져 있는 개발조직이 서버/클라이언트 환경을 선호한다면, 충돌이 불가피할 것이다. 분명히 아키텍트는 경험이 없는
서버/클라이언트 환경하에서의 수립을 달가워하지 않을 것이다. 위험부담이 있기 때문이다. 결국 아키텍처는 개발조직을 설득해야
할것이다. 최악의 경우에는 설득당해서 서버/클라이언트 환경으로 아키텍처를 수립해야 한다.
이 경우는 그나마 양호하다. 만약 개발조직이 윈도우즈 환경에 익숙하다면, 아키텍처를 수립하는데 더 큰 어려움을 겪게 될 것이다.
이러한 문제가 발생하지 않기 위해서, 아키텍트는 다양한 개발환경에 대한 풍부한 경험을 가지고 있어야 할 것이다. 혹은 개발조직을
그렇게 만들 수 있는 권한을 가지고 있어야 할 것이다. 가자 좋은 상황은 풍부한 경험과 권한 모든것을 가진 경우가 될 것이다.
이러한 경험과 권한외에도 현재 산업의 기술적인 환경이 아키텍처의 수립에 영향을 끼친다. 웹서비스를 제작한다고 하면, (국내환경의 경우)2년전만 해도 아키텍처의 수립시 웹표준을 심각하게 고려할 필요는 없었다. 그러나 Web2.0(:12)과 표준을 무기로한 글로벌 기업이 시장에 진입하면서 지금은 웹서비스를 위한 아키텍처에서 웹표준은 중요한 고려사항이 되고 있다.
마찬가지로 과거에는 웹서비스에서의 미들웨어, 플랫폼 적용등이 중요한 요소가 아니였지만 Ajax와 이를 이용한 MashUp 서비스의 등장으로 웹기반에서의 미들웨어, 플랫폼이 필수 고려사항이 되고 있다.
다른 이해관계자와 개발조직과의 관계
아키텍처는 유독 개발조직과 다른 이해관계자들 사이에서 발생하는 충돌을 잘 조절해서 아키텍처를 수립할 필요가 있다.
- 마케터는 빠른시간에 완벽한 기능을 가진 제품이 나오길 원한다.
- 개발시간이 단축되면 제품의 품질이 떨어진다.
- 고객의 다양한 요구에 모두 대응할 수 있는 유연한 제품을 만들길 원한다.
- 그럴 경우 개발기간이 길어지기 때문에, 개발조직은 고객의 요구를 한정시키길 원한다.
- 마케터는 인공지능을 가진 제품을 원한다. 대게가 이론적으로는 가능하다.
- 그러나 개발조직은 시스템과 기술적인 한계와 시간의 부족함을 느낀다.
결국 아키텍트는 모든 이해관계자의 환경과 요구사항을 분석해내야지만, 훌륭한 아키텍처를 수립할 수 있다.
아키텍처 수립활동
아키텍처의 수립을 위한 활동요소에는 다음과 같은 것들이 있다.
- 비지니스 기회 창출
- 요구사항 이해
- 아키텍처의 선택 혹은 수립
- 아키텍처 문서화 의사소통
- 아키텍처 분석과 평가
- 아키텍처 기반시스템 개발
- 아키텍처 준수 여부 확인
위의 활동요소는 아키텍처의 수준이 아니더라도 마케팅 프로세스 혹은 개발 프로세스 수준에도 통용될 수 있는 사항들이다.
필자는 인터넷 플랫폼의 품질의 보증을 위한 QOS 시스템을 구축하고 있다. 위의 아키텍처 수립활동에 따른다면 다음과 같이 QOS 아키텍처의 수립을 진행할 수 있을 것이다.
- 비지니스 기회 창출
QOS 시스템은 현재의 서비스 품질과 분석가능한 데이터를 이용해서 미래의 서비스를 예측할 수 있도록 만들어져야 할 것이다.
- 요구사항 이해
요구사항은 단기/중,장기로 나눌 수 있을 것이다. 단기적으로는 현재의 플랫폼의 신뢰성을 확보할 수 있는 모니터링과 관련된 요구사항들이다. 중,장기 적으로 간다면 서비스와 네트워크 그리고 시스템 정보를 분석해서 서비스의 품질을 예측하고 서비스 정책결정을 하는데 도움을 줄 수 있는 분석/예측 시스템을 제공할 수 있어야 한다.
- 아키텍처의 선택과 수립
QOS는 EMS와 비슷한 활동이 될 수 있으며, 몇개의 아키텍처와 아키텍처가 구현되어 있는 제품 - Zenoss와 같은 - 을 찾아낼 수도 있다. 그렇다면 기존의 아키텍처중 어느 것을 선택할 것인지를 결정해야 한다. 만약 기존의 아키텍처중 만족할 만한 것이 없다면, 새로 수립해야 할 것이다.
아키텍처를 선택했다고 해서 끝나는 것이 아니다. 아키텍처가 이해된 모든 요구사항을 만족하는 경우는 없기 때문에, 선택한 아키텍처를 다시 분석하고 재구성하는 활동을 해야 한다. 예로든 Zenoss의 경우는 분산 모니터링 요소가 아키텍처에 포함되어 있지 않다. 또한 분석/예측과 관련된 요소도 포함되어 있지 않다. 이들 요소를 포함할 수 있도록 아키텍처를 수정해야 할 것이다.
- 아키텍처 문서화 의사소통
QOS 시스템의 가질 수 있는 가장 큰 문제점은 막상 만들어 놨는데 사용하지 않는것이다. 힘들게 모니터링 환경을 구축해놨더니, 전혀 사용하지 않거나 극히 일부만 사용하는 경우를 흔히 찾아볼 수 있다. 그러므로 필요한 사항들을 문서화 해두고 이를 이용해서 이해당사자들과 꾸준히 의사소통을 해야 한다.
- 아키텍처 분석과 평가
선택된 아키텍처가 합리적인 것인지를 평가할 수 있어야 한다. 품질요소와 시나리오를 통한 평가라든지, ATAM, CBAM 등의 평가 결정방법이 있다고 한다. 이것은 나중에...
- 아키텍처 기반 시스템 개발
개발조직과 관련된 영역이다. 입출력 데이터, 시스템 환경등을 명확히 이해하고 구축할 수 있어야 한다. 많은 시간을 개발자와 협업하면서 명확한 시스템이 될 수 있도록 해야 한다.
- 아키텍처 준수 여부 확인
프로젝트가 진행되다 보면, 시간, 개발능력 기타 여러가지 이유로 아키텍처 정책을 따르지 않는 경우가 발생한다. 예를 들어 시스템의 이벤트 처리를 snmp trap을 이용하기로 결정했다고 가정해 보자. 만약 개발자가 snmp에 대한 충분한 이해를 하지 않고 있을 경우, snmp 대신 사용하기 편리한 syslog를
대신 사용할 수 있을 것이다. 당장 기능을 구현하는데에는 문제가 없겠지만, 분산 모니터링 환경을 위해서 이벤트를 OID로
통합하고, 이를 잉요해서 계층적 Event Class를 만들도록 계획했다면 구현막바지에 분명히 문제가 발생할 것이다.
좋은 아키텍처
최고의 아키텍처는 존재하지 않는다. 최선이라고 생각되는 아키텍처가 존재할 뿐이다. 어떤 제품은 성능을 우선시 할 수 있다. 이런
제품에 3Tier 클라이언트/서버 아키텍처는 적합하지 않다. 3Tier 클라이언트 / 서버 아키텍처는 유연하고 확장성이 용이한,
그렇지만 성능은 그다지 중요하지 않은 엔터프라이즈 환경에 적합한 아키텍쳐다.
그렇지만 좋은 아키텍처를 위한 일반적인 권고사항들은 있다.
- 아키텍트는 소수의 그룹으로 유지되어야 한다.
- 이해관계자의 요구사항을 수집 분석해야 하고, 이들 요구사항에 대한 우선순위를 정해야 한다.
- 아키텍처의 모든 내용은 이해관계자가 쉽게 이해할 수 있도록 문서화 되어야 한다.
- 현재 만들고 있는 QOS 시스템은 이러한 문서화가 부실한 것으로 생각된다. 내일부터 제대로된 문서를 만들어야 할거 같다.
- 아키텍처와 관련된 내용은 협업차원에서 이해관계자에게 배포되어야 한다.
- 성능, 확장성, 운용성등과 같은 것들은 수치로 정량화 될 수 있어야 한다.
- 일반적으로 좋은 아키텍처는 최소한의 기능을 포함하도록 하고, 후에 유연하게 다른 기능들을 포함시킬 수 있는 방향으로 설계될 필요가 있다.
- 소프트웨어개발은 한정된 시간과 자원을 가지고 이루어진다. 그러므로 이들 사이에 균형을 맞출 필요가 있다. 얼마만큼의 네트워크 자원을 소비하는지, 얼마만큼의 CPU 혹은 메모리 자원을 소모할지를 예상할 수 있어야 한다.
:::

1 소개
QOS와 관련된 내용들을 다룬다. 개론적인 내용은 인터넷을 통해 어렵지 않게 찾아볼 수 있으나, 기술적인 내용은 찾아보기 힘든것
같다. QOS에 대한 기술적인 내용까지 다루려고 한다. 다음과 같은 내용들을 주로 다루게 될 것이다.
- SMS(시스템 관리)
- NMS(네트워크 관리)
- SMS, NMS를 위한 각종 툴
- Traffic control을 위한 기술적인 내용
- 보안
- QOS
- EcoSystem
- 주요 웹서비스 애플리케이션에 대한 품질 모니터링
2 QOS 소개
서비스의 품질을 향상시키기 위한 방법을 뜻한다. 일반적으로 QOS는 IP에서 서비스별 flow 흐름을 제어하는 것으로 알려지고 있다. 여기에서의 QOS는 인터넷 서비스 혹은 인터넷 플랫폼에서의 QOS를 의미한다.
3 인터넷 서비스를 위한 QOS
인터넷 서비스에서의 QOS는 이미 오래전부터 시행해오고 있었다. 서비스를 이루는 서버들의 SMS(시스템 정보), NMS(네트워크 정보)등을 이용해서, 서비스가 원할히 운영될 수 있더록 정보를 수집하는 것이 주요한 일이었다.
넓은 의미로 보자면, 시스템/네트워크 보안, 트래픽 관리까지를 아우르고, 여기에서 얻은 정보로 서비스에 대한 의사결정까지 가능한 정보를 주는 것을 QOS라 할 수 있겠지만 포탈 수준에서 이루어지는 대규모의 인터넷 서비스를 제외하고는 관리정보만 주는게 일반적이였다.
4 인터넷 플랫폼을 위한 QOS
4.1 인터넷 플랫폼의 등장
그러다가 web2.0(:12)이 등장하게 된다. web2.0은 팀 오라일리-O'Reilly-에 의해서 소개된 개념으로, 차세대 웹환경을 기술하고 있다. 이러한 요소들 중 하나가 인터넷 서비스에서 인터넷 플랫폼으로의 전환이다.
기존의 인터넷
서비스는 시스템위에서 작동이 되었다. 이 시스템은 회사가 전적으로 제어가능했으며, 서비스를 위한 소프트웨어, 데이터, 인터넷
자원 등을 포함하고 있었다. 인터넷 서비스는 기본적으로 독립된 하나의 점포로써의 기능을 수행했다. 포탈이라는 좀더 큰규모의
서비스가 이루어지기도 했지만, 포탈 역시 CP로 불리우는 인터넷 서비스 제공업자를 하나의 도메인에 모은 것에 지나지 않았다.
혹은 다른 서비스로 보내는 역할을 하는게 포탈 이었다.
오라일리는 인터넷 서비스의 단계를 지나서 인터넷 플랫폼의 시대가 올 것으로 예상을 했으며, 실제 적중 했다. 이제 인터넷 기업은 서비스를 제공하는 대신에, 플랫폼을 제공하게 되었다. 플랫폼을 이루는 요소는 다음과 같다.
- 가상 파일 시스템
- 거대 정보
- 분산 처리 시스템
- 검색 엔진
그리고 OPEN API를 제공함으로써, 이들 플랫폼의 자원을 누구나사용할 수 있게 만들었다. 즉 인터넷 기업은 플랫폼 자원만을 제공하고, 실제 서비스를 일반유저들이 만들도록 한것이다.
인터넷 플랫폼의 개념은 간단해 보이지만, 웹환경을 혁신 시켰다. google, eBay, Amazon 등, 현재 인터넷을 이끌어가는 기업들은 모두 인터넷 플랫폼을 제공하고 있다. Amazon의 경우에는 사용자 정보, 도서정보, 추천정보, 결재 시스템, 배송시스템과 이들의 정보를 처리하기 위한 정보처리 시스템으로 이루어진 플랫폼을 제공하고, 일반유저가 플랫폼의 자원에 접근할 수 있도록 Open API를 제공했다.
이제 인터넷 사용자는 사용자인 동시에, 서비스 제공자가 될 수 있다. 사용자는 아무런 자원없이도 Amazon의 방대한 데이터를 이용해서 간단하게 자신의 사이트에 온라인 서점을
개설할 수 있게 되었다. 일종의 온라인 분점이 생겨난 것이다. 이 온라인 분점에서 생겨난 이익은 Amazon과 나눠 가지게
된다. 실제 Amazon이 벌어들이는 금액의 거의 60%정도를 이들 서비스 분점에서 벌어들이고 있다. eBay 역시
Amazon과 마찬가지로 누구나 경매 서비스를 할 수 있도록 하고 있으며, google는 자신의 검색엔진과 색인정보, 데이터 처리기술에 접근할 수 있는 API를 유저에게 제공함으로써, 애드센스와 같은 광고서비스가 가능하도록 하고 있다.
4.2 QOS의 재조명
인터넷 플랫폼은 그 복잡성 때문에, 인터넷 서비스와는 다른 수준의 QOS를 요구하고 있다. 실제 인터넷 플랫폼에서의 QOS 문제는 서비스때와는 달리 심각해질 수 있기 때문이다.
구글의 경우 Ajax Search API를
이용해서, 누구든지 간단하게 자신만의 검색서비스를 구축할 수 있도록 하고 있다. 만약 검색플랫폼에 문제가 생겨서, 서비스 호출에
제대로 반응하지 못하면 어떤일이 벌어지게 될까. 실제 이런일이 벌어졌었는데, 거의 하루 동안 구글검색창을 달고 있던 페이지
자체가 로딩안되는 사건이 있었다. 필자역시 이런일을 겪었었고, 어쩔 수 없이 구글 검색창을 주석처리해서 서비스했던 적이있다.
구글의 경우에는 이런류의 Open 검색시장에서 독점적인 데다가 초기라서 유저가 그나마 눈감아 줬었지만, 만약 경쟁체제에 놓여있었다면 회사의 이미지, 신뢰도, 영향력에서 엄청난 비용을 지불해야 했었을 것이다.
인터넷 서비스였다면, 그냥 2중화 시키면 끝이다. 최악의 경우에라도 한 10분정도 서비스 중지시키고 리붓시키면 되며, 문제는 서비스 영역으로 방문하는 유저에게만 인지할 수 있었을 것이다.
이때문에 QOS의 중요성과 활용범위가 재조명되고 있다.
5 EcoSystem
지금까지의 인터넷 플렛폼 에서의 QOS의 필요성에 대해서 간단히 언급해 보았다. 여기에서는 Eco System과 함께 좀더 폭넓게 다루어보도록 하겠다.
5.1 EcoSystem에 대해서
EcoSystem 은 생태계를 의미한다. 생태계는 크게 3가지 요소로 이루어진다.
- 토양 : 생태계에 필요한 양분을 제공한다.
- 객체 : 식물, 동물등 토양의 에너지를 이용해서 살아나가는 객체
- 먹이사슬 : 에너지가 이동하는 순환과정
단순히 3가지의 요소로 이루어질 뿐이지만, 이 3가지 요소는 매우 복잡한 생태계를 만들어내며, 이들이 어떻게 균형을 이루느냐에
따라서 건전한 생태계, 그렇지 않은 생태계, 사막, 오아시스, 열대우림 등등등 다양한 생태계가 만들어진다.
또한 생태계에 대한 많은 연구가 진행되고 있기도 하다. 최근들어 이러한 생태계에 대한 고찰을 컴퓨팅 환경에도 적용시키려는 시도가
이루어지고 있다. 사실은 꽤 오래전부터 진행되고 있었으나, EcoSystem을 적용시킬 만큼 컴퓨팅 환경이 복잡하지는 않았기
때문에, 그리 부각 되지 않았었다.
그러다가 지구규모의 네트워크와 지구규모의 데어터를 다루어야 하는 Web2.0 시대가 되면서, 네트워크 컴퓨팅 환경에서의 EcoSystem이 주목받게 되었다.
5.2 플랫폼에서의 Eco System
Web2.0으로 넘어오면서 플랫폼을 가지느냐 그렇지 않느냐가 기업생존에 중요한 요인이 되면서, 플랫폼을 관리해야할 필요성을 가지게 된다.
플랫폼에서의 Eco System도 생태계와 매우 비슷한 요소들로 구성된다. - 이하 Eco System은 플랫폼에서의 Eco System -
- Data
EcoSystem의 양분으로 토양의 역할을 한다. 건강하고 다양한 EcoSystem을 만들기 위해서는 토양이라고 할 수 있는,
양질의 데이터가 충분히 존재하고 있어야 한다. 각 포탈들이 양질의 데이터를 확보하기 위해서 기를 쓰는 이유이기도 하다.
- Service
Data를 양분으로 해서 Service가 만들어진다. 기존 웹서비스
시대의 서비스와 틀린점이라면, 기업이 자신의 서비스를 직접제어했었다면 플랫폼 기반에서는 User Service와 기업이 만든
Service와의 차이점이 없다는 것이다. 일반 유저도 MashUp, OpenAPI, OpenID 등을 이용해서 Data를 직접
Access해서 Service를 만들 수 있다.
- flow
EcoSystem에서 Data와 Service의 이동은 flow를 통해서 이루어진다. traffic이다. 생태계관점에서 보자면 먹이사슬을 위한 에너지의 순환이 가능하도록 해주는 요소다.
5.3 EcoSystem 과 QOS
EcoSystem이 만들어지는 최종 목적은 신뢰성, 견고함을 가진 양질의 서비스를 제공하기 위함이다. QoS는 튼튼하고 다양한 EcoSystem을 만드는게 그 목적이라고 할 수 있다.
EcoSystem은 자체적으로 복잡성을 가지고 있다. 이러한 복잡성을 관리하고 예측하는 것은 매우 힘든일이 될 수 있다. 어떤 Mashup 서비스를 만든다고 가정을 해보자. 이 서비스가 추가되었을때, 생태계(EcoSystem)에 끼치는 영향을 예측할 수 있어야 한다. 추가된 서비스로 인하여 EcoSystem에 무리가 온다면, 다른 서비스들의 품질까지 떨어질 수 있을 것이다. 또한 EcoSystem이 건전하게 운용되기 위해서는 위험징후를 미리 판단해서, 위험요소를 없애야 할 것이다.
QOS는 Eco System의 복잡성을 관리하고, 예측하며, 위험징후를 찾아내어서 양질의 서비스가 가능하도록 하는 복합적인 프로세스다.
6 QOS의 관리 요소
EcoSystem의 관점에서 QOS를 위해서는 다음과 같은 관리 요소가 있을 것이다.
- System health
EcoSystem을 이루는 객체는 Service다. 일차적으로 이들 서비스의 health가 관리될 필요가 있다. 자연 생태계관리에 있어서 가장 우선시 되는 것 중에 하나가 계를 이루는 동/식물의 건강을 체크하는 것과 마찬가지다.
이러한 행위는 SMS차원에서 기존에도 행해지고 있다. 이것을 Eco System에 맞도록 최적화/확장 시켜야 할 것이다.
- flow (traffic)
Eco System에 새로운 서비스가 추가되면, System 전체에 크건 작건간에 변화를 가져오게 된다. 이러한 변화는 서비스들간의 에너지의 흐름 즉 traffic의 변화로 나타난다.
간단히 생각하자면 NMS라고 볼 수도 있지만, 주로 SNMP에 의존하는 NMS와는 차원이 다르다.
서비스들간의 트래픽 흐름, 서비스의 트래픽 변화 추이, 트래픽의 변화에 따른 연결시간, 응답시간의 변화, 분산시스템이 작동중이다라면, 트래픽이 제대로 분산되고 있는지 등등의 한단계 높은 정보들이 필요로 된다.
- 보안
생태계를 위협할 수 있는 여러 요소들이 있다. 가능하면 문제가 발생하기 전에, 징후를 감지해 낼 수 있는 시스템이 구축되어 있어야 한다. 문제가 발생했다면, 문제원인을 최대한 빨리 찾아내어서, 해결할 수 있어야 한다.
예를들어서 검색서비스를 한다면, 검색서비스의 Qos는 다음과 같은 요소들이 상태를 체크할 수 있어야 상태를 파악하고 계획을 세울 수 있다.
- Client와 웹서버 간의 응답시간, 응답성공률, 가동율, 트래픽의 갑작스런 증감
- 웹서버와 검색시스템 간의 응답시간, 응답성공률
- 검색시스템 내에서의 트래픽 흐름
- 분산검색 시스템이라면, 제대로 분산이 이루어지고 있는지
- 시간지연이 발생한다면 어느 부분에서 발생하는지
- 각 장비들의 상태 : CPU, MEMORY, PROCESS, Disk Usage, Disk IO, Interface In/Out Error, Drop, Cols...
- Client의 Traffic 증감에 따른 검색시스템의 변화
- 가장 기본은 웹서버와 검색시스템이 작동하고 있는지 확인하는 것이다.
- Traffic 분석을 통한 확인
- 서비스 체크 프로그램을 이용한 확인 : 예전부터 간단하게 사용되었던 방법이다. 체크 프로그램을 탑재한 별도의 프로그램을
둔다음 해당 서비스에 직접 연결해서 결과를 확인하는 방법이다. 실제 유저입장에서의 서비스 상황을 확인할 수는 없지만, 간단하게
사용할 수 있다.
- 위의 2가지 방법을 함께 사용할 수 있을 것이다.
7 기술적인 측면
yundream이 다룰 수 있는 범위를 초과하기 때문에, 윈도우즈 환경은 고려하지 않도록 하겠다. 리눅스 환경을 기준으로 설명을 할 것이다.
과거에는 강력한 몇대의 컴퓨터와 이들의 파워를 가능한 끌어낼 수 있는 운영체제가 함께 움직이는 경우가 많았다. 하지만
플랫폼기반의 EcoSystem 에서는 비교적 저렴하고 덜 강력한 다수의 컴퓨터를 이용해서 컴퓨팅 환경을 만들어나가야 한다. 많은
수의 덜 강력한 컴퓨터를 운영해야 한다면, 어느정도의 신뢰성을 가진 저렴하고 유연한 운영체제로 통일하는게 여러모로 도움이 된다.
관리해야될 컴퓨터도 많은데다가 플랫폼의 특성상 다양한 실험과 시도가 가능해야 한다. 여기에 비싼 비용을 지불해야 하며, 거기에
유연하지 못한 운영체제와 프로그램으로 구성을 하려고 했다가는 경직된 플랫폼 환경이 될 수 있다.
플랫폼 환경으로 넘어가면서 Linux운영체제를 포함한 공개소프트웨어의 위상이 크게 높아질 것으로 생각된다. Web2.0은 오픈소스를 위한 세계 참고.
7.1 시스템 Health 체크
QoS의 가장 기본이 될 것이다. EcoSystem을 이루고 있는 최소단위가 시스템이기 때문이다. 이 분야는 SMS영역으로, 꽤나 오랜역사를 가지고 있다. 그런 관계로 상당히 많은 자료들과 활용가능한 믿음직한공개 라이브러리와 프로그램들이 존재한다.
아마 가장 널리 사용되는 프로그램은 SNMP프
로토콜을 사용하는 net-snmp와 같은 공개 소프트웨어일 것이다. 오랜 역사를 가졌고, 견고한 프로그램이긴 하지만 공개
프로젝트 산물들이 그렇듯이, 범용성을 강조하다 보니 지나치게 무거우며, 소스의 양이 방대하다는 단점을 가진다. 공개소프트웨어이기
때문에, 쉽게 유지보수 할 수 있을 거라고 생각할 수 있지만 절대로 그렇지 않다. Agent의 기능을 SNMP에 전적으로
맡긴다고 하더라도, Manager를 만드는 것은 결코 쉬운일이 아니다. 여기에 플랫폼의 특수성에 의한 새로운 요구사항이 생기면,
익숙하지도 않은 방대한 양의 소스를 학습해야 하는 문제도 발생한다.
그럴바에는 어느정도의 능력을 가진 개발자를 확보해서 별도의 SMS를 만드는게 더 낳다는게 개인적인 생각이다.
리눅스 시스템의 경우 proc 파일시스템에서 워낙에 방대한 시스템 데이터를 제공하는 관계로, 리눅스 시스템에 대한 어느정도의 이해를 가지고 있다면 의외로 쉽게 SMS 시스템을 개발할 수 있다.
proc 파일시스템을 이용한 리눅스 시스템 분석은 다음의 문서들을 참고하기 바란다. net-snmp로 얻을 수 있는 이상의 정보를 얻을 수 있을 것이다.
7.2 Traffic 분석
역시 SNMP 응용 프로그램으로 처리할 수 있을 거라고 생각할 수 있을 것이다. 그러나 SNMP는 전체 트래픽의 대략적인 상황만
보여줄 수 있을 뿐으로, EcoSystem 내에서의 각 객체(서비스)간의 흐름을 보여줄수는 없다. 예를 들자면 다음과 같은
것들이다.
- 다양한 서비스들에 대한 연결시간과 응답시간
- 서비스별 트래픽의 양 (bps/pps)
- 서비스별 연결 성공률및 응답성공률
- 분산시스템이라면, 분산시스템이 이용하는 서비스들의 트래픽이 제대로 분산되고 있는지
- 새로운 MashUp 서비스가 추가되었다. 서비스 추가에 따른 트래픽 유입량, 트래픽 유입 도메인영역, EcoSystem에 미치는 영향
- 여기에 위의 정보들의 추이를 확인할 수 있어야 한다.
- 트래픽에 대한 분석이 되면, DOS, DDOS, half connection, WARM 공격과 같은 위험징후도 사전에 감지할 수 있을 것이다.
- collision 분석 - 패킷의 크기가 작아서, 실제 트래픽양은 얼마되지 않지만 계속적인 collision이 발생 -
이런 것들은 SNMP 응용으로는 불가능하다. 결국에는 트래픽을 분석하는 수 밖에 없다. 트래픽을 분석하는데에는 2가지 방법이 존재한다.
yundream은 이중 패킷을 직접 Capture 해서 분석하는 방법에 대해서 알아볼 것이다.
패킷 캡춰 라이브러리로는 유명한 libpcap이 있다. libpcap은 tcpdump와 같은 간단한 트래픽 분석도구에서 부터, snort와 같은 거대한 공개소프트웨어와 상용 IDS에서 사용하는 효율적인 패킷 캡춰 라이브러리다. 이 라이브러리를 이용해서 패킷을 캡춰한다음에, 분석하기 좋게 효과적으로 정규화 시켜서 DB에 저장할 수 있다면, 위의 예로든 모든 일들이 가능한 트래픽 분석 프로그램을 만들 수 있을 것이다.
이러한 트래픽 분석 프로그램을 만드는 것은, 그 자체가 커다란 프로젝트 이므로 여기에서는 아이디어와 가능성만을 제시하도록 하겠다. 아래는 libpcap을 이용해서 트래픽을 분석하는 방법을 담고 있는 문서들이다.
- libpcap을 이용한 프로그래밍
- libpcap을 이용한 Port Scaning 검사툴
- libpcap을 이용한 DOS 공격 검사툴
- 네트워크 트래픽 분석을 통한 connection time 얻어오기
이러한 트래픽 분석은 Switch로 묶인 특정 LAN영역 전체에 대해서 이루어져야 할 것이다. 그렇다면, 트래픽을 수집하는 시스템을 준비해야 할 것이다. 아래의 두가지 방법중 하나를 이용해서 특정 시스템으로 패킷을 보낼 수 있을 것이다.
- Mirror Port
대부분의 Switch들이 Mirror Port 기능을 지원한다. 이 기능을 이용하면, 특정 포트의 트래픽을 다른 포트로 보낼 수
있다. 간단하게 사용할 수 있지만 VLAN으로 구성되어 있는 환경에 적용하기 힘들며, 제품에 따라서 Layer7 까지를 커버하기
힘들다는 문제점이 있다. 여기에 Switch 자체의 성능을 떨어트릴수 있다는 결정적인 문제점을 가지니다.
- Network Tap
Tap 문서를 참고하기 바란다. 이 방법을 사용하는 걸 추천한다.
8 모니터링 툴
| 이름 | 제목 | 변경일 | 크기 |  | zabbix | 공개 시스템 모니터링 툴 zabbix
| 2007/07/12 16:50 | 2358 |
9 DB 관리 / 애플리케이션
| 이름 | 제목 | 변경일 | 크기 |  | Mysql | Mysql 품질 관리 - Alive 체크
| 2007/07/23 09:38 | 4570 |  | Mysql_Admin | Mysql 품질관리 : Admin 정보
| 2007/07/25 22:32 | 5352 |
10 시스템 관리
:::

소개
확장성을 확보하기 위한 방법은 여러가지가 있을 것이다. 여기에서는 그중 PlugIn 방식을 이용한 확장성확보에 대한 내용을 다룰 것이다.
Agent&Manager 방식의 프로그램을 만든다고 가정해보자. SNMP 프로토콜을 응용한 Net SNMP가 가장 대표적인 경우가 될 것이다. 이왕 Net SNMP를 예로 들었으니, Agent&Manager 방식의 SMS을 만드는 것으로 가닥을 잡아보겠다.
이러한 시스템에서 Agent 프로그램을 만들려고 한다면, 설계단계에서 가장 중요하게 생각해야 할게 확장성의 확보가 될 것이다. 왜냐면 시스템 관리의
범위가 매우 넓은 관계로 필요에 따라 관리 요소가 계속 추가될 수 있기 때문이다. 당장 생각나는게, CPU, Memory,
Disk 관리쯤이 될것이다. 물론 초기에 완전하게 관리요소를 몽땅 예상하고 설계를 하는 방법도 있겠지만, 그렇게 될 경우 설계에
지나치게 많은 시간을 소비해야 할 것이다. 막상 그렇게 만들었다고 해도, 중간쯤 만들다 보면 관리요소가 새로 추가될 수도 있다.
심지어는 모두 만들고 나서 관리요소가 추가될 수도 있을 것이다.
이러한 경우 PlugIn 방식으로 각각의 성능을 모듈화 시켜서 붙이는 방식으로 개발시간을 아낄 수 있다. 거기에 덤으로 유연하고 확장성 좋은 시스템을 만들 수도 있다. 대략 다음과 같은 시스템 구성을 가지게 된다.
필요한 기술
이 문서를 읽기 위해서는 함수포인터, STL, 라이브러리를 제어하기 위한 기술들을 가지고 있어야 한다.
Dynamic Module Loading
동적으로 모듈을 로딩하는 PlugIn방식을 구현하기 위한 기본적인 기술요구 사항은 그리 복잡하지 않다. 동적라이브러리를 이용하면, 쉽게 구현할 수 있다. 이 경우 중요한 것은 모듈과 Agent와의 인터페이스를 통일하는게 될 것이다. 어떠한 기능이 모듈형태로 추가되더라도, Agent와 Manager의 소스코드 수정없이 모듈이 로딩될 수 있어야 하기 때문이다.
인터페이스 이름을 맞추는 것은 문제가 되지 않을 것이다. 문제는 인터페이스를 통해서 이동하는 데이터가 될것이다. 이는 각각의 성능마다 보여줘야 하는 정보가 다를 수 있기 때문인데, CPU의 경우라면 사용율을 Disk라면 장치명,마운트이름,사용율을 보내야 하기 때문이다. 그러므로 예상가능한 모든 종류의 데이터를 처리할 수 있는 방법이 준비되어야 한다. 이 문제는 세가지 정도의 방식으로 해결할 수 있다.
- 문자열 전송
간단하게 문자열을 전송한다. 성능=값1,값2 정도로 보내면 될 것이다. 포맷은 대략 아래와 같을 것이다. 성능이름이 들어가는 이유는, 나중에 Manager로 정보가 전달되었을때, 성능이름을 Key로 해서, 해당되는 모듈을 Plugin 방식으로 로딩하기 위함이다.
CPU=89 DSK=/dev/sda1,/root,58
- 구조체전송
구조체로도 전송이 가능하다. Agent는 데이터를 처리하지 않고, Manager로 보내기만 하면되므로, 구조체에 어떤 멤버변수들이 있는지는 알 필요가 없다. 단지 보내야 하는 구조체의 크기와 성능이름만 알고 있으면 된다. 구조체를 받은 Manager 측은 성능이름에 해당되는 Plugin 모듈을 로딩해서 구조체의 값을 처리하면 된다.
struct Info { int size; // 구조체의 크기 char id[4]; // 성능 이름 : DSK, CPU, MEM... ... // 나머지 정보들은 성능에 따라 달라질 수 있다. ... }
- XML 데이터 전송
잘 정의한다면, 유연하게 사용할 수 있을 것이다. 데이터의 크기가 커진다는 점을 고려하지 않아도 된다면, 가장 좋은 방법이라고 생각된다.
여기에서는 문자열을 보내는 것을 기준으로 설명하도록 하겠다.
Module Config
이제 설정파일을 만들어야 한다. 이 설정파일은 Key라고 할 수 있는 모듈 ID와 호출해야할 라이브러리의 이름들을 가진다. 다음과 같은 구조를 가지도록 하겠다.
[plugin] CPU=libmycpu.so MEM=libmymem.so
설정파일을 읽을 수 있는 라이브러리가 필요할 것 같아서, 급조한 코드가 있다. 간단 설정파일 Reader를 참고하기 바란다. 이 코드를 그대로 사용할 것이다.
프로시져
- 실행
- plugin 을 로딩하기 위해서 설정파일을 읽어들인다.
- plugin 목록을 읽어들인다.
- plugin 목록의 갯수만큼 루프를 돌면서, 라이브러리를 동적으로 적재한다.
- while 루프를 돌면서, 공통 인터페이스를 호출한다.
공통 인터페이스
공통 인터페이스를 정의해보도록 하자. 최대한 간단하게 정의하도록 하겠다.
- Init : 플러그인 모듈을 초기화 한다.
- Read : 플러그인 모듈로 부터, 데이터를 요청한다. 데이터는 문자열로 Key.IndexNum=Value,Value 형식으로 전달된다. IndexNum은 데이터가 2개이상일때, 사용하는 인덱스 번호다. 예를 들어 CPU가 2개라면
- RowNum : 몇개의 데이터가 있는지를 알려준다.
- Close : 플러그인 모듈을 닫는다.
테스트용 플러그인 모듈
libmycpu 와 libmysms 를 위한 모듈을 작성할 것이다. 이들은 공유라이브러리 형태로 작성될 것이다. 작성된 이들 플러그인 모듈은 dlopen(2) 함수를 이용해서 동적으로 적재 된다.
여기에서는 단순히 문자열을 리턴하는 dummy 모듈을 작성할 것이다.
플러그인 기능을 지원하는 Agent 프로그램
다음은 Agent 프로그램이다.
#include <iostream> #include <cstdlib> #include <qosconfig.h> #include <dlfcn.h> #include <vector>
using namespace std;
typedef char *(*Function)(); int main(int argc, char *argv[]) { Config *agentCfg; int rtv; char *key; char *value; void *handle; agentCfg = new Config(); Function myFunc; // 플러그인을 저장할 Vector로 함수 포인터를 원소로 가진다. vector<Function> FuncPList;
// 설정파일을 Open 한다. rtv = agentCfg->openCfg("config.cfg"); if (rtv == -1) { perror("Config Read Error"); }
// 플러그인 섹션에서 플러그인 목록을 읽어온다. if (agentCfg->findSection("PLUGIN")) { while(key = agentCfg->NextItem()) { printf("Loding Module %s:%s\n", key, agentCfg->NextValue()); // 플러그인을 로드한다. handle = dlopen(agentCfg->NextValue(), RTLD_NOW); if (!handle) { fputs(dlerror(), stderr); } else { // 공통인터페이스인 Read 함수를 함수포인터로 얻어오고 // vector에 push 한다. myFunc = (char *(*)())dlsym(handle, "Read"); FuncPList.push_back(myFunc); } } }
// 1초 간격으로 로딩된 플러그인 모듈로 부터, 데이터를 읽어온다. while(1) { for (int i = 0; i < FuncPList.size(); i++) { printf("%s",FuncPList[i]()); } printf("==============\n"); sleep(1); } return EXIT_SUCCESS; }
모듈 프로그램
이 프로그램은 dummy 프로그램으로, 공통 인터페이스 포멧에 맞는 문자열을 리턴한다.
#include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h>
char *rtvstr = NULL; int count; int Init() { rtvstr = (char *)malloc(80); count = 0; return 1; }
char *Read() { sprintf(rtvstr, "%s=%d\n", count); count++; }
int RowNum() { return 1; }
int Close() { if (rtvstr != NULL) free(rtvstr); count = 0; }
이 코드는 공유라이브러리로 컴파일을 한다. 라이브러리의 이름은 libdummy.so 로 하겠다. 공유라이브러리를 만드는 방법은 라이브러리 만들기 문서를 참고하기 바란다.
이제 아래와 같은 설정파일 만들고, 실행하면 된다.
[PLUGIN] DUMMY=libdummy.so
결론
동적라이브러리를 통한 확장가능한 프로그램을 만드는 방법에 대해서 알아보았다. 이 경우에는 데이터를 단순하게 제한했기 때문에, 비교적 손쉽게 인터페이스를 설계할 수 있었지만 실제 프로젝트에 도입해서 사용할때는 XML을 이용하거나, 데이터 처리 함수를 만들어야 하는 등, 좀더 복잡하게 구현될 수 있을 것이다. 이 문서는 수정될 수 있습니다. 최신문서는 Joinc Wiki에서. :::

이 문서는 수정될 수 있습니다. 최신글은 Joinc Wiki를 참고해 주세요.
나 같은 경우 일단 돌아가는 코드를 만들고 돌아가는지 눈으로 확인한다음 손을 보는 스타일이라서, 나중에 많은 잔손질 - 거창하게 리팩토링 -을 하게 된다. 이때 모듈화와 함께 가장먼저 손쉽게 진행할 수 있는게 경고메시지를 제거하는 것이다. 이 문서는 gcc 4.0.x 를 기준으로 작성되었다.
gcc라면 다음과 같은 옵션을 이용해서 경고메시지를 출력하도록 할 수 있다.
# gcc -Wall -c testcode.c # gcc -W -c testcode testcode.c ...
보통은 -Wall 옵션만을 사용하는 경우가 많을 것이다. 그러나 경고메시지는 다양한 영역을 가지고 있으며 -Wall 은 all이 붙은것과는 달리 그 중 일부 영역의 경고메시지만을 출력한다. 예를 들면 아래와 같이 리턴값이 명시되지 않은 경우 경고메시지를 출력한다.
int foo (unsigned int x) { int y; if (y < x) x=x+2; else x= x+1; }
-Wall 옵션을 주고 컴파일 해보자.
# gcc -Wall -c foo.c foo.c: In function `foo': foo.c:6: warning: control reaches end of non-void function
그러나 if (y < x)에서 unsigned와 signed와의 비교와 같은 경고는 잡아내지 않는 것을 알 수 있다. 결국 모든 경고메시지를 없애고 싶다면, 다양한 종류의 경고옵션을 함께 사용해야 한다.
-W
signed 와 unsigned의 비교. 조건문에서 body가 명시되지 않거나, 결코도달할 수 없는 조건문등을 찾아낼 수 있다.
아래의 코드는 컴파일되고 실행되는데 전혀 문제는 없을 것이다. 그러나 if (x < 0) 문은 결코 만족할 수 없다.
이러한 코드는 버그를 만들어낼 수 있을 것이다.
int foo (unsigned int x) { if (x < 0) return 0; // 결코 도달할 수 없다. else return 1; }
-Wall 옵션을 이용하면 경고메시지가 출력되지 않을 것이다.
# gcc -Wall -c foo.c
그러나 -W 옵션을 이용하면 다음과 같은 경고메시지가 출력되는걸 확인할 수 있다.
# gcc -W -c foo.c foo.c: In function `foo': foo.c:4: warning: comparison of unsigned expression < 0 is always false
일반적으로 -W 옵션은 -Wall 옵션과 함께 사용한다.
-Wconversion
이 옵션은 형변환(type conversion)과 관련되어서 잘못 사용된 코드에 대한 경고를 잡아낸다. floating-point와 integer, long과 short integers 사이의 형변환과 같은 것들이다. 예를 들어서 abs()는 실수형 정수에 대해서 절대값을 리턴하는 함수이다. 만약 인자로 float값을 입력한다면 원하지 않는 결과가 출력될 것이다.
#include <stdio.h> #include <stdlib.h>
int main (void) { double x = -3.14; double y = abs(x); /* fabs(x)를 사용해야 함. */ printf ("x = %g |x| = %g\n", x, y); return 0; }
-Wall 옵션을 주고 컴파일 하면, 경고메시지를 출력하지 않을 것이다. 그러나 프로그램을 실행시키면 잘못된 결과를 보여주게 된다.
# gcc -Wall -o abs abs.c # ./abs x = -3.14 |x| = 3
이제 -Wconversion 옵션을 주고 실행시켜 보자.
# gcc -Wconversion -o abs abs.c abs.c: In function ‘main’: abs.c:7: warning: passing argument 1 of ‘abs’ as integer rather than floating due to prototype
abs() 함수대신에 fabs()함수를 이용하면, 위 코드의 논리적오류를 수정할 수 있다.
이 외에도 -Wconversion 옵션은 변수에 잘못된 값을 할당하는 오류도 찾아낸다.
unsigned int x = -1;
기술적으로 ANSI/ISO C 표준은 위의 코드를 허용한다. 그러므로 대부분의 컴파일러가 에러없이 컴파일을 해준다. 그러나 코드가 제대로 작동할지는 보장할 수 없다.
-Wshadow
이것은 선언된 변수명을 다른 scope에서 다시 선언한 경우 경고를 발생시킨다. 이렇게 변수가 선언될 경우 이것을 shadowing변수라고 한다. 다음의 코드를 확인해 보도록 하자.
#include <stdio.h> double test (double x) { double y = 1.0; { double y; y = x; } return y; } int main (void) { printf("%lf\n", test(5.0)); }
2개의 scope에서 y변수가 선언되었음을 알 수 있다. 이경우 비록 이름은
같지만, scope가 다르므로 전혀다른 변수 이름 테이블을 가지게 된다. 당신이 사용하는 컴파일러가 ANSI/ISO C를
준수한다면, 1을 리턴할 것이다. shadowing 변수의 사용자체가 문제가 되는건 아니지만, 보통의 경우 실수로 사용하는
경우가 많으므로 -Wshadow 옵션을 이용해서 제거하도록 하자.
# gcc -Wshadow -o abs abs.c abs.c: In function ‘test’: abs.c:7: warning: declaration of ‘y’ shadows a previous local
-Wcast-qual
const와 같은 타입 제한자를 잘못 사용했을 경우 경고메시지를 출력한다. 아래의 코드와 같은 경우다.
#include <stdio.h>
void f (const char * str) { char * s = (char *)str; s[0] = '\0'; }
int main() { char *a = "hello World"; f(a); }
이 프로그램은 아무런 문제없이 컴파일 될 것이다. 그러나 실행시키면 segmentation fault를 출력하고 종료되어 버릴 것이다. 오히려 위의 경우는 프로그램이 죽어버림으로 즉시 문제를 찾을 수 있으니 큰 문제가 되지 않을 것이다. 다음과 같은 경우가 문제가 된다.
int main() { char a[] = "hello World"; f(a); printf("%s\n", a); }
우리가 f 함수의 인자를 const 로 한것은 str이 변경되는걸 막기 위한 목적도 가지고 있을 것이다. 그런데 위의 경우 의도하지 않게 str이 변경되어 버리게 된다. -Wcast-qual 옵션을 이용하면 이러한 문제를 사전에 예방할 수 있다.
# gcc -Wcast-qual -o f f.c f.c: In function ‘f’: f.c:5: warning: cast discards qualifiers from pointer target type
-Wtraditional
대부분의 컴파일러는 ANSI/ISO 표준을 따르지만, 좀 더 유연하게 사용할 수 있도록 확장된 부분이 있다. 이 옵션을 주면
ANSI/ISO의 표준을 엄격하게 검사하고 이에 대한 경고메시지를 출력한다. 이 기종간 호환되는 코드를 작성하고자 한다면
고려해볼만 하다.
경고메시지 제거
이제 위에 언급된 옵션을 이용해서 parse.cc를 컴파일 해보도록 하자. parse.cc는 두번의 리팩토링 과정이 끝난 코드로 리팩토링 - 모듈화문서의 코드를 사용할 것이다.
# g++ -W -Wall -Wcast-qual -Wshadow -o parse parse.cc parse.cc: In function `char* html_trim(char*, char*, int)': parse.cc:54: warning: unused variable `char specia[10]' parse.cc: In function `int main(int, char**)': parse.cc:87: warning: declaration of `lt_flag' shadows a global declaration parse.cc:22: warning: shadowed declaration is here parse.cc:83: warning: unused variable `int ridx' parse.cc:84: warning: unused variable `int widx' parse.cc:87: warning: unused variable `int lt_flag' parse.cc:96: warning: unused variable `int tag_status'
대부분 선언만 하고 사용하지 않는 변수에 관한 경고이고, shadows 변수사용에 따른 경고가 발견되었다.
다음은 경고가 발생한 부분을 모두 정리한 코드다.
#include <stdio.h> #include <sys/types.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #include <stdlib.h>
using namespace std;
const int MAX_BUF_SIZE=1024;
enum tag_token {TAG_LT = '<', TAG_GT='>'};
void help() { printf("Usage : ./parse [-h] [-f FILENAME]\n"); printf("-f : Input Source File\n"); printf("-h : This Message\n"); }
int lt_flag = 0;
char *html_trim(char *src, char *dst, int size) { int ridx = 0; int widx = 0;
while(ridx < size) { if (src[ridx] == TAG_LT) { lt_flag++; } if (src[ridx] == TAG_GT) { lt_flag--; if (lt_flag == 0) { ridx++; continue; } }
if (lt_flag == 1) { ridx++; continue; }
if(src[ridx] == '&') { unsigned int i = 0; char specia[10] = {0x00,}; for (i = 0; i < 10; i++) { if (src[ridx+i] == ';') { ridx= (ridx+i); break; } } }
if (src[ridx] == '\n' || src[ridx] =='\r') { dst[widx] = ' '; } else { dst[widx] = src[ridx]; } widx++; ridx++; } return dst; }
int main(int argc, char **argv) { int fd; int readn; int ridx; int widx; char rbuf[MAX_BUF_SIZE] = {0x00,}; char wbuf[MAX_BUF_SIZE] = {0x00,}; int lt_flag = 0; int test_argv=0; int c; char *src_file;
// used tokenizing char seps[] = "()|{}, \t.;&-[]\"\':`+#="; char *tr;
int tag_status = 0; int offset = 0;
while((c = getopt(argc, argv, "hf:")) != -1) { switch(c) { case 'h': break; case 'f': src_file = optarg; test_argv = 1; break; default: break; } }
if (!test_argv) { help(); return 1; }
if ((fd = open(src_file, O_RDONLY)) < 0) { return 1; }
while ((readn = read(fd, rbuf+offset, MAX_BUF_SIZE)) > 0) { html_trim(rbuf, wbuf, readn); tr = strtok(wbuf, seps); while (tr != NULL) { printf("%s ", tr); tr = strtok(NULL, seps); } memset(rbuf, 0x00, MAX_BUF_SIZE); memset(wbuf, 0x00, MAX_BUF_SIZE); } return 0; }
:::

|